Merge branch 'production'
authorRadek Czajka <radoslaw.czajka@nowoczesnapolska.org.pl>
Mon, 30 Aug 2010 23:56:26 +0000 (01:56 +0200)
committerRadek Czajka <radoslaw.czajka@nowoczesnapolska.org.pl>
Mon, 30 Aug 2010 23:56:26 +0000 (01:56 +0200)
374 files changed:
.gitignore
.gitmodules [new file with mode: 0644]
LICENSE [new file with mode: 0644]
NOTICE [new file with mode: 0644]
README [deleted file]
README.md [new file with mode: 0644]
apps/api/handlers.py
apps/catalogue/admin.py
apps/catalogue/fields.py
apps/catalogue/forms.py
apps/catalogue/locale/de/LC_MESSAGES/django.mo [new file with mode: 0644]
apps/catalogue/locale/de/LC_MESSAGES/django.po [new file with mode: 0644]
apps/catalogue/locale/en/LC_MESSAGES/django.mo [new file with mode: 0644]
apps/catalogue/locale/en/LC_MESSAGES/django.po [new file with mode: 0644]
apps/catalogue/locale/es/LC_MESSAGES/django.mo [new file with mode: 0644]
apps/catalogue/locale/es/LC_MESSAGES/django.po [new file with mode: 0644]
apps/catalogue/locale/fr/LC_MESSAGES/django.mo [new file with mode: 0644]
apps/catalogue/locale/fr/LC_MESSAGES/django.po [new file with mode: 0644]
apps/catalogue/locale/lt/LC_MESSAGES/django.mo [new file with mode: 0644]
apps/catalogue/locale/lt/LC_MESSAGES/django.po [new file with mode: 0644]
apps/catalogue/locale/pl/LC_MESSAGES/django.mo [new file with mode: 0644]
apps/catalogue/locale/pl/LC_MESSAGES/django.po [new file with mode: 0644]
apps/catalogue/locale/ru/LC_MESSAGES/django.mo [new file with mode: 0644]
apps/catalogue/locale/ru/LC_MESSAGES/django.po [new file with mode: 0644]
apps/catalogue/locale/uk/LC_MESSAGES/django.mo [new file with mode: 0644]
apps/catalogue/locale/uk/LC_MESSAGES/django.po [new file with mode: 0644]
apps/catalogue/management/commands/importbooks.py
apps/catalogue/migrations/0001_initial.py
apps/catalogue/migrations/0002_add_extra_info_to_book.py [deleted file]
apps/catalogue/migrations/0002_auto__add_bookstub__add_field_tag_death.py [new file with mode: 0644]
apps/catalogue/migrations/0003_add_mp3_and_ogg_files_to_book.py [deleted file]
apps/catalogue/migrations/0003_fix_book_count_on_shelves.py [new file with mode: 0644]
apps/catalogue/migrations/0004_add_gazeta_links.py [deleted file]
apps/catalogue/migrations/0004_book_html_shorts_translations.py [new file with mode: 0644]
apps/catalogue/migrations/0005_add_wiki_links.py [deleted file]
apps/catalogue/migrations/0005_fragment_html_shorts_translations.py [new file with mode: 0644]
apps/catalogue/migrations/0006_epub_tag_counters_and_ltags_descendants.py [new file with mode: 0644]
apps/catalogue/migrations/0007_remove_empty_html.py [new file with mode: 0644]
apps/catalogue/migrations/0008_unique_tag_category_slug.py [new file with mode: 0644]
apps/catalogue/migrations/0009_chg_book_count__heavy_cleaning.py [new file with mode: 0644]
apps/catalogue/migrations/0010_auto__add_filerecord.py [new file with mode: 0644]
apps/catalogue/models.py
apps/catalogue/templatetags/catalogue_tags.py
apps/catalogue/templatetags/switch_tag.py [new file with mode: 0644]
apps/catalogue/test_utils.py [new file with mode: 0644]
apps/catalogue/tests/__init__.py [new file with mode: 0644]
apps/catalogue/tests/book_import.py [new file with mode: 0644]
apps/catalogue/tests/search.py [new file with mode: 0644]
apps/catalogue/tests/tags.py [new file with mode: 0644]
apps/catalogue/tests/templatetags.py [new file with mode: 0644]
apps/catalogue/urls.py
apps/catalogue/utils.py
apps/catalogue/views.py
apps/chunks/locale/de/LC_MESSAGES/django.mo [new file with mode: 0644]
apps/chunks/locale/de/LC_MESSAGES/django.po [new file with mode: 0644]
apps/chunks/locale/en/LC_MESSAGES/django.mo [new file with mode: 0644]
apps/chunks/locale/en/LC_MESSAGES/django.po [new file with mode: 0644]
apps/chunks/locale/es/LC_MESSAGES/django.mo [new file with mode: 0644]
apps/chunks/locale/es/LC_MESSAGES/django.po [new file with mode: 0644]
apps/chunks/locale/fr/LC_MESSAGES/django.mo [new file with mode: 0644]
apps/chunks/locale/fr/LC_MESSAGES/django.po [new file with mode: 0644]
apps/chunks/locale/lt/LC_MESSAGES/django.mo [new file with mode: 0644]
apps/chunks/locale/lt/LC_MESSAGES/django.po [new file with mode: 0644]
apps/chunks/locale/pl/LC_MESSAGES/django.mo [new file with mode: 0644]
apps/chunks/locale/pl/LC_MESSAGES/django.po [new file with mode: 0644]
apps/chunks/locale/ru/LC_MESSAGES/django.mo [new file with mode: 0644]
apps/chunks/locale/ru/LC_MESSAGES/django.po [new file with mode: 0644]
apps/chunks/locale/uk/LC_MESSAGES/django.mo [new file with mode: 0644]
apps/chunks/locale/uk/LC_MESSAGES/django.po [new file with mode: 0644]
apps/chunks/models.py
apps/chunks/templatetags/chunks.py
apps/compress/filter_base.py
apps/compress/filters/csstidy/__init__.py
apps/compress/filters/csstidy_python/__init__.py
apps/compress/management/commands/synccompress.py
apps/compress/utils.py
apps/infopages/__init__.py [new file with mode: 0644]
apps/infopages/admin.py [new file with mode: 0644]
apps/infopages/fixtures/wl_data.json [new file with mode: 0644]
apps/infopages/migrations/0001_initial.py [new file with mode: 0644]
apps/infopages/migrations/__init__.py [new file with mode: 0644]
apps/infopages/models.py [new file with mode: 0644]
apps/infopages/views.py [new file with mode: 0644]
apps/lessons/admin.py
apps/lessons/locale/de/LC_MESSAGES/django.mo [new file with mode: 0644]
apps/lessons/locale/de/LC_MESSAGES/django.po [new file with mode: 0644]
apps/lessons/locale/en/LC_MESSAGES/django.mo [new file with mode: 0644]
apps/lessons/locale/en/LC_MESSAGES/django.po [new file with mode: 0644]
apps/lessons/locale/es/LC_MESSAGES/django.mo [new file with mode: 0644]
apps/lessons/locale/es/LC_MESSAGES/django.po [new file with mode: 0644]
apps/lessons/locale/fr/LC_MESSAGES/django.mo [new file with mode: 0644]
apps/lessons/locale/fr/LC_MESSAGES/django.po [new file with mode: 0644]
apps/lessons/locale/lt/LC_MESSAGES/django.mo [new file with mode: 0644]
apps/lessons/locale/lt/LC_MESSAGES/django.po [new file with mode: 0644]
apps/lessons/locale/pl/LC_MESSAGES/django.mo [new file with mode: 0644]
apps/lessons/locale/pl/LC_MESSAGES/django.po [new file with mode: 0644]
apps/lessons/locale/ru/LC_MESSAGES/django.mo [new file with mode: 0644]
apps/lessons/locale/ru/LC_MESSAGES/django.po [new file with mode: 0644]
apps/lessons/locale/uk/LC_MESSAGES/django.mo [new file with mode: 0644]
apps/lessons/locale/uk/LC_MESSAGES/django.po [new file with mode: 0644]
apps/lessons/models.py
apps/lessons/urls.py
apps/lessons/views.py
apps/modeltranslation/__init__.py [new file with mode: 0644]
apps/modeltranslation/admin.py [new file with mode: 0644]
apps/modeltranslation/fields.py [new file with mode: 0644]
apps/modeltranslation/management/__init__.py [new file with mode: 0644]
apps/modeltranslation/management/commands/__init__.py [new file with mode: 0644]
apps/modeltranslation/management/commands/update_translation_fields.py [new file with mode: 0644]
apps/modeltranslation/models.py [new file with mode: 0644]
apps/modeltranslation/tests.py [new file with mode: 0644]
apps/modeltranslation/testurls.py [new file with mode: 0644]
apps/modeltranslation/translator.py [new file with mode: 0644]
apps/modeltranslation/utils.py [new file with mode: 0644]
apps/newtagging/admin.py
apps/newtagging/locale/de/LC_MESSAGES/django.mo [new file with mode: 0644]
apps/newtagging/locale/de/LC_MESSAGES/django.po [new file with mode: 0644]
apps/newtagging/locale/en/LC_MESSAGES/django.mo [new file with mode: 0644]
apps/newtagging/locale/en/LC_MESSAGES/django.po [new file with mode: 0644]
apps/newtagging/locale/es/LC_MESSAGES/django.mo [new file with mode: 0644]
apps/newtagging/locale/es/LC_MESSAGES/django.po [new file with mode: 0644]
apps/newtagging/locale/fr/LC_MESSAGES/django.mo [new file with mode: 0644]
apps/newtagging/locale/fr/LC_MESSAGES/django.po [new file with mode: 0644]
apps/newtagging/locale/lt/LC_MESSAGES/django.mo [new file with mode: 0644]
apps/newtagging/locale/lt/LC_MESSAGES/django.po [new file with mode: 0644]
apps/newtagging/locale/pl/LC_MESSAGES/django.mo [new file with mode: 0644]
apps/newtagging/locale/pl/LC_MESSAGES/django.po [new file with mode: 0644]
apps/newtagging/locale/ru/LC_MESSAGES/django.mo [new file with mode: 0644]
apps/newtagging/locale/ru/LC_MESSAGES/django.po [new file with mode: 0644]
apps/newtagging/locale/uk/LC_MESSAGES/django.mo [new file with mode: 0644]
apps/newtagging/locale/uk/LC_MESSAGES/django.po [new file with mode: 0644]
apps/newtagging/managers.py
apps/newtagging/models.py
apps/newtagging/views.py
apps/pagination/__init__.py [deleted file]
apps/pagination/middleware.py [deleted file]
apps/pagination/models.py [deleted file]
apps/pagination/templates/pagination/pagination.html [deleted file]
apps/pagination/templatetags/__init__.py [deleted file]
apps/pagination/templatetags/pagination_tags.py [deleted file]
apps/pagination/tests.py [deleted file]
apps/piston/authentication.py
apps/piston/decorator.py
apps/piston/doc.py
apps/piston/emitters.py
apps/piston/forms.py
apps/piston/handler.py
apps/piston/managers.py
apps/piston/models.py
apps/piston/oauth.py
apps/piston/resource.py
apps/piston/signals.py
apps/piston/store.py
apps/piston/templates/documentation.html
apps/piston/templates/piston/authorize_token.html
apps/piston/test.py
apps/piston/tests.py
apps/piston/utils.py
apps/sorl/__init__.py [deleted file]
apps/sorl/thumbnail/__init__.py [deleted file]
apps/sorl/thumbnail/base.py [deleted file]
apps/sorl/thumbnail/defaults.py [deleted file]
apps/sorl/thumbnail/fields.py [deleted file]
apps/sorl/thumbnail/main.py [deleted file]
apps/sorl/thumbnail/management/__init__.py [deleted file]
apps/sorl/thumbnail/management/commands/__init__.py [deleted file]
apps/sorl/thumbnail/management/commands/thumbnail_cleanup.py [deleted file]
apps/sorl/thumbnail/models.py [deleted file]
apps/sorl/thumbnail/processors.py [deleted file]
apps/sorl/thumbnail/templatetags/__init__.py [deleted file]
apps/sorl/thumbnail/templatetags/thumbnail.py [deleted file]
apps/sorl/thumbnail/tests/__init__.py [deleted file]
apps/sorl/thumbnail/tests/base.py [deleted file]
apps/sorl/thumbnail/tests/classes.py [deleted file]
apps/sorl/thumbnail/tests/fields.py [deleted file]
apps/sorl/thumbnail/tests/templatetags.py [deleted file]
apps/sorl/thumbnail/tests/utils.py [deleted file]
apps/sorl/thumbnail/utils.py [deleted file]
apps/south/__init__.py [deleted file]
apps/south/db/__init__.py [deleted file]
apps/south/db/generic.py [deleted file]
apps/south/db/mysql.py [deleted file]
apps/south/db/postgresql_psycopg2.py [deleted file]
apps/south/db/sql_server/__init__.py [deleted file]
apps/south/db/sql_server/pyodbc.py [deleted file]
apps/south/db/sqlite3.py [deleted file]
apps/south/docs/CHANGELOG [deleted file]
apps/south/docs/CONTRIBUTING [deleted file]
apps/south/docs/LICENSE [deleted file]
apps/south/docs/README [deleted file]
apps/south/management/__init__.py [deleted file]
apps/south/management/commands/__init__.py [deleted file]
apps/south/management/commands/migrate.py [deleted file]
apps/south/management/commands/startmigration.py [deleted file]
apps/south/management/commands/syncdb.py [deleted file]
apps/south/management/commands/test.py [deleted file]
apps/south/migration.py [deleted file]
apps/south/models.py [deleted file]
apps/south/setup.py [deleted file]
apps/south/tests/__init__.py [deleted file]
apps/south/tests/db.py [deleted file]
apps/south/tests/fakeapp/__init__.py [deleted file]
apps/south/tests/fakeapp/migrations/0001_spam.py [deleted file]
apps/south/tests/fakeapp/migrations/0002_eggs.py [deleted file]
apps/south/tests/fakeapp/migrations/0003_alter_spam.py [deleted file]
apps/south/tests/fakeapp/migrations/__init__.py [deleted file]
apps/south/tests/fakeapp/models.py [deleted file]
apps/south/tests/logic.py [deleted file]
apps/sponsors/__init__.py
apps/sponsors/admin.py
apps/sponsors/fields.py
apps/sponsors/locale/de/LC_MESSAGES/django.mo [new file with mode: 0644]
apps/sponsors/locale/de/LC_MESSAGES/django.po [new file with mode: 0644]
apps/sponsors/locale/en/LC_MESSAGES/django.mo [new file with mode: 0644]
apps/sponsors/locale/en/LC_MESSAGES/django.po [new file with mode: 0644]
apps/sponsors/locale/es/LC_MESSAGES/django.mo [new file with mode: 0644]
apps/sponsors/locale/es/LC_MESSAGES/django.po [new file with mode: 0644]
apps/sponsors/locale/fr/LC_MESSAGES/django.mo [new file with mode: 0644]
apps/sponsors/locale/fr/LC_MESSAGES/django.po [new file with mode: 0644]
apps/sponsors/locale/lt/LC_MESSAGES/django.mo [new file with mode: 0644]
apps/sponsors/locale/lt/LC_MESSAGES/django.po [new file with mode: 0644]
apps/sponsors/locale/pl/LC_MESSAGES/django.mo [new file with mode: 0644]
apps/sponsors/locale/pl/LC_MESSAGES/django.po [new file with mode: 0644]
apps/sponsors/locale/ru/LC_MESSAGES/django.mo [new file with mode: 0644]
apps/sponsors/locale/ru/LC_MESSAGES/django.po [new file with mode: 0644]
apps/sponsors/locale/uk/LC_MESSAGES/django.mo [new file with mode: 0644]
apps/sponsors/locale/uk/LC_MESSAGES/django.po [new file with mode: 0644]
apps/sponsors/migrations/0001_initial.py [new file with mode: 0644]
apps/sponsors/migrations/__init__.py [new file with mode: 0644]
apps/sponsors/models.py
apps/sponsors/processors.py
apps/sponsors/static/sponsors/css/footer_admin.css
apps/sponsors/static/sponsors/js/footer_admin.js
apps/sponsors/templates/sponsors/page.html
apps/sponsors/templatetags/sponsor_tags.py
apps/sponsors/widgets.py
apps/suggest/__init__.py [new file with mode: 0644]
apps/suggest/admin.py [new file with mode: 0644]
apps/suggest/forms.py [new file with mode: 0644]
apps/suggest/locale/de/LC_MESSAGES/django.mo [new file with mode: 0644]
apps/suggest/locale/de/LC_MESSAGES/django.po [new file with mode: 0644]
apps/suggest/locale/en/LC_MESSAGES/django.mo [new file with mode: 0644]
apps/suggest/locale/en/LC_MESSAGES/django.po [new file with mode: 0644]
apps/suggest/locale/es/LC_MESSAGES/django.mo [new file with mode: 0644]
apps/suggest/locale/es/LC_MESSAGES/django.po [new file with mode: 0644]
apps/suggest/locale/fr/LC_MESSAGES/django.mo [new file with mode: 0644]
apps/suggest/locale/fr/LC_MESSAGES/django.po [new file with mode: 0644]
apps/suggest/locale/lt/LC_MESSAGES/django.mo [new file with mode: 0644]
apps/suggest/locale/lt/LC_MESSAGES/django.po [new file with mode: 0644]
apps/suggest/locale/pl/LC_MESSAGES/django.mo [new file with mode: 0644]
apps/suggest/locale/pl/LC_MESSAGES/django.po [new file with mode: 0644]
apps/suggest/locale/ru/LC_MESSAGES/django.mo [new file with mode: 0644]
apps/suggest/locale/ru/LC_MESSAGES/django.po [new file with mode: 0644]
apps/suggest/locale/uk/LC_MESSAGES/django.mo [new file with mode: 0644]
apps/suggest/locale/uk/LC_MESSAGES/django.po [new file with mode: 0644]
apps/suggest/migrations/0001_initial.py [new file with mode: 0644]
apps/suggest/migrations/__init__.py [new file with mode: 0644]
apps/suggest/models.py [new file with mode: 0644]
apps/suggest/templates/suggest.html [new file with mode: 0644]
apps/suggest/urls.py [new file with mode: 0644]
apps/suggest/views.py [new file with mode: 0644]
deployment.py [new file with mode: 0755]
fabfile.py
lib/feedparser.py [deleted file]
lib/librarian [new submodule]
lib/markupstring.py
lib/slughifi.py
requirements-test.txt [new file with mode: 0644]
requirements.txt
scripts/conv_genre_families.py
scripts/git-archive-all.sh [new file with mode: 0755]
scripts/import_links.py
scripts/irename.py
scripts/remove_duplicates.py
scripts/setmainpage.py
scripts/test_api.py
wolnelektury.vhost.tmpl [new file with mode: 0644]
wolnelektury.wsgi.template
wolnelektury.wsgi.tmpl [new file with mode: 0644]
wolnelektury/context_processors.py [new file with mode: 0644]
wolnelektury/locale/de/LC_MESSAGES/django.mo [new file with mode: 0644]
wolnelektury/locale/de/LC_MESSAGES/django.po [new file with mode: 0644]
wolnelektury/locale/en/LC_MESSAGES/django.mo [new file with mode: 0644]
wolnelektury/locale/en/LC_MESSAGES/django.po [new file with mode: 0644]
wolnelektury/locale/es/LC_MESSAGES/django.mo [new file with mode: 0644]
wolnelektury/locale/es/LC_MESSAGES/django.po [new file with mode: 0644]
wolnelektury/locale/fr/LC_MESSAGES/django.mo [new file with mode: 0644]
wolnelektury/locale/fr/LC_MESSAGES/django.po [new file with mode: 0644]
wolnelektury/locale/lt/LC_MESSAGES/django.mo [new file with mode: 0644]
wolnelektury/locale/lt/LC_MESSAGES/django.po [new file with mode: 0644]
wolnelektury/locale/pl/LC_MESSAGES/django.mo
wolnelektury/locale/pl/LC_MESSAGES/django.po
wolnelektury/locale/ru/LC_MESSAGES/django.mo [new file with mode: 0644]
wolnelektury/locale/ru/LC_MESSAGES/django.po [new file with mode: 0644]
wolnelektury/locale/uk/LC_MESSAGES/django.mo [new file with mode: 0644]
wolnelektury/locale/uk/LC_MESSAGES/django.po [new file with mode: 0644]
wolnelektury/manage.py
wolnelektury/middleware.py
wolnelektury/settings.py
wolnelektury/static/css/facelist_2-0.css [new file with mode: 0644]
wolnelektury/static/css/jquery.countdown.css [new file with mode: 0644]
wolnelektury/static/css/master.book.css
wolnelektury/static/css/master.css
wolnelektury/static/css/sponsors.css
wolnelektury/static/css/widget.css [new file with mode: 0644]
wolnelektury/static/img/search.png [new file with mode: 0644]
wolnelektury/static/js/book.js
wolnelektury/static/js/catalogue.js
wolnelektury/static/js/jquery-ui-1.8.2.custom.min.js [new file with mode: 0644]
wolnelektury/static/js/jquery.autocomplete.js
wolnelektury/static/js/jquery.cookie.js [deleted file]
wolnelektury/static/js/jquery.countdown-de.js [new file with mode: 0644]
wolnelektury/static/js/jquery.countdown-es.js [new file with mode: 0644]
wolnelektury/static/js/jquery.countdown-fr.js [new file with mode: 0644]
wolnelektury/static/js/jquery.countdown-lt.js [new file with mode: 0644]
wolnelektury/static/js/jquery.countdown-pl.js [new file with mode: 0644]
wolnelektury/static/js/jquery.countdown-ru.js [new file with mode: 0644]
wolnelektury/static/js/jquery.countdown-uk.js [new file with mode: 0644]
wolnelektury/static/js/jquery.countdown.js [new file with mode: 0644]
wolnelektury/static/js/jquery.eventdelegation.js
wolnelektury/static/js/jquery.form.js
wolnelektury/static/js/jquery.highlightfade.js
wolnelektury/static/js/jquery.jqmodal.js
wolnelektury/static/js/jquery.js
wolnelektury/static/js/jquery.labelify.js
wolnelektury/static/js/jquery.marquee.js [new file with mode: 0644]
wolnelektury/static/js/jquery.scrollto.js
wolnelektury/static/js/ordered_select_multiple.js
wolnelektury/static/js/widget.js [new file with mode: 0644]
wolnelektury/static/js/widgetInit.js [new file with mode: 0644]
wolnelektury/static/sponsors/css/footer_admin.css
wolnelektury/static/sponsors/js/footer_admin.js
wolnelektury/static/widget.html [new file with mode: 0644]
wolnelektury/templates/1percent.html
wolnelektury/templates/404.html
wolnelektury/templates/500.html
wolnelektury/templates/503.html [new file with mode: 0644]
wolnelektury/templates/admin/base_site.html
wolnelektury/templates/admin/catalogue/book/change_list.html
wolnelektury/templates/auth/login.html
wolnelektury/templates/base.html
wolnelektury/templates/catalogue/book_detail.html
wolnelektury/templates/catalogue/book_fragments.html
wolnelektury/templates/catalogue/book_list.html
wolnelektury/templates/catalogue/book_sets.html
wolnelektury/templates/catalogue/book_short.html
wolnelektury/templates/catalogue/book_stub_detail.html [new file with mode: 0644]
wolnelektury/templates/catalogue/book_text.html
wolnelektury/templates/catalogue/breadcrumbs.html
wolnelektury/templates/catalogue/differentiate_tags.html [new file with mode: 0644]
wolnelektury/templates/catalogue/folded_tag_list.html
wolnelektury/templates/catalogue/fragment_sets.html
wolnelektury/templates/catalogue/fragment_short.html
wolnelektury/templates/catalogue/main_page.html
wolnelektury/templates/catalogue/pd_counter.html [new file with mode: 0644]
wolnelektury/templates/catalogue/search_multiple_hits.html [new file with mode: 0644]
wolnelektury/templates/catalogue/search_no_hits.html [new file with mode: 0644]
wolnelektury/templates/catalogue/search_too_short.html [new file with mode: 0644]
wolnelektury/templates/catalogue/tag_list.html
wolnelektury/templates/catalogue/tagged_object_list.html
wolnelektury/templates/catalogue/user_shelves.html
wolnelektury/templates/info/about_us.html [deleted file]
wolnelektury/templates/info/base.html [new file with mode: 0644]
wolnelektury/templates/info/help_us.html [deleted file]
wolnelektury/templates/info/join_us.html [new file with mode: 0644]
wolnelektury/templates/info/voluntary_services.html [deleted file]
wolnelektury/templates/lessons/ajax_document_detail.html
wolnelektury/templates/lessons/document_detail.html
wolnelektury/templates/lessons/document_list.html
wolnelektury/templates/pagination/pagination.html
wolnelektury/translation.py [new file with mode: 0644]
wolnelektury/urls.py
wolnelektury/wolnelektury.fcgi [deleted file]
wolnelektury/wolnelektury.wsgi [deleted file]

index f11a79b..a3f95c0 100644 (file)
@@ -1,12 +1,31 @@
 localsettings.py
 dev.sqlite
+*.db
+*~
+*.orig
+
+# Compress output
+/wolnelektury/static/css/all.min*.css
+/wolnelektury/static/js/all*.min.js
+/wolnelektury/static/css/book.min*.css
+/wolnelektury/static/js/book*.min.js
+/wolnelektury/static/js/jquery.min.js
 
 # Python garbage
 *.pyc
 .coverage
+pip-log.txt
+nosetests.xml
 
 # Mac OS X garbage
 .DS_Store
 
 # Windows garbage
 thumbs.db
+
+# Eclipse
+.project
+.settings
+.pydevproject
+.tmp_*
+
diff --git a/.gitmodules b/.gitmodules
new file mode 100644 (file)
index 0000000..56b9c42
--- /dev/null
@@ -0,0 +1,3 @@
+[submodule "lib/librarian"]
+       path = lib/librarian
+       url = git://github.com/fnp/librarian.git
diff --git a/LICENSE b/LICENSE
new file mode 100644 (file)
index 0000000..2def0e8
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,661 @@
+                    GNU AFFERO GENERAL PUBLIC LICENSE
+                       Version 3, 19 November 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The GNU Affero General Public License is a free, copyleft license for
+software and other kinds of works, specifically designed to ensure
+cooperation with the community in the case of network server software.
+
+  The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+our General Public Licenses are intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+  Developers that use our General Public Licenses protect your rights
+with two steps: (1) assert copyright on the software, and (2) offer
+you this License which gives you legal permission to copy, distribute
+and/or modify the software.
+
+  A secondary benefit of defending all users' freedom is that
+improvements made in alternate versions of the program, if they
+receive widespread use, become available for other developers to
+incorporate.  Many developers of free software are heartened and
+encouraged by the resulting cooperation.  However, in the case of
+software used on network servers, this result may fail to come about.
+The GNU General Public License permits making a modified version and
+letting the public access it on a server without ever releasing its
+source code to the public.
+
+  The GNU Affero General Public License is designed specifically to
+ensure that, in such cases, the modified source code becomes available
+to the community.  It requires the operator of a network server to
+provide the source code of the modified version running there to the
+users of that server.  Therefore, public use of a modified version, on
+a publicly accessible server, gives the public access to the source
+code of the modified version.
+
+  An older license, called the Affero General Public License and
+published by Affero, was designed to accomplish similar goals.  This is
+a different license, not a version of the Affero GPL, but Affero has
+released a new version of the Affero GPL which permits relicensing under
+this license.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                       TERMS AND CONDITIONS
+
+  0. Definitions.
+
+  "This License" refers to version 3 of the GNU Affero General Public License.
+
+  "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+  "The Program" refers to any copyrightable work licensed under this
+License.  Each licensee is addressed as "you".  "Licensees" and
+"recipients" may be individuals or organizations.
+
+  To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy.  The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+  A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+  To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy.  Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+  To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies.  Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+  An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License.  If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+  1. Source Code.
+
+  The "source code" for a work means the preferred form of the work
+for making modifications to it.  "Object code" means any non-source
+form of a work.
+
+  A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+  The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form.  A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+  The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities.  However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work.  For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+  The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+  The Corresponding Source for a work in source code form is that
+same work.
+
+  2. Basic Permissions.
+
+  All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met.  This License explicitly affirms your unlimited
+permission to run the unmodified Program.  The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work.  This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+  You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force.  You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright.  Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+  Conveying under any other circumstances is permitted solely under
+the conditions stated below.  Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+  No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+  When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+  4. Conveying Verbatim Copies.
+
+  You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+  You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+  5. Conveying Modified Source Versions.
+
+  You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+    a) The work must carry prominent notices stating that you modified
+    it, and giving a relevant date.
+
+    b) The work must carry prominent notices stating that it is
+    released under this License and any conditions added under section
+    7.  This requirement modifies the requirement in section 4 to
+    "keep intact all notices".
+
+    c) You must license the entire work, as a whole, under this
+    License to anyone who comes into possession of a copy.  This
+    License will therefore apply, along with any applicable section 7
+    additional terms, to the whole of the work, and all its parts,
+    regardless of how they are packaged.  This License gives no
+    permission to license the work in any other way, but it does not
+    invalidate such permission if you have separately received it.
+
+    d) If the work has interactive user interfaces, each must display
+    Appropriate Legal Notices; however, if the Program has interactive
+    interfaces that do not display Appropriate Legal Notices, your
+    work need not make them do so.
+
+  A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit.  Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+  6. Conveying Non-Source Forms.
+
+  You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+    a) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by the
+    Corresponding Source fixed on a durable physical medium
+    customarily used for software interchange.
+
+    b) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by a
+    written offer, valid for at least three years and valid for as
+    long as you offer spare parts or customer support for that product
+    model, to give anyone who possesses the object code either (1) a
+    copy of the Corresponding Source for all the software in the
+    product that is covered by this License, on a durable physical
+    medium customarily used for software interchange, for a price no
+    more than your reasonable cost of physically performing this
+    conveying of source, or (2) access to copy the
+    Corresponding Source from a network server at no charge.
+
+    c) Convey individual copies of the object code with a copy of the
+    written offer to provide the Corresponding Source.  This
+    alternative is allowed only occasionally and noncommercially, and
+    only if you received the object code with such an offer, in accord
+    with subsection 6b.
+
+    d) Convey the object code by offering access from a designated
+    place (gratis or for a charge), and offer equivalent access to the
+    Corresponding Source in the same way through the same place at no
+    further charge.  You need not require recipients to copy the
+    Corresponding Source along with the object code.  If the place to
+    copy the object code is a network server, the Corresponding Source
+    may be on a different server (operated by you or a third party)
+    that supports equivalent copying facilities, provided you maintain
+    clear directions next to the object code saying where to find the
+    Corresponding Source.  Regardless of what server hosts the
+    Corresponding Source, you remain obligated to ensure that it is
+    available for as long as needed to satisfy these requirements.
+
+    e) Convey the object code using peer-to-peer transmission, provided
+    you inform other peers where the object code and Corresponding
+    Source of the work are being offered to the general public at no
+    charge under subsection 6d.
+
+  A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+  A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling.  In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage.  For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product.  A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+  "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source.  The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+  If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information.  But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+  The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed.  Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+  Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+  7. Additional Terms.
+
+  "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law.  If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+  When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it.  (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.)  You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+  Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+    a) Disclaiming warranty or limiting liability differently from the
+    terms of sections 15 and 16 of this License; or
+
+    b) Requiring preservation of specified reasonable legal notices or
+    author attributions in that material or in the Appropriate Legal
+    Notices displayed by works containing it; or
+
+    c) Prohibiting misrepresentation of the origin of that material, or
+    requiring that modified versions of such material be marked in
+    reasonable ways as different from the original version; or
+
+    d) Limiting the use for publicity purposes of names of licensors or
+    authors of the material; or
+
+    e) Declining to grant rights under trademark law for use of some
+    trade names, trademarks, or service marks; or
+
+    f) Requiring indemnification of licensors and authors of that
+    material by anyone who conveys the material (or modified versions of
+    it) with contractual assumptions of liability to the recipient, for
+    any liability that these contractual assumptions directly impose on
+    those licensors and authors.
+
+  All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10.  If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term.  If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+  If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+  Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+  8. Termination.
+
+  You may not propagate or modify a covered work except as expressly
+provided under this License.  Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+  However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+  Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+  Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+  9. Acceptance Not Required for Having Copies.
+
+  You are not required to accept this License in order to receive or
+run a copy of the Program.  Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance.  However,
+nothing other than this License grants you permission to propagate or
+modify any covered work.  These actions infringe copyright if you do
+not accept this License.  Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+  10. Automatic Licensing of Downstream Recipients.
+
+  Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License.  You are not responsible
+for enforcing compliance by third parties with this License.
+
+  An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations.  If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+  You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License.  For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+  11. Patents.
+
+  A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based.  The
+work thus licensed is called the contributor's "contributor version".
+
+  A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version.  For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+  Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+  In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement).  To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+  If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients.  "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+  If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+  A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License.  You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+  Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+  12. No Surrender of Others' Freedom.
+
+  If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all.  For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+  13. Remote Network Interaction; Use with the GNU General Public License.
+
+  Notwithstanding any other provision of this License, if you modify the
+Program, your modified version must prominently offer all users
+interacting with it remotely through a computer network (if your version
+supports such interaction) an opportunity to receive the Corresponding
+Source of your version by providing access to the Corresponding Source
+from a network server at no charge, through some standard or customary
+means of facilitating copying of software.  This Corresponding Source
+shall include the Corresponding Source for any work covered by version 3
+of the GNU General Public License that is incorporated pursuant to the
+following paragraph.
+
+  Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU General Public License into a single
+combined work, and to convey the resulting work.  The terms of this
+License will continue to apply to the part which is the covered work,
+but the work with which it is combined will remain governed by version
+3 of the GNU General Public License.
+
+  14. Revised Versions of this License.
+
+  The Free Software Foundation may publish revised and/or new versions of
+the GNU Affero General Public License from time to time.  Such new versions
+will be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+  Each version is given a distinguishing version number.  If the
+Program specifies that a certain numbered version of the GNU Affero General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation.  If the Program does not specify a version number of the
+GNU Affero General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+  If the Program specifies that a proxy can decide which future
+versions of the GNU Affero General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+  Later license versions may give you additional or different
+permissions.  However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+  15. Disclaimer of Warranty.
+
+  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. Limitation of Liability.
+
+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+  17. Interpretation of Sections 15 and 16.
+
+  If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU Affero General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Affero General Public License for more details.
+
+    You should have received a copy of the GNU Affero General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+  If your software can interact with users remotely through a computer
+network, you should also make sure that it provides a way for users to
+get its source.  For example, if your program is a web application, its
+interface could display a "Source" link that leads users to an archive
+of the code.  There are many ways you could offer source, and different
+solutions will be better for different programs; see section 13 for the
+specific requirements.
+
+  You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU AGPL, see
+<http://www.gnu.org/licenses/>.
\ No newline at end of file
diff --git a/NOTICE b/NOTICE
new file mode 100644 (file)
index 0000000..7bd9844
--- /dev/null
+++ b/NOTICE
@@ -0,0 +1,19 @@
+    
+    FNP Wolnelektury
+
+    Copyright © 2010 Fundacja Nowoczesna Polska <fundacja@nowoczesnapolska.org.pl>
+    
+    For full list of contributors see AUTHORS file. 
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU Affero General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Affero General Public License for more details.
+
+    You should have received a copy of the GNU Affero General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
\ No newline at end of file
diff --git a/README b/README
deleted file mode 100644 (file)
index fa3064e..0000000
--- a/README
+++ /dev/null
@@ -1,93 +0,0 @@
-Dependencies
-============
-
- * [Django 1.0](http://djangoproject.com/) (application framework)
- * [lxml 2.0.0](http://codespeak.net/lxml/) (for importing books)
- * [librarian 1.1](http://redmine.nowoczesnapolska.org.pl/projects/show/librarian) (for importing books)
- * Python libraries from lib directory
- * Django applications from apps directory
-
-
-How to deploy
-=============
-
-Just execute this commands:
-    
-    cd wolnelektury.pl
-    source setpythonpath.sh
-    cd wolnelektury
-    ./manage.py syncdbc
-    ./manage.py importbooks ../books/01 ../books/02 ../books/03
-    ../setmainpage.py
-
-[TODO]
-
-
-Używany kod open-source
-=======================
-
-django
-------
- - Źródła: [djangoproject.com](http://www.djangoproject.com/)
- - Autorzy: [wielu autorów](http://code.djangoproject.com/browser/django/trunk/AUTHORS)
- - Licencja: [BSD License](http://code.djangoproject.com/browser/django/trunk/LICENSE)
- - Typ: framework
-
-django-chunks
--------------
- - Źródła: [Google Code](http://code.google.com/p/django-chunks/)
- - Autorzy: Clint Ecker <clintecker@gmail.com>
- - Licencja: [New BSD License](http://www.opensource.org/licenses/bsd-license.php)
- - Typ: biblioteka (aplikacja django)
-
-django-pagination
------------------
- - Źródła: [Google Code](http://code.google.com/p/django-pagination/)
- - Autorzy: James Tauber <jtauber@gmail.com>, leidel@gmail.com
- - Licencja: [New BSD License](http://www.opensource.org/licenses/bsd-license.php)
- - Typ: biblioteka (aplikacja django)
-
-django-compress
----------------
- - Źródła: [Google Code](http://code.google.com/p/django-compress/)
- - Autorzy: Andreas Pelme <andreas.pelme@gmail.com>
- - Licencja: [MIT License](http://www.opensource.org/licenses/mit-license.php)
- - Typ: biblioteka (aplikacja django)
-
-django-newtagging
------------------
- - Źródła: [BitBucket](http://www.bitbucket.org/zuber/django-newtagging/)
- - Autorzy: Marek Stępniowski <marek@stepniowski.com>
- - Licencja: [MIT License](http://www.opensource.org/licenses/mit-license.php)
- - Typ: biblioteka (aplikacja django)
- - Nota: Aplikacja wzorowana na [django-tagging](http://code.google.com/p/django-tagging/), która jest również wydana na licencji [MIT](http://www.opensource.org/licenses/mit-license.php) Około połowa kodu jest dzielona.
-
-south
------
-- Źródła: [aercode.org](http://south.aeracode.org/)
-- Autorzy: Andrew Godwin <andrew@aeracode.org>, Andy McCurdy <sedrik@gmail.com>
-- Licencja: [Apache License 2.0](http://www.opensource.org/licenses/apache2.0.php)
-- Typ: biblioteka (aplikacja django)
-
-feedparser
-----------
- - Źródła: [Google Code](http://code.google.com/p/feedparser/)
- - Autorzy: Mark Pilgrim <pilgrim@gmail.com>
- - Licencja: [MIT License](http://www.opensource.org/licenses/mit-license.php)
- - Typ: biblioteka
-
-markupstring
-------------
- - Żródła: [ASPN Cookbook](http://code.activestate.com/recipes/389023/)
- - Autorzy: Thomas Hinkle
- - Licencja: [MIT License](http://code.activestate.com/help/terms/)
- - Typ: biblioteka
- - Nota: Zmienione przez Marka Stępniowskiego <marek@stepniowski.com> tak, żeby akceptowało ciągi znaków Unicode
-lxml
-----
- - Żródła: [codespeak.net](http://codespeak.net/lxml/index.html#download)
- - Autorzy: [wielu autorów](http://codespeak.net/lxml/credits.html)
- - Licencja: [BSD License](http://codespeak.net/lxml/index.html#license)
- - Typ: biblioteka
-
diff --git a/README.md b/README.md
new file mode 100644 (file)
index 0000000..725dc7c
--- /dev/null
+++ b/README.md
@@ -0,0 +1,151 @@
+License
+-------
+
+  ![AGPL Logo](http://www.gnu.org/graphics/agplv3-155x51.png)
+    
+    Copyright © 2008,2009,2010 Fundacja Nowoczesna Polska <fundacja@nowoczesnapolska.org.pl>
+    
+    For full list of contributors see AUTHORS section at the end. 
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU Affero General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Affero General Public License for more details.
+
+    You should have received a copy of the GNU Affero General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+    
+Dependencies
+============
+
+ * All packages listed in requirements.txt
+ * Python libraries from lib directory
+ * Django applications from apps directory
+
+How to deploy (development version)
+=============
+
+1. Checkout the source code from Github
+2. Install libraries (we recommend using pip):
+
+    pip install -r requirements.txt
+    
+3. Setup your local configuration based on settings.py. You need to generate a new SECRET_KEY, database stuff and domain related stuff.
+4. Populate database:
+    
+    ./wolnelektury/manage.py syncdb
+    ./wolnelektury/manage.py migrate
+
+5. Run the server
+
+   ./wolnelektury/manage.py runserver
+
+    
+6. Import some books which are available on http://www.wolnelektury.pl or on bitbucket mirror: http://bitbucket.org/lqc/wlbooks/
+   If you use Bitbucket, you also need Mercurial to fetch books (you can install it using: pip install mercurial).
+   After downloading books, log into administration, go to Books and choose 'Browse' to select book file,
+   then fire 'Import book' to upload it. Some books have invalid XML, so you can get an error
+   (just ignore it and look for other books).
+   
+7. We provide localization of the software in following languages: Polish, Russian, German, English, Spanish, French and Lithuanian.
+   Translation strings are based on gettext and can be found under 'locale' dir.
+   There are also JavaScript files for jQuery countdown plugin (static/js/jquery.countdown-*.js).
+
+Full list of used open-source software
+======================================
+
+External
+--------
+
+django
+--------
+ - Source: [djangoproject.com](http://www.djangoproject.com/)
+ - Authors: [many authors](http://code.djangoproject.com/browser/django/trunk/AUTHORS)
+ - License: [BSD License](http://code.djangoproject.com/browser/django/trunk/LICENSE)
+ - Type: framework
+
+django-pagination
+-----------------
+ - Source: [Google Code](http://code.google.com/p/django-pagination/)
+ - Authors: James Tauber <jtauber@gmail.com>, leidel@gmail.com
+ - License: [New BSD License](http://www.opensource.org/licenses/bsd-license.php)
+ - Type: library (django application)
+
+django-rosetta
+-----------------
+ - Source: [Google Code](http://code.google.com/p/django-rosetta/)
+ - Authors: James Tauber <jtauber@gmail.com>, leidel@gmail.com
+ - License: [MIT License](http://www.opensource.org/licenses/mit-license.php)
+ - Type: library (django application)
+
+Django South
+------------
+- Source: [aercode.org](http://south.aeracode.org/)
+- Authors: Andrew Godwin <andrew@aeracode.org>, Andy McCurdy <sedrik@gmail.com>
+- License: [Apache License 2.0](http://www.opensource.org/licenses/apache2.0.php)
+- Type: library (django application)
+
+lxml
+---------
+ - Source: [codespeak.net](http://codespeak.net/lxml/index.html#download)
+ - Authors: [many authors](http://codespeak.net/lxml/credits.html)
+ - License: [BSD License](http://codespeak.net/lxml/index.html#license)
+ - Type: library
+feedparser
+----------
+ - Source: [Google Code](http://code.google.com/p/feedparser/)
+ - Authors: Mark Pilgrim <pilgrim@gmail.com>
+ - License: [MIT License](http://www.opensource.org/licenses/mit-license.php)
+ - Type: library
+
+
+Internal (means we hacked on sources of those): 
+---------
+django-compress
+---------------
+ - Source: [Google Code](http://code.google.com/p/django-compress/)
+ - Authors: Andreas Pelme <andreas.pelme@gmail.com>
+ - License: [MIT License](http://www.opensource.org/licenses/mit-license.php)
+ - Type: library (Django application)
+ django-chunks
+-------------
+ - Source: [Google Code](http://code.google.com/p/django-chunks/)
+ - Authors: Clint Ecker <clintecker@gmail.com>
+ - License: [New BSD License](http://www.opensource.org/licenses/bsd-license.php)
+ - Type: library (Django application)
+django-newtagging
+-----------------
+ - Source: [BitBucket](http://www.bitbucket.org/zuber/django-newtagging/)
+ - Authors: Marek Stępniowski <marek@stepniowski.com>
+ - License: [MIT License](http://www.opensource.org/licenses/mit-license.php)
+ - Type: library (Django aplication)
+ - Notes: Aplication based on  [django-tagging](http://code.google.com/p/django-tagging/), also [MIT](http://www.opensource.org/licenses/mit-license.php) license.
+django-piston (0.2.3rc)
+------------------------
+ - http://bitbucket.org/jespern/django-piston/wiki/Home
+
+markupstring
+------------
+ - Source: [ASPN Cookbook](http://code.activestate.com/recipes/389023/)
+ - Authors: Thomas Hinkle
+ - License: [MIT License](http://code.activestate.com/help/terms/)
+ - Type: library
+ - Notes: Patched by Marek Stępniowski <marek@stepniowski.com> to accept Unicode strings
+Authors
+=======
+ * Marek Stępniowski  <marek@stepniowski.com>
+ * Łukasz Rekucki <lrekucki@gmail.com>
index 03115d8..40121d6 100644 (file)
@@ -1,3 +1,7 @@
+# -*- coding: utf-8 -*-
+# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
 from django.shortcuts import get_object_or_404
 from django.contrib.auth.decorators import login_required, user_passes_test
 from piston.handler import BaseHandler
@@ -12,14 +16,14 @@ staff_required = user_passes_test(lambda user: user.is_staff)
 class BookHandler(BaseHandler):
     model = Book
     fields = ('slug', 'title')
-    
+
     @staff_required
     def read(self, request, slug=None):
         if slug:
             return get_object_or_404(Book, slug=slug)
         else:
             return Book.objects.all()
-    
+
     @staff_required
     def create(self, request):
         form = BookImportForm(request.POST, request.FILES)
index 9f1770d..0275094 100644 (file)
@@ -1,8 +1,11 @@
 # -*- coding: utf-8 -*-
+# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
 from django.contrib import admin
 
 from newtagging.admin import TaggableModelAdmin
-from catalogue.models import Tag, Book, Fragment
+from catalogue.models import Tag, Book, Fragment, BookStub
 
 
 class TagAdmin(admin.ModelAdmin):
@@ -17,8 +20,8 @@ class TagAdmin(admin.ModelAdmin):
 
 class BookAdmin(TaggableModelAdmin):
     tag_model = Tag
-    
-    list_display = ('title', 'slug', 'has_pdf_file', 'has_odt_file', 'has_html_file', 'has_description',)
+
+    list_display = ('title', 'slug', 'has_pdf_file', 'has_epub_file', 'has_odt_file', 'has_html_file', 'has_description',)
     search_fields = ('title',)
     ordering = ('title',)
 
@@ -27,11 +30,22 @@ class BookAdmin(TaggableModelAdmin):
 
 class FragmentAdmin(TaggableModelAdmin):
     tag_model = Tag
-    
+
     list_display = ('book', 'anchor',)
     ordering = ('book', 'anchor',)
 
 
+class BookStubAdmin(admin.ModelAdmin):
+    # tag_model = Tag
+
+    list_display = ('title', 'author', 'slug','pd')
+    search_fields = ('title','author')
+    ordering = ('title',)
+
+    prepopulated_fields = {'slug': ('title',)}
+
+
+admin.site.register(BookStub, BookStubAdmin)
 admin.site.register(Tag, TagAdmin)
 admin.site.register(Book, BookAdmin)
 admin.site.register(Fragment, FragmentAdmin)
index eedff67..11c730c 100644 (file)
@@ -1,4 +1,7 @@
 # -*- coding: utf-8 -*-
+# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
 import datetime
 
 from django.conf import settings
@@ -6,10 +9,12 @@ from django.db import models
 from django.db.models import signals
 from django import forms
 from django.forms.widgets import flatatt
-from django.forms.util import smart_unicode
+from django.utils.encoding import smart_unicode
 from django.utils import simplejson as json
 from django.utils.html import escape
 from django.utils.safestring import mark_safe
+from django.utils.translation import ugettext_lazy as _
+from south.modelsinspector import add_introspection_rules
 
 
 class JSONEncoder(json.JSONEncoder):
@@ -33,13 +38,13 @@ def loads(str):
 
 class JSONFormField(forms.CharField):
     widget = forms.Textarea
-    
+
     def clean(self, value):
         try:
             loads(value)
             return value
         except ValueError, e:
-            raise forms.ValidationError('Enter a valid JSON value. Error: %s' % e)
+            raise forms.ValidationError(_('Enter a valid JSON value. Error: %s') % e)
 
 
 class JSONField(models.TextField):
@@ -56,7 +61,7 @@ class JSONField(models.TextField):
 
     def contribute_to_class(self, cls, name):
         super(JSONField, self).contribute_to_class(cls, name)
-        
+
         def get_value(model_instance):
             return loads(getattr(model_instance, self.attname, None))
         setattr(cls, 'get_%s_value' % self.name, get_value)
@@ -65,6 +70,8 @@ class JSONField(models.TextField):
             return setattr(model_instance, self.attname, dumps(json))
         setattr(cls, 'set_%s_value' % self.name, set_value)
 
+add_introspection_rules([], ["^catalogue\.fields\.JSONField"])
+
 
 class JQueryAutoCompleteWidget(forms.TextInput):
     def __init__(self, source, options=None, *args, **kwargs):
@@ -73,23 +80,23 @@ class JQueryAutoCompleteWidget(forms.TextInput):
         if options:
             self.options = dumps(options)
         super(JQueryAutoCompleteWidget, self).__init__(*args, **kwargs)
-    
+
     def render_js(self, field_id):
         source = "'%s'" % escape(self.source)
         options = ''
         if self.options:
             options += ', %s' % self.options
-        
-        return u'$(\'#%s\').autocomplete(%s%s);' % (field_id, source, options)
-    
+
+        return u'$(\'#%s\').autocomplete(%s%s).result(autocomplete_result_handler);' % (field_id, source, options)
+
     def render(self, name, value=None, attrs=None):
         final_attrs = self.build_attrs(attrs, name=name)
         if value:
             final_attrs['value'] = smart_unicode(value)
-        
+
         if not self.attrs.has_key('id'):
             final_attrs['id'] = 'id_%s' % name
-        
+
         html = u'''<input type="text" %(attrs)s/>
             <script type="text/javascript">//<!--
             %(js)s//--></script>
@@ -97,7 +104,7 @@ class JQueryAutoCompleteWidget(forms.TextInput):
                 'attrs' : flatatt(final_attrs),
                 'js' : self.render_js(final_attrs['id']),
             }
-        
+
         return mark_safe(html)
 
 
@@ -105,6 +112,18 @@ class JQueryAutoCompleteField(forms.CharField):
     def __init__(self, source, options=None, *args, **kwargs):
         if 'widget' not in kwargs:
             kwargs['widget'] = JQueryAutoCompleteWidget(source, options)
-        
+
         super(JQueryAutoCompleteField, self).__init__(*args, **kwargs)
 
+try:
+    # check for south
+    from south.modelsinspector import add_introspection_rules
+
+    add_introspection_rules([
+    (
+        [JSONField], # Class(es) these apply to
+        [], # Positional arguments (not used)
+        {}, # Keyword argument
+    ), ], ["^catalogue\.fields\.JSONField"])
+except ImportError:
+    pass
index bf6b0df..3aceb4f 100644 (file)
@@ -1,5 +1,9 @@
 # -*- coding: utf-8 -*-
+# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
 from django import forms
+from django.utils.translation import ugettext_lazy as _
 from slughifi import slughifi
 
 from catalogue.models import Tag, Book
@@ -10,18 +14,19 @@ from catalogue import utils
 class BookImportForm(forms.Form):
     book_xml_file = forms.FileField()
 
-    def save(self, commit=True):
-        return Book.from_xml_file(self.cleaned_data['book_xml_file'], overwrite=True)
+    def save(self, commit=True, **kwargs):
+        return Book.from_xml_file(self.cleaned_data['book_xml_file'], overwrite=True, **kwargs)
 
 
 class SearchForm(forms.Form):
-    q = JQueryAutoCompleteField('/katalog/tags/', {'minChars': 2, 'selectFirst': True, 'cacheLength': 50})
+    q = JQueryAutoCompleteField('/katalog/tags/', {'minChars': 2, 'selectFirst': True, 'cacheLength': 50, 'matchContains': "word"})
     tags = forms.CharField(widget=forms.HiddenInput, required=False)
-    
+
     def __init__(self, *args, **kwargs):
         tags = kwargs.pop('tags', [])
         super(SearchForm, self).__init__(*args, **kwargs)
-        self.fields['q'].widget.attrs['title'] = u'tytuł, autor, motyw/temat, epoka, rodzaj, gatunek'
+        self.fields['q'].widget.attrs['title'] = _('title, author, theme/topic, epoch, kind, genre')
+           #self.fields['q'].widget.attrs['style'] = ''
         self.fields['tags'].initial = '/'.join(tag.slug for tag in Tag.get_tag_list(tags))
 
 
@@ -34,29 +39,29 @@ class UserSetsForm(forms.Form):
 
 
 class ObjectSetsForm(forms.Form):
-    def __init__(self, obj, user, *args, **kwargs):        
+    def __init__(self, obj, user, *args, **kwargs):
         super(ObjectSetsForm, self).__init__(*args, **kwargs)
         self.fields['set_ids'] = forms.MultipleChoiceField(
-            label=u'Półki',
+            label=_('Shelves'),
             required=False,
-            choices=[(tag.id, "%s (%s)" % (tag.name, tag.book_count)) for tag in Tag.objects.filter(category='set', user=user)],
+            choices=[(tag.id, "%s (%s)" % (tag.name, tag.get_count())) for tag in Tag.objects.filter(category='set', user=user)],
             initial=[tag.id for tag in obj.tags.filter(category='set', user=user)],
             widget=forms.CheckboxSelectMultiple
         )
-        
+
 
 class NewSetForm(forms.Form):
     name = forms.CharField(max_length=50, required=True)
-    
+
     def __init__(self, *args, **kwargs):
         super(NewSetForm, self).__init__(*args, **kwargs)
-        self.fields['name'].widget.attrs['title'] = u'nazwa nowej półki'
-        
+        self.fields['name'].widget.attrs['title'] = _('Name of the new shelf')
+
     def save(self, user, commit=True):
         name = self.cleaned_data['name']
         new_set = Tag(name=name, slug=utils.get_random_hash(name), sort_key=slughifi(name),
             category='set', user=user)
-        
+
         new_set.save()
         return new_set
 
@@ -67,12 +72,13 @@ FORMATS = (
     ('pdf', 'PDF'),
     ('odt', 'ODT'),
     ('txt', 'TXT'),
+    ('epub', 'EPUB'),
 )
 
 
 class DownloadFormatsForm(forms.Form):
     formats = forms.MultipleChoiceField(required=False, choices=FORMATS, widget=forms.CheckboxSelectMultiple)
-    
+
     def __init__(self, *args, **kwargs):
          super(DownloadFormatsForm, self).__init__(*args, **kwargs)
 
diff --git a/apps/catalogue/locale/de/LC_MESSAGES/django.mo b/apps/catalogue/locale/de/LC_MESSAGES/django.mo
new file mode 100644 (file)
index 0000000..3e56cd1
Binary files /dev/null and b/apps/catalogue/locale/de/LC_MESSAGES/django.mo differ
diff --git a/apps/catalogue/locale/de/LC_MESSAGES/django.po b/apps/catalogue/locale/de/LC_MESSAGES/django.po
new file mode 100644 (file)
index 0000000..575defb
--- /dev/null
@@ -0,0 +1,280 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+# 
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-08-25 10:24+0000\n"
+"PO-Revision-Date: 2010-08-25 10:45\n"
+"Last-Translator: <radek.czajka@gmail.com>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Translated-Using: django-rosetta 0.5.6\n"
+
+#: fields.py:47
+#, python-format
+msgid "Enter a valid JSON value. Error: %s"
+msgstr "Geben Sie eine gültige JSON-Wert. Fehler:% s"
+
+#: forms.py:28
+msgid "title, author, theme/topic, epoch, kind, genre"
+msgstr "Titel, Autor, Motiv/Thema, Epoche, Art, Gattung"
+
+#: forms.py:45
+msgid "Shelves"
+msgstr "Bücherregale"
+
+#: forms.py:58
+msgid "Name of the new shelf"
+msgstr "Name für ein neues Bücherregal"
+
+#: models.py:25 models.py:585
+msgid "author"
+msgstr "Autor"
+
+#: models.py:26
+msgid "epoch"
+msgstr "Epoche"
+
+#: models.py:27
+msgid "kind"
+msgstr "Art"
+
+#: models.py:28
+msgid "genre"
+msgstr "Gattung"
+
+#: models.py:29
+msgid "theme"
+msgstr "Motiv"
+
+#: models.py:30
+msgid "set"
+msgstr "Bücherregal"
+
+#: models.py:31 models.py:204
+msgid "book"
+msgstr "Buch"
+
+#: models.py:45
+msgid "name"
+msgstr "Name"
+
+#: models.py:46 models.py:170 models.py:587 models.py:612
+msgid "slug"
+msgstr "slug"
+
+#: models.py:47
+msgid "sort key"
+msgstr "Sortierschlüssel"
+
+#: models.py:48
+msgid "category"
+msgstr "Kategorie"
+
+#: models.py:50 models.py:87 models.py:171 models.py:306
+msgid "description"
+msgstr "Beschreibung"
+
+#: models.py:51
+msgid "main page"
+msgstr "Startseite"
+
+#: models.py:51
+msgid "Show tag on main page"
+msgstr "Tag für die Startseite anzeigen"
+
+#: models.py:54
+msgid "book count"
+msgstr "Anzahl der Bücher"
+
+#: models.py:55
+msgid "year of death"
+msgstr "Todesjahr"
+
+#: models.py:71
+msgid "tag"
+msgstr "tag"
+
+#: models.py:72
+msgid "tags"
+msgstr "tags"
+
+#: models.py:169 models.py:584
+msgid "title"
+msgstr "Titel"
+
+#: models.py:172
+msgid "creation date"
+msgstr "Erstellungsdatum"
+
+#: models.py:173
+msgid "short HTML"
+msgstr "kurze HTML"
+
+#: models.py:174
+msgid "parent number"
+msgstr "Nummer der  Eltern"
+
+#: models.py:175
+msgid "extra information"
+msgstr "extra Informationen"
+
+#: models.py:181
+msgid "XML file"
+msgstr "XML-Datei"
+
+#: models.py:182
+msgid "HTML file"
+msgstr "HTML-Datei"
+
+#: models.py:183
+msgid "PDF file"
+msgstr "PDF-Datei"
+
+#: models.py:184
+msgid "EPUB file"
+msgstr "EPUB-Datei"
+
+#: models.py:185
+msgid "ODT file"
+msgstr "ODT-Datei"
+
+#: models.py:186
+msgid "TXT file"
+msgstr "TXT-Datei"
+
+#: models.py:187
+msgid "MP3 file"
+msgstr "MP3-Datei"
+
+#: models.py:188
+msgid "OGG file"
+msgstr "OGG-Datei"
+
+#: models.py:205
+msgid "books"
+msgstr "Bücher"
+
+#: models.py:263
+msgid "Read online"
+msgstr "Online lesen"
+
+#: models.py:403
+#, python-format
+msgid "Book %s already exists"
+msgstr "Buch %s bereits vorhanden"
+
+#: models.py:444
+#, python-format
+msgid "Book with slug = \"%s\" does not exist."
+msgstr "Buch mit slug = \"%s\" nicht vorhanden."
+
+#: models.py:565
+msgid "fragment"
+msgstr "Auszug"
+
+#: models.py:566
+msgid "fragments"
+msgstr "Auszüge"
+
+#: models.py:586
+msgid "goes to public domain"
+msgstr "gehe zur Public Domain"
+
+#: models.py:588
+msgid "translator"
+msgstr "Übersetzer"
+
+#: models.py:589
+msgid "year of translator's death"
+msgstr "Todesjahr des Übersetzers"
+
+#: models.py:593
+msgid "book stub"
+msgstr "Buch Vorschau"
+
+#: models.py:594
+msgid "book stubs"
+msgstr "Bücher Vorschau"
+
+#: models.py:613
+msgid "type"
+msgstr ""
+
+#: models.py:614
+msgid "sha-1 hash"
+msgstr ""
+
+#: models.py:615
+#, fuzzy
+msgid "time"
+msgstr ""
+
+#: models.py:619
+msgid "file record"
+msgstr ""
+
+#: models.py:620
+msgid "file records"
+msgstr ""
+
+#: views.py:452
+msgid "<p>To maintain your shelves you need to be logged in.</p>"
+msgstr "<p>Um die Bücherregale zu verwalten, musst du eingeloggt sein.</p>"
+
+#: views.py:470
+msgid "<p>Shelves were sucessfully saved.</p>"
+msgstr "<p>Bücherregale wurden erfolgreich gespeichert.</p>"
+
+#: views.py:494
+msgid "Book was successfully removed from the shelf"
+msgstr "Das Buch wurde erfolgreich entfernt"
+
+#: views.py:496
+msgid "This book is not on the shelf"
+msgstr "Das Buch ist nicht im Regal"
+
+#: views.py:599
+#, python-format
+msgid "<p>Shelf <strong>%s</strong> was successfully created</p>"
+msgstr "<p>Büchrregal <strong>%s</strong> wurde erfolgreich erstellt</p>"
+
+#: views.py:614
+#, python-format
+msgid "<p>Shelf <strong>%s</strong> was successfully removed</p>"
+msgstr "<p>Bücherregal<strong>%s</strong> wurde erfolgreich entfernt</p>"
+
+#: views.py:673
+#, python-format
+msgid ""
+"An error occurred: %(exception)s\n"
+"\n"
+"%(tb)s"
+msgstr ""
+"Ein Fehler ist aufgetreten: %(exception)s\n"
+"\n"
+"%(tb)s"
+
+#: views.py:674
+msgid "Book imported successfully"
+msgstr "Buch wurde erfolgreich importiert"
+
+#: views.py:676
+#, python-format
+msgid "Error importing file: %r"
+msgstr "Fehler beim Importieren der Datei: %r"
+
+#~ msgid "Today is %(month)s, %(day)s."
+#~ msgstr "Heute ist %(month)s, %(day)s."
+
+#~ msgid "content type"
+#~ msgstr "Inhaltstyp"
+
+#~ msgid "object id"
+#~ msgstr "Objekt ID"
diff --git a/apps/catalogue/locale/en/LC_MESSAGES/django.mo b/apps/catalogue/locale/en/LC_MESSAGES/django.mo
new file mode 100644 (file)
index 0000000..45ddee8
Binary files /dev/null and b/apps/catalogue/locale/en/LC_MESSAGES/django.mo differ
diff --git a/apps/catalogue/locale/en/LC_MESSAGES/django.po b/apps/catalogue/locale/en/LC_MESSAGES/django.po
new file mode 100644 (file)
index 0000000..fe91865
--- /dev/null
@@ -0,0 +1,279 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+# 
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-08-25 10:24+0000\n"
+"PO-Revision-Date: 2010-08-25 10:45\n"
+"Last-Translator: <radek.czajka@gmail.com>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Translated-Using: django-rosetta 0.5.6\n"
+
+#: fields.py:47
+#, python-format
+msgid "Enter a valid JSON value. Error: %s"
+msgstr "Enter a valid JSON value. Error: %s"
+
+#: forms.py:28
+msgid "title, author, theme/topic, epoch, kind, genre"
+msgstr "title, author, motifs/theme, period, form, genre"
+
+#: forms.py:45
+msgid "Shelves"
+msgstr "Shelves"
+
+#: forms.py:58
+msgid "Name of the new shelf"
+msgstr "Name of the new shelf"
+
+#: models.py:25 models.py:585
+msgid "author"
+msgstr "author"
+
+#: models.py:26
+msgid "epoch"
+msgstr "period"
+
+#: models.py:27
+msgid "kind"
+msgstr "form"
+
+#: models.py:28
+msgid "genre"
+msgstr "genre"
+
+#: models.py:29
+msgid "theme"
+msgstr "motif"
+
+#: models.py:30
+msgid "set"
+msgstr "set"
+
+#: models.py:31 models.py:204
+msgid "book"
+msgstr "book"
+
+#: models.py:45
+msgid "name"
+msgstr "name"
+
+#: models.py:46 models.py:170 models.py:587 models.py:612
+msgid "slug"
+msgstr "Slug"
+
+#: models.py:47
+msgid "sort key"
+msgstr "Sort key"
+
+#: models.py:48
+msgid "category"
+msgstr "Category"
+
+#: models.py:50 models.py:87 models.py:171 models.py:306
+msgid "description"
+msgstr "Description"
+
+#: models.py:51
+msgid "main page"
+msgstr "Main page"
+
+#: models.py:51
+msgid "Show tag on main page"
+msgstr "Show tag on main page"
+
+#: models.py:54
+msgid "book count"
+msgstr "Number of books"
+
+#: models.py:55
+msgid "year of death"
+msgstr "Year of death"
+
+#: models.py:71
+msgid "tag"
+msgstr "tag"
+
+#: models.py:72
+msgid "tags"
+msgstr "tags"
+
+#: models.py:169 models.py:584
+msgid "title"
+msgstr "Title"
+
+#: models.py:172
+msgid "creation date"
+msgstr "Date of publication"
+
+#: models.py:173
+msgid "short HTML"
+msgstr "short HTML"
+
+#: models.py:174
+msgid "parent number"
+msgstr "Parent number"
+
+#: models.py:175
+msgid "extra information"
+msgstr "Additional information"
+
+#: models.py:181
+msgid "XML file"
+msgstr "XML file"
+
+#: models.py:182
+msgid "HTML file"
+msgstr "HTML file"
+
+#: models.py:183
+msgid "PDF file"
+msgstr "PDF file"
+
+#: models.py:184
+msgid "EPUB file"
+msgstr "EPUB file"
+
+#: models.py:185
+msgid "ODT file"
+msgstr "ODT file"
+
+#: models.py:186
+msgid "TXT file"
+msgstr "TXT file"
+
+#: models.py:187
+msgid "MP3 file"
+msgstr "MP3 file"
+
+#: models.py:188
+msgid "OGG file"
+msgstr "OGG file"
+
+#: models.py:205
+msgid "books"
+msgstr "Books"
+
+#: models.py:263
+msgid "Read online"
+msgstr "Read online"
+
+#: models.py:403
+#, python-format
+msgid "Book %s already exists"
+msgstr "Book %s already exists"
+
+#: models.py:444
+#, python-format
+msgid "Book with slug = \"%s\" does not exist."
+msgstr "Book with slug = \"%s\" does not exist."
+
+#: models.py:565
+msgid "fragment"
+msgstr "Fragment"
+
+#: models.py:566
+msgid "fragments"
+msgstr "Fragments"
+
+#: models.py:586
+msgid "goes to public domain"
+msgstr "Goes to public domain"
+
+#: models.py:588
+msgid "translator"
+msgstr "Translator"
+
+#: models.py:589
+msgid "year of translator's death"
+msgstr "Year of translator's death"
+
+#: models.py:593
+msgid "book stub"
+msgstr "Book stub"
+
+#: models.py:594
+msgid "book stubs"
+msgstr "Book stubs"
+
+#: models.py:613
+msgid "type"
+msgstr ""
+
+#: models.py:614
+msgid "sha-1 hash"
+msgstr ""
+
+#: models.py:615
+msgid "time"
+msgstr "time"
+
+#: models.py:619
+msgid "file record"
+msgstr ""
+
+#: models.py:620
+msgid "file records"
+msgstr ""
+
+#: views.py:452
+msgid "<p>To maintain your shelves you need to be logged in.</p>"
+msgstr "<p>To administer your shelves you need to be logged in.</p>"
+
+#: views.py:470
+msgid "<p>Shelves were sucessfully saved.</p>"
+msgstr "<p>Shelves were sucessfully saved.</p>"
+
+#: views.py:494
+msgid "Book was successfully removed from the shelf"
+msgstr "Book was successfully removed from the shelf"
+
+#: views.py:496
+msgid "This book is not on the shelf"
+msgstr "This book is not on the shelf"
+
+#: views.py:599
+#, python-format
+msgid "<p>Shelf <strong>%s</strong> was successfully created</p>"
+msgstr "<p>Shelf <strong>%s</strong> was successfully created</p>"
+
+#: views.py:614
+#, python-format
+msgid "<p>Shelf <strong>%s</strong> was successfully removed</p>"
+msgstr "<p>Shelf <strong>%s</strong> was successfully removed</p>"
+
+#: views.py:673
+#, python-format
+msgid ""
+"An error occurred: %(exception)s\n"
+"\n"
+"%(tb)s"
+msgstr ""
+"An error occurred: %(exception)s\n"
+"\n"
+"%(tb)s"
+
+#: views.py:674
+msgid "Book imported successfully"
+msgstr "Book imported succesfully"
+
+#: views.py:676
+#, python-format
+msgid "Error importing file: %r"
+msgstr "Error occured while importing file: %r"
+
+#~ msgid "Today is %(month)s, %(day)s."
+#~ msgstr "Today is %(month)s, %(day)s."
+
+#~ msgid "content type"
+#~ msgstr "content type"
+
+#~ msgid "object id"
+#~ msgstr "object id"
diff --git a/apps/catalogue/locale/es/LC_MESSAGES/django.mo b/apps/catalogue/locale/es/LC_MESSAGES/django.mo
new file mode 100644 (file)
index 0000000..8f94d47
Binary files /dev/null and b/apps/catalogue/locale/es/LC_MESSAGES/django.mo differ
diff --git a/apps/catalogue/locale/es/LC_MESSAGES/django.po b/apps/catalogue/locale/es/LC_MESSAGES/django.po
new file mode 100644 (file)
index 0000000..c105555
--- /dev/null
@@ -0,0 +1,280 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+# 
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-08-25 10:24+0000\n"
+"PO-Revision-Date: 2010-08-25 10:48\n"
+"Last-Translator: <radek.czajka@gmail.com>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Translated-Using: django-rosetta 0.5.6\n"
+
+#: fields.py:47
+#, python-format
+msgid "Enter a valid JSON value. Error: %s"
+msgstr "Introduce un valor válido de JSON. Error: %s"
+
+#: forms.py:28
+msgid "title, author, theme/topic, epoch, kind, genre"
+msgstr "título, autor, tema/motivo, época, género, subgénero"
+
+#: forms.py:45
+msgid "Shelves"
+msgstr "Estantes"
+
+#: forms.py:58
+msgid "Name of the new shelf"
+msgstr "Nombre del estante nuevo"
+
+#: models.py:25 models.py:585
+msgid "author"
+msgstr "autor"
+
+#: models.py:26
+msgid "epoch"
+msgstr "época"
+
+#: models.py:27
+msgid "kind"
+msgstr "género"
+
+#: models.py:28
+msgid "genre"
+msgstr "subgénero"
+
+#: models.py:29
+msgid "theme"
+msgstr "tema"
+
+#: models.py:30
+msgid "set"
+msgstr "colección"
+
+#: models.py:31 models.py:204
+msgid "book"
+msgstr "libro"
+
+#: models.py:45
+msgid "name"
+msgstr "nombre"
+
+#: models.py:46 models.py:170 models.py:587 models.py:612
+msgid "slug"
+msgstr "slug"
+
+#: models.py:47
+msgid "sort key"
+msgstr "clave de clasificación"
+
+#: models.py:48
+msgid "category"
+msgstr "categoría"
+
+#: models.py:50 models.py:87 models.py:171 models.py:306
+msgid "description"
+msgstr "descripción"
+
+#: models.py:51
+msgid "main page"
+msgstr "página principal"
+
+#: models.py:51
+msgid "Show tag on main page"
+msgstr "Mostrar tag en la página principal"
+
+#: models.py:54
+msgid "book count"
+msgstr "número de los libros"
+
+#: models.py:55
+msgid "year of death"
+msgstr "año de muerte"
+
+#: models.py:71
+msgid "tag"
+msgstr "tag"
+
+#: models.py:72
+msgid "tags"
+msgstr "tags"
+
+#: models.py:169 models.py:584
+msgid "title"
+msgstr "título"
+
+#: models.py:172
+msgid "creation date"
+msgstr "fecha de creación"
+
+#: models.py:173
+msgid "short HTML"
+msgstr "HTML corto"
+
+#: models.py:174
+msgid "parent number"
+msgstr "cifra matriz"
+
+#: models.py:175
+msgid "extra information"
+msgstr "informacion adiccional"
+
+#: models.py:181
+msgid "XML file"
+msgstr "archivo XML"
+
+#: models.py:182
+msgid "HTML file"
+msgstr "archivo HTML"
+
+#: models.py:183
+msgid "PDF file"
+msgstr "archivo PDF"
+
+#: models.py:184
+msgid "EPUB file"
+msgstr "archivo EPUB"
+
+#: models.py:185
+msgid "ODT file"
+msgstr "archivo ODT"
+
+#: models.py:186
+msgid "TXT file"
+msgstr "archivo TXT"
+
+#: models.py:187
+msgid "MP3 file"
+msgstr "archivo MP3"
+
+#: models.py:188
+msgid "OGG file"
+msgstr "archivo OGG"
+
+#: models.py:205
+msgid "books"
+msgstr "libros"
+
+#: models.py:263
+msgid "Read online"
+msgstr "Leer online"
+
+#: models.py:403
+#, python-format
+msgid "Book %s already exists"
+msgstr "Libro %s ya existe"
+
+#: models.py:444
+#, python-format
+msgid "Book with slug = \"%s\" does not exist."
+msgstr "Libro con slug = \"%s\" no existe."
+
+#: models.py:565
+msgid "fragment"
+msgstr "fragmento"
+
+#: models.py:566
+msgid "fragments"
+msgstr "fragmentos"
+
+#: models.py:586
+msgid "goes to public domain"
+msgstr "pasa al dominio público"
+
+#: models.py:588
+msgid "translator"
+msgstr "traductor"
+
+#: models.py:589
+msgid "year of translator's death"
+msgstr "año de la muerte del traductor"
+
+#: models.py:593
+msgid "book stub"
+msgstr "vista previa del libro"
+
+#: models.py:594
+msgid "book stubs"
+msgstr "vista previa de libros"
+
+#: models.py:613
+msgid "type"
+msgstr ""
+
+#: models.py:614
+msgid "sha-1 hash"
+msgstr ""
+
+#: models.py:615
+#, fuzzy
+msgid "time"
+msgstr ""
+
+#: models.py:619
+msgid "file record"
+msgstr ""
+
+#: models.py:620
+msgid "file records"
+msgstr ""
+
+#: views.py:452
+#, fuzzy
+msgid "<p>To maintain your shelves you need to be logged in.</p>"
+msgstr "<p>Para organizar tus estantes tienes que ingresar.</p> "
+
+#: views.py:470
+msgid "<p>Shelves were sucessfully saved.</p>"
+msgstr "<p>Estantes han sido guardados. </p>"
+
+#: views.py:494
+msgid "Book was successfully removed from the shelf"
+msgstr "El libro ha sido eliminado del estante."
+
+#: views.py:496
+msgid "This book is not on the shelf"
+msgstr "Este libro no está en el estante"
+
+#: views.py:599
+#, python-format
+msgid "<p>Shelf <strong>%s</strong> was successfully created</p>"
+msgstr "<p>Estante <strong>%s</strong> ha sido creado</p>"
+
+#: views.py:614
+#, python-format
+msgid "<p>Shelf <strong>%s</strong> was successfully removed</p>"
+msgstr "<p>Estante <strong>%s</strong> ha sido eliminado</p>"
+
+# msgid "Today is %(month)s, %(day)s."
+# msgstr "Hoy es el %(día)s de %(mes)es"
+#: views.py:673
+#, python-format
+msgid ""
+"An error occurred: %(exception)s\n"
+"\n"
+"%(tb)s"
+msgstr ""
+"Ha ocurrido un error: %(exception)s\n"
+"\n"
+"%(tb)s"
+
+#: views.py:674
+msgid "Book imported successfully"
+msgstr "El libro ha sido importado."
+
+#: views.py:676
+#, python-format
+msgid "Error importing file: %r"
+msgstr "Ha ocurrido un error al cargar el archivo: %r"
+
+#~ msgid "content type"
+#~ msgstr "tipo de contenido"
+
+#~ msgid "object id"
+#~ msgstr "id de objeto"
diff --git a/apps/catalogue/locale/fr/LC_MESSAGES/django.mo b/apps/catalogue/locale/fr/LC_MESSAGES/django.mo
new file mode 100644 (file)
index 0000000..9f0caac
Binary files /dev/null and b/apps/catalogue/locale/fr/LC_MESSAGES/django.mo differ
diff --git a/apps/catalogue/locale/fr/LC_MESSAGES/django.po b/apps/catalogue/locale/fr/LC_MESSAGES/django.po
new file mode 100644 (file)
index 0000000..1fb3e64
--- /dev/null
@@ -0,0 +1,287 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-05-25 11:21+0200\n"
+"PO-Revision-Date: 2010-08-07 20:25+0100\n"
+"Last-Translator: Natalia Kertyczak <natalczyk@o2.pl>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: fields.py:47
+#, python-format
+msgid "Enter a valid JSON value. Error: %s"
+msgstr "Entrer une valeur JSON valide. Erreur: %s."
+
+#: forms.py:28
+msgid "title, author, theme/topic, epoch, kind, genre"
+msgstr "titre, auteur, thème/sujet, époque, type, genre"
+
+#: forms.py:44
+msgid "Shelves"
+msgstr "Etagères"
+
+#: forms.py:57
+msgid "Name of the new shelf"
+msgstr "Nom de l'étagère nouvelle"
+
+#: models.py:24
+#: models.py:363
+msgid "author"
+msgstr "auteur"
+
+#: models.py:25
+msgid "epoch"
+msgstr "époque"
+
+#: models.py:26
+msgid "kind"
+msgstr "type"
+
+#: models.py:27
+msgid "genre"
+msgstr "genre"
+
+#: models.py:28
+msgid "theme"
+msgstr "thème"
+
+#: models.py:29
+msgid "set"
+msgstr "série"
+
+#: models.py:30
+#: models.py:322
+msgid "book"
+msgstr "livre"
+
+#: models.py:44
+#: migrations/0001_initial.py:47
+msgid "name"
+msgstr "nom"
+
+#: models.py:45
+#: models.py:103
+#: models.py:365
+#: migrations/0001_initial.py:19
+#: migrations/0001_initial.py:48
+msgid "slug"
+msgstr "slug"
+
+#: models.py:46
+#: migrations/0001_initial.py:49
+msgid "sort key"
+msgstr "critère de tri"
+
+#: models.py:47
+#: migrations/0001_initial.py:50
+msgid "category"
+msgstr "catégorie"
+
+#: models.py:49
+#: models.py:60
+#: models.py:104
+#: models.py:185
+#: migrations/0001_initial.py:20
+#: migrations/0001_initial.py:51
+msgid "description"
+msgstr "description"
+
+#: models.py:50
+#: migrations/0001_initial.py:52
+msgid "main page"
+msgstr "page d'accueil"
+
+#: models.py:50
+#: migrations/0001_initial.py:52
+msgid "Show tag on main page"
+msgstr "Montrer le tag au page d'accueil"
+
+#: models.py:53
+#: migrations/0001_initial.py:54
+msgid "book count"
+msgstr "nombre des livres"
+
+#: models.py:54
+msgid "year of death"
+msgstr "année de la mort"
+
+#: models.py:80
+#: migrations/0001_initial.py:61
+msgid "tag"
+msgstr "tag"
+
+#: models.py:81
+msgid "tags"
+msgstr "tags"
+
+#: models.py:102
+#: models.py:362
+#: migrations/0001_initial.py:18
+msgid "title"
+msgstr "titre"
+
+#: models.py:105
+#: migrations/0001_initial.py:21
+msgid "creation date"
+msgstr "date de création"
+
+#: models.py:106
+#: migrations/0001_initial.py:22
+msgid "short HTML"
+msgstr "HTML court"
+
+#: models.py:107
+#: migrations/0001_initial.py:23
+msgid "parent number"
+msgstr "nombre de parent"
+
+#: models.py:108
+msgid "extra information"
+msgstr "information supplémentaire"
+
+#: models.py:114
+#: migrations/0001_initial.py:24
+msgid "XML file"
+msgstr "fichier XML"
+
+#: models.py:115
+#: migrations/0001_initial.py:25
+msgid "HTML file"
+msgstr "fichier HTML"
+
+#: models.py:116
+#: migrations/0001_initial.py:26
+msgid "PDF file"
+msgstr "fichier PDF"
+
+#: models.py:117
+#: migrations/0001_initial.py:27
+msgid "ODT file"
+msgstr "fichier ODT"
+
+#: models.py:118
+#: migrations/0001_initial.py:28
+msgid "TXT file"
+msgstr "fichier TXT"
+
+#: models.py:119
+msgid "MP3 file"
+msgstr "fichier MP3"
+
+#: models.py:120
+msgid "OGG file"
+msgstr "fichier OGG"
+
+#: models.py:141
+msgid "Read online"
+msgstr "Lire en ligne"
+
+#: models.py:221
+#, python-format
+msgid "Book %s already exists"
+msgstr "Livre %s existe déjà"
+
+#: models.py:264
+#, python-format
+msgid "Book with slug = \"%s\" does not exist."
+msgstr "Livre au slug = \"%s\" n'existe pas."
+
+#: models.py:323
+msgid "books"
+msgstr "livres"
+
+#: models.py:357
+msgid "fragment"
+msgstr "extrait"
+
+#: models.py:358
+msgid "fragments"
+msgstr "extraits"
+
+#: models.py:364
+msgid "goes to public domain"
+msgstr "entre dans le domaine public"
+
+#: models.py:366
+msgid "translator"
+msgstr "traducteur"
+
+#: models.py:367
+msgid "year of translator's death"
+msgstr "année de la mort du traducteur"
+
+#: models.py:385
+msgid "book stub"
+msgstr "ébauche du livre"
+
+#: models.py:386
+msgid "book stubs"
+msgstr "ébauches des livres"
+
+#: views.py:339
+msgid "<p>To maintain your shelves you need to be logged in.</p>"
+msgstr "<p>Connectez-vous pour gérer vos étagères.</p>"
+
+#: views.py:357
+msgid "<p>Shelves were sucessfully saved.</p>"
+msgstr "<p>Les étagères <strong>%s</strong>ont été enregistrées</p>"
+
+#: views.py:381
+msgid "Book was successfully removed from the shelf"
+msgstr "Le livre a été supprimé de l'étagère"
+
+#: views.py:383
+msgid "This book is not on the shelf"
+msgstr "Le livre n'est pas sur l'étagère"
+
+#: views.py:479
+#, python-format
+msgid "<p>Shelf <strong>%s</strong> was successfully created</p>"
+msgstr "<p>L'étagère <strong>%s</strong>a été créée</p>"
+
+#: views.py:494
+#, python-format
+msgid "<p>Shelf <strong>%s</strong> was successfully removed</p>"
+msgstr "<p>L'étagère <strong>%s</strong>a été supprimée</p>"
+
+#: views.py:553
+#, python-format
+#msgid "Today is %(month)s, %(day)s."
+#msgstr "Aujourd'hui nous sommes le"
+
+#: views.py:554
+#, python-format
+msgid ""
+"An error occurred: %(exception)s\n"
+"\n"
+"%(tb)s"
+msgstr ""
+"Un erreur a eu lieu : %(exception)s\n"
+"\n"
+"%(tb)s"
+
+#: views.py:555
+msgid "Book imported successfully"
+msgstr "Livre importé avec succès"
+
+#: views.py:557
+#, python-format
+msgid "Error importing file: %r"
+msgstr "Erreur dans l'importation du fichier: %r"
+
+#: migrations/0001_initial.py:62
+msgid "content type"
+msgstr "type du contenu"
+
+#: migrations/0001_initial.py:63
+msgid "object id"
+msgstr "ID de l'objet"
+
diff --git a/apps/catalogue/locale/lt/LC_MESSAGES/django.mo b/apps/catalogue/locale/lt/LC_MESSAGES/django.mo
new file mode 100644 (file)
index 0000000..602cf55
Binary files /dev/null and b/apps/catalogue/locale/lt/LC_MESSAGES/django.mo differ
diff --git a/apps/catalogue/locale/lt/LC_MESSAGES/django.po b/apps/catalogue/locale/lt/LC_MESSAGES/django.po
new file mode 100644 (file)
index 0000000..03f79a5
--- /dev/null
@@ -0,0 +1,280 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-08-25 10:24+0000\n"
+"PO-Revision-Date: 2010-07-12 19:07+0100\n"
+"Last-Translator: Alicja Sinkiewicz <alicja.sinkiewicz@gmail.com>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Translated-Using: django-rosetta 0.5.3\n"
+
+#: fields.py:47
+#, python-format
+msgid "Enter a valid JSON value. Error: %s"
+msgstr "Įvėsk atitinkama vertybę JSON. Klaida: %s"
+
+#: forms.py:28
+msgid "title, author, theme/topic, epoch, kind, genre"
+msgstr "Pavadinimas , autorius, motyvas /tema, gadynė, \trūšis, sortas"
+
+#: forms.py:45
+msgid "Shelves"
+msgstr "Lentynos"
+
+#: forms.py:58
+msgid "Name of the new shelf"
+msgstr "Naujos lentynos pavadinimas"
+
+#: models.py:25 models.py:585
+msgid "author"
+msgstr "autorius"
+
+#: models.py:26
+msgid "epoch"
+msgstr "gadynė"
+
+#: models.py:27
+msgid "kind"
+msgstr "rūšis"
+
+#: models.py:28
+msgid "genre"
+msgstr "sortas"
+
+#: models.py:29
+msgid "theme"
+msgstr "motyvas"
+
+#: models.py:30
+msgid "set"
+msgstr "rinkinys"
+
+#: models.py:31 models.py:204
+msgid "book"
+msgstr "knyga"
+
+#: models.py:45
+msgid "name"
+msgstr "pavadinimas"
+
+#: models.py:46 models.py:170 models.py:587 models.py:612
+msgid "slug"
+msgstr "slugas"
+
+#: models.py:47
+msgid "sort key"
+msgstr "rūšiavimo raktas"
+
+#: models.py:48
+msgid "category"
+msgstr "kategorija  "
+
+#: models.py:50 models.py:87 models.py:171 models.py:306
+msgid "description"
+msgstr "aprašymas"
+
+#: models.py:51
+msgid "main page"
+msgstr "pagrindinis puslapis"
+
+#: models.py:51
+msgid "Show tag on main page"
+msgstr "Parodyk tagą pagrindinemę puslapyję"
+
+#: models.py:54
+msgid "book count"
+msgstr "knygų skaičius"
+
+#: models.py:55
+msgid "year of death"
+msgstr "mirimo metai"
+
+#: models.py:71
+msgid "tag"
+msgstr "tagas"
+
+#: models.py:72
+msgid "tags"
+msgstr "tagai"
+
+#: models.py:169 models.py:584
+msgid "title"
+msgstr "pavadinimas"
+
+#: models.py:172
+msgid "creation date"
+msgstr "sukūrimo data"
+
+#: models.py:173
+msgid "short HTML"
+msgstr "trumpas  HTML"
+
+#: models.py:174
+msgid "parent number"
+msgstr "vieno iš tėvų numeris "
+
+#: models.py:175
+msgid "extra information"
+msgstr "papildomos informacijos"
+
+#: models.py:181
+msgid "XML file"
+msgstr "XML failas "
+
+#: models.py:182
+msgid "HTML file"
+msgstr "HTML failas"
+
+#: models.py:183
+msgid "PDF file"
+msgstr "PDF failas"
+
+#: models.py:184
+#, fuzzy
+msgid "EPUB file"
+msgstr "PDF failas"
+
+#: models.py:185
+msgid "ODT file"
+msgstr "ODT failas"
+
+#: models.py:186
+msgid "TXT file"
+msgstr "TXT failsa"
+
+#: models.py:187
+msgid "MP3 file"
+msgstr "MP3 failas"
+
+#: models.py:188
+msgid "OGG file"
+msgstr "OGG failas"
+
+#: models.py:205
+msgid "books"
+msgstr "knygos"
+
+#: models.py:263
+msgid "Read online"
+msgstr "Skaityk online"
+
+#: models.py:403
+#, python-format
+msgid "Book %s already exists"
+msgstr "Knyga %s jau egzistuoja"
+
+#: models.py:444
+#, python-format
+msgid "Book with slug = \"%s\" does not exist."
+msgstr "Knyga su slug = \"%s\" neegzistuoja."
+
+#: models.py:565
+msgid "fragment"
+msgstr "fragmentas"
+
+#: models.py:566
+msgid "fragments"
+msgstr "fragmentai"
+
+#: models.py:586
+msgid "goes to public domain"
+msgstr "keliauja į viešą tinklapį  "
+
+#: models.py:588
+msgid "translator"
+msgstr "vertėjas"
+
+#: models.py:589
+msgid "year of translator's death"
+msgstr "vertėjo mirimo metai"
+
+#: models.py:593
+msgid "book stub"
+msgstr "knygos paskelbimas"
+
+#: models.py:594
+msgid "book stubs"
+msgstr "knygu paskelbimai"
+
+#: models.py:613
+msgid "type"
+msgstr ""
+
+#: models.py:614
+msgid "sha-1 hash"
+msgstr ""
+
+#: models.py:615
+#, fuzzy
+msgid "time"
+msgstr "motyvas"
+
+#: models.py:619
+msgid "file record"
+msgstr ""
+
+#: models.py:620
+msgid "file records"
+msgstr ""
+
+#: views.py:452
+msgid "<p>To maintain your shelves you need to be logged in.</p>"
+msgstr "<p>Kad valdyti savo lentynom, turi prisijungti.</p>"
+
+#: views.py:470
+msgid "<p>Shelves were sucessfully saved.</p>"
+msgstr "<p>Lentynos liko užrašytos.</p>"
+
+#: views.py:494
+msgid "Book was successfully removed from the shelf"
+msgstr "pašalinta"
+
+#: views.py:496
+msgid "This book is not on the shelf"
+msgstr "Lentynoje trūksta knygos"
+
+#: views.py:599
+#, python-format
+msgid "<p>Shelf <strong>%s</strong> was successfully created</p>"
+msgstr "<p>Lentyna <strong>%s</strong> sukurta</p>"
+
+#: views.py:614
+#, python-format
+msgid "<p>Shelf <strong>%s</strong> was successfully removed</p>"
+msgstr "<p>Lentyna <strong>%s</strong>pašalinta</p>"
+
+# msgid "Today is %(month)s, %(day)s."
+# msgstr "Šiandien yra %(mėnuo), %(diena)."
+#: views.py:673
+#, python-format
+msgid ""
+"An error occurred: %(exception)s\n"
+"\n"
+"%(tb)s"
+msgstr ""
+"Įvyko klaida: %(exception)s\n"
+"\n"
+"%(tb)s"
+
+#: views.py:674
+msgid "Book imported successfully"
+msgstr "knygos importavimas"
+
+#: views.py:676
+#, python-format
+msgid "Error importing file: %r"
+msgstr "Failo klaida imortavimo metu: %r"
+
+#~ msgid "content type"
+#~ msgstr "turinio rūšis"
+
+#~ msgid "object id"
+#~ msgstr "id obiektas"
diff --git a/apps/catalogue/locale/pl/LC_MESSAGES/django.mo b/apps/catalogue/locale/pl/LC_MESSAGES/django.mo
new file mode 100644 (file)
index 0000000..e138c2a
Binary files /dev/null and b/apps/catalogue/locale/pl/LC_MESSAGES/django.mo differ
diff --git a/apps/catalogue/locale/pl/LC_MESSAGES/django.po b/apps/catalogue/locale/pl/LC_MESSAGES/django.po
new file mode 100644 (file)
index 0000000..0fcfc61
--- /dev/null
@@ -0,0 +1,270 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+# 
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-08-25 10:24+0000\n"
+"PO-Revision-Date: 2010-08-25 11:02\n"
+"Last-Translator: <radek.czajka@gmail.com>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Translated-Using: django-rosetta 0.5.6\n"
+
+#: fields.py:47
+#, python-format
+msgid "Enter a valid JSON value. Error: %s"
+msgstr "Wprowadź prawidłową wartość JSON. Błąd: %s"
+
+#: forms.py:28
+msgid "title, author, theme/topic, epoch, kind, genre"
+msgstr "tytuł, autor, motyw/temat, epoka, rodzaj, gatunek"
+
+#: forms.py:45
+msgid "Shelves"
+msgstr "Półki"
+
+#: forms.py:58
+msgid "Name of the new shelf"
+msgstr "nazwa nowej półki"
+
+#: models.py:25 models.py:585
+msgid "author"
+msgstr "autor"
+
+#: models.py:26
+msgid "epoch"
+msgstr "epoka"
+
+#: models.py:27
+msgid "kind"
+msgstr "rodzaj"
+
+#: models.py:28
+msgid "genre"
+msgstr "gatunek"
+
+#: models.py:29
+msgid "theme"
+msgstr "motyw"
+
+#: models.py:30
+msgid "set"
+msgstr "półka"
+
+#: models.py:31 models.py:204
+msgid "book"
+msgstr "książka"
+
+#: models.py:45
+msgid "name"
+msgstr "nazwa"
+
+#: models.py:46 models.py:170 models.py:587 models.py:612
+msgid "slug"
+msgstr ""
+
+#: models.py:47
+msgid "sort key"
+msgstr "klucz sortowania"
+
+#: models.py:48
+msgid "category"
+msgstr "kategoria"
+
+#: models.py:50 models.py:87 models.py:171 models.py:306
+msgid "description"
+msgstr "opis"
+
+#: models.py:51
+msgid "main page"
+msgstr "strona główna"
+
+#: models.py:51
+msgid "Show tag on main page"
+msgstr "Pokazuj tag na stronie głównej"
+
+#: models.py:54
+msgid "book count"
+msgstr "liczba książek"
+
+#: models.py:55
+msgid "year of death"
+msgstr "rok śmierci"
+
+#: models.py:71
+msgid "tag"
+msgstr "tag"
+
+#: models.py:72
+msgid "tags"
+msgstr "tagi"
+
+#: models.py:169 models.py:584
+msgid "title"
+msgstr "tytuł"
+
+#: models.py:172
+msgid "creation date"
+msgstr "data utworzenia"
+
+#: models.py:173
+msgid "short HTML"
+msgstr "krótki HTML"
+
+#: models.py:174
+msgid "parent number"
+msgstr "numer rodzica"
+
+#: models.py:175
+msgid "extra information"
+msgstr "dodatkowe informacje"
+
+#: models.py:181
+msgid "XML file"
+msgstr "Plik XML"
+
+#: models.py:182
+msgid "HTML file"
+msgstr "Plik HTML"
+
+#: models.py:183
+msgid "PDF file"
+msgstr "Plik PDF"
+
+#: models.py:184
+msgid "EPUB file"
+msgstr "Plik EPUB"
+
+#: models.py:185
+msgid "ODT file"
+msgstr "Plik ODT"
+
+#: models.py:186
+msgid "TXT file"
+msgstr "Plik TXT"
+
+#: models.py:187
+msgid "MP3 file"
+msgstr "Plik MP3"
+
+#: models.py:188
+msgid "OGG file"
+msgstr "Plik OGG"
+
+#: models.py:205
+msgid "books"
+msgstr "książki"
+
+#: models.py:263
+msgid "Read online"
+msgstr "Czytaj online"
+
+#: models.py:403
+#, python-format
+msgid "Book %s already exists"
+msgstr "Książka %s już istnieje"
+
+#: models.py:444
+#, python-format
+msgid "Book with slug = \"%s\" does not exist."
+msgstr "Książki ο slug = \"%s\" nie istnieje."
+
+#: models.py:565
+msgid "fragment"
+msgstr "fragment"
+
+#: models.py:566
+msgid "fragments"
+msgstr "fragmenty"
+
+#: models.py:586
+msgid "goes to public domain"
+msgstr "trafia do domeny publicznej"
+
+#: models.py:588
+msgid "translator"
+msgstr "tłumacz"
+
+#: models.py:589
+msgid "year of translator's death"
+msgstr "rok śmierci tłumacza"
+
+#: models.py:593
+msgid "book stub"
+msgstr "zapowiedź książki"
+
+#: models.py:594
+msgid "book stubs"
+msgstr "zapowiedzi książek"
+
+#: models.py:613
+msgid "type"
+msgstr ""
+
+#: models.py:614
+msgid "sha-1 hash"
+msgstr ""
+
+#: models.py:615
+msgid "time"
+msgstr "czas"
+
+#: models.py:619
+msgid "file record"
+msgstr ""
+
+#: models.py:620
+msgid "file records"
+msgstr ""
+
+#: views.py:452
+msgid "<p>To maintain your shelves you need to be logged in.</p>"
+msgstr "<p>Aby zarządzać swoimi półkami, musisz się zalogować.</p>"
+
+#: views.py:470
+msgid "<p>Shelves were sucessfully saved.</p>"
+msgstr "<p>Półki zostały zapisane.</p>"
+
+#: views.py:494
+msgid "Book was successfully removed from the shelf"
+msgstr "Usunięto"
+
+#: views.py:496
+msgid "This book is not on the shelf"
+msgstr "Książki nie ma na półce"
+
+#: views.py:599
+#, python-format
+msgid "<p>Shelf <strong>%s</strong> was successfully created</p>"
+msgstr "<p>Półka <strong>%s</strong> została utworzona</p>"
+
+#: views.py:614
+#, python-format
+msgid "<p>Shelf <strong>%s</strong> was successfully removed</p>"
+msgstr "<p>Półka <strong>%s</strong> została usunięta</p>"
+
+#: views.py:673
+#, python-format
+msgid ""
+"An error occurred: %(exception)s\n"
+"\n"
+"%(tb)s"
+msgstr ""
+"Wystąpił błąd: %(exception)s\n"
+"\n"
+"%(tb)s"
+
+#: views.py:674
+msgid "Book imported successfully"
+msgstr "Książka zaimportowana"
+
+#: views.py:676
+#, python-format
+msgid "Error importing file: %r"
+msgstr "Błąd podczas importowania pliku: %r"
diff --git a/apps/catalogue/locale/ru/LC_MESSAGES/django.mo b/apps/catalogue/locale/ru/LC_MESSAGES/django.mo
new file mode 100644 (file)
index 0000000..ed1bfbe
Binary files /dev/null and b/apps/catalogue/locale/ru/LC_MESSAGES/django.mo differ
diff --git a/apps/catalogue/locale/ru/LC_MESSAGES/django.po b/apps/catalogue/locale/ru/LC_MESSAGES/django.po
new file mode 100644 (file)
index 0000000..9652781
--- /dev/null
@@ -0,0 +1,280 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+# 
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-08-25 10:24+0000\n"
+"PO-Revision-Date: 2010-08-25 11:02\n"
+"Last-Translator: <radek.czajka@gmail.com>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Translated-Using: django-rosetta 0.5.6\n"
+
+#: fields.py:47
+#, python-format
+msgid "Enter a valid JSON value. Error: %s"
+msgstr "Ввести правильное JSON значение. Ошибка: %s"
+
+#: forms.py:28
+msgid "title, author, theme/topic, epoch, kind, genre"
+msgstr "Заглавие, автор, мотив/тема, эпоха, форма, жанр"
+
+#: forms.py:45
+msgid "Shelves"
+msgstr "Полки"
+
+#: forms.py:58
+msgid "Name of the new shelf"
+msgstr "Название новой полки"
+
+#: models.py:25 models.py:585
+msgid "author"
+msgstr "автор"
+
+#: models.py:26
+msgid "epoch"
+msgstr "эпоха"
+
+#: models.py:27
+msgid "kind"
+msgstr "форма"
+
+#: models.py:28
+msgid "genre"
+msgstr "жанр"
+
+#: models.py:29
+msgid "theme"
+msgstr "мотив"
+
+#: models.py:30
+msgid "set"
+msgstr "набор"
+
+#: models.py:31 models.py:204
+msgid "book"
+msgstr "книга"
+
+#: models.py:45
+msgid "name"
+msgstr "название"
+
+#: models.py:46 models.py:170 models.py:587 models.py:612
+msgid "slug"
+msgstr "slug"
+
+#: models.py:47
+msgid "sort key"
+msgstr "ключ сортировки "
+
+#: models.py:48
+msgid "category"
+msgstr "категория"
+
+#: models.py:50 models.py:87 models.py:171 models.py:306
+msgid "description"
+msgstr "описание"
+
+#: models.py:51
+msgid "main page"
+msgstr "главная страница"
+
+#: models.py:51
+msgid "Show tag on main page"
+msgstr "Показать таг на главной странице"
+
+#: models.py:54
+msgid "book count"
+msgstr "число книг"
+
+#: models.py:55
+msgid "year of death"
+msgstr "год смерти"
+
+#: models.py:71
+msgid "tag"
+msgstr "таг"
+
+#: models.py:72
+msgid "tags"
+msgstr "таги"
+
+#: models.py:169 models.py:584
+msgid "title"
+msgstr "заглавие"
+
+#: models.py:172
+msgid "creation date"
+msgstr "дата создания"
+
+#: models.py:173
+msgid "short HTML"
+msgstr "короткий  HTML"
+
+#: models.py:174
+msgid "parent number"
+msgstr "номер родителя"
+
+#: models.py:175
+msgid "extra information"
+msgstr "дополнительная информация"
+
+#: models.py:181
+msgid "XML file"
+msgstr "XML файл"
+
+#: models.py:182
+msgid "HTML file"
+msgstr "HTML файл"
+
+#: models.py:183
+msgid "PDF file"
+msgstr "PDF файл"
+
+#: models.py:184
+msgid "EPUB file"
+msgstr "EPUB файл"
+
+#: models.py:185
+msgid "ODT file"
+msgstr "ODT файл"
+
+#: models.py:186
+msgid "TXT file"
+msgstr "TXT файл"
+
+#: models.py:187
+msgid "MP3 file"
+msgstr "MP3 файл"
+
+#: models.py:188
+msgid "OGG file"
+msgstr "OGG файл"
+
+#: models.py:205
+msgid "books"
+msgstr "книги"
+
+#: models.py:263
+msgid "Read online"
+msgstr "Читать онлайн"
+
+#: models.py:403
+#, python-format
+msgid "Book %s already exists"
+msgstr "Книга %s уже существует"
+
+#: models.py:444
+#, python-format
+msgid "Book with slug = \"%s\" does not exist."
+msgstr "Книга со slug = \"%s\"  не существует."
+
+#: models.py:565
+msgid "fragment"
+msgstr "фрагмент"
+
+#: models.py:566
+msgid "fragments"
+msgstr "фрагменты"
+
+#: models.py:586
+msgid "goes to public domain"
+msgstr "идти к публичной домене"
+
+#: models.py:588
+msgid "translator"
+msgstr "переводчик"
+
+#: models.py:589
+msgid "year of translator's death"
+msgstr "год смерти переводчика"
+
+#: models.py:593
+msgid "book stub"
+msgstr "анонс книги"
+
+#: models.py:594
+msgid "book stubs"
+msgstr "анонсы книги"
+
+#: models.py:613
+msgid "type"
+msgstr ""
+
+#: models.py:614
+msgid "sha-1 hash"
+msgstr ""
+
+#: models.py:615
+#, fuzzy
+msgid "time"
+msgstr "мотив"
+
+#: models.py:619
+msgid "file record"
+msgstr ""
+
+#: models.py:620
+msgid "file records"
+msgstr ""
+
+#: views.py:452
+msgid "<p>To maintain your shelves you need to be logged in.</p>"
+msgstr "<p>Зарегиструйтесь, чтобы сохранить свои полки.</p>"
+
+#: views.py:470
+msgid "<p>Shelves were sucessfully saved.</p>"
+msgstr "<p>Полки - удачно сохранены.</p>"
+
+#: views.py:494
+msgid "Book was successfully removed from the shelf"
+msgstr "Книга была удачно удалена с полки"
+
+#: views.py:496
+msgid "This book is not on the shelf"
+msgstr "Эта книга не находится на полке"
+
+#: views.py:599
+#, python-format
+msgid "<p>Shelf <strong>%s</strong> was successfully created</p>"
+msgstr "<p>Полка <strong>%s</strong>была удачно создана</p>"
+
+#: views.py:614
+#, python-format
+msgid "<p>Shelf <strong>%s</strong> was successfully removed</p>"
+msgstr "<p>Полка<strong>%s</strong>была удачно удалена."
+
+#: views.py:673
+#, python-format
+msgid ""
+"An error occurred: %(exception)s\n"
+"\n"
+"%(tb)s"
+msgstr ""
+"Появилась ошибка: %(exception)s\n"
+"\n"
+"%(tb)s"
+
+#: views.py:674
+msgid "Book imported successfully"
+msgstr "Вы удачно заимпортировали книгу"
+
+#: views.py:676
+#, python-format
+msgid "Error importing file: %r"
+msgstr "Ошибка импорта файла: %r"
+
+#~ msgid "Today is %(month)s, %(day)s."
+#~ msgstr "Сегодня %(month)s, %(day)s."
+
+#~ msgid "content type"
+#~ msgstr "тип содержания"
+
+#~ msgid "object id"
+#~ msgstr "ID объекта"
diff --git a/apps/catalogue/locale/uk/LC_MESSAGES/django.mo b/apps/catalogue/locale/uk/LC_MESSAGES/django.mo
new file mode 100644 (file)
index 0000000..3edab2d
Binary files /dev/null and b/apps/catalogue/locale/uk/LC_MESSAGES/django.mo differ
diff --git a/apps/catalogue/locale/uk/LC_MESSAGES/django.po b/apps/catalogue/locale/uk/LC_MESSAGES/django.po
new file mode 100644 (file)
index 0000000..9ad1640
--- /dev/null
@@ -0,0 +1,280 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-08-25 10:24+0000\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: Natalia Kertyczak <natalczyk@o2.pl>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: fields.py:47
+#, python-format
+msgid "Enter a valid JSON value. Error: %s"
+msgstr "Введіть правильну вартість JSON. Помилка: %s"
+
+#: forms.py:28
+msgid "title, author, theme/topic, epoch, kind, genre"
+msgstr "заголовок, автор, тема, епоха, рід, жанр"
+
+#: forms.py:45
+msgid "Shelves"
+msgstr "Полиці"
+
+#: forms.py:58
+msgid "Name of the new shelf"
+msgstr "Назва нової полиці"
+
+#: models.py:25 models.py:585
+msgid "author"
+msgstr "автор"
+
+#: models.py:26
+msgid "epoch"
+msgstr "епоха"
+
+#: models.py:27
+msgid "kind"
+msgstr "рід"
+
+#: models.py:28
+msgid "genre"
+msgstr "жанр"
+
+#: models.py:29
+msgid "theme"
+msgstr "тема"
+
+#: models.py:30
+msgid "set"
+msgstr "вибір"
+
+#: models.py:31 models.py:204
+msgid "book"
+msgstr "книжка"
+
+#: models.py:45
+msgid "name"
+msgstr "назва"
+
+#: models.py:46 models.py:170 models.py:587 models.py:612
+msgid "slug"
+msgstr "слуґ"
+
+#: models.py:47
+msgid "sort key"
+msgstr "ключ сортування"
+
+#: models.py:48
+msgid "category"
+msgstr "категорія"
+
+#: models.py:50 models.py:87 models.py:171 models.py:306
+msgid "description"
+msgstr "опис"
+
+
+#: models.py:51
+msgid "main page"
+msgstr "головна сторінка"
+
+#: models.py:51
+msgid "Show tag on main page"
+msgstr "Показати теґ на головній сторінці"
+
+#: models.py:54
+msgid "book count"
+msgstr "кількість книжок"
+
+#: models.py:55
+msgid "year of death"
+msgstr "дата смерті"
+
+#: models.py:71
+msgid "tag"
+msgstr "теґ"
+
+#: models.py:72
+msgid "tags"
+msgstr "теґи"
+
+#: models.py:169 models.py:584
+msgid "title"
+msgstr "заголовок"
+
+#: models.py:172
+msgid "creation date"
+msgstr "дата створення"
+
+#: models.py:173
+msgid "short HTML"
+msgstr "короткий HTML"
+
+#: models.py:174
+msgid "parent number"
+msgstr "номер батька"
+
+#: models.py:175
+msgid "extra information"
+msgstr "додаткова інформація"
+
+#: models.py:181
+msgid "XML file"
+msgstr "файл XML"
+
+#: models.py:182
+msgid "HTML file"
+msgstr "файл HTML"
+
+#: models.py:183
+msgid "PDF file"
+msgstr "файл PDF"
+
+#: models.py:184
+msgid "EPUB file"
+msgstr ""
+
+#: models.py:185
+msgid "ODT file"
+msgstr "файл ODT"
+
+#: models.py:186
+msgid "TXT file"
+msgstr "файл TXT"
+
+#: models.py:187
+msgid "MP3 file"
+msgstr "файл MP3"
+
+#: models.py:188
+msgid "OGG file"
+msgstr "файл OGG"
+
+
+#: models.py:263
+msgid "Read online"
+msgstr "Читати онлайн"
+
+#: models.py:403
+#, python-format
+msgid "Book %s already exists"
+msgstr "Книжка %s вже існує"
+
+#: models.py:444
+#, python-format
+msgid "Book with slug = \"%s\" does not exist."
+msgstr "Книжки зі слуґом = \"%s\" не існує."
+
+#: models.py:323
+msgid "books"
+msgstr "книжки"
+
+#: models.py:565
+msgid "fragment"
+msgstr "фрагмент"
+
+#: models.py:566
+msgid "fragments"
+msgstr "фрагменти"
+
+#: models.py:586
+msgid "goes to public domain"
+msgstr "входить у суспільне надбання"
+
+#: models.py:588
+msgid "translator"
+msgstr "перекладач"
+
+#: models.py:589
+msgid "year of translator's death"
+msgstr "рік смерті перекладача"
+
+#: models.py:593
+msgid "book stub"
+msgstr "заготовка книжки"
+
+#: models.py:594
+msgid "book stubs"
+msgstr "заготовки книжок"
+
+#: models.py:613
+msgid "type"
+msgstr ""
+
+#: models.py:614
+msgid "sha-1 hash"
+msgstr ""
+
+#: models.py:615
+msgid "time"
+msgstr ""
+
+#: models.py:619
+msgid "file record"
+msgstr ""
+
+#: models.py:620
+msgid "file records"
+msgstr ""
+
+#: views.py:452
+msgid "<p>To maintain your shelves you need to be logged in.</p>"
+msgstr "<p>Щоб управляти своїми полицями, увійдть в акаунт</p>"
+
+#: views.py:470
+msgid "<p>Shelves were sucessfully saved.</p>"
+msgstr "<p>Полиці успішно збережено.</p>"
+
+#: views.py:494
+msgid "Book was successfully removed from the shelf"
+msgstr "Книжку було успішно видалено з полиці"
+
+#: views.py:496
+msgid "This book is not on the shelf"
+msgstr "Цієї книжки немає на полиці"
+
+#: views.py:599
+#, python-format
+msgid "<p>Shelf <strong>%s</strong> was successfully created</p>"
+msgstr "<p>Полицю <strong>%s</strong> успішно створено</p>"
+
+#: views.py:614
+#, python-format
+msgid "<p>Shelf <strong>%s</strong> was successfully removed</p>"
+msgstr "<p>Полицю <strong>%s</strong> успішно видалено</p>"
+
+
+#: views.py:673
+#, python-format
+msgid ""
+"An error occurred: %(exception)s\n"
+"\n"
+"%(tb)s"
+msgstr ""
+"Система виявила помилку  %(exception)s\n"
+"\n"
+"%(tb)s"
+
+#: views.py:674
+msgid "Book imported successfully"
+msgstr "Книжку успіщно завантажено"
+
+#: views.py:676
+#, python-format
+msgid "Error importing file: %r"
+msgstr "Помилка в завантаженні файла: %r"
+
+#: migrations/0001_initial.py:62
+msgid "content type"
+msgstr "тип змісту"
+
+#: migrations/0001_initial.py:63
+msgid "object id"
+msgstr "ІД об'єкту"
index 0aa8081..ee469ba 100644 (file)
@@ -1,3 +1,7 @@
+# -*- coding: utf-8 -*-
+# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
 import os
 import sys
 from optparse import make_option
@@ -35,34 +39,38 @@ class Command(BaseCommand):
 
         files_imported = 0
         files_skipped = 0
-        
+
         for dir_name in directories:
             if not os.path.isdir(dir_name):
                 print self.style.ERROR("%s: Not a directory. Skipping." % dir_name)
             else:
-                for file_name in os.listdir(dir_name):
+                for file_name in sorted(os.listdir(dir_name)):
                     file_path = os.path.join(dir_name, file_name)
                     file_base, ext = os.path.splitext(file_path)
-                    
+
                     # Skip files that are not XML files
                     if not ext == '.xml':
                         continue
-                    
+
                     if verbose > 0:
                         print "Parsing '%s'" % file_path
                     else:
                         sys.stdout.write('.')
                         sys.stdout.flush()
-                    
+
                     # Import book files
                     try:
                         book = Book.from_xml_file(file_path, overwrite=force)
                         files_imported += 1
-                        
+
                         if os.path.isfile(file_base + '.pdf'):
                             book.pdf_file.save('%s.pdf' % book.slug, File(file(file_base + '.pdf')))
                             if verbose:
-                                print "Importing %s.pdf" % file_base 
+                                print "Importing %s.pdf" % file_base
+                        if os.path.isfile(file_base + '.epub'):
+                            book.epub_file.save('%s.epub' % book.slug, File(file(file_base + '.epub')))
+                            if verbose:
+                                print "Importing %s.epub" % file_base
                         if os.path.isfile(file_base + '.odt'):
                             book.odt_file.save('%s.odt' % book.slug, File(file(file_base + '.odt')))
                             if verbose:
@@ -79,20 +87,20 @@ class Command(BaseCommand):
                             book.ogg_file.save('%s.ogg' % book.slug, File(file(os.path.join(dir_name, book.slug + '.ogg'))))
                             if verbose:
                                 print "Importing %s.ogg" % book.slug
-                            
+
                         book.save()
-                    
+
                     except Book.AlreadyExists, msg:
                         print self.style.ERROR('%s: Book already imported. Skipping. To overwrite use --force.' %
                             file_path)
                         files_skipped += 1
-                        
+
         # Print results
         print
         print "Results: %d files imported, %d skipped, %d total." % (
             files_imported, files_skipped, files_imported + files_skipped)
         print
-                        
+
         transaction.commit()
         transaction.leave_transaction_management()
 
index 3b16076..2aabb82 100644 (file)
-from django.db import models
-from django.contrib.contenttypes.models import ContentType
-from django.contrib.auth.models import User
+# encoding: utf-8
+import datetime
 from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
 
+class Migration(SchemaMigration):
 
-# Mock gettext
-_ = lambda s: s
+    def forwards(self, orm):
+
+        # Adding model 'Tag'
+        db.create_table('catalogue_tag', (
+            ('category', self.gf('django.db.models.fields.CharField')(max_length=50, db_index=True)),
+            ('gazeta_link', self.gf('django.db.models.fields.CharField')(max_length=240, blank=True)),
+            ('description', self.gf('django.db.models.fields.TextField')(blank=True)),
+            ('main_page', self.gf('django.db.models.fields.BooleanField')(default=False, db_index=True, blank=True)),
+            ('sort_key', self.gf('django.db.models.fields.SlugField')(max_length=120, db_index=True)),
+            ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+            ('wiki_link', self.gf('django.db.models.fields.CharField')(max_length=240, blank=True)),
+            ('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'], null=True, blank=True)),
+            ('slug', self.gf('django.db.models.fields.SlugField')(unique=True, max_length=120, db_index=True)),
+            ('book_count', self.gf('django.db.models.fields.IntegerField')(default=0)),
+            ('name', self.gf('django.db.models.fields.CharField')(max_length=50, db_index=True)),
+        ))
+        db.send_create_signal('catalogue', ['Tag'])
+
+        # Adding model 'TagRelation'
+        db.create_table('catalogue_tag_relation', (
+            ('tag', self.gf('django.db.models.fields.related.ForeignKey')(related_name='items', to=orm['catalogue.Tag'])),
+            ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+            ('content_type', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['contenttypes.ContentType'])),
+            ('object_id', self.gf('django.db.models.fields.PositiveIntegerField')(db_index=True)),
+        ))
+        db.send_create_signal('catalogue', ['TagRelation'])
 
+        # Adding unique constraint on 'TagRelation', fields ['tag', 'content_type', 'object_id']
+        db.create_unique('catalogue_tag_relation', ['tag_id', 'content_type_id', 'object_id'])
 
-class Migration:
-    
-    def forwards(self):
-        # Model 'Book'
-        Book = db.mock_model(model_name='Book', db_table='catalogue_book', db_tablespace='', pk_field_name='id', pk_field_type=models.AutoField)
+        # Adding model 'Book'
         db.create_table('catalogue_book', (
-            ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
-            ('title', models.CharField(_('title'), max_length=120)),
-            ('slug', models.SlugField(_('slug'), max_length=120, unique=True, db_index=True)),
-            ('description', models.TextField(_('description'), blank=True)),
-            ('created_at', models.DateTimeField(_('creation date'), auto_now=True)),
-            ('_short_html', models.TextField(_('short HTML'), editable=False)),
-            ('parent_number', models.IntegerField(_('parent number'), default=0)),
-            ('xml_file', models.FileField(_('XML file'), blank=True)),
-            ('html_file', models.FileField(_('HTML file'), blank=True)),
-            ('pdf_file', models.FileField(_('PDF file'), blank=True)),
-            ('odt_file', models.FileField(_('ODT file'), blank=True)),
-            ('txt_file', models.FileField(_('TXT file'), blank=True)),
-            ('parent', models.ForeignKey(Book, blank=True, null=True, related_name='children')),
+            ('parent', self.gf('django.db.models.fields.related.ForeignKey')(blank=True, related_name='children', null=True, to=orm['catalogue.Book'])),
+            ('mp3_file', self.gf('django.db.models.fields.files.FileField')(max_length=100, blank=True)),
+            ('xml_file', self.gf('django.db.models.fields.files.FileField')(max_length=100, blank=True)),
+            ('description', self.gf('django.db.models.fields.TextField')(blank=True)),
+            ('wiki_link', self.gf('django.db.models.fields.CharField')(max_length=240, blank=True)),
+            ('title', self.gf('django.db.models.fields.CharField')(max_length=120)),
+            ('txt_file', self.gf('django.db.models.fields.files.FileField')(max_length=100, blank=True)),
+            ('created_at', self.gf('django.db.models.fields.DateTimeField')(auto_now=True, blank=True)),
+            ('pdf_file', self.gf('django.db.models.fields.files.FileField')(max_length=100, blank=True)),
+            ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+            ('html_file', self.gf('django.db.models.fields.files.FileField')(max_length=100, blank=True)),
+            ('_short_html', self.gf('django.db.models.fields.TextField')()),
+            ('parent_number', self.gf('django.db.models.fields.IntegerField')(default=0)),
+            ('ogg_file', self.gf('django.db.models.fields.files.FileField')(max_length=100, blank=True)),
+            ('odt_file', self.gf('django.db.models.fields.files.FileField')(max_length=100, blank=True)),
+            ('slug', self.gf('django.db.models.fields.SlugField')(unique=True, max_length=120, db_index=True)),
+            ('gazeta_link', self.gf('django.db.models.fields.CharField')(max_length=240, blank=True)),
+            ('extra_info', self.gf('catalogue.fields.JSONField')()),
         ))
-        
-        # Model 'Fragment'
-        Fragment = db.mock_model(model_name='Fragment', db_table='catalogue_fragment', db_tablespace='', pk_field_name='id', pk_field_type=models.AutoField)
+        db.send_create_signal('catalogue', ['Book'])
+
+        # Adding model 'Fragment'
         db.create_table('catalogue_fragment', (
-            ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
-            ('text', models.TextField()),
-            ('short_text', models.TextField(editable=False)),
-            ('_short_html', models.TextField(editable=False)),
-            ('anchor', models.CharField(max_length=120)),
-            ('book', models.ForeignKey(Book, related_name='fragments')),
-        ))
-        
-        # Model 'Tag'
-        Tag = db.mock_model(model_name='Tag', db_table='catalogue_tag', db_tablespace='', pk_field_name='id', pk_field_type=models.AutoField)
-        db.create_table('catalogue_tag', (
-            ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
-            ('name', models.CharField(_('name'), max_length=50, db_index=True)),
-            ('slug', models.SlugField(_('slug'), max_length=120, unique=True, db_index=True)),
-            ('sort_key', models.SlugField(_('sort key'), max_length=120, db_index=True)),
-            ('category', models.CharField(_('category'), max_length=50, blank=False, null=False, db_index=True)),
-            ('description', models.TextField(_('description'), blank=True)),
-            ('main_page', models.BooleanField(_('main page'), default=False, db_index=True, help_text=_('Show tag on main page'))),
-            ('user', models.ForeignKey(User, blank=True, null=True)),
-            ('book_count', models.IntegerField(_('book count'), default=0, blank=False, null=False)),
+            ('text', self.gf('django.db.models.fields.TextField')()),
+            ('anchor', self.gf('django.db.models.fields.CharField')(max_length=120)),
+            ('_short_html', self.gf('django.db.models.fields.TextField')()),
+            ('book', self.gf('django.db.models.fields.related.ForeignKey')(related_name='fragments', to=orm['catalogue.Book'])),
+            ('short_text', self.gf('django.db.models.fields.TextField')()),
+            ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
         ))
-        
-        # Model 'TagRelation'
-        TagRelation = db.mock_model(model_name='TagRelation', db_table='catalogue_tag_relation', db_tablespace='', pk_field_name='id', pk_field_type=models.AutoField)
-        db.create_table('catalogue_tag_relation', (
-            ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
-            ('tag', models.ForeignKey(Tag, verbose_name=_('tag'), related_name='items')),
-            ('content_type', models.ForeignKey(ContentType, verbose_name=_('content type'))),
-            ('object_id', models.PositiveIntegerField(_('object id'), db_index=True)),
-        ))
-        
-        db.send_create_signal('catalogue', ['Book','Fragment'])
-    
-    def backwards(self):
-        db.delete_table('catalogue_tag_relation')
+        db.send_create_signal('catalogue', ['Fragment'])
+
+
+    def backwards(self, orm):
+
+        # Deleting model 'Tag'
         db.delete_table('catalogue_tag')
-        db.delete_table('catalogue_fragment')
+
+        # Deleting model 'TagRelation'
+        db.delete_table('catalogue_tag_relation')
+
+        # Removing unique constraint on 'TagRelation', fields ['tag', 'content_type', 'object_id']
+        db.delete_unique('catalogue_tag_relation', ['tag_id', 'content_type_id', 'object_id'])
+
+        # Deleting model 'Book'
         db.delete_table('catalogue_book')
-        
+
+        # Deleting model 'Fragment'
+        db.delete_table('catalogue_fragment')
+
+
+    models = {
+        'auth.group': {
+            'Meta': {'object_name': 'Group'},
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+            'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'})
+        },
+        'auth.permission': {
+            'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+            'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+        },
+        'auth.user': {
+            'Meta': {'object_name': 'User'},
+            'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+            'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+            'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+            'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+            'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+            'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+            'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+            'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+            'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+            'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}),
+            'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+        },
+        'catalogue.book': {
+            'Meta': {'object_name': 'Book'},
+            '_short_html': ('django.db.models.fields.TextField', [], {}),
+            'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
+            'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'extra_info': ('catalogue.fields.JSONField', [], {}),
+            'gazeta_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'}),
+            'html_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'mp3_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+            'odt_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+            'ogg_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+            'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'children'", 'null': 'True', 'to': "orm['catalogue.Book']"}),
+            'parent_number': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+            'pdf_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+            'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '120', 'db_index': 'True'}),
+            'title': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
+            'txt_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+            'wiki_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'}),
+            'xml_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'})
+        },
+        'catalogue.fragment': {
+            'Meta': {'object_name': 'Fragment'},
+            '_short_html': ('django.db.models.fields.TextField', [], {}),
+            'anchor': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
+            'book': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'fragments'", 'to': "orm['catalogue.Book']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'short_text': ('django.db.models.fields.TextField', [], {}),
+            'text': ('django.db.models.fields.TextField', [], {})
+        },
+        'catalogue.tag': {
+            'Meta': {'object_name': 'Tag'},
+            'book_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+            'category': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}),
+            'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'gazeta_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'main_page': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True', 'blank': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}),
+            'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '120', 'db_index': 'True'}),
+            'sort_key': ('django.db.models.fields.SlugField', [], {'max_length': '120', 'db_index': 'True'}),
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
+            'wiki_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'})
+        },
+        'catalogue.tagrelation': {
+            'Meta': {'unique_together': "(('tag', 'content_type', 'object_id'),)", 'object_name': 'TagRelation', 'db_table': "'catalogue_tag_relation'"},
+            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'object_id': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
+            'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'items'", 'to': "orm['catalogue.Tag']"})
+        },
+        'contenttypes.contenttype': {
+            'Meta': {'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+            'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+        }
+    }
+
+    complete_apps = ['catalogue']
diff --git a/apps/catalogue/migrations/0002_add_extra_info_to_book.py b/apps/catalogue/migrations/0002_add_extra_info_to_book.py
deleted file mode 100644 (file)
index 6de40ba..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-from south.db import db
-from catalogue.fields import JSONField
-
-class Migration:
-    
-    def forwards(self):
-        db.add_column('catalogue_book', 'extra_info', JSONField(null=True))
-    
-    def backwards(self):
-        db.delete_column('catalogue_book', 'extra_info')
-
diff --git a/apps/catalogue/migrations/0002_auto__add_bookstub__add_field_tag_death.py b/apps/catalogue/migrations/0002_auto__add_bookstub__add_field_tag_death.py
new file mode 100644 (file)
index 0000000..c278a83
--- /dev/null
@@ -0,0 +1,137 @@
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+class Migration(SchemaMigration):
+
+    def forwards(self, orm):
+
+        # Adding model 'BookStub'
+        db.create_table('catalogue_bookstub', (
+            ('author', self.gf('django.db.models.fields.CharField')(max_length=120)),
+            ('title', self.gf('django.db.models.fields.CharField')(max_length=120)),
+            ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+            ('translator', self.gf('django.db.models.fields.TextField')(blank=True)),
+            ('translator_death', self.gf('django.db.models.fields.TextField')(blank=True)),
+            ('pd', self.gf('django.db.models.fields.IntegerField')(null=True, blank=True)),
+            ('slug', self.gf('django.db.models.fields.SlugField')(unique=True, max_length=120, db_index=True)),
+        ))
+        db.send_create_signal('catalogue', ['BookStub'])
+
+        # Adding field 'Tag.death'
+        db.add_column('catalogue_tag', 'death', self.gf('django.db.models.fields.IntegerField')(null=True, blank=True), keep_default=False)
+
+
+    def backwards(self, orm):
+
+        # Deleting model 'BookStub'
+        db.delete_table('catalogue_bookstub')
+
+        # Deleting field 'Tag.death'
+        db.delete_column('catalogue_tag', 'death')
+
+
+    models = {
+        'auth.group': {
+            'Meta': {'object_name': 'Group'},
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+            'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'})
+        },
+        'auth.permission': {
+            'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+            'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+        },
+        'auth.user': {
+            'Meta': {'object_name': 'User'},
+            'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+            'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+            'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+            'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+            'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+            'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+            'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+            'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+            'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+            'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}),
+            'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+        },
+        'catalogue.book': {
+            'Meta': {'object_name': 'Book'},
+            '_short_html': ('django.db.models.fields.TextField', [], {}),
+            'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
+            'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'extra_info': ('catalogue.fields.JSONField', [], {}),
+            'gazeta_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'}),
+            'html_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'mp3_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+            'odt_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+            'ogg_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+            'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'children'", 'null': 'True', 'to': "orm['catalogue.Book']"}),
+            'parent_number': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+            'pdf_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+            'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '120', 'db_index': 'True'}),
+            'title': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
+            'txt_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+            'wiki_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'}),
+            'xml_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'})
+        },
+        'catalogue.bookstub': {
+            'Meta': {'object_name': 'BookStub'},
+            'author': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'pd': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+            'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '120', 'db_index': 'True'}),
+            'title': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
+            'translator': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'translator_death': ('django.db.models.fields.TextField', [], {'blank': 'True'})
+        },
+        'catalogue.fragment': {
+            'Meta': {'object_name': 'Fragment'},
+            '_short_html': ('django.db.models.fields.TextField', [], {}),
+            'anchor': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
+            'book': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'fragments'", 'to': "orm['catalogue.Book']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'short_text': ('django.db.models.fields.TextField', [], {}),
+            'text': ('django.db.models.fields.TextField', [], {})
+        },
+        'catalogue.tag': {
+            'Meta': {'object_name': 'Tag'},
+            'book_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+            'category': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}),
+            'death': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+            'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'gazeta_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'main_page': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True', 'blank': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}),
+            'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '120', 'db_index': 'True'}),
+            'sort_key': ('django.db.models.fields.SlugField', [], {'max_length': '120', 'db_index': 'True'}),
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
+            'wiki_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'})
+        },
+        'catalogue.tagrelation': {
+            'Meta': {'unique_together': "(('tag', 'content_type', 'object_id'),)", 'object_name': 'TagRelation', 'db_table': "'catalogue_tag_relation'"},
+            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'object_id': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
+            'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'items'", 'to': "orm['catalogue.Tag']"})
+        },
+        'contenttypes.contenttype': {
+            'Meta': {'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+            'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+        }
+    }
+
+    complete_apps = ['catalogue']
diff --git a/apps/catalogue/migrations/0003_add_mp3_and_ogg_files_to_book.py b/apps/catalogue/migrations/0003_add_mp3_and_ogg_files_to_book.py
deleted file mode 100644 (file)
index 80d94c0..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-from south.db import db
-from django.db.models import FileField
-
-class Migration:
-    
-    def forwards(self):
-        db.add_column('catalogue_book', 'mp3_file', FileField(null=True))
-        db.add_column('catalogue_book', 'ogg_file', FileField(null=True))
-    
-    def backwards(self):
-        db.delete_column('catalogue_book', 'mp3_file')
-        db.delete_column('catalogue_book', 'ogg_file')
-
diff --git a/apps/catalogue/migrations/0003_fix_book_count_on_shelves.py b/apps/catalogue/migrations/0003_fix_book_count_on_shelves.py
new file mode 100644 (file)
index 0000000..8180311
--- /dev/null
@@ -0,0 +1,138 @@
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import DataMigration
+from django.db import connection, models
+qn = connection.ops.quote_name
+
+class Migration(DataMigration):
+
+    def forwards(self, orm):
+        model = orm.Book
+        model_table = qn(model._meta.db_table)
+        for tag in orm.Tag.objects.exclude(user=None):
+            query = """
+            SELECT COUNT(%(model_pk)s)        -- count books
+            FROM %(model)s, %(tagged_item)s   -- from books x tagged
+            WHERE
+              %(tagged_item)s.tag_id=%(tag_id)s   -- get only the shelf
+              AND %(model_pk)s = %(tagged_item)s.object_id  -- get only books on the shelf
+            GROUP BY %(tagged_item)s.tag_id""" % {
+                'model_pk': '%s.%s' % (model_table, qn(model._meta.pk.column)),
+                'model': model_table,
+                'tagged_item': qn(orm.TagRelation._meta.db_table),
+                'tag_id': tag.pk,
+            }
+
+            cursor = connection.cursor()
+            cursor.execute(query)
+            book_count = (cursor.fetchone() or (0,))[0]
+
+            tag.book_count = book_count
+            tag.save()
+
+    def backwards(self, orm):
+        "Write your backwards methods here."
+
+    models = {
+        'auth.group': {
+            'Meta': {'object_name': 'Group'},
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+            'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'})
+        },
+        'auth.permission': {
+            'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+            'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+        },
+        'auth.user': {
+            'Meta': {'object_name': 'User'},
+            'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+            'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+            'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+            'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+            'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+            'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+            'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+            'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+            'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+            'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}),
+            'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+        },
+        'catalogue.book': {
+            'Meta': {'object_name': 'Book'},
+            '_short_html': ('django.db.models.fields.TextField', [], {}),
+            'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
+            'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'extra_info': ('catalogue.fields.JSONField', [], {}),
+            'gazeta_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'}),
+            'html_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'mp3_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+            'odt_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+            'ogg_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+            'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'children'", 'null': 'True', 'to': "orm['catalogue.Book']"}),
+            'parent_number': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+            'pdf_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+            'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '120', 'db_index': 'True'}),
+            'title': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
+            'txt_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+            'wiki_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'}),
+            'xml_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'})
+        },
+        'catalogue.bookstub': {
+            'Meta': {'object_name': 'BookStub'},
+            'author': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'pd': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+            'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '120', 'db_index': 'True'}),
+            'title': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
+            'translator': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'translator_death': ('django.db.models.fields.TextField', [], {'blank': 'True'})
+        },
+        'catalogue.fragment': {
+            'Meta': {'object_name': 'Fragment'},
+            '_short_html': ('django.db.models.fields.TextField', [], {}),
+            'anchor': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
+            'book': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'fragments'", 'to': "orm['catalogue.Book']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'short_text': ('django.db.models.fields.TextField', [], {}),
+            'text': ('django.db.models.fields.TextField', [], {})
+        },
+        'catalogue.tag': {
+            'Meta': {'object_name': 'Tag'},
+            'book_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+            'category': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}),
+            'death': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+            'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'gazeta_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'main_page': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True', 'blank': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}),
+            'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '120', 'db_index': 'True'}),
+            'sort_key': ('django.db.models.fields.SlugField', [], {'max_length': '120', 'db_index': 'True'}),
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
+            'wiki_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'})
+        },
+        'catalogue.tagrelation': {
+            'Meta': {'unique_together': "(('tag', 'content_type', 'object_id'),)", 'object_name': 'TagRelation', 'db_table': "'catalogue_tag_relation'"},
+            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'object_id': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
+            'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'items'", 'to': "orm['catalogue.Tag']"})
+        },
+        'contenttypes.contenttype': {
+            'Meta': {'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+            'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+        }
+    }
+
+    complete_apps = ['catalogue']
diff --git a/apps/catalogue/migrations/0004_add_gazeta_links.py b/apps/catalogue/migrations/0004_add_gazeta_links.py
deleted file mode 100644 (file)
index 1e8457d..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-# -*- coding: utf-8 -*-
-from south.db import db
-from django.db import models
-
-
-class Migration:    
-    def forwards(self):
-        db.add_column('catalogue_tag', 'gazeta_link', models.CharField(blank=True, max_length=240, default=''))
-        db.add_column('catalogue_book', 'gazeta_link', models.CharField(blank=True,  max_length=240, default=''))
-    
-    def backwards(self):
-        db.delete_column('catalogue_tag', 'gazeta_link')
-        db.delete_column('catalogue_book', 'gazeta_link')
diff --git a/apps/catalogue/migrations/0004_book_html_shorts_translations.py b/apps/catalogue/migrations/0004_book_html_shorts_translations.py
new file mode 100644 (file)
index 0000000..d9e7b53
--- /dev/null
@@ -0,0 +1,172 @@
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+class Migration(SchemaMigration):
+
+    def forwards(self, orm):
+
+        # Adding field 'Book._short_html_en'
+        db.add_column('catalogue_book', '_short_html_en', self.gf('django.db.models.fields.TextField')(null=True, blank=True), keep_default=False)
+
+        # Adding field 'Book._short_html_es'
+        db.add_column('catalogue_book', '_short_html_es', self.gf('django.db.models.fields.TextField')(null=True, blank=True), keep_default=False)
+
+        # Adding field 'Book._short_html_de'
+        db.add_column('catalogue_book', '_short_html_de', self.gf('django.db.models.fields.TextField')(null=True, blank=True), keep_default=False)
+
+        # Adding field 'Book._short_html_fr'
+        db.add_column('catalogue_book', '_short_html_fr', self.gf('django.db.models.fields.TextField')(null=True, blank=True), keep_default=False)
+
+        # Adding field 'Book._short_html_uk'
+        db.add_column('catalogue_book', '_short_html_uk', self.gf('django.db.models.fields.TextField')(null=True, blank=True), keep_default=False)
+
+        # Adding field 'Book._short_html_pl'
+        db.add_column('catalogue_book', '_short_html_pl', self.gf('django.db.models.fields.TextField')(null=True, blank=True), keep_default=False)
+
+        # Adding field 'Book._short_html_ru'
+        db.add_column('catalogue_book', '_short_html_ru', self.gf('django.db.models.fields.TextField')(null=True, blank=True), keep_default=False)
+
+        # Adding field 'Book._short_html_lt'
+        db.add_column('catalogue_book', '_short_html_lt', self.gf('django.db.models.fields.TextField')(null=True, blank=True), keep_default=False)
+
+
+    def backwards(self, orm):
+
+        # Deleting field 'Book._short_html_en'
+        db.delete_column('catalogue_book', '_short_html_en')
+
+        # Deleting field 'Book._short_html_es'
+        db.delete_column('catalogue_book', '_short_html_es')
+
+        # Deleting field 'Book._short_html_de'
+        db.delete_column('catalogue_book', '_short_html_de')
+
+        # Deleting field 'Book._short_html_fr'
+        db.delete_column('catalogue_book', '_short_html_fr')
+
+        # Deleting field 'Book._short_html_uk'
+        db.delete_column('catalogue_book', '_short_html_uk')
+
+        # Deleting field 'Book._short_html_pl'
+        db.delete_column('catalogue_book', '_short_html_pl')
+
+        # Deleting field 'Book._short_html_ru'
+        db.delete_column('catalogue_book', '_short_html_ru')
+
+        # Deleting field 'Book._short_html_lt'
+        db.delete_column('catalogue_book', '_short_html_lt')
+
+
+    models = {
+        'auth.group': {
+            'Meta': {'object_name': 'Group'},
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+            'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'})
+        },
+        'auth.permission': {
+            'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+            'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+        },
+        'auth.user': {
+            'Meta': {'object_name': 'User'},
+            'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+            'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+            'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+            'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+            'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+            'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+            'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+            'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+            'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+            'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}),
+            'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+        },
+        'catalogue.book': {
+            'Meta': {'object_name': 'Book'},
+            '_short_html': ('django.db.models.fields.TextField', [], {}),
+            '_short_html_de': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_en': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_es': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_fr': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_lt': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_pl': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_ru': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_uk': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
+            'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'extra_info': ('catalogue.fields.JSONField', [], {}),
+            'gazeta_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'}),
+            'html_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'mp3_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+            'odt_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+            'ogg_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+            'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'children'", 'null': 'True', 'to': "orm['catalogue.Book']"}),
+            'parent_number': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+            'pdf_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+            'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '120', 'db_index': 'True'}),
+            'title': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
+            'txt_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+            'wiki_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'}),
+            'xml_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'})
+        },
+        'catalogue.bookstub': {
+            'Meta': {'object_name': 'BookStub'},
+            'author': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'pd': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+            'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '120', 'db_index': 'True'}),
+            'title': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
+            'translator': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'translator_death': ('django.db.models.fields.TextField', [], {'blank': 'True'})
+        },
+        'catalogue.fragment': {
+            'Meta': {'object_name': 'Fragment'},
+            '_short_html': ('django.db.models.fields.TextField', [], {}),
+            'anchor': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
+            'book': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'fragments'", 'to': "orm['catalogue.Book']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'short_text': ('django.db.models.fields.TextField', [], {}),
+            'text': ('django.db.models.fields.TextField', [], {})
+        },
+        'catalogue.tag': {
+            'Meta': {'object_name': 'Tag'},
+            'book_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+            'category': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}),
+            'death': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+            'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'gazeta_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'main_page': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True', 'blank': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}),
+            'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '120', 'db_index': 'True'}),
+            'sort_key': ('django.db.models.fields.SlugField', [], {'max_length': '120', 'db_index': 'True'}),
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
+            'wiki_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'})
+        },
+        'catalogue.tagrelation': {
+            'Meta': {'unique_together': "(('tag', 'content_type', 'object_id'),)", 'object_name': 'TagRelation', 'db_table': "'catalogue_tag_relation'"},
+            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'object_id': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
+            'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'items'", 'to': "orm['catalogue.Tag']"})
+        },
+        'contenttypes.contenttype': {
+            'Meta': {'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+            'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+        }
+    }
+
+    complete_apps = ['catalogue']
diff --git a/apps/catalogue/migrations/0005_add_wiki_links.py b/apps/catalogue/migrations/0005_add_wiki_links.py
deleted file mode 100644 (file)
index 3fb423a..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-# -*- coding: utf-8 -*-
-from south.db import db
-from django.db import models
-
-
-class Migration:    
-    def forwards(self):
-        db.add_column('catalogue_tag', 'wiki_link', models.CharField(blank=True,  max_length=240, default=''))
-        db.add_column('catalogue_book', 'wiki_link', models.CharField(blank=True,  max_length=240, default=''))
-    
-    def backwards(self):
-        db.delete_column('catalogue_tag', 'wiki_link')
-        db.delete_column('catalogue_book', 'wiki_link')
diff --git a/apps/catalogue/migrations/0005_fragment_html_shorts_translations.py b/apps/catalogue/migrations/0005_fragment_html_shorts_translations.py
new file mode 100644 (file)
index 0000000..8322b4c
--- /dev/null
@@ -0,0 +1,180 @@
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+class Migration(SchemaMigration):
+
+    def forwards(self, orm):
+
+        # Adding field 'Fragment._short_html_de'
+        db.add_column('catalogue_fragment', '_short_html_de', self.gf('django.db.models.fields.TextField')(null=True, blank=True), keep_default=False)
+
+        # Adding field 'Fragment._short_html_pl'
+        db.add_column('catalogue_fragment', '_short_html_pl', self.gf('django.db.models.fields.TextField')(null=True, blank=True), keep_default=False)
+
+        # Adding field 'Fragment._short_html_lt'
+        db.add_column('catalogue_fragment', '_short_html_lt', self.gf('django.db.models.fields.TextField')(null=True, blank=True), keep_default=False)
+
+        # Adding field 'Fragment._short_html_en'
+        db.add_column('catalogue_fragment', '_short_html_en', self.gf('django.db.models.fields.TextField')(null=True, blank=True), keep_default=False)
+
+        # Adding field 'Fragment._short_html_fr'
+        db.add_column('catalogue_fragment', '_short_html_fr', self.gf('django.db.models.fields.TextField')(null=True, blank=True), keep_default=False)
+
+        # Adding field 'Fragment._short_html_ru'
+        db.add_column('catalogue_fragment', '_short_html_ru', self.gf('django.db.models.fields.TextField')(null=True, blank=True), keep_default=False)
+
+        # Adding field 'Fragment._short_html_es'
+        db.add_column('catalogue_fragment', '_short_html_es', self.gf('django.db.models.fields.TextField')(null=True, blank=True), keep_default=False)
+
+        # Adding field 'Fragment._short_html_uk'
+        db.add_column('catalogue_fragment', '_short_html_uk', self.gf('django.db.models.fields.TextField')(null=True, blank=True), keep_default=False)
+
+
+    def backwards(self, orm):
+
+        # Deleting field 'Fragment._short_html_de'
+        db.delete_column('catalogue_fragment', '_short_html_de')
+
+        # Deleting field 'Fragment._short_html_pl'
+        db.delete_column('catalogue_fragment', '_short_html_pl')
+
+        # Deleting field 'Fragment._short_html_lt'
+        db.delete_column('catalogue_fragment', '_short_html_lt')
+
+        # Deleting field 'Fragment._short_html_en'
+        db.delete_column('catalogue_fragment', '_short_html_en')
+
+        # Deleting field 'Fragment._short_html_fr'
+        db.delete_column('catalogue_fragment', '_short_html_fr')
+
+        # Deleting field 'Fragment._short_html_ru'
+        db.delete_column('catalogue_fragment', '_short_html_ru')
+
+        # Deleting field 'Fragment._short_html_es'
+        db.delete_column('catalogue_fragment', '_short_html_es')
+
+        # Deleting field 'Fragment._short_html_uk'
+        db.delete_column('catalogue_fragment', '_short_html_uk')
+
+
+    models = {
+        'auth.group': {
+            'Meta': {'object_name': 'Group'},
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+            'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'})
+        },
+        'auth.permission': {
+            'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+            'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+        },
+        'auth.user': {
+            'Meta': {'object_name': 'User'},
+            'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+            'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+            'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+            'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+            'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+            'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+            'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+            'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+            'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+            'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}),
+            'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+        },
+        'catalogue.book': {
+            'Meta': {'object_name': 'Book'},
+            '_short_html': ('django.db.models.fields.TextField', [], {}),
+            '_short_html_de': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_en': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_es': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_fr': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_lt': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_pl': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_ru': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_uk': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
+            'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'extra_info': ('catalogue.fields.JSONField', [], {}),
+            'gazeta_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'}),
+            'html_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'mp3_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+            'odt_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+            'ogg_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+            'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'children'", 'null': 'True', 'to': "orm['catalogue.Book']"}),
+            'parent_number': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+            'pdf_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+            'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '120', 'db_index': 'True'}),
+            'title': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
+            'txt_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+            'wiki_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'}),
+            'xml_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'})
+        },
+        'catalogue.bookstub': {
+            'Meta': {'object_name': 'BookStub'},
+            'author': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'pd': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+            'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '120', 'db_index': 'True'}),
+            'title': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
+            'translator': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'translator_death': ('django.db.models.fields.TextField', [], {'blank': 'True'})
+        },
+        'catalogue.fragment': {
+            'Meta': {'object_name': 'Fragment'},
+            '_short_html': ('django.db.models.fields.TextField', [], {}),
+            '_short_html_de': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_en': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_es': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_fr': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_lt': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_pl': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_ru': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_uk': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            'anchor': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
+            'book': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'fragments'", 'to': "orm['catalogue.Book']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'short_text': ('django.db.models.fields.TextField', [], {}),
+            'text': ('django.db.models.fields.TextField', [], {})
+        },
+        'catalogue.tag': {
+            'Meta': {'object_name': 'Tag'},
+            'book_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+            'category': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}),
+            'death': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+            'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'gazeta_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'main_page': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True', 'blank': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}),
+            'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '120', 'db_index': 'True'}),
+            'sort_key': ('django.db.models.fields.SlugField', [], {'max_length': '120', 'db_index': 'True'}),
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
+            'wiki_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'})
+        },
+        'catalogue.tagrelation': {
+            'Meta': {'unique_together': "(('tag', 'content_type', 'object_id'),)", 'object_name': 'TagRelation', 'db_table': "'catalogue_tag_relation'"},
+            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'object_id': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
+            'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'items'", 'to': "orm['catalogue.Tag']"})
+        },
+        'contenttypes.contenttype': {
+            'Meta': {'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+            'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+        }
+    }
+
+    complete_apps = ['catalogue']
diff --git a/apps/catalogue/migrations/0006_epub_tag_counters_and_ltags_descendants.py b/apps/catalogue/migrations/0006_epub_tag_counters_and_ltags_descendants.py
new file mode 100644 (file)
index 0000000..b990fc3
--- /dev/null
@@ -0,0 +1,186 @@
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+def get_ltag(book, orm):
+    ltag, created = orm.Tag.objects.get_or_create(slug='l-' + book.slug, category='book')
+    if created:
+        ltag.name = book.title
+        ltag.sort_key = ('l-' + book.slug)[:120]
+        ltag.save()
+    return ltag
+
+
+class Migration(SchemaMigration):
+
+    def forwards(self, orm):
+        """ Add _tag_counter and make sure all books carry their ancestors' l-tags """
+
+        # Adding fields
+        db.add_column('catalogue_book', '_tag_counter', self.gf('catalogue.fields.JSONField')(null=True))
+        db.add_column('catalogue_book', '_theme_counter', self.gf('catalogue.fields.JSONField')(null=True))
+        db.add_column('catalogue_book', 'epub_file', self.gf('django.db.models.fields.files.FileField')(default='', max_length=100, blank=True), keep_default=False)
+
+        def ltag_descendants(book, ltags=None):
+            if ltags is None:
+                ltags = []
+            for tag in ltags:
+                orm.TagRelation(object_id=book.pk, tag=tag, content_type=book_ct).save()
+                print book, tag
+            ltag = get_ltag(book, orm)
+            for child in book.children.all():
+                ltag_descendants(child, ltags + [ltag])
+
+        if not db.dry_run:
+            try:
+                book_ct = orm['contenttypes.contenttype'].objects.get(app_label='catalogue', model='book')
+            except:
+                return
+            # remove all l-tags on books
+            orm.TagRelation.objects.filter(content_type=book_ct, tag__category='book').delete()
+            for book in orm.Book.objects.filter(parent=None):
+                ltag_descendants(book)
+
+
+    def backwards(self, orm):
+        """ Delete _tag_counter and make sure books carry own l-tag. """
+
+        # Deleting fields
+        db.delete_column('catalogue_book', '_tag_counter')
+        db.delete_column('catalogue_book', '_theme_counter')
+        db.delete_column('catalogue_book', 'epub_file')
+
+        if not db.dry_run:
+            try:
+                book_ct = orm['contenttypes.contenttype'].objects.get(app_label='catalogue', model='book')
+            except:
+                return
+            # remove all l-tags on books
+            orm.TagRelation.objects.filter(content_type=book_ct, tag__category='book').delete()
+            for book in orm.Book.objects.filter(parent=None):
+                orm.TagRelation(object_id=book.pk, tag=get_ltag(book, orm), content_type=book_ct).save()
+
+
+    models = {
+        'auth.group': {
+            'Meta': {'object_name': 'Group'},
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+            'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'})
+        },
+        'auth.permission': {
+            'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+            'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+        },
+        'auth.user': {
+            'Meta': {'object_name': 'User'},
+            'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+            'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+            'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+            'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+            'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+            'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+            'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+            'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+            'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+            'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}),
+            'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+        },
+        'catalogue.book': {
+            'Meta': {'object_name': 'Book'},
+            '_short_html': ('django.db.models.fields.TextField', [], {}),
+            '_short_html_de': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_en': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_es': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_fr': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_lt': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_pl': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_ru': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_uk': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_tag_counter': ('catalogue.fields.JSONField', [], {'null': 'True'}),
+            '_theme_counter': ('catalogue.fields.JSONField', [], {'null': 'True'}),
+            'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
+            'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'epub_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+            'extra_info': ('catalogue.fields.JSONField', [], {}),
+            'gazeta_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'}),
+            'html_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'mp3_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+            'odt_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+            'ogg_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+            'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'children'", 'null': 'True', 'to': "orm['catalogue.Book']"}),
+            'parent_number': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+            'pdf_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+            'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '120', 'db_index': 'True'}),
+            'title': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
+            'txt_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+            'wiki_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'}),
+            'xml_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'})
+        },
+        'catalogue.bookstub': {
+            'Meta': {'object_name': 'BookStub'},
+            'author': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'pd': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+            'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '120', 'db_index': 'True'}),
+            'title': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
+            'translator': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'translator_death': ('django.db.models.fields.TextField', [], {'blank': 'True'})
+        },
+        'catalogue.fragment': {
+            'Meta': {'object_name': 'Fragment'},
+            '_short_html': ('django.db.models.fields.TextField', [], {}),
+            '_short_html_de': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_en': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_es': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_fr': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_lt': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_pl': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_ru': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_uk': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            'anchor': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
+            'book': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'fragments'", 'to': "orm['catalogue.Book']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'short_text': ('django.db.models.fields.TextField', [], {}),
+            'text': ('django.db.models.fields.TextField', [], {})
+        },
+        'catalogue.tag': {
+            'Meta': {'object_name': 'Tag'},
+            'book_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+            'category': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}),
+            'death': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+            'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'gazeta_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'main_page': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True', 'blank': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}),
+            'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '120', 'db_index': 'True'}),
+            'sort_key': ('django.db.models.fields.SlugField', [], {'max_length': '120', 'db_index': 'True'}),
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
+            'wiki_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'})
+        },
+        'catalogue.tagrelation': {
+            'Meta': {'unique_together': "(('tag', 'content_type', 'object_id'),)", 'object_name': 'TagRelation', 'db_table': "'catalogue_tag_relation'"},
+            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'object_id': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
+            'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'items'", 'to': "orm['catalogue.Tag']"})
+        },
+        'contenttypes.contenttype': {
+            'Meta': {'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+            'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+        }
+    }
+
+    complete_apps = ['catalogue']
diff --git a/apps/catalogue/migrations/0007_remove_empty_html.py b/apps/catalogue/migrations/0007_remove_empty_html.py
new file mode 100644 (file)
index 0000000..5b6f453
--- /dev/null
@@ -0,0 +1,146 @@
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import DataMigration
+from django.db import models
+
+class Migration(DataMigration):
+
+    def forwards(self, orm):
+        """ Look for HTML files without any real content and delete them """
+        from lxml import etree
+        from librarian.html import html_has_content
+
+        for book in orm.Book.objects.exclude(html_file=''):
+            if not html_has_content(etree.parse(book.html_file)):
+                book.html_file.delete()
+                # must do it by hand, we don't see real Book.save
+                for key in filter(lambda x: x.startswith('_short_html'), book.__dict__):
+                    book.__setattr__(key, '')
+                book.save()
+
+    def backwards(self, orm):
+        """ Do nothing. We don't want empty HTML files anyway. """
+        pass
+
+    models = {
+        'auth.group': {
+            'Meta': {'object_name': 'Group'},
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+            'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'})
+        },
+        'auth.permission': {
+            'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+            'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+        },
+        'auth.user': {
+            'Meta': {'object_name': 'User'},
+            'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+            'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+            'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+            'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+            'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+            'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+            'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+            'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+            'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+            'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}),
+            'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+        },
+        'catalogue.book': {
+            'Meta': {'object_name': 'Book'},
+            '_short_html': ('django.db.models.fields.TextField', [], {}),
+            '_short_html_de': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_en': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_es': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_fr': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_lt': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_pl': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_ru': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_uk': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_tag_counter': ('catalogue.fields.JSONField', [], {'null': 'True'}),
+            '_theme_counter': ('catalogue.fields.JSONField', [], {'null': 'True'}),
+            'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
+            'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'epub_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+            'extra_info': ('catalogue.fields.JSONField', [], {}),
+            'gazeta_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'}),
+            'html_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'mp3_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+            'odt_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+            'ogg_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+            'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'children'", 'null': 'True', 'to': "orm['catalogue.Book']"}),
+            'parent_number': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+            'pdf_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+            'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '120', 'db_index': 'True'}),
+            'title': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
+            'txt_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+            'wiki_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'}),
+            'xml_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'})
+        },
+        'catalogue.bookstub': {
+            'Meta': {'object_name': 'BookStub'},
+            'author': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'pd': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+            'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '120', 'db_index': 'True'}),
+            'title': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
+            'translator': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'translator_death': ('django.db.models.fields.TextField', [], {'blank': 'True'})
+        },
+        'catalogue.fragment': {
+            'Meta': {'object_name': 'Fragment'},
+            '_short_html': ('django.db.models.fields.TextField', [], {}),
+            '_short_html_de': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_en': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_es': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_fr': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_lt': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_pl': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_ru': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_uk': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            'anchor': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
+            'book': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'fragments'", 'to': "orm['catalogue.Book']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'short_text': ('django.db.models.fields.TextField', [], {}),
+            'text': ('django.db.models.fields.TextField', [], {})
+        },
+        'catalogue.tag': {
+            'Meta': {'object_name': 'Tag'},
+            'book_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+            'category': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}),
+            'death': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+            'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'gazeta_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'main_page': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True', 'blank': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}),
+            'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '120', 'db_index': 'True'}),
+            'sort_key': ('django.db.models.fields.SlugField', [], {'max_length': '120', 'db_index': 'True'}),
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
+            'wiki_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'})
+        },
+        'catalogue.tagrelation': {
+            'Meta': {'unique_together': "(('tag', 'content_type', 'object_id'),)", 'object_name': 'TagRelation', 'db_table': "'catalogue_tag_relation'"},
+            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'object_id': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
+            'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'items'", 'to': "orm['catalogue.Tag']"})
+        },
+        'contenttypes.contenttype': {
+            'Meta': {'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+            'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+        }
+    }
+
+    complete_apps = ['catalogue']
diff --git a/apps/catalogue/migrations/0008_unique_tag_category_slug.py b/apps/catalogue/migrations/0008_unique_tag_category_slug.py
new file mode 100644 (file)
index 0000000..d130819
--- /dev/null
@@ -0,0 +1,147 @@
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+class Migration(SchemaMigration):
+
+    def forwards(self, orm):
+
+        # Removing unique constraint on 'Tag', fields ['slug']
+        db.delete_unique('catalogue_tag', ['slug'])
+
+        # Adding unique constraint on 'Tag', fields ['category', 'slug']
+        db.create_unique('catalogue_tag', ['category', 'slug'])
+
+
+    def backwards(self, orm):
+
+        # Adding unique constraint on 'Tag', fields ['slug']
+        db.create_unique('catalogue_tag', ['slug'])
+
+        # Removing unique constraint on 'Tag', fields ['category', 'slug']
+        db.delete_unique('catalogue_tag', ['category', 'slug'])
+
+
+    models = {
+        'auth.group': {
+            'Meta': {'object_name': 'Group'},
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+            'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'})
+        },
+        'auth.permission': {
+            'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+            'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+        },
+        'auth.user': {
+            'Meta': {'object_name': 'User'},
+            'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+            'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+            'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+            'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+            'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+            'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+            'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+            'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+            'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+            'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}),
+            'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+        },
+        'catalogue.book': {
+            'Meta': {'object_name': 'Book'},
+            '_short_html': ('django.db.models.fields.TextField', [], {}),
+            '_short_html_de': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_en': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_es': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_fr': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_lt': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_pl': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_ru': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_uk': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_tag_counter': ('catalogue.fields.JSONField', [], {'null': 'True'}),
+            '_theme_counter': ('catalogue.fields.JSONField', [], {'null': 'True'}),
+            'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
+            'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'epub_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+            'extra_info': ('catalogue.fields.JSONField', [], {}),
+            'gazeta_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'}),
+            'html_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'mp3_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+            'odt_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+            'ogg_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+            'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'children'", 'null': 'True', 'to': "orm['catalogue.Book']"}),
+            'parent_number': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+            'pdf_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+            'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '120', 'db_index': 'True'}),
+            'title': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
+            'txt_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+            'wiki_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'}),
+            'xml_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'})
+        },
+        'catalogue.bookstub': {
+            'Meta': {'object_name': 'BookStub'},
+            'author': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'pd': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+            'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '120', 'db_index': 'True'}),
+            'title': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
+            'translator': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'translator_death': ('django.db.models.fields.TextField', [], {'blank': 'True'})
+        },
+        'catalogue.fragment': {
+            'Meta': {'object_name': 'Fragment'},
+            '_short_html': ('django.db.models.fields.TextField', [], {}),
+            '_short_html_de': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_en': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_es': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_fr': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_lt': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_pl': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_ru': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_uk': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            'anchor': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
+            'book': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'fragments'", 'to': "orm['catalogue.Book']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'short_text': ('django.db.models.fields.TextField', [], {}),
+            'text': ('django.db.models.fields.TextField', [], {})
+        },
+        'catalogue.tag': {
+            'Meta': {'unique_together': "(('slug', 'category'),)", 'object_name': 'Tag'},
+            'book_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+            'category': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}),
+            'death': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+            'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'gazeta_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'main_page': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True', 'blank': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}),
+            'slug': ('django.db.models.fields.SlugField', [], {'max_length': '120', 'db_index': 'True'}),
+            'sort_key': ('django.db.models.fields.SlugField', [], {'max_length': '120', 'db_index': 'True'}),
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
+            'wiki_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'})
+        },
+        'catalogue.tagrelation': {
+            'Meta': {'unique_together': "(('tag', 'content_type', 'object_id'),)", 'object_name': 'TagRelation', 'db_table': "'catalogue_tag_relation'"},
+            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'object_id': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
+            'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'items'", 'to': "orm['catalogue.Tag']"})
+        },
+        'contenttypes.contenttype': {
+            'Meta': {'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+            'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+        }
+    }
+
+    complete_apps = ['catalogue']
diff --git a/apps/catalogue/migrations/0009_chg_book_count__heavy_cleaning.py b/apps/catalogue/migrations/0009_chg_book_count__heavy_cleaning.py
new file mode 100644 (file)
index 0000000..ed4f2b3
--- /dev/null
@@ -0,0 +1,226 @@
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+class Migration(SchemaMigration):
+
+    def forwards(self, orm):
+
+        # Changing field 'Tag.book_count'
+        db.alter_column('catalogue_tag', 'book_count', self.gf('django.db.models.fields.IntegerField')(null=True))
+
+        if not db.dry_run:
+            from django.contrib.contenttypes.models import ContentType
+            from django.utils.simplejson import loads, dumps
+
+            manager = orm.TagRelation.objects
+
+            def type_id(model):
+                return ContentType.objects.get_for_model(model).pk
+
+            def tagged_with_any(model, tags):
+                object_ids = {}
+                for relation in manager.filter(content_type=type_id(model), tag__in=tags):
+                    object_ids[relation.object_id] = 1
+                return model.objects.filter(pk__in=object_ids.keys())
+
+            def get_tags(instance):
+                return [relation.tag for relation in manager.filter(
+                            content_type=type_id(type(instance)), object_id=instance.pk).select_related()]
+
+            def refresh_book_count(tag):
+                if tag.category == 'theme':
+                    objects = tagged_with_any(orm.Fragment, [tag]).only()
+                else:
+                    objects = tagged_with_any(orm.Book, [tag]).only('slug')
+                    if tag.category != 'set':
+                        # eliminate descendants
+                        l_tags = orm.Tag.objects.filter(slug__in=['l-'+book.slug for book in objects])
+                        descendants_keys = [book.pk for book in tagged_with_any(orm.Book, l_tags)]
+                        if descendants_keys:
+                            objects = objects.exclude(pk__in=descendants_keys)
+                tag.book_count = objects.count()
+                tag.save()
+
+            def refresh_tag_counter(book):
+                tags = {}
+                for child in book.children.all().order_by():
+                    for tag_pk, value in tag_counter(child).iteritems():
+                        tags[tag_pk] = tags.get(tag_pk, 0) + value
+                for tag in [tag for tag in get_tags(book) if tag.category not in ('book', 'theme', 'set')]:
+                    tags[tag.pk] = 1
+                book._tag_counter = dumps(tags)
+                book.save()
+                return tags
+
+            def tag_counter(book):
+                if book._tag_counter is None:
+                    return refresh_tag_counter(book)
+                return dict((int(k), v) for k, v in loads(book._tag_counter).iteritems())
+
+            def theme_counter(book):
+                if book._theme_counter is None:
+                    tags = {}
+                    l_tag = orm.Tag.objects.get(slug='l-'+book.slug)
+                    for fragment in tagged_with_any(orm.Fragment, [l_tag]):
+                        for tag in [tag for tag in get_tags(fragment) if tag.category=='theme']:
+                            tags[tag.pk] = tags.get(tag.pk, 0) + 1
+                    book._theme_counter = dumps(tags)
+                    book.save()
+
+
+            # remove orphaned relations
+            book_type_id = type_id(orm.Book)
+            book_ids = [b.pk for b in orm.Book.objects.all().only()]
+            manager.filter(content_type=book_type_id).exclude(object_id__in=book_ids).delete()
+            del book_ids
+
+            fragment_type_id = type_id(orm.Fragment)
+            fragment_ids = [b.pk for b in orm.Fragment.objects.all().only()]
+            manager.filter(content_type=fragment_type_id).exclude(object_id__in=fragment_ids).delete()
+            del fragment_ids
+
+            tag_ids = [t.pk for t in orm.Tag.objects.all().only()]
+            manager.exclude(tag__in=tag_ids).delete()
+            del tag_ids
+
+            # remove theme tags for books
+            manager.filter(content_type=book_type_id).filter(tag__category='theme').delete()
+
+            # reset count fields
+            for tag in orm.Tag.objects.exclude(category__in=('book', 'set')).iterator():
+                refresh_book_count(tag)
+            for book in orm.Book.objects.all().iterator():
+                theme_counter(book)
+            for book in orm.Book.objects.filter(parent=None).iterator():
+                tag_counter(book)
+
+    def backwards(self, orm):
+
+        # Changing field 'Tag.book_count'
+        db.alter_column('catalogue_tag', 'book_count', self.gf('django.db.models.fields.IntegerField')())
+
+
+    models = {
+        'auth.group': {
+            'Meta': {'object_name': 'Group'},
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+            'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'})
+        },
+        'auth.permission': {
+            'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+            'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+        },
+        'auth.user': {
+            'Meta': {'object_name': 'User'},
+            'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+            'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+            'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+            'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+            'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+            'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+            'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+            'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+            'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+            'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}),
+            'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+        },
+        'catalogue.book': {
+            'Meta': {'object_name': 'Book'},
+            '_short_html': ('django.db.models.fields.TextField', [], {}),
+            '_short_html_de': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_en': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_es': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_fr': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_lt': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_pl': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_ru': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_uk': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_tag_counter': ('catalogue.fields.JSONField', [], {'null': 'True'}),
+            '_theme_counter': ('catalogue.fields.JSONField', [], {'null': 'True'}),
+            'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
+            'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'epub_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+            'extra_info': ('catalogue.fields.JSONField', [], {}),
+            'gazeta_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'}),
+            'html_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'mp3_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+            'odt_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+            'ogg_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+            'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'children'", 'null': 'True', 'to': "orm['catalogue.Book']"}),
+            'parent_number': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+            'pdf_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+            'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '120', 'db_index': 'True'}),
+            'title': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
+            'txt_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+            'wiki_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'}),
+            'xml_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'})
+        },
+        'catalogue.bookstub': {
+            'Meta': {'object_name': 'BookStub'},
+            'author': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'pd': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+            'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '120', 'db_index': 'True'}),
+            'title': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
+            'translator': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'translator_death': ('django.db.models.fields.TextField', [], {'blank': 'True'})
+        },
+        'catalogue.fragment': {
+            'Meta': {'object_name': 'Fragment'},
+            '_short_html': ('django.db.models.fields.TextField', [], {}),
+            '_short_html_de': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_en': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_es': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_fr': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_lt': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_pl': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_ru': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_uk': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            'anchor': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
+            'book': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'fragments'", 'to': "orm['catalogue.Book']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'short_text': ('django.db.models.fields.TextField', [], {}),
+            'text': ('django.db.models.fields.TextField', [], {})
+        },
+        'catalogue.tag': {
+            'Meta': {'unique_together': "(('slug', 'category'),)", 'object_name': 'Tag'},
+            'book_count': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
+            'category': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}),
+            'death': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+            'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'gazeta_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'main_page': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True', 'blank': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}),
+            'slug': ('django.db.models.fields.SlugField', [], {'max_length': '120', 'db_index': 'True'}),
+            'sort_key': ('django.db.models.fields.SlugField', [], {'max_length': '120', 'db_index': 'True'}),
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
+            'wiki_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'})
+        },
+        'catalogue.tagrelation': {
+            'Meta': {'unique_together': "(('tag', 'content_type', 'object_id'),)", 'object_name': 'TagRelation', 'db_table': "'catalogue_tag_relation'"},
+            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'object_id': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
+            'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'items'", 'to': "orm['catalogue.Tag']"})
+        },
+        'contenttypes.contenttype': {
+            'Meta': {'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+            'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+        }
+    }
+
+    complete_apps = ['catalogue']
diff --git a/apps/catalogue/migrations/0010_auto__add_filerecord.py b/apps/catalogue/migrations/0010_auto__add_filerecord.py
new file mode 100644 (file)
index 0000000..f072365
--- /dev/null
@@ -0,0 +1,156 @@
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+class Migration(SchemaMigration):
+    
+    def forwards(self, orm):
+        
+        # Adding model 'FileRecord'
+        db.create_table('catalogue_filerecord', (
+            ('time', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)),
+            ('sha1', self.gf('django.db.models.fields.CharField')(max_length=40)),
+            ('type', self.gf('django.db.models.fields.CharField')(max_length=20, db_index=True)),
+            ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+            ('slug', self.gf('django.db.models.fields.SlugField')(max_length=120, db_index=True)),
+        ))
+        db.send_create_signal('catalogue', ['FileRecord'])
+    
+    
+    def backwards(self, orm):
+        
+        # Deleting model 'FileRecord'
+        db.delete_table('catalogue_filerecord')
+    
+    
+    models = {
+        'auth.group': {
+            'Meta': {'object_name': 'Group'},
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+            'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'})
+        },
+        'auth.permission': {
+            'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+            'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+        },
+        'auth.user': {
+            'Meta': {'object_name': 'User'},
+            'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+            'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+            'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+            'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+            'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+            'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+            'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+            'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+            'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+            'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}),
+            'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+        },
+        'catalogue.book': {
+            'Meta': {'object_name': 'Book'},
+            '_short_html': ('django.db.models.fields.TextField', [], {}),
+            '_short_html_de': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_en': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_es': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_fr': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_lt': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_pl': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_ru': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_uk': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_tag_counter': ('catalogue.fields.JSONField', [], {'null': 'True'}),
+            '_theme_counter': ('catalogue.fields.JSONField', [], {'null': 'True'}),
+            'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
+            'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'epub_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+            'extra_info': ('catalogue.fields.JSONField', [], {}),
+            'gazeta_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'}),
+            'html_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'mp3_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+            'odt_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+            'ogg_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+            'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'children'", 'null': 'True', 'to': "orm['catalogue.Book']"}),
+            'parent_number': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+            'pdf_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+            'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '120', 'db_index': 'True'}),
+            'title': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
+            'txt_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+            'wiki_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'}),
+            'xml_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'})
+        },
+        'catalogue.bookstub': {
+            'Meta': {'object_name': 'BookStub'},
+            'author': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'pd': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+            'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '120', 'db_index': 'True'}),
+            'title': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
+            'translator': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'translator_death': ('django.db.models.fields.TextField', [], {'blank': 'True'})
+        },
+        'catalogue.filerecord': {
+            'Meta': {'object_name': 'FileRecord'},
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'sha1': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
+            'slug': ('django.db.models.fields.SlugField', [], {'max_length': '120', 'db_index': 'True'}),
+            'time': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'type': ('django.db.models.fields.CharField', [], {'max_length': '20', 'db_index': 'True'})
+        },
+        'catalogue.fragment': {
+            'Meta': {'object_name': 'Fragment'},
+            '_short_html': ('django.db.models.fields.TextField', [], {}),
+            '_short_html_de': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_en': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_es': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_fr': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_lt': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_pl': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_ru': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            '_short_html_uk': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            'anchor': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
+            'book': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'fragments'", 'to': "orm['catalogue.Book']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'short_text': ('django.db.models.fields.TextField', [], {}),
+            'text': ('django.db.models.fields.TextField', [], {})
+        },
+        'catalogue.tag': {
+            'Meta': {'unique_together': "(('slug', 'category'),)", 'object_name': 'Tag'},
+            'book_count': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
+            'category': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}),
+            'death': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+            'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'gazeta_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'main_page': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True', 'blank': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}),
+            'slug': ('django.db.models.fields.SlugField', [], {'max_length': '120', 'db_index': 'True'}),
+            'sort_key': ('django.db.models.fields.SlugField', [], {'max_length': '120', 'db_index': 'True'}),
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
+            'wiki_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'})
+        },
+        'catalogue.tagrelation': {
+            'Meta': {'unique_together': "(('tag', 'content_type', 'object_id'),)", 'object_name': 'TagRelation', 'db_table': "'catalogue_tag_relation'"},
+            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'object_id': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
+            'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'items'", 'to': "orm['catalogue.Tag']"})
+        },
+        'contenttypes.contenttype': {
+            'Meta': {'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+            'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+        }
+    }
+    
+    complete_apps = ['catalogue']
index 2f4e7fe..d3b24d3 100644 (file)
@@ -1,4 +1,7 @@
 # -*- coding: utf-8 -*-
+# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
 from django.db import models
 from django.db.models import permalink, Q
 from django.utils.translation import ugettext_lazy as _
@@ -6,13 +9,15 @@ from django.contrib.auth.models import User
 from django.core.files import File
 from django.template.loader import render_to_string
 from django.utils.safestring import mark_safe
+from django.utils.translation import get_language
 from django.core.urlresolvers import reverse
+from datetime import datetime
 
-from newtagging.models import TagBase
+from newtagging.models import TagBase, tags_updated
 from newtagging import managers
 from catalogue.fields import JSONField
 
-from librarian import html, dcparser
+from librarian import dcparser, html, epub, NoDublinCore
 from mutagen import id3
 
 
@@ -31,51 +36,129 @@ class TagSubcategoryManager(models.Manager):
     def __init__(self, subcategory):
         super(TagSubcategoryManager, self).__init__()
         self.subcategory = subcategory
-        
+
     def get_query_set(self):
         return super(TagSubcategoryManager, self).get_query_set().filter(category=self.subcategory)
 
 
 class Tag(TagBase):
     name = models.CharField(_('name'), max_length=50, db_index=True)
-    slug = models.SlugField(_('slug'), max_length=120, unique=True, db_index=True)
+    slug = models.SlugField(_('slug'), max_length=120, db_index=True)
     sort_key = models.SlugField(_('sort key'), max_length=120, db_index=True)
-    category = models.CharField(_('category'), max_length=50, blank=False, null=False, 
+    category = models.CharField(_('category'), max_length=50, blank=False, null=False,
         db_index=True, choices=TAG_CATEGORIES)
     description = models.TextField(_('description'), blank=True)
     main_page = models.BooleanField(_('main page'), default=False, db_index=True, help_text=_('Show tag on main page'))
-    
+
     user = models.ForeignKey(User, blank=True, null=True)
-    book_count = models.IntegerField(_('book count'), default=0, blank=False, null=False)
-    gazeta_link = models.CharField(blank=True,  max_length=240)
-    wiki_link = models.CharField(blank=True,  max_length=240)
-    
-    def has_description(self):
-        return len(self.description) > 0
-    has_description.short_description = _('description')
-    has_description.boolean = True
+    book_count = models.IntegerField(_('book count'), blank=False, null=True)
+    death = models.IntegerField(_(u'year of death'), blank=True, null=True)
+    gazeta_link = models.CharField(blank=True, max_length=240)
+    wiki_link = models.CharField(blank=True, max_length=240)
+
+    categories_rev = {
+        'autor': 'author',
+        'epoka': 'epoch',
+        'rodzaj': 'kind',
+        'gatunek': 'genre',
+        'motyw': 'theme',
+        'polka': 'set',
+    }
+    categories_dict = dict((item[::-1] for item in categories_rev.iteritems()))
 
-    @permalink
-    def get_absolute_url(self):
-        return ('catalogue.views.tagged_object_list', [self.slug])
-    
     class Meta:
         ordering = ('sort_key',)
         verbose_name = _('tag')
         verbose_name_plural = _('tags')
-    
+        unique_together = (("slug", "category"),)
+
     def __unicode__(self):
         return self.name
 
+    def __repr__(self):
+        return "Tag(slug=%r)" % self.slug
+
+    @permalink
+    def get_absolute_url(self):
+        return ('catalogue.views.tagged_object_list', [self.url_chunk])
+
+    def has_description(self):
+        return len(self.description) > 0
+    has_description.short_description = _('description')
+    has_description.boolean = True
+
+    def alive(self):
+        return self.death is None
+
+    def in_pd(self):
+        """ tests whether an author is in public domain """
+        return self.death is not None and self.goes_to_pd() <= datetime.now().year
+
+    def goes_to_pd(self):
+        """ calculates the year of public domain entry for an author """
+        return self.death + 71 if self.death is not None else None
+
+    def get_count(self):
+        """ returns global book count for book tags, fragment count for themes """
+
+        if self.book_count is None:
+            if self.category == 'book':
+                # never used
+                objects = Book.objects.none()
+            elif self.category == 'theme':
+                objects = Fragment.tagged.with_all((self,))
+            else:
+                objects = Book.tagged.with_all((self,)).order_by()
+                if self.category != 'set':
+                    # eliminate descendants
+                    l_tags = Tag.objects.filter(slug__in=[book.book_tag_slug() for book in objects])
+                    descendants_keys = [book.pk for book in Book.tagged.with_any(l_tags)]
+                    if descendants_keys:
+                        objects = objects.exclude(pk__in=descendants_keys)
+            self.book_count = objects.count()
+            self.save()
+        return self.book_count
+
     @staticmethod
     def get_tag_list(tags):
         if isinstance(tags, basestring):
-            tag_slugs = tags.split('/')
-            return [Tag.objects.get(slug=slug) for slug in tag_slugs]
+            real_tags = []
+            ambiguous_slugs = []
+            category = None
+            tags_splitted = tags.split('/')
+            for index, name in enumerate(tags_splitted):
+                if name in Tag.categories_rev:
+                    category = Tag.categories_rev[name]
+                else:
+                    if category:
+                        real_tags.append(Tag.objects.get(slug=name, category=category))
+                        category = None
+                    else:
+                        try:
+                            real_tags.append(Tag.objects.exclude(category='book').get(slug=name))
+                        except Tag.MultipleObjectsReturned, e:
+                            ambiguous_slugs.append(name)
+
+            if category:
+                # something strange left off
+                raise Tag.DoesNotExist()
+            if ambiguous_slugs:
+                # some tags should be qualified
+                e = Tag.MultipleObjectsReturned()
+                e.tags = real_tags
+                e.ambiguous_slugs = ambiguous_slugs
+                raise e
+            else:
+                return real_tags
         else:
             return TagBase.get_tag_list(tags)
 
+    @property
+    def url_chunk(self):
+        return '/'.join((Tag.categories_dict[self.category], self.slug))
+
 
+# TODO: why is this hard-coded ?
 def book_upload_path(ext):
     def get_dynamic_path(book, filename):
         return 'lektura/%s.%s' % (book.slug, ext)
@@ -90,42 +173,98 @@ class Book(models.Model):
     _short_html = models.TextField(_('short HTML'), editable=False)
     parent_number = models.IntegerField(_('parent number'), default=0)
     extra_info = JSONField(_('extra information'))
-    gazeta_link = models.CharField(blank=True,  max_length=240)
-    wiki_link = models.CharField(blank=True,  max_length=240)
+    gazeta_link = models.CharField(blank=True, max_length=240)
+    wiki_link = models.CharField(blank=True, max_length=240)
+
 
-    
     # Formats
     xml_file = models.FileField(_('XML file'), upload_to=book_upload_path('xml'), blank=True)
     html_file = models.FileField(_('HTML file'), upload_to=book_upload_path('html'), blank=True)
     pdf_file = models.FileField(_('PDF file'), upload_to=book_upload_path('pdf'), blank=True)
+    epub_file = models.FileField(_('EPUB file'), upload_to=book_upload_path('epub'), blank=True)
     odt_file = models.FileField(_('ODT file'), upload_to=book_upload_path('odt'), blank=True)
     txt_file = models.FileField(_('TXT file'), upload_to=book_upload_path('txt'), blank=True)
     mp3_file = models.FileField(_('MP3 file'), upload_to=book_upload_path('mp3'), blank=True)
     ogg_file = models.FileField(_('OGG file'), upload_to=book_upload_path('ogg'), blank=True)
-    
+
     parent = models.ForeignKey('self', blank=True, null=True, related_name='children')
-    
+
     objects = models.Manager()
     tagged = managers.ModelTaggedItemManager(Tag)
     tags = managers.TagDescriptor(Tag)
 
-    
+    _tag_counter = JSONField(null=True, editable=False)
+    _theme_counter = JSONField(null=True, editable=False)
+
+    class AlreadyExists(Exception):
+        pass
+
+    class Meta:
+        ordering = ('title',)
+        verbose_name = _('book')
+        verbose_name_plural = _('books')
+
+    def __unicode__(self):
+        return self.title
+
+    def save(self, force_insert=False, force_update=False, reset_short_html=True, refresh_mp3=True, **kwargs):
+        if reset_short_html:
+            # Reset _short_html during save
+            update = {}
+            for key in filter(lambda x: x.startswith('_short_html'), self.__dict__):
+                update[key] = ''
+                self.__setattr__(key, '')
+            # Fragment.short_html relies on book's tags, so reset it here too
+            self.fragments.all().update(**update)
+
+        book = super(Book, self).save(force_insert, force_update)
+
+        if refresh_mp3 and self.mp3_file:
+            print self.mp3_file, self.mp3_file.path
+            extra_info = self.get_extra_info_value()
+            extra_info.update(self.get_mp3_info())
+            self.set_extra_info_value(extra_info)
+            book = super(Book, self).save(force_insert, force_update)
+
+        return book
+
+    @permalink
+    def get_absolute_url(self):
+        return ('catalogue.views.book_detail', [self.slug])
+
     @property
     def name(self):
         return self.title
-    
+
+    def book_tag_slug(self):
+        return ('l-' + self.slug)[:120]
+
+    def book_tag(self):
+        slug = self.book_tag_slug()
+        book_tag, created = Tag.objects.get_or_create(slug=slug, category='book')
+        if created:
+            book_tag.name = self.title[:50]
+            book_tag.sort_key = slug
+            book_tag.save()
+        return book_tag
+
     def short_html(self):
-        if len(self._short_html):
-            return mark_safe(self._short_html)
+        key = '_short_html_%s' % get_language()
+        short_html = getattr(self, key)
+
+        if short_html and len(short_html):
+            return mark_safe(short_html)
         else:
             tags = self.tags.filter(~Q(category__in=('set', 'theme', 'book')))
             tags = [mark_safe(u'<a href="%s">%s</a>' % (tag.get_absolute_url(), tag.name)) for tag in tags]
 
             formats = []
             if self.html_file:
-                formats.append(u'<a href="%s">Czytaj online</a>' % reverse('book_text', kwargs={'slug': self.slug}))
+                formats.append(u'<a href="%s">%s</a>' % (reverse('book_text', kwargs={'slug': self.slug}), _('Read online')))
             if self.pdf_file:
                 formats.append(u'<a href="%s">PDF</a>' % self.pdf_file.url)
+            if self.root_ancestor.epub_file:
+                formats.append(u'<a href="%s">EPUB</a>' % self.root_ancestor.epub_file.url)
             if self.odt_file:
                 formats.append(u'<a href="%s">ODT</a>' % self.odt_file.url)
             if self.txt_file:
@@ -134,109 +273,165 @@ class Book(models.Model):
                 formats.append(u'<a href="%s">MP3</a>' % self.mp3_file.url)
             if self.ogg_file:
                 formats.append(u'<a href="%s">OGG</a>' % self.ogg_file.url)
-            
+
             formats = [mark_safe(format) for format in formats]
-            
-            self._short_html = unicode(render_to_string('catalogue/book_short.html',
-                {'book': self, 'tags': tags, 'formats': formats}))
+
+            setattr(self, key, unicode(render_to_string('catalogue/book_short.html',
+                {'book': self, 'tags': tags, 'formats': formats})))
             self.save(reset_short_html=False)
-            return mark_safe(self._short_html)
-    
-    def save(self, force_insert=False, force_update=False, reset_short_html=True):
-        if reset_short_html:
-            # Reset _short_html during save
-            self._short_html = ''
-        
-        book = super(Book, self).save(force_insert, force_update)
-        
-        if self.mp3_file:
-            print self.mp3_file, self.mp3_file.path
-            extra_info = self.get_extra_info_value()
-            extra_info.update(self.get_mp3_info())
-            self.set_extra_info_value(extra_info)
-            book = super(Book, self).save(force_insert, force_update)
-        
-        return book
-    
+            return mark_safe(getattr(self, key))
+
+
+    @property
+    def root_ancestor(self):
+        """ returns the oldest ancestor """
+
+        if not hasattr(self, '_root_ancestor'):
+            book = self
+            while book.parent:
+                book = book.parent
+            self._root_ancestor = book
+        return self._root_ancestor
+
+
     def get_mp3_info(self):
         """Retrieves artist and director names from audio ID3 tags."""
         audio = id3.ID3(self.mp3_file.path)
         artist_name = ', '.join(', '.join(tag.text) for tag in audio.getall('TPE1'))
         director_name = ', '.join(', '.join(tag.text) for tag in audio.getall('TPE3'))
         return {'artist_name': artist_name, 'director_name': director_name}
-        
+
     def has_description(self):
         return len(self.description) > 0
     has_description.short_description = _('description')
     has_description.boolean = True
-    
+
     def has_pdf_file(self):
         return bool(self.pdf_file)
     has_pdf_file.short_description = 'PDF'
     has_pdf_file.boolean = True
-    
+
+    def has_epub_file(self):
+        return bool(self.epub_file)
+    has_epub_file.short_description = 'EPUB'
+    has_epub_file.boolean = True
+
     def has_odt_file(self):
         return bool(self.odt_file)
     has_odt_file.short_description = 'ODT'
     has_odt_file.boolean = True
-    
+
     def has_html_file(self):
         return bool(self.html_file)
     has_html_file.short_description = 'HTML'
     has_html_file.boolean = True
 
-    class AlreadyExists(Exception):
-        pass
+    def build_epub(self, remove_descendants=True):
+        """ (Re)builds the epub file.
+            If book has a parent, does nothing.
+            Unless remove_descendants is False, descendants' epubs are removed.
+        """
     
-    @staticmethod
-    def from_xml_file(xml_file, overwrite=False):
+        from StringIO import StringIO
+        from hashlib import sha1
+        from django.core.files.base import ContentFile
+        from librarian import DocProvider
+
+        class BookImportDocProvider(DocProvider):
+            """ used for joined EPUBs """
+
+            def __init__(self, book):
+                self.book = book
+
+            def by_slug(self, slug):
+                if slug == self.book.slug:
+                    return self.book.xml_file
+                else:
+                    return Book.objects.get(slug=slug).xml_file
+
+        if self.parent:
+            # don't need an epub
+            return
+
+        epub_file = StringIO()
+        try:
+            epub.transform(BookImportDocProvider(self), self.slug, epub_file)
+            self.epub_file.save('%s.epub' % self.slug, ContentFile(epub_file.getvalue()), save=False)
+            self.save()
+            FileRecord(slug=self.slug, type='epub', sha1=sha1(epub_file.getvalue()).hexdigest()).save()
+        except NoDublinCore:
+            pass
+
+        book_descendants = list(self.children.all())
+        while len(book_descendants) > 0:
+            child_book = book_descendants.pop(0)
+            if remove_descendants and child_book.has_epub_file():
+                child_book.epub_file.delete()
+            # save anyway, to refresh short_html
+            child_book.save()
+            book_descendants += list(child_book.children.all())
+
+
+    @classmethod
+    def from_xml_file(cls, xml_file, overwrite=False):
+        # use librarian to parse meta-data
+        book_info = dcparser.parse(xml_file)
+
+        if not isinstance(xml_file, File):
+            xml_file = File(open(xml_file))
+
+        try:
+            return cls.from_text_and_meta(xml_file, book_info, overwrite)
+        finally:
+            xml_file.close()
+
+    @classmethod
+    def from_text_and_meta(cls, raw_file, book_info, overwrite=False):
         from tempfile import NamedTemporaryFile
         from slughifi import slughifi
         from markupstring import MarkupString
-        
+        from django.core.files.storage import default_storage
+
         # Read book metadata
-        book_info = dcparser.parse(xml_file)
         book_base, book_slug = book_info.url.rsplit('/', 1)
         book, created = Book.objects.get_or_create(slug=book_slug)
-        
+
         if created:
             book_shelves = []
         else:
             if not overwrite:
-                raise Book.AlreadyExists('Book %s already exists' % book_slug)
+                raise Book.AlreadyExists(_('Book %s already exists') % book_slug)
             # Save shelves for this book
             book_shelves = list(book.tags.filter(category='set'))
-        
+
         book.title = book_info.title
         book.set_extra_info_value(book_info.to_dict())
         book._short_html = ''
         book.save()
-        
+
         book_tags = []
-        for category in ('kind', 'genre', 'author', 'epoch'):    
-            tag_name = getattr(book_info, category)
-            tag_sort_key = tag_name
-            if category == 'author':
-                tag_sort_key = tag_name.last_name
-                tag_name = ' '.join(tag_name.first_names) + ' ' + tag_name.last_name
-            tag, created = Tag.objects.get_or_create(slug=slughifi(tag_name))
-            if created:
-                tag.name = tag_name
-                tag.sort_key = slughifi(tag_sort_key)
-                tag.category = category
-                tag.save()
-            book_tags.append(tag)
-            
-        book_tag, created = Tag.objects.get_or_create(slug=('l-' + book.slug)[:120])
-        if created:
-            book_tag.name = book.title[:50]
-            book_tag.sort_key = ('l-' + book.slug)[:120]
-            book_tag.category = 'book'
-            book_tag.save()
-        book_tags.append(book_tag)
-        
-        book.tags = book_tags
-        
+        categories = (('kinds', 'kind'), ('genres', 'genre'), ('authors', 'author'), ('epochs', 'epoch'))
+        for field_name, category in categories:
+            try:
+                tag_names = getattr(book_info, field_name)
+            except:
+                tag_names = [getattr(book_info, category)]
+            for tag_name in tag_names:
+                tag_sort_key = tag_name
+                if category == 'author':
+                    tag_sort_key = tag_name.last_name
+                    tag_name = ' '.join(tag_name.first_names) + ' ' + tag_name.last_name
+                tag, created = Tag.objects.get_or_create(slug=slughifi(tag_name), category=category)
+                if created:
+                    tag.name = tag_name
+                    tag.sort_key = slughifi(tag_sort_key)
+                    tag.save()
+                book_tags.append(tag)
+
+        book.tags = book_tags + book_shelves
+
+        book_tag = book.book_tag()
+
         if hasattr(book_info, 'parts'):
             for n, part_url in enumerate(book_info.parts):
                 base, slug = part_url.rsplit('/', 1)
@@ -246,69 +441,112 @@ class Book(models.Model):
                     child_book.parent_number = n
                     child_book.save()
                 except Book.DoesNotExist, e:
-                    raise Book.DoesNotExist(u'Book with slug = "%s" does not exist.' % slug)
-        
-        book_descendants = list(book.children.all())
-        while len(book_descendants) > 0:
-            child_book = book_descendants.pop(0)
-            for fragment in child_book.fragments.all():
-                fragment.tags = set(list(fragment.tags) + [book_tag])
-            book_descendants += list(child_book.children.all())
-            
+                    raise Book.DoesNotExist(_('Book with slug = "%s" does not exist.') % slug)
+
         # Save XML and HTML files
-        if not isinstance(xml_file, File):
-            xml_file = File(file(xml_file))
-        book.xml_file.save('%s.xml' % book.slug, xml_file, save=False)
-        
+        book.xml_file.save('%s.xml' % book.slug, raw_file, save=False)
+
         html_file = NamedTemporaryFile()
-        if html.transform(book.xml_file.path, html_file):
+        if html.transform(book.xml_file.path, html_file, parse_dublincore=False):
             book.html_file.save('%s.html' % book.slug, File(html_file), save=False)
-            
+
             # Extract fragments
             closed_fragments, open_fragments = html.extract_fragments(book.html_file.path)
-            book_themes = []
             for fragment in closed_fragments.values():
-                text = fragment.to_string()
-                short_text = ''
-                if (len(MarkupString(text)) > 240):
-                    short_text = unicode(MarkupString(text)[:160])
-                new_fragment, created = Fragment.objects.get_or_create(anchor=fragment.id, book=book, 
-                    defaults={'text': text, 'short_text': short_text})
-                
                 try:
                     theme_names = [s.strip() for s in fragment.themes.split(',')]
                 except AttributeError:
                     continue
                 themes = []
                 for theme_name in theme_names:
-                    tag, created = Tag.objects.get_or_create(slug=slughifi(theme_name))
+                    if not theme_name:
+                        continue
+                    tag, created = Tag.objects.get_or_create(slug=slughifi(theme_name), category='theme')
                     if created:
                         tag.name = theme_name
                         tag.sort_key = slughifi(theme_name)
-                        tag.category = 'theme'
                         tag.save()
                     themes.append(tag)
+                if not themes:
+                    continue
+
+                text = fragment.to_string()
+                short_text = ''
+                if (len(MarkupString(text)) > 240):
+                    short_text = unicode(MarkupString(text)[:160])
+                new_fragment, created = Fragment.objects.get_or_create(anchor=fragment.id, book=book,
+                    defaults={'text': text, 'short_text': short_text})
+
                 new_fragment.save()
-                new_fragment.tags = set(list(book.tags) + themes + [book_tag])
-                book_themes += themes
-            
-            book_themes = set(book_themes)
-            book.tags = list(book.tags) + list(book_themes) + book_shelves
-        
+                new_fragment.tags = set(book_tags + themes + [book_tag])
+
+        book.build_epub(remove_descendants=False)
+
+        book_descendants = list(book.children.all())
+        # add l-tag to descendants and their fragments
+        # delete unnecessary EPUB files
+        while len(book_descendants) > 0:
+            child_book = book_descendants.pop(0)
+            child_book.tags = list(child_book.tags) + [book_tag]
+            if child_book.has_epub_file():
+                child_book.epub_file.delete()
+            child_book.save()
+            for fragment in child_book.fragments.all():
+                fragment.tags = set(list(fragment.tags) + [book_tag])
+            book_descendants += list(child_book.children.all())
+
+        # refresh cache
+        book.tag_counter
+        book.theme_counter
+
         book.save()
         return book
-    
-    @permalink
-    def get_absolute_url(self):
-        return ('catalogue.views.book_detail', [self.slug])
-        
-    class Meta:
-        ordering = ('title',)
-        verbose_name = _('book')
-        verbose_name_plural = _('books')
 
-    def __unicode__(self):
-        return self.title
+
+    def refresh_tag_counter(self):
+        tags = {}
+        for child in self.children.all().order_by():
+            for tag_pk, value in child.tag_counter.iteritems():
+                tags[tag_pk] = tags.get(tag_pk, 0) + value
+        for tag in self.tags.exclude(category__in=('book', 'theme', 'set')).order_by():
+            tags[tag.pk] = 1
+        self.set__tag_counter_value(tags)
+        self.save(reset_short_html=False, refresh_mp3=False)
+        return tags
+
+    def reset_tag_counter(self):
+        self._tag_counter = None
+        self.save(reset_short_html=False, refresh_mp3=False)
+        if self.parent:
+            self.parent.reset_tag_counter()
+
+    @property
+    def tag_counter(self):
+        if self._tag_counter is None:
+            return self.refresh_tag_counter()
+        return dict((int(k), v) for k, v in self.get__tag_counter_value().iteritems())
+
+    def refresh_theme_counter(self):
+        tags = {}
+        for fragment in Fragment.tagged.with_any([self.book_tag()]).order_by():
+            for tag in fragment.tags.filter(category='theme').order_by():
+                tags[tag.pk] = tags.get(tag.pk, 0) + 1
+        self.set__theme_counter_value(tags)
+        self.save(reset_short_html=False, refresh_mp3=False)
+        return tags
+
+    def reset_theme_counter(self):
+        self._theme_counter = None
+        self.save(reset_short_html=False, refresh_mp3=False)
+        if self.parent:
+            self.parent.reset_theme_counter()
+
+    @property
+    def theme_counter(self):
+        if self._theme_counter is None:
+            return self.refresh_theme_counter()
+        return dict((int(k), v) for k, v in self.get__theme_counter_value().iteritems())
+
 
 
 class Fragment(models.Model):
@@ -321,24 +559,83 @@ class Fragment(models.Model):
     objects = models.Manager()
     tagged = managers.ModelTaggedItemManager(Tag)
     tags = managers.TagDescriptor(Tag)
-    
+
+    class Meta:
+        ordering = ('book', 'anchor',)
+        verbose_name = _('fragment')
+        verbose_name_plural = _('fragments')
+
+    def get_absolute_url(self):
+        return '%s#m%s' % (reverse('book_text', kwargs={'slug': self.book.slug}), self.anchor)
+
     def short_html(self):
-        if len(self._short_html):
-            return mark_safe(self._short_html)
+        key = '_short_html_%s' % get_language()
+        short_html = getattr(self, key)
+        if short_html and len(short_html):
+            return mark_safe(short_html)
         else:
-            book_authors = [mark_safe(u'<a href="%s">%s</a>' % (tag.get_absolute_url(), tag.name)) 
-                for tag in self.book.tags if tag.category == 'author']
-            
-            self._short_html = unicode(render_to_string('catalogue/fragment_short.html',
-                {'fragment': self, 'book': self.book, 'book_authors': book_authors}))
+            setattr(self, key, unicode(render_to_string('catalogue/fragment_short.html',
+                {'fragment': self})))
             self.save()
-            return mark_safe(self._short_html)
-    
+            return mark_safe(getattr(self, key))
+
+
+class BookStub(models.Model):
+    title = models.CharField(_('title'), max_length=120)
+    author = models.CharField(_('author'), max_length=120)
+    pd = models.IntegerField(_('goes to public domain'), null=True, blank=True)
+    slug = models.SlugField(_('slug'), max_length=120, unique=True, db_index=True)
+    translator = models.TextField(_('translator'), blank=True)
+    translator_death = models.TextField(_('year of translator\'s death'), blank=True)
+
+    class Meta:
+        ordering = ('title',)
+        verbose_name = _('book stub')
+        verbose_name_plural = _('book stubs')
+
+    def __unicode__(self):
+        return self.title
+
+    @permalink
     def get_absolute_url(self):
-        return '%s#m%s' % (reverse('book_text', kwargs={'slug': self.book.slug}), self.anchor)
-    
+        return ('catalogue.views.book_detail', [self.slug])
+
+    def in_pd(self):
+        return self.pd is not None and self.pd <= datetime.now().year
+
+    @property
+    def name(self):
+        return self.title
+
+
+class FileRecord(models.Model):
+    slug = models.SlugField(_('slug'), max_length=120, db_index=True)
+    type = models.CharField(_('type'), max_length=20, db_index=True)
+    sha1 = models.CharField(_('sha-1 hash'), max_length=40)
+    time = models.DateTimeField(_('time'), auto_now_add=True)
+
     class Meta:
-        ordering = ('book', 'anchor',)
-        verbose_name = _('fragment')
-        verbose_name_plural = _('fragments')
+        ordering = ('-time','-slug', '-type')
+        verbose_name = _('file record')
+        verbose_name_plural = _('file records')
+
+    def __unicode__(self):
+        return "%s %s.%s" % (self.sha1,  self.slug, self.type)
+
+
+def _tags_updated_handler(sender, affected_tags, **kwargs):
+    # reset tag global counter
+    Tag.objects.filter(pk__in=[tag.pk for tag in affected_tags]).update(book_count=None)
+
+    # if book tags changed, reset book tag counter
+    if isinstance(sender, Book) and \
+                Tag.objects.filter(pk__in=(tag.pk for tag in affected_tags)).\
+                    exclude(category__in=('book', 'theme', 'set')).count():
+        sender.reset_tag_counter()
+    # if fragment theme changed, reset book theme counter
+    elif isinstance(sender, Fragment) and \
+                Tag.objects.filter(pk__in=(tag.pk for tag in affected_tags)).\
+                    filter(category='theme').count():
+        sender.book.reset_theme_counter()
+tags_updated.connect(_tags_updated_handler)
 
index d3f608a..6ad83a0 100644 (file)
@@ -1,4 +1,7 @@
 # -*- coding: utf-8 -*-
+# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
 import feedparser
 import datetime
 
@@ -8,6 +11,8 @@ from django.utils.encoding import smart_str
 from django.core.urlresolvers import reverse
 from django.contrib.auth.forms import UserCreationForm, AuthenticationForm
 from django.db.models import Q
+from django.conf import settings
+from django.utils.translation import ugettext as _
 
 
 register = template.Library()
@@ -42,21 +47,42 @@ def capfirst(text):
 
 
 def simple_title(tags):
-    mapping = {
-        'author': u'Autor',
-        'theme': u'motyw',
-        'epoch': u'epoka',
-        'genre': u'gatunek',
-        'kind': u'rodzaj',
-        'set': u'półka',
-    }
-    
     title = []
     for tag in tags:
-        title.append("%s: %s" % (mapping[tag.category], tag.name))
+        title.append("%s: %s" % (_(tag.category), tag.name))
     return capfirst(', '.join(title))
 
 
+def book_stub_title(book):
+    return ', '.join((book.author, book.title))
+
+
+@register.simple_tag
+def book_title(book, html_links=False):
+    try:
+        names = list(book.tags.filter(category='author'))
+    except AttributeError:
+        return book_stub_title(book)
+
+    books = []
+    while book:
+        books.append(book)
+        book = book.parent
+    names.extend(reversed(books))
+
+    if html_links:
+        names = ['<a href="%s">%s</a>' % (tag.get_absolute_url(), tag.name) for tag in names]
+    else:
+        names = [tag.name for tag in names]
+
+    return ', '.join(names)
+
+
+@register.simple_tag
+def book_title_html(book):
+    return book_title(book, html_links=True)
+
+
 @register.simple_tag
 def title_from_tags(tags):
     def split_tags(tags):
@@ -64,46 +90,46 @@ def title_from_tags(tags):
         for tag in tags:
             result[tag.category] = tag
         return result
-    
+
     # TODO: Remove this after adding flection mechanism
     return simple_title(tags)
-    
+
     class Flection(object):
         def get_case(self, name, flection):
             return name
     flection = Flection()
-    
+
     self = split_tags(tags)
-    
+
     title = u''
-    
+
     # Specjalny przypadek oglądania wszystkich lektur na danej półce
     if len(self) == 1 and 'set' in self:
         return u'Półka %s' % self['set']
-    
+
     # Specjalny przypadek "Twórczość w pozytywizmie", wtedy gdy tylko epoka
     # jest wybrana przez użytkownika
     if 'epoch' in self and len(self) == 1:
         text = u'Twórczość w %s' % flection.get_case(unicode(self['epoch']), u'miejscownik')
         return capfirst(text)
-    
+
     # Specjalny przypadek "Dramat w twórczości Sofoklesa", wtedy gdy podane
     # są tylko rodzaj literacki i autor
     if 'kind' in self and 'author' in self and len(self) == 2:
-        text = u'%s w twórczości %s' % (unicode(self['kind']), 
+        text = u'%s w twórczości %s' % (unicode(self['kind']),
             flection.get_case(unicode(self['author']), u'dopełniacz'))
         return capfirst(text)
-    
+
     # Przypadki ogólniejsze
     if 'theme' in self:
         title += u'Motyw %s' % unicode(self['theme'])
-    
+
     if 'genre' in self:
         if 'theme' in self:
             title += u' w %s' % flection.get_case(unicode(self['genre']), u'miejscownik')
         else:
             title += unicode(self['genre'])
-            
+
     if 'kind' in self or 'author' in self or 'epoch' in self:
         if 'genre' in self or 'theme' in self:
             if 'kind' in self:
@@ -112,15 +138,27 @@ def title_from_tags(tags):
                 title += u' w twórczości '
         else:
             title += u'%s ' % unicode(self.get('kind', u'twórczość'))
-            
+
     if 'author' in self:
         title += flection.get_case(unicode(self['author']), u'dopełniacz')
     elif 'epoch' in self:
         title += flection.get_case(unicode(self['epoch']), u'dopełniacz')
-    
+
     return capfirst(title)
 
 
+@register.simple_tag
+def book_tree(book_list, books_by_parent):
+    text = "".join("<li><a href='%s'>%s</a>%s</li>" % (
+        book.get_absolute_url(), book.title, book_tree(books_by_parent.get(book, ()), books_by_parent)
+        ) for book in book_list)
+
+    if text:
+        return "<ol>%s</ol>" % text
+    else:
+        return ''
+
+
 @register.simple_tag
 def user_creation_form():
     return RegistrationForm(prefix='registration').as_ul()
@@ -135,7 +173,11 @@ def authentication_form():
 def breadcrumbs(tags, search_form=True):
     from catalogue.forms import SearchForm
     context = {'tag_list': tags}
-    if search_form and len(tags) < 6:
+    try:
+        max_tag_list = settings.MAX_TAG_LIST
+    except AttributeError:
+        max_tag_list = -1
+    if search_form and (max_tag_list == -1 or len(tags) < max_tag_list):
         context['search_form'] = SearchForm(tags=tags)
     return context
 
@@ -144,7 +186,7 @@ def breadcrumbs(tags, search_form=True):
 def catalogue_url(parser, token):
     bits = token.split_contents()
     tag_name = bits[0]
-    
+
     tags_to_add = []
     tags_to_remove = []
     for bit in bits[1:]:
@@ -152,7 +194,7 @@ def catalogue_url(parser, token):
             tags_to_remove.append(bit[1:])
         else:
             tags_to_add.append(bit)
-    
+
     return CatalogueURLNode(tags_to_add, tags_to_remove)
 
 
@@ -160,7 +202,7 @@ class CatalogueURLNode(Node):
     def __init__(self, tags_to_add, tags_to_remove):
         self.tags_to_add = [Variable(tag) for tag in tags_to_add]
         self.tags_to_remove = [Variable(tag) for tag in tags_to_remove]
-    
+
     def render(self, context):
         tags_to_add = []
         tags_to_remove = []
@@ -178,14 +220,14 @@ class CatalogueURLNode(Node):
                 tags_to_remove += [t for t in tag]
             else:
                 tags_to_remove.append(tag)
-            
-        tag_slugs = [tag.slug for tag in tags_to_add]
+
+        tag_slugs = [tag.url_chunk for tag in tags_to_add]
         for tag in tags_to_remove:
             try:
-                tag_slugs.remove(tag.slug)
+                tag_slugs.remove(tag.url_chunk)
             except KeyError:
                 pass
-        
+
         if len(tag_slugs) > 0:
             return reverse('tagged_object_list', kwargs={'tags': '/'.join(tag_slugs)})
         else:
@@ -193,7 +235,7 @@ class CatalogueURLNode(Node):
 
 
 @register.inclusion_tag('catalogue/latest_blog_posts.html')
-def latest_blog_posts(feed_url, posts_to_show=5):    
+def latest_blog_posts(feed_url, posts_to_show=5):
     try:
         feed = feedparser.parse(str(feed_url))
         posts = []
@@ -222,11 +264,12 @@ def tag_list(tags, choices=None):
 
 @register.inclusion_tag('catalogue/folded_tag_list.html')
 def folded_tag_list(tags, choices=None):
+    tags = [tag for tag in tags if tag.count]
     if choices is None:
         choices = []
     some_tags_hidden = False
     tag_count = len(tags)
-    
+
     if tag_count == 1:
         one_tag = tags[0]
     else:
diff --git a/apps/catalogue/templatetags/switch_tag.py b/apps/catalogue/templatetags/switch_tag.py
new file mode 100644 (file)
index 0000000..72476be
--- /dev/null
@@ -0,0 +1,135 @@
+# Source: http://djangosnippets.org/snippets/967/
+# Author: adurdin
+# Posted: August 13, 2008
+#
+#
+# We can use it based on djangosnippets Terms of Service:
+# (http://djangosnippets.org/about/tos/)
+#
+# 2. That you grant any third party who sees the code you post
+# a royalty-free, non-exclusive license to copy and distribute that code
+# and to make and distribute derivative works based on that code. You may
+# include license terms in snippets you post, if you wish to use
+# a particular license (such as the BSD license or GNU GPL), but that
+# license must permit royalty-free copying, distribution and modification
+# of the code to which it is applied.
+
+from django import template
+from django.template import Library, Node, VariableDoesNotExist
+
+register = Library()
+
+
+@register.tag(name="switch")
+def do_switch(parser, token):
+    """
+    The ``{% switch %}`` tag compares a variable against one or more values in
+    ``{% case %}`` tags, and outputs the contents of the matching block.  An
+    optional ``{% else %}`` tag sets off the default output if no matches
+    could be found::
+
+        {% switch result_count %}
+            {% case 0 %}
+                There are no search results.
+            {% case 1 %}
+                There is one search result.
+            {% else %}
+                Jackpot! Your search found {{ result_count }} results.
+        {% endswitch %}
+
+    Each ``{% case %}`` tag can take multiple values to compare the variable
+    against::
+
+        {% switch username %}
+            {% case "Jim" "Bob" "Joe" %}
+                Me old mate {{ username }}! How ya doin?
+            {% else %}
+                Hello {{ username }}
+        {% endswitch %}
+    """
+    bits = token.contents.split()
+    tag_name = bits[0]
+    if len(bits) != 2:
+        raise template.TemplateSyntaxError("'%s' tag requires one argument" % tag_name)
+    variable = parser.compile_filter(bits[1])
+
+    class BlockTagList(object):
+        # This is a bit of a hack, as it embeds knowledge of the behaviour
+        # of Parser.parse() relating to the "parse_until" argument.
+        def __init__(self, *names):
+            self.names = set(names)
+        def __contains__(self, token_contents):
+            name = token_contents.split()[0]
+            return name in self.names
+
+    # Skip over everything before the first {% case %} tag
+    parser.parse(BlockTagList('case', 'endswitch'))
+
+    cases = []
+    token = parser.next_token()
+    got_case = False
+    got_else = False
+    while token.contents != 'endswitch':
+        nodelist = parser.parse(BlockTagList('case', 'else', 'endswitch'))
+
+        if got_else:
+            raise template.TemplateSyntaxError("'else' must be last tag in '%s'." % tag_name)
+
+        contents = token.contents.split()
+        token_name, token_args = contents[0], contents[1:]
+
+        if token_name == 'case':
+            tests = map(parser.compile_filter, token_args)
+            case = (tests, nodelist)
+            got_case = True
+        else:
+            # The {% else %} tag
+            case = (None, nodelist)
+            got_else = True
+        cases.append(case)
+        token = parser.next_token()
+
+    if not got_case:
+        raise template.TemplateSyntaxError("'%s' must have at least one 'case'." % tag_name)
+
+    return SwitchNode(variable, cases)
+
+class SwitchNode(Node):
+    def __init__(self, variable, cases):
+        self.variable = variable
+        self.cases = cases
+
+    def __repr__(self):
+        return "<Switch node>"
+
+    def __iter__(self):
+        for tests, nodelist in self.cases:
+            for node in nodelist:
+                yield node
+
+    def get_nodes_by_type(self, nodetype):
+        nodes = []
+        if isinstance(self, nodetype):
+            nodes.append(self)
+        for tests, nodelist in self.cases:
+            nodes.extend(nodelist.get_nodes_by_type(nodetype))
+        return nodes
+
+    def render(self, context):
+        try:
+            value_missing = False
+            value = self.variable.resolve(context, True)
+        except VariableDoesNotExist:
+            no_value = True
+            value_missing = None
+
+        for tests, nodelist in self.cases:
+            if tests is None:
+                return nodelist.render(context)
+            elif not value_missing:
+                for test in tests:
+                    test_value = test.resolve(context, True)
+                    if value == test_value:
+                        return nodelist.render(context)
+        else:
+            return ""
diff --git a/apps/catalogue/test_utils.py b/apps/catalogue/test_utils.py
new file mode 100644 (file)
index 0000000..398a0fe
--- /dev/null
@@ -0,0 +1,50 @@
+from django.conf import settings
+from django.test import TestCase
+import shutil
+import tempfile
+from slughifi import slughifi
+
+class WLTestCase(TestCase):
+    """
+        Generic base class for tests. Adds settings freeze and clears MEDIA_ROOT.
+    """
+    def setUp(self):
+        self._MEDIA_ROOT, settings.MEDIA_ROOT = settings.MEDIA_ROOT, tempfile.mkdtemp(prefix='djangotest_')
+
+    def tearDown(self):
+        shutil.rmtree(settings.MEDIA_ROOT, True)
+        settings.MEDIA_ROOT = self._MEDIA_ROOT
+
+class PersonStub(object):
+
+    def __init__(self, first_names, last_name):
+        self.first_names = first_names
+        self.last_name = last_name
+
+
+class BookInfoStub(object):
+
+    def __init__(self, **kwargs):
+        self.__dict = kwargs
+
+    def __setattr__(self, key, value):
+        if not key.startswith('_'):
+            self.__dict[key] = value
+        return object.__setattr__(self, key, value)
+
+    def __getattr__(self, key):
+        return self.__dict[key]
+
+    def to_dict(self):
+        return dict((key, unicode(value)) for key, value in self.__dict.items())
+
+
+def info_args(title):
+    """ generate some keywords for comfortable BookInfoCreation  """
+    slug = unicode(slughifi(title))
+    return {
+        'title': unicode(title),
+        'slug': slug,
+        'url': u"http://wolnelektury.pl/example/%s" % slug,
+        'about': u"http://wolnelektury.pl/example/URI/%s" % slug,
+    }
diff --git a/apps/catalogue/tests/__init__.py b/apps/catalogue/tests/__init__.py
new file mode 100644 (file)
index 0000000..2366653
--- /dev/null
@@ -0,0 +1,4 @@
+from catalogue.tests.book_import import *
+from catalogue.tests.search import *
+from catalogue.tests.tags import *
+from catalogue.tests.templatetags import *
diff --git a/apps/catalogue/tests/book_import.py b/apps/catalogue/tests/book_import.py
new file mode 100644 (file)
index 0000000..cb63fc0
--- /dev/null
@@ -0,0 +1,155 @@
+# -*- coding: utf-8 -*-
+from django.core.files.base import ContentFile
+from catalogue.test_utils import *
+from catalogue import models
+
+class BookImportLogicTests(WLTestCase):
+
+    def setUp(self):
+        WLTestCase.setUp(self)
+        self.book_info = BookInfoStub(
+            url=u"http://wolnelektury.pl/example/default_book",
+            about=u"http://wolnelektury.pl/example/URI/default_book",
+            title=u"Default Book",
+            author=PersonStub(("Jim",), "Lazy"),
+            kind="X-Kind",
+            genre="X-Genre",
+            epoch="X-Epoch",
+        )
+
+        self.expected_tags = [
+           ('author', 'jim-lazy'),
+           ('genre', 'x-genre'),
+           ('epoch', 'x-epoch'),
+           ('kind', 'x-kind'),
+        ]
+        self.expected_tags.sort()
+
+    def test_empty_book(self):
+        BOOK_TEXT = "<utwor />"
+        book = models.Book.from_text_and_meta(ContentFile(BOOK_TEXT), self.book_info)
+
+        self.assertEqual(book.title, "Default Book")
+        self.assertEqual(book.slug, "default_book")
+        self.assert_(book.parent is None)
+        self.assertFalse(book.has_html_file())
+
+        # no fragments generated
+        self.assertEqual(book.fragments.count(), 0)
+
+        # TODO: this should be filled out probably...
+        self.assertEqual(book.wiki_link, '')
+        self.assertEqual(book.gazeta_link, '')
+        self.assertEqual(book._short_html, '')
+        self.assertEqual(book.description, '')
+
+        tags = [ (tag.category, tag.slug) for tag in book.tags ]
+        tags.sort()
+
+        self.assertEqual(tags, self.expected_tags)
+
+    def test_not_quite_empty_book(self):
+        """ Not empty, but without any real text.
+
+        Should work like any other non-empty book.
+        """
+
+        BOOK_TEXT = """<utwor>
+        <liryka_l>
+            <nazwa_utworu>Nic</nazwa_utworu>
+        </liryka_l></utwor>
+        """
+
+        book = models.Book.from_text_and_meta(ContentFile(BOOK_TEXT), self.book_info)
+        self.assertTrue(book.has_html_file())
+
+    def test_book_with_fragment(self):
+        BOOK_TEXT = """<utwor>
+        <opowiadanie>
+            <akap><begin id="m01" /><motyw id="m01">Love</motyw>Ala ma kota<end id="m01" /></akap>
+        </opowiadanie></utwor>
+        """
+
+        book = models.Book.from_text_and_meta(ContentFile(BOOK_TEXT), self.book_info)
+        self.assertTrue(book.has_html_file())
+
+        self.assertEqual(book.fragments.count(), 1)
+        self.assertEqual(book.fragments.all()[0].text, u'<p class="paragraph">Ala ma kota</p>\n')
+
+        self.assert_(('theme', 'love') in [ (tag.category, tag.slug) for tag in book.fragments.all()[0].tags ])
+
+    def test_book_with_empty_theme(self):
+        """ empty themes should be ignored """
+
+        BOOK_TEXT = """<utwor>
+        <opowiadanie>
+            <akap><begin id="m01" /><motyw id="m01"> , Love , , </motyw>Ala ma kota<end id="m01" /></akap>
+        </opowiadanie></utwor>
+        """
+
+        book = models.Book.from_text_and_meta(ContentFile(BOOK_TEXT), self.book_info)
+        self.assert_([('theme', 'love')],
+                         [ (tag.category, tag.slug) for tag in book.fragments.all()[0].tags.filter(category='theme') ])
+
+    def test_book_with_no_theme(self):
+        """ fragments with no themes shouldn't be created at all """
+
+        BOOK_TEXT = """<utwor>
+        <opowiadanie>
+            <akap><begin id="m01" /><motyw id="m01"></motyw>Ala ma kota<end id="m01" /></akap>
+        </opowiadanie></utwor>
+        """
+
+        book = models.Book.from_text_and_meta(ContentFile(BOOK_TEXT), self.book_info)
+        self.assertEqual(book.fragments.count(), 0)
+        self.assertEqual(book.tags.filter(category='theme').count(), 0)
+
+    def test_book_replace_title(self):
+        BOOK_TEXT = """<utwor />"""
+        book = models.Book.from_text_and_meta(ContentFile(BOOK_TEXT), self.book_info)
+        self.book_info.title = u"Extraordinary"
+        book = models.Book.from_text_and_meta(ContentFile(BOOK_TEXT), self.book_info, overwrite=True)
+
+        tags = [ (tag.category, tag.slug) for tag in book.tags ]
+        tags.sort()
+
+        self.assertEqual(tags, self.expected_tags)
+
+    def test_book_replace_author(self):
+        BOOK_TEXT = """<utwor />"""
+        book = models.Book.from_text_and_meta(ContentFile(BOOK_TEXT), self.book_info)
+        self.book_info.author = PersonStub(("Hans", "Christian"), "Andersen")
+        book = models.Book.from_text_and_meta(ContentFile(BOOK_TEXT), self.book_info, overwrite=True)
+
+        tags = [ (tag.category, tag.slug) for tag in book.tags ]
+        tags.sort()
+
+        self.expected_tags.remove(('author', 'jim-lazy'))
+        self.expected_tags.append(('author', 'hans-christian-andersen'))
+        self.expected_tags.sort()
+
+        self.assertEqual(tags, self.expected_tags)
+
+        # the old tag shouldn't disappear
+        models.Tag.objects.get(slug="jim-lazy", category="author")
+
+    def test_multiple_tags(self):
+        BOOK_TEXT = """<utwor />"""
+        self.book_info.authors = self.book_info.author, PersonStub(("Joe",), "Dilligent"),
+        self.book_info.kinds = self.book_info.kind, 'Y-Kind',
+        self.book_info.genres = self.book_info.genre, 'Y-Genre',
+        self.book_info.epochs = self.book_info.epoch, 'Y-Epoch',
+
+        self.expected_tags.extend([
+           ('author', 'joe-dilligent'),
+           ('genre', 'y-genre'),
+           ('epoch', 'y-epoch'),
+           ('kind', 'y-kind'),
+        ])
+        self.expected_tags.sort()
+
+        book = models.Book.from_text_and_meta(ContentFile(BOOK_TEXT), self.book_info)
+        tags = [ (tag.category, tag.slug) for tag in book.tags ]
+        tags.sort()
+
+        self.assertEqual(tags, self.expected_tags)
diff --git a/apps/catalogue/tests/search.py b/apps/catalogue/tests/search.py
new file mode 100644 (file)
index 0000000..93bec87
--- /dev/null
@@ -0,0 +1,71 @@
+# -*- coding: utf-8 -*-
+from catalogue import models, views
+from catalogue.test_utils import *
+
+from nose.tools import raises
+
+class BasicSearchLogicTests(WLTestCase):
+
+    def setUp(self):
+        WLTestCase.setUp(self)
+        self.author_tag = models.Tag.objects.create(
+                                name=u'Adam Mickiewicz [SubWord]',
+                                category=u'author', slug="one")
+
+        self.unicode_tag = models.Tag.objects.create(
+                                name=u'Tadeusz Żeleński (Boy)',
+                                category=u'author', slug="two")
+
+        self.polish_tag = models.Tag.objects.create(
+                                name=u'ĘÓĄŚŁŻŹĆŃęóąśłżźćń',
+                                category=u'author', slug="three")
+
+    @raises(ValueError)
+    def test_empty_query(self):
+        """ Check that empty queries raise an error. """
+        views.find_best_matches(u'')
+
+    @raises(ValueError)
+    def test_one_letter_query(self):
+        """ Check that one letter queries aren't permitted. """
+        views.find_best_matches(u't')
+
+    def test_match_by_prefix(self):
+        """ Tags should be matched by prefix of words within it's name. """
+        self.assertEqual(views.find_best_matches(u'Ada'), (self.author_tag,))
+        self.assertEqual(views.find_best_matches(u'Mic'), (self.author_tag,))
+        self.assertEqual(views.find_best_matches(u'Mickiewicz'), (self.author_tag,))
+
+    def test_match_case_insensitive(self):
+        """ Tag names should match case insensitive. """
+        self.assertEqual(views.find_best_matches(u'adam mickiewicz'), (self.author_tag,))
+
+    def test_match_case_insensitive_unicode(self):
+        """ Tag names should match case insensitive (unicode). """
+        self.assertEqual(views.find_best_matches(u'tadeusz żeleński (boy)'), (self.unicode_tag,))
+
+    def test_word_boundary(self):
+        self.assertEqual(views.find_best_matches(u'SubWord'), (self.author_tag,))
+        self.assertEqual(views.find_best_matches(u'[SubWord'), (self.author_tag,))
+
+    def test_unrelated_search(self):
+        self.assertEqual(views.find_best_matches(u'alamakota'), tuple())
+        self.assertEqual(views.find_best_matches(u'Adama'), ())
+
+    def test_infix_doesnt_match(self):
+        """ Searching for middle of a word shouldn't match. """
+        self.assertEqual(views.find_best_matches(u'deusz'), tuple())
+
+    def test_diactricts_removal_pl(self):
+        """ Tags should match both with and without national characters. """
+        self.assertEqual(views.find_best_matches(u'ĘÓĄŚŁŻŹĆŃęóąśłżźćń'), (self.polish_tag,))
+        self.assertEqual(views.find_best_matches(u'EOASLZZCNeoaslzzcn'), (self.polish_tag,))
+        self.assertEqual(views.find_best_matches(u'eoaslzzcneoaslzzcn'), (self.polish_tag,))
+
+    def test_diactricts_query_removal_pl(self):
+        """ Tags without national characters shouldn't be matched by queries with them. """
+        self.assertEqual(views.find_best_matches(u'Adąm'), ())
+
+    def test_sloppy(self):
+        self.assertEqual(views.find_best_matches(u'Żelenski'), (self.unicode_tag,))
+        self.assertEqual(views.find_best_matches(u'zelenski'), (self.unicode_tag,))
diff --git a/apps/catalogue/tests/tags.py b/apps/catalogue/tests/tags.py
new file mode 100644 (file)
index 0000000..1d257f9
--- /dev/null
@@ -0,0 +1,287 @@
+# -*- coding: utf-8 -*-
+from catalogue import models
+from catalogue.test_utils import *
+from django.core.files.base import ContentFile
+
+from nose.tools import raises
+
+
+class BooksByTagTests(WLTestCase):
+    """ tests the /katalog/tag page for found books """
+
+    def setUp(self):
+        WLTestCase.setUp(self)
+        author = PersonStub(("Common",), "Man")
+
+        # grandchild
+        self.gchild_info = BookInfoStub(genre='Genre', epoch='Epoch', kind='Kind', author=author,
+                                        **info_args("GChild"))
+        # child
+        self.child_info = BookInfoStub(genre='Genre', epoch='Epoch', kind='Other Kind', author=author,
+                                       parts=[self.gchild_info.url],
+                                       **info_args("Child"))
+        # parent
+        self.parent_info = BookInfoStub(genre='Genre', epoch='Epoch', kind='Kind', author=author,
+                                        parts=[self.child_info.url],
+                                        **info_args("Parent"))
+
+        self.book_file = ContentFile('<utwor />')
+
+    def test_nonexistent_tag(self):
+        """ Looking for a non-existent tag should yield 404 """
+        # NOTE: this yields a false positive, 'cause of URL change
+        self.assertEqual(404, self.client.get('/katalog/czeslaw_milosz/').status_code)
+
+    def test_book_tag(self):
+        """ Looking for a book tag isn't permitted """
+        models.Book.from_text_and_meta(self.book_file, self.gchild_info)
+        self.assertEqual(404, self.client.get('/katalog/gchild/').status_code)
+
+    def test_tag_empty(self):
+        """ Tag with no books should return no books """
+        models.Book.from_text_and_meta(self.book_file, self.gchild_info)
+        models.Tag.objects.create(name='Empty tag', slug='empty', category='author')
+
+        context = self.client.get('/katalog/empty/').context
+        self.assertEqual(0, len(context['object_list']))
+
+    def test_tag_eliminate(self):
+        """ Filtering by tag should only yield top-level qualifying books. """
+        for info in self.gchild_info, self.child_info, self.parent_info:
+            models.Book.from_text_and_meta(self.book_file, info)
+
+        # all three qualify
+        context = self.client.get('/katalog/genre/').context
+        self.assertEqual([book.title for book in context['object_list']],
+                         ['Parent'])
+
+        # parent and gchild qualify, child doesn't
+        context = self.client.get('/katalog/kind/').context
+        self.assertEqual([book.title for book in context['object_list']],
+                         ['Parent'])
+
+        # Filtering by child's tag should yield the child
+        context = self.client.get('/katalog/other-kind/').context
+        self.assertEqual([book.title for book in context['object_list']],
+                         ['Child'])
+
+
+
+class TagRelatedTagsTests(WLTestCase):
+    """ tests the /katalog/tag/ page for related tags """
+
+    def setUp(self):
+        WLTestCase.setUp(self)
+        author = PersonStub(("Common",), "Man")
+
+        gchild_info = BookInfoStub(author=author, genre="GchildGenre", epoch='Epoch', kind="Kind",
+                                   **info_args(u"GChild"))
+        child1_info = BookInfoStub(author=author, genre="ChildGenre", epoch='Epoch', kind="ChildKind",
+                                   parts=[gchild_info.url],
+                                   **info_args(u"Child1"))
+        child2_info = BookInfoStub(author=author, genre="ChildGenre", epoch='Epoch', kind="ChildKind",
+                                   **info_args(u"Child2"))
+        parent_info = BookInfoStub(author=author, genre="Genre", epoch='Epoch', kind="Kind",
+                                   parts=[child1_info.url, child2_info.url],
+                                   **info_args(u"Parent"))
+
+        for info in gchild_info, child1_info, child2_info, parent_info:
+            book_text = """<utwor><opowiadanie><akap>
+                <begin id="m01" />
+                    <motyw id="m01">Theme, %sTheme</motyw>
+                    Ala ma kota
+                <end id="m01" />
+                </akap></opowiadanie></utwor>
+                """ % info.title.encode('utf-8')
+            book = models.Book.from_text_and_meta(ContentFile(book_text), info)
+            book.save()
+
+        tag_empty = models.Tag(name='Empty tag', slug='empty', category='author')
+        tag_empty.save()
+
+    def test_empty(self):
+        """ empty tag should have no related tags """
+
+        cats = self.client.get('/katalog/empty/').context['categories']
+        self.assertEqual(cats, {}, 'tags related to empty tag')
+
+    def test_has_related(self):
+        """ related own and descendants' tags should be generated """
+
+        cats = self.client.get('/katalog/kind/').context['categories']
+        self.assertTrue('Common Man' in [tag.name for tag in cats['author']],
+                        'missing `author` related tag')
+        self.assertTrue('Epoch' in [tag.name for tag in cats['epoch']],
+                        'missing `epoch` related tag')
+        self.assertTrue("ChildKind" in [tag.name for tag in cats['kind']],
+                        "missing `kind` related tag")
+        self.assertTrue("Genre" in [tag.name for tag in cats['genre']],
+                        'missing `genre` related tag')
+        self.assertTrue("ChildGenre" in [tag.name for tag in cats['genre']],
+                        "missing child's related tag")
+        self.assertTrue("GchildGenre" in [tag.name for tag in cats['genre']],
+                        "missing grandchild's related tag")
+        self.assertTrue('Theme' in [tag.name for tag in cats['theme']],
+                        "missing related theme")
+        self.assertTrue('Child1Theme' in [tag.name for tag in cats['theme']],
+                        "missing child's related theme")
+        self.assertTrue('GChildTheme' in [tag.name for tag in cats['theme']],
+                        "missing grandchild's related theme")
+
+
+    def test_related_differ(self):
+        """ related tags shouldn't include filtering tags """
+
+        cats = self.client.get('/katalog/kind/').context['categories']
+        self.assertFalse('Kind' in [tag.name for tag in cats['kind']],
+                         'filtering tag wrongly included in related')
+        cats = self.client.get('/katalog/theme/').context['categories']
+        self.assertFalse('Theme' in [tag.name for tag in cats['theme']],
+                         'filtering theme wrongly included in related')
+
+
+    def test_parent_tag_once(self):
+        """ if parent and descendants have a common tag, count it only once """
+
+        cats = self.client.get('/katalog/kind/').context['categories']
+        self.assertEqual([(tag.name, tag.count) for tag in cats['epoch']],
+                         [('Epoch', 1)],
+                         'wrong related tag epoch tag on tag page')
+
+
+    def test_siblings_tags_count(self):
+        """ if children have tags and parent hasn't, count the children """
+
+        cats = self.client.get('/katalog/epoch/').context['categories']
+        self.assertTrue(('ChildKind', 2) in [(tag.name, tag.count) for tag in cats['kind']],
+                    'wrong related kind tags on tag page')
+
+        # all occurencies of theme should be counted
+        self.assertTrue(('Theme', 4) in [(tag.name, tag.count) for tag in cats['theme']],
+                    'wrong related theme count')
+
+
+class CleanTagRelationTests(WLTestCase):
+    """ tests for tag relations cleaning after deleting things """
+
+    def setUp(self):
+        WLTestCase.setUp(self)
+        author = PersonStub(("Common",), "Man")
+
+        book_info = BookInfoStub(author=author, genre="G", epoch='E', kind="K",
+                                   **info_args(u"Book"))
+        book_text = """<utwor><opowiadanie><akap>
+            <begin id="m01" /><motyw id="m01">Theme</motyw>Ala ma kota
+            <end id="m01" />
+            </akap></opowiadanie></utwor>
+            """
+        book = models.Book.from_text_and_meta(ContentFile(book_text), book_info)
+
+    def test_delete_objects(self):
+        """ there should be no related tags left after deleting some objects """
+
+        models.Book.objects.all().delete()
+        cats = self.client.get('/katalog/k/').context['categories']
+        self.assertEqual(cats, {})
+        self.assertEqual(models.Fragment.objects.all().count(), 0,
+                         "orphaned fragments left")
+        self.assertEqual(models.Tag.intermediary_table_model.objects.all().count(), 0,
+                         "orphaned TagRelation objects left")
+
+    def test_deleted_tag(self):
+        """ there should be no tag relations left after deleting tags """
+
+        models.Tag.objects.all().delete()
+        cats = self.client.get('/katalog/lektura/book/').context['categories']
+        self.assertEqual(cats, {})
+        self.assertEqual(models.Tag.intermediary_table_model.objects.all().count(), 0,
+                         "orphaned TagRelation objects left")
+
+
+class TestIdenticalTag(WLTestCase):
+
+    def setUp(self):
+        WLTestCase.setUp(self)
+        author = PersonStub((), "Tag")
+
+        self.book_info = BookInfoStub(author=author,
+                                 genre="tag",
+                                 epoch='tag',
+                                 kind="tag",
+                                   **info_args(u"tag"))
+        self.book_text = """<utwor>
+            <opowiadanie>
+            <akap>
+                <begin id="m01" /><motyw id="m01">tag</motyw>Ala ma kota<end id="m01" />
+            </akap>
+            </opowiadanie>
+            </utwor>
+        """
+
+
+    def test_book_tags(self):
+        """ there should be all related tags in relevant categories """
+        models.Book.from_text_and_meta(ContentFile(self.book_text), self.book_info)
+
+        context = self.client.get('/katalog/lektura/tag/').context
+        for category in 'author', 'kind', 'genre', 'epoch':
+            self.assertTrue('tag' in [tag.slug for tag in context['categories'][category]],
+                            'missing related tag for %s' % category)
+        self.assertTrue('tag' in [tag.slug for tag in context['book_themes']])
+
+    def test_qualified_url(self):
+        models.Book.from_text_and_meta(ContentFile(self.book_text), self.book_info)
+        categories = {'author': 'autor', 'theme': 'motyw', 'epoch': 'epoka', 'kind':'rodzaj', 'genre':'gatunek'}
+        for cat, localcat in categories.iteritems():
+            context = self.client.get('/katalog/%s/tag/' % localcat).context
+            self.assertEqual(1, len(context['object_list']))
+            self.assertNotEqual({}, context['categories'])
+            self.assertFalse(cat in context['categories'])
+
+
+class BookTagsTests(WLTestCase):
+    """ tests the /katalog/lektura/book/ page for related tags """
+
+    def setUp(self):
+        WLTestCase.setUp(self)
+        author1 = PersonStub(("Common",), "Man")
+        author2 = PersonStub(("Jim",), "Lazy")
+
+        child_info = BookInfoStub(authors=(author1, author2), genre="ChildGenre", epoch='Epoch', kind="ChildKind",
+                                   **info_args(u"Child"))
+        parent_info = BookInfoStub(author=author1, genre="Genre", epoch='Epoch', kind="Kind",
+                                   parts=[child_info.url],
+                                   **info_args(u"Parent"))
+
+        for info in child_info, parent_info:
+            book_text = """<utwor><opowiadanie><akap>
+                <begin id="m01" />
+                    <motyw id="m01">Theme, %sTheme</motyw>
+                    Ala ma kota
+                <end id="m01" />
+                </akap></opowiadanie></utwor>
+                """ % info.title.encode('utf-8')
+            book = models.Book.from_text_and_meta(ContentFile(book_text), info)
+
+    def test_book_tags(self):
+        """ book should have own tags and whole tree's themes """
+
+        context = self.client.get('/katalog/lektura/parent/').context
+
+        self.assertEqual([tag.name for tag in context['categories']['author']],
+                         ['Common Man'])
+        self.assertEqual([tag.name for tag in context['categories']['kind']],
+                         ['Kind'])
+        self.assertEqual([(tag.name, tag.count) for tag in context['book_themes']],
+                         [('ChildTheme', 1), ('ParentTheme', 1), ('Theme', 2)])
+
+    def test_main_page_tags(self):
+        """ test main page tags and counts """
+
+        context = self.client.get('/katalog/').context
+
+        self.assertEqual([(tag.name, tag.count) for tag in context['categories']['author']],
+                         [('Jim Lazy', 1), ('Common Man', 1)])
+        self.assertEqual([(tag.name, tag.count) for tag in context['fragment_tags']],
+                         [('ChildTheme', 1), ('ParentTheme', 1), ('Theme', 2)])
+
diff --git a/apps/catalogue/tests/templatetags.py b/apps/catalogue/tests/templatetags.py
new file mode 100644 (file)
index 0000000..7a2ac36
--- /dev/null
@@ -0,0 +1,27 @@
+# -*- coding: utf-8 -*-
+from catalogue import models
+from catalogue.templatetags import catalogue_tags
+from catalogue.test_utils import *
+from django.core.files.base import ContentFile
+
+
+class BookDescTests(WLTestCase):
+    """ tests book_title template tag """
+
+    def setUp(self):
+        WLTestCase.setUp(self)
+        authors = PersonStub(("Common",), "Man"), PersonStub(("Jane",), "Doe")
+
+        child_info = BookInfoStub(authors=authors, genre="Genre", epoch='Epoch', kind="Kind",
+                                   **info_args(u"Child"))
+        parent_info = BookInfoStub(authors=authors, genre="Genre", epoch='Epoch', kind="Kind",
+                                   parts=[child_info.url],
+                                   **info_args(u"Parent"))
+
+        self.child = models.Book.from_text_and_meta(ContentFile('<utwor/>'), child_info)
+        models.Book.from_text_and_meta(ContentFile('<utwor/>'), parent_info)
+        self.child = models.Book.objects.get(pk=self.child.pk)
+
+    def test_book_desc(self):
+        """ book description should return authors, ancestors, book """
+        self.assertEqual(catalogue_tags.book_title(self.child), 'Jane Doe, Common Man, Parent, Child')
index 327e0fc..70d5fd8 100644 (file)
@@ -1,4 +1,7 @@
 # -*- coding: utf-8 -*-
+# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
 from django.conf.urls.defaults import *
 
 
@@ -13,8 +16,12 @@ urlpatterns = patterns('catalogue.views',
     url(r'^lektura/(?P<slug>[a-zA-Z0-9-]+)/polki/', 'book_sets', name='book_shelves'),
     url(r'^polki/nowa/$', 'new_set', name='new_set'),
     url(r'^tags/$', 'tags_starting_with', name='hint'),
+    url(r'^jtags/$', 'json_tags_starting_with', name='jhint'),
     url(r'^szukaj/$', 'search', name='search'),
-    
+
+    # tools
+    url(r'^zegar', 'clock', name='clock'),
+
     # Public interface. Do not change this URLs.
     url(r'^lektura/(?P<slug>[a-zA-Z0-9-]+)\.html$', 'book_text', name='book_text'),
     url(r'^lektura/(?P<slug>[a-zA-Z0-9-]+)/$', 'book_detail', name='book_detail'),
index 72b0973..e44b379 100644 (file)
@@ -1,4 +1,7 @@
 # -*- coding: utf-8 -*-
+# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
 import random
 import time
 from base64 import urlsafe_b64encode
@@ -16,7 +19,7 @@ MAX_SESSION_KEY = 18446744073709551616L     # 2 << 63
 
 
 def get_random_hash(seed):
-    sha_digest = sha_constructor('%s%s%s%s' % 
+    sha_digest = sha_constructor('%s%s%s%s' %
         (randrange(0, MAX_SESSION_KEY), time.time(), unicode(seed).encode('utf-8', 'replace'),
         settings.SECRET_KEY)).digest()
     return urlsafe_b64encode(sha_digest).replace('=', '').replace('_', '-').lower()
index 92aa3e0..556bae1 100644 (file)
@@ -1,10 +1,17 @@
 # -*- coding: utf-8 -*-
+# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
 import tempfile
 import zipfile
 import sys
 import pprint
 import traceback
+import re
+import itertools
+from operator import itemgetter
 
+from django.conf import settings
 from django.template import RequestContext
 from django.shortcuts import render_to_response, get_object_or_404
 from django.http import HttpResponse, HttpResponseRedirect, Http404
@@ -18,7 +25,10 @@ from django.contrib.auth.forms import UserCreationForm, AuthenticationForm
 from django.utils import simplejson
 from django.utils.functional import Promise
 from django.utils.encoding import force_unicode
+from django.utils.http import urlquote_plus
 from django.views.decorators import cache
+from django.utils.translation import ugettext as _
+from django.views.generic.list_detail import object_list
 
 from catalogue import models
 from catalogue import forms
@@ -35,111 +45,223 @@ class LazyEncoder(simplejson.JSONEncoder):
             return force_unicode(obj)
         return obj
 
+# shortcut for JSON reponses
+class JSONResponse(HttpResponse):
+    def __init__(self, data={}, callback=None, **kwargs):
+        # get rid of mimetype
+        kwargs.pop('mimetype', None)
+        data = simplejson.dumps(data)
+        if callback:
+            data = callback + "(" + data + ");" 
+        super(JSONResponse, self).__init__(data, mimetype="application/json", **kwargs)
 
-def main_page(request):    
+
+def main_page(request):
     if request.user.is_authenticated():
         shelves = models.Tag.objects.filter(category='set', user=request.user)
         new_set_form = forms.NewSetForm()
-    extra_where = 'NOT catalogue_tag.category = "set"'
-    tags = models.Tag.objects.usage_for_model(models.Book, counts=True, extra={'where': [extra_where]})
-    fragment_tags = models.Tag.objects.usage_for_model(models.Fragment, counts=True,
-        extra={'where': ['catalogue_tag.category = "theme"'] + [extra_where]})
+
+    tags = models.Tag.objects.exclude(category__in=('set', 'book'))
+    for tag in tags:
+        tag.count = tag.get_count()
     categories = split_tags(tags)
-    
+    fragment_tags = categories.get('theme', [])
+
     form = forms.SearchForm()
     return render_to_response('catalogue/main_page.html', locals(),
         context_instance=RequestContext(request))
 
 
 def book_list(request):
-    books = models.Book.objects.all()
     form = forms.SearchForm()
-    
-    books_by_first_letter = SortedDict()
-    for book in books:
-        books_by_first_letter.setdefault(book.title[0], []).append(book)
-    
+
+    books_by_parent = {}
+    for book in models.Book.objects.all().order_by('parent_number'):
+        books_by_parent.setdefault(book.parent, []).append(book)
+
+    orphans = []
+    books_by_author = SortedDict()
+    for tag in models.Tag.objects.filter(category='author'):
+        books_by_author[tag] = []
+
+    for book in books_by_parent[None]:
+        authors = list(book.tags.filter(category='author'))
+        if authors:
+            for author in authors:
+                books_by_author[author].append(book)
+        else:
+            orphans.append(book)
+
     return render_to_response('catalogue/book_list.html', locals(),
         context_instance=RequestContext(request))
 
 
+def differentiate_tags(request, tags, ambiguous_slugs):
+    beginning = '/'.join(tag.url_chunk for tag in tags)
+    unparsed = '/'.join(ambiguous_slugs[1:])
+    options = []
+    for tag in models.Tag.objects.exclude(category='book').filter(slug=ambiguous_slugs[0]):
+        options.append({
+            'url_args': '/'.join((beginning, tag.url_chunk, unparsed)).strip('/'),
+            'tags': [tag]
+        })
+    return render_to_response('catalogue/differentiate_tags.html',
+                {'tags': tags, 'options': options, 'unparsed': ambiguous_slugs[1:]},
+                context_instance=RequestContext(request))
+
+
 def tagged_object_list(request, tags=''):
-    # Prevent DoS attacks on our database
-    if len(tags.split('/')) > 6:
-        raise Http404
-        
     try:
         tags = models.Tag.get_tag_list(tags)
     except models.Tag.DoesNotExist:
         raise Http404
-    
+    except models.Tag.MultipleObjectsReturned, e:
+        return differentiate_tags(request, e.tags, e.ambiguous_slugs)
+
+    try:
+        if len(tags) > settings.MAX_TAG_LIST:
+            raise Http404
+    except AttributeError:
+        pass
+
     if len([tag for tag in tags if tag.category == 'book']):
         raise Http404
-    
-    model = models.Book
-    shelf = [tag for tag in tags if tag.category == 'set']
-    shelf_is_set = (len(tags) == 1 and tags[0].category == 'set')
-    theme_is_set = len([tag for tag in tags if tag.category == 'theme']) > 0
-    if theme_is_set:
-        model = models.Fragment
 
-    user_is_owner = (len(shelf) and request.user.is_authenticated() and request.user == shelf[0].user)
-    
-    extra_where = 'catalogue_tag.category NOT IN ("set", "book")'
-    related_tags = models.Tag.objects.related_for_model(tags, model, counts=True, extra={'where': [extra_where]})
-    categories = split_tags(related_tags)
+    theme_is_set = [tag for tag in tags if tag.category == 'theme']
+    shelf_is_set = [tag for tag in tags if tag.category == 'set']
+    only_shelf = shelf_is_set and len(tags) == 1
+    only_my_shelf = only_shelf and request.user.is_authenticated() and request.user == tags[0].user
 
-    if not (theme_is_set or shelf_is_set):
-        model=models.Book.objects.filter(parent=None)
-    
-    return newtagging_views.tagged_object_list(
+    objects = only_author = pd_counter = None
+    categories = {}
+
+    if theme_is_set:
+        shelf_tags = [tag for tag in tags if tag.category == 'set']
+        fragment_tags = [tag for tag in tags if tag.category != 'set']
+        fragments = models.Fragment.tagged.with_all(fragment_tags)
+
+        if shelf_tags:
+            books = models.Book.tagged.with_all(shelf_tags).order_by()
+            l_tags = models.Tag.objects.filter(category='book', slug__in=[book.book_tag_slug() for book in books])
+            fragments = models.Fragment.tagged.with_any(l_tags, fragments)
+
+        # newtagging goes crazy if we just try:
+        #related_tags = models.Tag.objects.usage_for_queryset(fragments, counts=True,
+        #                    extra={'where': ["catalogue_tag.category != 'book'"]})
+        fragment_keys = [fragment.pk for fragment in fragments]
+        if fragment_keys:
+            related_tags = models.Fragment.tags.usage(counts=True,
+                                filters={'pk__in': fragment_keys},
+                                extra={'where': ["catalogue_tag.category != 'book'"]})
+            related_tags = (tag for tag in related_tags if tag not in fragment_tags)
+            categories = split_tags(related_tags)
+
+            objects = fragments
+    else:
+        # get relevant books and their tags
+        objects = models.Book.tagged.with_all(tags).order_by()
+        if not shelf_is_set:
+            # eliminate descendants
+            l_tags = models.Tag.objects.filter(category='book', slug__in=[book.book_tag_slug() for book in objects])
+            descendants_keys = [book.pk for book in models.Book.tagged.with_any(l_tags)]
+            if descendants_keys:
+                objects = objects.exclude(pk__in=descendants_keys)
+
+        # get related tags from `tag_counter` and `theme_counter`
+        related_counts = {}
+        tags_pks = [tag.pk for tag in tags]
+        for book in objects:
+            for tag_pk, value in itertools.chain(book.tag_counter.iteritems(), book.theme_counter.iteritems()):
+                if tag_pk in tags_pks:
+                    continue
+                related_counts[tag_pk] = related_counts.get(tag_pk, 0) + value
+        related_tags = models.Tag.objects.filter(pk__in=related_counts.keys())
+        related_tags = [tag for tag in related_tags if tag not in tags]
+        for tag in related_tags:
+            tag.count = related_counts[tag.pk]
+
+        categories = split_tags(related_tags)
+        del related_tags
+
+    if not objects:
+        only_author = len(tags) == 1 and tags[0].category == 'author'
+        pd_counter = only_author and tags[0].goes_to_pd()
+        objects = models.Book.objects.none()
+
+    return object_list(
         request,
-        tag_model=models.Tag,
-        queryset_or_model=model,
-        tags=tags,
+        objects,
         template_name='catalogue/tagged_object_list.html',
-        extra_context = {
+        extra_context={
             'categories': categories,
-            'shelf_is_set': shelf_is_set,
-            'user_is_owner': user_is_owner,
+            'only_shelf': only_shelf,
+            'only_author': only_author,
+            'pd_counter': pd_counter,
+            'only_my_shelf': only_my_shelf,
             'formats_form': forms.DownloadFormatsForm(),
-        },
+
+            'tags': tags,
+        }
     )
 
 
 def book_fragments(request, book_slug, theme_slug):
     book = get_object_or_404(models.Book, slug=book_slug)
-    book_tag = get_object_or_404(models.Tag, slug='l-' + book_slug)
-    theme = get_object_or_404(models.Tag, slug=theme_slug)
+    book_tag = get_object_or_404(models.Tag, slug='l-' + book_slug, category='book')
+    theme = get_object_or_404(models.Tag, slug=theme_slug, category='theme')
     fragments = models.Fragment.tagged.with_all([book_tag, theme])
-    
+
     form = forms.SearchForm()
     return render_to_response('catalogue/book_fragments.html', locals(),
         context_instance=RequestContext(request))
 
 
 def book_detail(request, slug):
-    book = get_object_or_404(models.Book, slug=slug)
-    book_tag = get_object_or_404(models.Tag, slug = 'l-' + slug)
+    try:
+        book = models.Book.objects.get(slug=slug)
+    except models.Book.DoesNotExist:
+        return book_stub_detail(request, slug)
+
+    book_tag = book.book_tag()
     tags = list(book.tags.filter(~Q(category='set')))
     categories = split_tags(tags)
     book_children = book.children.all().order_by('parent_number')
-    extra_where = 'catalogue_tag.category = "theme"'
-    book_themes = models.Tag.objects.related_for_model(book_tag, models.Fragment, counts=True, extra={'where': [extra_where]})
-    extra_info = book.get_extra_info_value()
     
+    _book = book
+    parents = []
+    while _book.parent:
+        parents.append(_book.parent)
+        _book = _book.parent
+    parents = reversed(parents)
+
+    theme_counter = book.theme_counter
+    book_themes = models.Tag.objects.filter(pk__in=theme_counter.keys())
+    for tag in book_themes:
+        tag.count = theme_counter[tag.pk]
+
+    extra_info = book.get_extra_info_value()
+
     form = forms.SearchForm()
     return render_to_response('catalogue/book_detail.html', locals(),
         context_instance=RequestContext(request))
 
 
+def book_stub_detail(request, slug):
+    book = get_object_or_404(models.BookStub, slug=slug)
+    pd_counter = book.pd
+    form = forms.SearchForm()
+
+    return render_to_response('catalogue/book_stub_detail.html', locals(),
+        context_instance=RequestContext(request))
+
+
 def book_text(request, slug):
     book = get_object_or_404(models.Book, slug=slug)
     book_themes = {}
     for fragment in book.fragments.all():
         for theme in fragment.tags.filter(category='theme'):
             book_themes.setdefault(theme, []).append(fragment)
-    
+
     book_themes = book_themes.items()
     book_themes.sort(key=lambda s: s[0].sort_key)
     return render_to_response('catalogue/book_text.html', locals(),
@@ -149,40 +271,135 @@ def book_text(request, slug):
 # ==========
 # = Search =
 # ==========
-def _tags_starting_with(prefix, user):
-    books = models.Book.objects.filter(title__icontains=prefix)
-    tags = models.Tag.objects.filter(name__icontains=prefix)
-    if user.is_authenticated():
+
+def _no_diacritics_regexp(query):
+    """ returns a regexp for searching for a query without diacritics
+
+    should be locale-aware """
+    names = {
+        u'a':u'aąĄ', u'c':u'cćĆ', u'e':u'eęĘ', u'l': u'lłŁ', u'n':u'nńŃ', u'o':u'oóÓ', u's':u'sśŚ', u'z':u'zźżŹŻ',
+        u'ą':u'ąĄ', u'ć':u'ćĆ', u'ę':u'ęĘ', u'ł': u'łŁ', u'ń':u'ńŃ', u'ó':u'óÓ', u'ś':u'śŚ', u'ź':u'źŹ', u'ż':u'żŻ'
+        }
+    def repl(m):
+        l = m.group()
+        return u"(%s)" % '|'.join(names[l])
+    return re.sub(u'[%s]' % (u''.join(names.keys())), repl, query)
+
+def unicode_re_escape(query):
+    """ Unicode-friendly version of re.escape """
+    return re.sub('(?u)(\W)', r'\\\1', query)
+
+def _word_starts_with(name, prefix):
+    """returns a Q object getting models having `name` contain a word
+    starting with `prefix`
+
+    We define word characters as alphanumeric and underscore, like in JS.
+
+    Works for MySQL, PostgreSQL, Oracle.
+    For SQLite, _sqlite* version is substituted for this.
+    """
+    kwargs = {}
+
+    prefix = _no_diacritics_regexp(unicode_re_escape(prefix))
+    # can't use [[:<:]] (word start),
+    # but we want both `xy` and `(xy` to catch `(xyz)`
+    kwargs['%s__iregex' % name] = u"(^|[^[:alnum:]_])%s" % prefix
+
+    return Q(**kwargs)
+
+
+def _sqlite_word_starts_with(name, prefix):
+    """ version of _word_starts_with for SQLite
+
+    SQLite in Django uses Python re module
+    """
+    kwargs = {}
+    prefix = _no_diacritics_regexp(unicode_re_escape(prefix))
+    kwargs['%s__iregex' % name] = ur"(^|(?<=[^\wąćęłńóśźżĄĆĘŁŃÓŚŹŻ]))%s" % prefix
+    return Q(**kwargs)
+
+
+if settings.DATABASE_ENGINE == 'sqlite3':
+    _word_starts_with = _sqlite_word_starts_with
+
+
+def _tags_starting_with(prefix, user=None):
+    prefix = prefix.lower()
+    book_stubs = models.BookStub.objects.filter(_word_starts_with('title', prefix))
+    books = models.Book.objects.filter(_word_starts_with('title', prefix))
+    book_stubs = filter(lambda x: x not in books, book_stubs)
+    tags = models.Tag.objects.filter(_word_starts_with('name', prefix))
+    if user and user.is_authenticated():
         tags = tags.filter(~Q(category='book') & (~Q(category='set') | Q(user=user)))
     else:
         tags = tags.filter(~Q(category='book') & ~Q(category='set'))
+    return list(books) + list(tags) + list(book_stubs)
+
+
+def _get_result_link(match, tag_list):
+    if isinstance(match, models.Book) or isinstance(match, models.BookStub):
+        return match.get_absolute_url()
+    else:
+        return reverse('catalogue.views.tagged_object_list',
+            kwargs={'tags': '/'.join(tag.url_chunk for tag in tag_list + [match])}
+        )
+
+def _get_result_type(match):
+    if isinstance(match, models.Book) or isinstance(match, models.BookStub):
+        type = 'book'
+    else:
+        type = match.category
+    return type
+
+
+
+def find_best_matches(query, user=None):
+    """ Finds a Book, Tag or Bookstub best matching a query.
+
+    Returns a with:
+      - zero elements when nothing is found,
+      - one element when a best result is found,
+      - more then one element on multiple exact matches
+
+    Raises a ValueError on too short a query.
+    """
+
+    query = query.lower()
+    if len(query) < 2:
+        raise ValueError("query must have at least two characters")
+
+    result = tuple(_tags_starting_with(query, user))
+    exact_matches = tuple(res for res in result if res.name.lower() == query)
+    if exact_matches:
+        return exact_matches
+    else:
+        return result[:1]
 
-    return list(books) + list(tags)
-        
 
 def search(request):
     tags = request.GET.get('tags', '')
     prefix = request.GET.get('q', '')
-    # Prefix must have at least 2 characters
-    if len(prefix) < 2:
-        return HttpResponse('')
-    
+
     try:
         tag_list = models.Tag.get_tag_list(tags)
     except:
         tag_list = []
-    
-    result = _tags_starting_with(prefix, request.user)
-    if len(result) > 0:
-        tag = result[0]
-        if isinstance(tag, models.Book):
-            return HttpResponseRedirect(tag.get_absolute_url())
-        else:
-            tag_list.append(tag)
-        
-    return HttpResponseRedirect(reverse('catalogue.views.tagged_object_list', 
-        kwargs={'tags': '/'.join(tag.slug for tag in tag_list)}
-    ))
+
+    try:
+        result = find_best_matches(prefix, request.user)
+    except ValueError:
+        return render_to_response('catalogue/search_too_short.html', {'tags':tag_list, 'prefix':prefix},
+            context_instance=RequestContext(request))
+
+    if len(result) == 1:
+        return HttpResponseRedirect(_get_result_link(result[0], tag_list))
+    elif len(result) > 1:
+        return render_to_response('catalogue/search_multiple_hits.html',
+            {'tags':tag_list, 'prefix':prefix, 'results':((x, _get_result_link(x, tag_list), _get_result_type(x)) for x in result)},
+            context_instance=RequestContext(request))
+    else:
+        return render_to_response('catalogue/search_no_hits.html', {'tags':tag_list, 'prefix':prefix},
+            context_instance=RequestContext(request))
 
 
 def tags_starting_with(request):
@@ -190,9 +407,29 @@ def tags_starting_with(request):
     # Prefix must have at least 2 characters
     if len(prefix) < 2:
         return HttpResponse('')
-    
-    return HttpResponse('\n'.join(tag.name for tag in _tags_starting_with(prefix, request.user)))
-
+    tags_list = []
+    result = ""   
+    for tag in _tags_starting_with(prefix, request.user):
+        if not tag.name in tags_list:
+            result += "\n" + tag.name
+            tags_list.append(tag.name)
+    return HttpResponse(result)
+
+def json_tags_starting_with(request, callback=None):
+    # Callback for JSONP
+    prefix = request.GET.get('q', '')
+    callback = request.GET.get('callback', '')
+    # Prefix must have at least 2 characters
+    if len(prefix) < 2:
+        return HttpResponse('')
+    tags_list = []
+    result = ""   
+    for tag in _tags_starting_with(prefix, request.user):
+        if not tag.name in tags_list:
+            result += "\n" + tag.name
+            tags_list.append(tag.name)
+    dict_result = {"matches": tags_list}
+    return JSONResponse(dict_result, callback)
 
 # ====================
 # = Shelf management =
@@ -210,33 +447,33 @@ def book_sets(request, slug):
     book = get_object_or_404(models.Book, slug=slug)
     user_sets = models.Tag.objects.filter(category='set', user=request.user)
     book_sets = book.tags.filter(category='set', user=request.user)
-    
+
     if not request.user.is_authenticated():
-        return HttpResponse('<p>Aby zarządzać swoimi półkami, musisz się zalogować.</p>')
-    
+        return HttpResponse(_('<p>To maintain your shelves you need to be logged in.</p>'))
+
     if request.method == 'POST':
         form = forms.ObjectSetsForm(book, request.user, request.POST)
         if form.is_valid():
             old_shelves = list(book.tags.filter(category='set'))
             new_shelves = [models.Tag.objects.get(pk=id) for id in form.cleaned_data['set_ids']]
-            
+
             for shelf in [shelf for shelf in old_shelves if shelf not in new_shelves]:
-                shelf.book_count -= 1
+                shelf.book_count = None
                 shelf.save()
-                
+
             for shelf in [shelf for shelf in new_shelves if shelf not in old_shelves]:
-                shelf.book_count += 1
+                shelf.book_count = None
                 shelf.save()
-            
+
             book.tags = new_shelves + list(book.tags.filter(~Q(category='set') | ~Q(user=request.user)))
             if request.is_ajax():
-                return HttpResponse('<p>Półki zostały zapisane.</p>')
+                return HttpResponse(_('<p>Shelves were sucessfully saved.</p>'))
             else:
                 return HttpResponseRedirect('/')
     else:
         form = forms.ObjectSetsForm(book, request.user)
         new_set_form = forms.NewSetForm()
-    
+
     return render_to_response('catalogue/book_sets.html', locals(),
         context_instance=RequestContext(request))
 
@@ -247,13 +484,16 @@ def book_sets(request, slug):
 def remove_from_shelf(request, shelf, book):
     book = get_object_or_404(models.Book, slug=book)
     shelf = get_object_or_404(models.Tag, slug=shelf, category='set', user=request.user)
-    
-    models.Tag.objects.remove_tag(book, shelf)
-    
-    shelf.book_count -= 1
-    shelf.save()
-    
-    return HttpResponse('Usunieto')
+
+    if shelf in book.tags:
+        models.Tag.objects.remove_tag(book, shelf)
+
+        shelf.book_count = None
+        shelf.save()
+
+        return HttpResponse(_('Book was successfully removed from the shelf'))
+    else:
+        return HttpResponse(_('This book is not on the shelf'))
 
 
 def collect_books(books):
@@ -274,25 +514,30 @@ def download_shelf(request, slug):
     """"
     Create a ZIP archive on disk and transmit it in chunks of 8KB,
     without loading the whole file into memory. A similar approach can
-    be used for large dynamic PDF files.                                        
+    be used for large dynamic PDF files.
     """
     shelf = get_object_or_404(models.Tag, slug=slug, category='set')
-    
+
     formats = []
     form = forms.DownloadFormatsForm(request.GET)
     if form.is_valid():
         formats = form.cleaned_data['formats']
     if len(formats) == 0:
-        formats = ['pdf', 'odt', 'txt', 'mp3', 'ogg']
-    
+        formats = ['pdf', 'epub', 'odt', 'txt', 'mp3', 'ogg']
+
     # Create a ZIP archive
-    temp = temp = tempfile.TemporaryFile()
+    temp = tempfile.TemporaryFile()
     archive = zipfile.ZipFile(temp, 'w')
-    
+
+    already = set()
     for book in collect_books(models.Book.tagged.with_all(shelf)):
         if 'pdf' in formats and book.pdf_file:
             filename = book.pdf_file.path
             archive.write(filename, str('%s.pdf' % book.slug))
+        if book.root_ancestor not in already and 'epub' in formats and book.root_ancestor.epub_file:
+            filename = book.root_ancestor.epub_file.path
+            archive.write(filename, str('%s.epub' % book.root_ancestor.slug))
+            already.add(book.root_ancestor)
         if 'odt' in formats and book.odt_file:
             filename = book.odt_file.path
             archive.write(filename, str('%s.odt' % book.slug))
@@ -306,11 +551,11 @@ def download_shelf(request, slug):
             filename = book.ogg_file.path
             archive.write(filename, str('%s.ogg' % book.slug))
     archive.close()
-    
+
     response = HttpResponse(content_type='application/zip', mimetype='application/x-zip-compressed')
     response['Content-Disposition'] = 'attachment; filename=%s.zip' % shelf.sort_key
     response['Content-Length'] = temp.tell()
-    
+
     temp.seek(0)
     response.write(temp.read())
     return response
@@ -323,11 +568,13 @@ def shelf_book_formats(request, shelf):
     """
     shelf = get_object_or_404(models.Tag, slug=shelf, category='set')
 
-    formats = {'pdf': False, 'odt': False, 'txt': False, 'mp3': False, 'ogg': False}
-    
+    formats = {'pdf': False, 'epub': False, 'odt': False, 'txt': False, 'mp3': False, 'ogg': False}
+
     for book in collect_books(models.Book.tagged.with_all(shelf)):
         if book.pdf_file:
             formats['pdf'] = True
+        if book.root_ancestor.epub_file:
+            formats['epub'] = True
         if book.odt_file:
             formats['odt'] = True
         if book.txt_file:
@@ -349,7 +596,7 @@ def new_set(request):
         new_set = new_set_form.save(request.user)
 
         if request.is_ajax():
-            return HttpResponse(u'<p>Półka <strong>%s</strong> została utworzona</p>' % new_set)
+            return HttpResponse(_('<p>Shelf <strong>%s</strong> was successfully created</p>') % new_set)
         else:
             return HttpResponseRedirect('/')
 
@@ -364,7 +611,7 @@ def delete_shelf(request, slug):
     user_set.delete()
 
     if request.is_ajax():
-        return HttpResponse(u'<p>Półka <strong>%s</strong> została usunięta</p>' % user_set.name)
+        return HttpResponse(_('<p>Shelf <strong>%s</strong> was successfully removed</p>') % user_set.name)
     else:
         return HttpResponseRedirect('/')
 
@@ -391,7 +638,7 @@ def register(request):
     if registration_form.is_valid():
         user = registration_form.save()
         user = auth.authenticate(
-            username=registration_form.cleaned_data['username'], 
+            username=registration_form.cleaned_data['username'],
             password=registration_form.cleaned_data['password1']
         )
         auth.login(request, user)
@@ -404,7 +651,7 @@ def register(request):
 @cache.never_cache
 def logout_then_redirect(request):
     auth.logout(request)
-    return HttpResponseRedirect(request.GET.get('next', '/'))
+    return HttpResponseRedirect(urlquote_plus(request.GET.get('next', '/'), safe='/?='))
 
 
 
@@ -423,7 +670,16 @@ def import_book(request):
             info = sys.exc_info()
             exception = pprint.pformat(info[1])
             tb = '\n'.join(traceback.format_tb(info[2]))
-            return HttpResponse("An error occurred: %s\n\n%s" % (exception, tb), mimetype='text/plain')
-        return HttpResponse("Book imported successfully")
+            return HttpResponse(_("An error occurred: %(exception)s\n\n%(tb)s") % {'exception':exception, 'tb':tb}, mimetype='text/plain')
+        return HttpResponse(_("Book imported successfully"))
     else:
-        return HttpResponse("Error importing file: %r" % book_import_form.errors)
\ No newline at end of file
+        return HttpResponse(_("Error importing file: %r") % book_import_form.errors)
+
+
+
+def clock(request):
+    """ Provides server time for jquery.countdown,
+    in a format suitable for Date.parse()
+    """
+    from datetime import datetime
+    return HttpResponse(datetime.now().strftime('%Y/%m/%d %H:%M:%S'))
diff --git a/apps/chunks/locale/de/LC_MESSAGES/django.mo b/apps/chunks/locale/de/LC_MESSAGES/django.mo
new file mode 100644 (file)
index 0000000..0b7ee14
Binary files /dev/null and b/apps/chunks/locale/de/LC_MESSAGES/django.mo differ
diff --git a/apps/chunks/locale/de/LC_MESSAGES/django.po b/apps/chunks/locale/de/LC_MESSAGES/django.po
new file mode 100644 (file)
index 0000000..2e83462
--- /dev/null
@@ -0,0 +1,54 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-05-18 10:58+0200\n"
+"PO-Revision-Date: 2010-06-23 11:45+0100\n"
+"Last-Translator: Iwona Fiałkowska <ifialkowska@gmail.com>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: models.py:10
+#: models.py:24
+msgid "key"
+msgstr "Schlüssel"
+
+#: models.py:10
+msgid "A unique name for this chunk of content"
+msgstr "Ein besonderer Name für diesen Inhaltsauszug"
+
+#: models.py:11
+msgid "description"
+msgstr "Beschreibung"
+
+#: models.py:12
+msgid "content"
+msgstr "Inhalt"
+
+#: models.py:16
+msgid "chunk"
+msgstr "Auszug"
+
+#: models.py:17
+msgid "chunks"
+msgstr "Auszüge"
+
+#: models.py:24
+msgid "A unique name for this attachment"
+msgstr "Ein besonderer Name für diese Anlage"
+
+#: models.py:29
+msgid "attachment"
+msgstr "Anlage"
+
+#: models.py:29
+msgid "attachments"
+msgstr "Anlagen"
+
diff --git a/apps/chunks/locale/en/LC_MESSAGES/django.mo b/apps/chunks/locale/en/LC_MESSAGES/django.mo
new file mode 100644 (file)
index 0000000..db3d0ee
Binary files /dev/null and b/apps/chunks/locale/en/LC_MESSAGES/django.mo differ
diff --git a/apps/chunks/locale/en/LC_MESSAGES/django.po b/apps/chunks/locale/en/LC_MESSAGES/django.po
new file mode 100644 (file)
index 0000000..07a8dcb
--- /dev/null
@@ -0,0 +1,54 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-05-18 10:58+0200\n"
+"PO-Revision-Date: 2010-06-09 16:25+0100\n"
+"Last-Translator: K Izdebska <villdeo.tess@gmail.com>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: models.py:10
+#: models.py:24
+msgid "key"
+msgstr "key"
+
+#: models.py:10
+msgid "A unique name for this chunk of content"
+msgstr "A unique name for this piece of content"
+
+#: models.py:11
+msgid "description"
+msgstr "description"
+
+#: models.py:12
+msgid "content"
+msgstr "content"
+
+#: models.py:16
+msgid "chunk"
+msgstr "piece"
+
+#: models.py:17
+msgid "chunks"
+msgstr "pieces"
+
+#: models.py:24
+msgid "A unique name for this attachment"
+msgstr "A unique name for this attachment"
+
+#: models.py:29
+msgid "attachment"
+msgstr "attachment"
+
+#: models.py:29
+msgid "attachments"
+msgstr "attachments"
+
diff --git a/apps/chunks/locale/es/LC_MESSAGES/django.mo b/apps/chunks/locale/es/LC_MESSAGES/django.mo
new file mode 100644 (file)
index 0000000..368d60a
Binary files /dev/null and b/apps/chunks/locale/es/LC_MESSAGES/django.mo differ
diff --git a/apps/chunks/locale/es/LC_MESSAGES/django.po b/apps/chunks/locale/es/LC_MESSAGES/django.po
new file mode 100644 (file)
index 0000000..727f37a
--- /dev/null
@@ -0,0 +1,54 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-05-18 10:58+0200\n"
+"PO-Revision-Date: 2010-08-10 17:15+0100\n"
+"Last-Translator: Katarzyna Flis <kas.flis@gmail.com>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: models.py:10
+#: models.py:24
+msgid "key"
+msgstr "clave"
+
+#: models.py:10
+msgid "A unique name for this chunk of content"
+msgstr "El nombre único para este elemento del contenido"
+
+#: models.py:11
+msgid "description"
+msgstr "descripción"
+
+#: models.py:12
+msgid "content"
+msgstr "contenido"
+
+#: models.py:16
+msgid "chunk"
+msgstr "elemento"
+
+#: models.py:17
+msgid "chunks"
+msgstr "elementos"
+
+#: models.py:24
+msgid "A unique name for this attachment"
+msgstr "El nombre único para este adjunto"
+
+#: models.py:29
+msgid "attachment"
+msgstr "adjunto"
+
+#: models.py:29
+msgid "attachments"
+msgstr "adjuntos"
+
diff --git a/apps/chunks/locale/fr/LC_MESSAGES/django.mo b/apps/chunks/locale/fr/LC_MESSAGES/django.mo
new file mode 100644 (file)
index 0000000..18da01d
Binary files /dev/null and b/apps/chunks/locale/fr/LC_MESSAGES/django.mo differ
diff --git a/apps/chunks/locale/fr/LC_MESSAGES/django.po b/apps/chunks/locale/fr/LC_MESSAGES/django.po
new file mode 100644 (file)
index 0000000..20b9342
--- /dev/null
@@ -0,0 +1,54 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-05-18 10:58+0200\n"
+"PO-Revision-Date: 2010-06-27 00:08+0100\n"
+"Last-Translator: Natalia Kertyczak <natalczyk@o2.pl>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: models.py:10
+#: models.py:24
+msgid "key"
+msgstr "clé"
+
+#: models.py:10
+msgid "A unique name for this chunk of content"
+msgstr "Nom unique pour ce fragment du contenu"
+
+#: models.py:11
+msgid "description"
+msgstr "description"
+
+#: models.py:12
+msgid "content"
+msgstr "contenu"
+
+#: models.py:16
+msgid "chunk"
+msgstr "fragment"
+
+#: models.py:17
+msgid "chunks"
+msgstr "fragments"
+
+#: models.py:24
+msgid "A unique name for this attachment"
+msgstr "Nom unique pour cette pièce jointe"
+
+#: models.py:29
+msgid "attachment"
+msgstr "pièce jointe"
+
+#: models.py:29
+msgid "attachments"
+msgstr "pièces jointes"
+
diff --git a/apps/chunks/locale/lt/LC_MESSAGES/django.mo b/apps/chunks/locale/lt/LC_MESSAGES/django.mo
new file mode 100644 (file)
index 0000000..a3e42fb
Binary files /dev/null and b/apps/chunks/locale/lt/LC_MESSAGES/django.mo differ
diff --git a/apps/chunks/locale/lt/LC_MESSAGES/django.po b/apps/chunks/locale/lt/LC_MESSAGES/django.po
new file mode 100644 (file)
index 0000000..b93b9fa
--- /dev/null
@@ -0,0 +1,55 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-05-18 10:59+0200\n"
+"PO-Revision-Date: 2010-07-12 18:49+0100\n"
+"Last-Translator: Alicja Sinkiewicz <alicja.sinkiewicz@gmail.com>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Translated-Using: django-rosetta 0.5.3\n"
+
+#: models.py:10
+#: models.py:24
+msgid "key"
+msgstr "raktas"
+
+#: models.py:10
+msgid "A unique name for this chunk of content"
+msgstr "Unikalus šio turinio gabalelio pavadnimas"
+
+#: models.py:11
+msgid "description"
+msgstr "aprašymas"
+
+#: models.py:12
+msgid "content"
+msgstr "turinys"
+
+#: models.py:16
+msgid "chunk"
+msgstr "gabalėlis"
+
+#: models.py:17
+msgid "chunks"
+msgstr "gabalėliai"
+
+#: models.py:24
+msgid "A unique name for this attachment"
+msgstr "Unikalus šio priedo pavadnimas"
+
+#: models.py:29
+msgid "attachment"
+msgstr "priedas"
+
+#: models.py:29
+msgid "attachments"
+msgstr "priedai"
+
diff --git a/apps/chunks/locale/pl/LC_MESSAGES/django.mo b/apps/chunks/locale/pl/LC_MESSAGES/django.mo
new file mode 100644 (file)
index 0000000..838d4e3
Binary files /dev/null and b/apps/chunks/locale/pl/LC_MESSAGES/django.mo differ
diff --git a/apps/chunks/locale/pl/LC_MESSAGES/django.po b/apps/chunks/locale/pl/LC_MESSAGES/django.po
new file mode 100644 (file)
index 0000000..e0a6139
--- /dev/null
@@ -0,0 +1,53 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+# 
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-05-18 10:59+0200\n"
+"PO-Revision-Date: 2010-05-19 16:19\n"
+"Last-Translator: <radoslaw.czajka@nowoczesnapolska.org.pl>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Translated-Using: django-rosetta 0.5.3\n"
+
+#: models.py:10 models.py:24
+msgid "key"
+msgstr "klucz"
+
+#: models.py:10
+msgid "A unique name for this chunk of content"
+msgstr "Unikalna nazwa dla tego kawałka treści"
+
+#: models.py:11
+msgid "description"
+msgstr "opis"
+
+#: models.py:12
+msgid "content"
+msgstr "zawartość"
+
+#: models.py:16
+msgid "chunk"
+msgstr "kawałek"
+
+#: models.py:17
+msgid "chunks"
+msgstr "kawałki"
+
+#: models.py:24
+msgid "A unique name for this attachment"
+msgstr "Unikalna nazwa dla tego załącznika"
+
+#: models.py:29
+msgid "attachment"
+msgstr "załącznik"
+
+#: models.py:29
+msgid "attachments"
+msgstr "załączniki"
diff --git a/apps/chunks/locale/ru/LC_MESSAGES/django.mo b/apps/chunks/locale/ru/LC_MESSAGES/django.mo
new file mode 100644 (file)
index 0000000..857e6c6
Binary files /dev/null and b/apps/chunks/locale/ru/LC_MESSAGES/django.mo differ
diff --git a/apps/chunks/locale/ru/LC_MESSAGES/django.po b/apps/chunks/locale/ru/LC_MESSAGES/django.po
new file mode 100644 (file)
index 0000000..7718f6c
--- /dev/null
@@ -0,0 +1,54 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-05-18 10:58+0200\n"
+"PO-Revision-Date: 2010-06-02 17:07+0100\n"
+"Last-Translator: I <moth_04@yahoo.pl>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: models.py:10
+#: models.py:24
+msgid "key"
+msgstr "ключ"
+
+#: models.py:10
+msgid "A unique name for this chunk of content"
+msgstr "Уникальное имя для этого фрагмента содержания"
+
+#: models.py:11
+msgid "description"
+msgstr "описание"
+
+#: models.py:12
+msgid "content"
+msgstr "содержание"
+
+#: models.py:16
+msgid "chunk"
+msgstr "фрагмент"
+
+#: models.py:17
+msgid "chunks"
+msgstr "фрагменты"
+
+#: models.py:24
+msgid "A unique name for this attachment"
+msgstr "Уникальное имя для этого приложения"
+
+#: models.py:29
+msgid "attachment"
+msgstr "приложение"
+
+#: models.py:29
+msgid "attachments"
+msgstr "приложения"
+
diff --git a/apps/chunks/locale/uk/LC_MESSAGES/django.mo b/apps/chunks/locale/uk/LC_MESSAGES/django.mo
new file mode 100644 (file)
index 0000000..2190079
Binary files /dev/null and b/apps/chunks/locale/uk/LC_MESSAGES/django.mo differ
diff --git a/apps/chunks/locale/uk/LC_MESSAGES/django.po b/apps/chunks/locale/uk/LC_MESSAGES/django.po
new file mode 100644 (file)
index 0000000..432c1d6
--- /dev/null
@@ -0,0 +1,54 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-05-18 10:58+0200\n"
+"PO-Revision-Date: 2010-08-26 13:13+0100\n"
+"Last-Translator: Natalia Kertyczak <natalczyk@o2.pl>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: models.py:10
+#: models.py:24
+msgid "key"
+msgstr "ключ"
+
+#: models.py:10
+msgid "A unique name for this chunk of content"
+msgstr "Унікальна назва для цієї частини змісту"
+
+#: models.py:11
+msgid "description"
+msgstr "опис"
+
+#: models.py:12
+msgid "content"
+msgstr "зміст"
+
+#: models.py:16
+msgid "chunk"
+msgstr "частина"
+
+#: models.py:17
+msgid "chunks"
+msgstr "частини"
+
+#: models.py:24
+msgid "A unique name for this attachment"
+msgstr "Унікальна назва для цього додатку"
+
+#: models.py:29
+msgid "attachment"
+msgstr "додаток"
+
+#: models.py:29
+msgid "attachments"
+msgstr "додатки"
+
index 86f0466..cd9cf4e 100644 (file)
@@ -15,7 +15,7 @@ class Chunk(models.Model):
         ordering = ('key',)
         verbose_name = _('chunk')
         verbose_name_plural = _('chunks')
-    
+
     def __unicode__(self):
         return self.key
 
@@ -23,7 +23,7 @@ class Chunk(models.Model):
 class Attachment(models.Model):
     key = models.CharField(_('key'), help_text=_('A unique name for this attachment'), primary_key=True, max_length=255)
     attachment = models.FileField(upload_to='chunks/attachment')
-    
+
     class Meta:
         ordering = ('key',)
         verbose_name, verbose_name_plural = _('attachment'), _('attachments')
index 595482f..083c48a 100644 (file)
@@ -30,7 +30,7 @@ class ChunkNode(template.Node):
     def __init__(self, key, cache_time=0):
        self.key = key
        self.cache_time = cache_time
-    
+
     def render(self, context):
         try:
             cache_key = 'chunk_' + self.key
@@ -44,7 +44,7 @@ class ChunkNode(template.Node):
             n.save()
             return ''
         return content
-        
+
 register.tag('chunk', do_get_chunk)
 
 
@@ -58,6 +58,6 @@ def attachment(key, cache_time=0):
         return c.attachment.url
     except Attachment.DoesNotExist:
         return ''
-    
+
 register.simple_tag(attachment)
 
index 9b98531..9bb23b2 100644 (file)
@@ -6,7 +6,7 @@ class FilterBase:
         raise NotImplementedError
     def filter_js(self, js):
         raise NotImplementedError
-        
+
 class FilterError(Exception):
     """
     This exception is raised when a filter fails
index d40e8ee..ae7c103 100644 (file)
@@ -18,16 +18,16 @@ class CSSTidyFilter(FilterBase):
         tmp_file.flush()
 
         output_file = tempfile.NamedTemporaryFile(mode='w+b')
-        
+
         command = '%s %s %s %s' % (BINARY, tmp_file.name, ARGUMENTS, output_file.name)
-        
+
         command_output = os.popen(command).read()
-        
+
         filtered_css = output_file.read()
         output_file.close()
         tmp_file.close()
-        
+
         if self.verbose:
             print command_output
-        
+
         return filtered_css
index 7d581ed..03a4ac0 100644 (file)
@@ -8,12 +8,12 @@ COMPRESS_CSSTIDY_SETTINGS = getattr(settings, 'COMPRESS_CSSTIDY_SETTINGS', {})
 class CSSTidyFilter(FilterBase):
     def filter_css(self, css):
         tidy = CSSTidy()
-        
+
         for k, v in COMPRESS_CSSTIDY_SETTINGS.items():
             tidy.setSetting(k, v)
 
         tidy.parse(css)
 
         r = tidy.Output('string')
-        
+
         return r
index 6e31d25..8217979 100644 (file)
@@ -6,9 +6,6 @@ from django.conf import settings
 class Command(NoArgsCommand):
     option_list = NoArgsCommand.option_list + (
         make_option('--force', action='store_true', default=False, help='Force update of all files, even if the source files are older than the current compressed file.'),
-        make_option('--verbosity', action='store', dest='verbosity', default='1',
-            type='choice', choices=['0', '1', '2'],
-            help='Verbosity level; 0=minimal output, 1=normal output, 2=all output'),
     )
     help = 'Updates and compresses CSS and JavsScript on-demand, without restarting Django'
     args = ''
@@ -21,7 +18,8 @@ class Command(NoArgsCommand):
         from compress.utils import needs_update, filter_css, filter_js
 
         for name, css in settings.COMPRESS_CSS.items():
-            u, version = needs_update(css['output_filename'], css['source_filenames'])
+            u, version = needs_update(css['output_filename'], 
+                css['source_filenames'])
 
             if (force or u) or verbosity >= 2:
                 msg = 'CSS Group \'%s\'' % name
@@ -36,7 +34,8 @@ class Command(NoArgsCommand):
                 print
 
         for name, js in settings.COMPRESS_JS.items():
-            u, version = needs_update(js['output_filename'], js['source_filenames'])
+            u, version = needs_update(js['output_filename'], 
+                js['source_filenames'])
 
             if (force or u) or verbosity >= 2:
                 msg = 'JavaScript Group \'%s\'' % name
@@ -48,4 +47,12 @@ class Command(NoArgsCommand):
                 filter_js(js, verbosity)
 
             if (force or u) or verbosity >= 2:
-                print
\ No newline at end of file
+                print
+
+# Backwards compatibility for Django r9110
+if not [opt for opt in Command.option_list if opt.dest=='verbosity']:
+    Command.option_list += (
+    make_option('--verbosity', '-v', action="store", dest="verbosity",
+        default='1', type='choice', choices=['0', '1', '2'],
+        help="Verbosity level; 0=minimal output, 1=normal output, 2=all output"),
+    )
index 3c59728..89b04a5 100644 (file)
@@ -97,7 +97,7 @@ def get_version(version):
     except ValueError:
         return str(version)
 
-def remove_files(path, filename, verbosity=0):    
+def remove_files(path, filename, verbosity=0):
     regex = re.compile(r'^%s$' % (os.path.basename(get_output_filename(settings.COMPRESS_VERSION_PLACEHOLDER.join([re.escape(part) for part in filename.split(settings.COMPRESS_VERSION_PLACEHOLDER)]), r'\d+'))))
 
     for f in os.listdir(path):
diff --git a/apps/infopages/__init__.py b/apps/infopages/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/apps/infopages/admin.py b/apps/infopages/admin.py
new file mode 100644 (file)
index 0000000..66f2996
--- /dev/null
@@ -0,0 +1,9 @@
+from django.contrib import admin
+
+from modeltranslation.admin import TranslationAdmin
+from infopages.models import InfoPage
+
+class InfoPageAdmin(TranslationAdmin):
+    list_display = ('title',)
+
+admin.site.register(InfoPage, InfoPageAdmin)
\ No newline at end of file
diff --git a/apps/infopages/fixtures/wl_data.json b/apps/infopages/fixtures/wl_data.json
new file mode 100644 (file)
index 0000000..61ea9e8
--- /dev/null
@@ -0,0 +1,174 @@
+[
+    {
+        "pk": 3, 
+        "model": "infopages.infopage", 
+        "fields": {
+            "title_de": "\u00dcber das Projekt \"Freie Lekt\u00fcren\"", 
+            "page_title": "About Wolne Lektury project", 
+            "left_column_uk": "<h2>Wolne Lektury</h2>\r\n\r\n \r\n\r\n <p>\u0406\u043d\u0442\u0435\u0440\u043d\u0435\u0442 \u0431\u0456\u0431\u043b\u0456\u043e\u0442\u0435\u043a\u0430 \u0448\u043a\u0456\u043b\u044c\u043d\u043e\u0457 \u043b\u0456\u0442\u0435\u0440\u0430\u0442\u0443\u0440\u0438 \"Wolne Lektury\u201d (www.wolnelektury.pl) \u0446\u0435 \u043f\u0440\u043e\u0435\u043a\u0442 \u0440\u0435\u0430\u043b\u0456\u0437\u043e\u0432\u0430\u043d\u0438\u0439 \u0424\u043e\u043d\u0434\u043e\u043c \u041c\u043e\u0434\u0435\u0440\u043d\u0430 \u041f\u043e\u043b\u044c\u0449\u0430. \u0414\u0456\u0454 \u0432\u0456\u043d \u0437 2007 \u0440\u043e\u043a\u0443 \u0456 \u043d\u0430\u0434\u0430\u0454 \u0434\u043e\u0441\u0442\u0443\u043f \u0434\u043e \u0441\u0432\u043e\u0454\u0457 \u043a\u043e\u043b\u0435\u043a\u0446\u0456\u0457 \u0448\u043a\u0456\u043b\u044c\u043d\u043e\u0457 \u043b\u0456\u0442\u0435\u0440\u0430\u0442\u0443\u0440\u0438, \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u043e\u0432\u0430\u043d\u043e\u0457 \u041c\u0456\u043d\u0456\u0441\u0442\u0435\u0440\u0441\u0442\u0432\u043e\u043c \u043d\u0430\u0446\u0456\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0457 \u043e\u0441\u0432\u0456\u0442\u0438, \u044f\u043a\u0430 \u0454 \u0432\u0436\u0435 \u0447\u0430\u0441\u0442\u0438\u043d\u043e\u044e \u0441\u0443\u0441\u043f\u0456\u043b\u044c\u043d\u043e\u0433\u043e \u043d\u0430\u0434\u0431\u0430\u043d\u043d\u044f. \u0422\u0432\u043e\u0440\u0438 \u0454 \u043e\u043f\u0440\u0430\u0446\u044c\u043e\u0432\u0430\u043d\u0456, \u0434\u043e \u043d\u0438\u0445 \u0434\u043e\u0434\u0430\u044e\u0442\u044c\u0441\u044f \u043a\u043e\u043c\u0435\u043d\u0442\u0430\u0440\u0456 \u0456 \u043d\u0430\u0434\u0430\u0454\u0442\u044c\u0441\u044f \u0434\u043e\u0441\u0442\u0443\u043f \u0432 \u0434\u0435\u043a\u0456\u043b\u044c\u043a\u043e\u0445 \u0444\u043e\u0440\u043c\u0430\u0442\u0430\u0445 (html, epub, mp3, ogg, odt, txt i pdf). \u041c\u043e\u0436\u043d\u0430 \u0457\u0445 \u043b\u0435\u0433\u0430\u043b\u044c\u043d\u043e \u043f\u0435\u0440\u0435\u0433\u043b\u044f\u0434\u0430\u0442\u0438, \u0437\u0430\u0432\u0430\u043d\u0442\u0430\u0436\u0443\u0432\u0430\u0442\u0438 \u043d\u0430 \u0432\u043b\u0430\u0441\u043d\u0438\u0439 \u043a\u043e\u043c\u043f\u2019\u044e\u0442\u0435\u0440, \u043d\u0430\u0434\u0430\u0432\u0430\u0442\u0438 \u0434\u043e\u0441\u0442\u0443\u043f \u0434\u043e \u043d\u0438\u0445 \u0456\u043d\u0448\u0438\u043c \u0442\u0430 \u0446\u0438\u0442\u0443\u0432\u0430\u0442\u0438.</p>\r\n\r\n \r\n\r\n <p>\u041a\u043e\u043c\u0430\u043d\u0434\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0443 Wolne Lektury \u0441\u043a\u043b\u0430\u0434\u0430\u0454\u0442\u044c\u0441\u044f \u0437 \u0434\u043e\u0441\u0432\u0456\u0434\u0447\u0435\u043d\u0438\u0445 \u0440\u0435\u0434\u0430\u043a\u0442\u043e\u0440\u043e\u043a \u0442\u0430 \u0432\u0447\u0438\u0442\u0435\u043b\u044c\u043e\u043a, \u0449\u043e \u0437\u0430\u0431\u0435\u0437\u043f\u0435\u0447\u0443\u0454 \u043d\u0430\u0434\u0456\u0439\u043d\u0456\u0441\u0442\u044c \u043d\u0430\u0448\u043e\u0433\u043e \u0440\u0435\u0441\u0443\u0440\u0441\u0443. \u0412 \u0439\u043e\u0433\u043e \u0442\u0432\u043e\u0440\u0435\u043d\u043d\u0456 \u043c\u0438 \u0441\u043f\u0456\u0432\u043f\u0440\u0430\u0446\u044e\u0454\u043c\u043e \u0437 \u041d\u0430\u0446\u0456\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u044e \u0431\u0456\u0431\u043b\u0456\u043e\u0442\u0435\u043a\u043e\u044e, \u044f\u043a\u0430 \u043d\u0430\u0434\u0430\u0454 \u043d\u0430\u043c \u043d\u0430\u0439\u043a\u0440\u0430\u0449\u0456 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u0456 \u0432\u0438\u0434\u0430\u043d\u043d\u044f \u0442\u0430 \u043a\u0440\u0438\u0442\u0438\u0447\u043d\u0456 \u043e\u043f\u0440\u0430\u0446\u044e\u0432\u0430\u043d\u043d\u044f \u0448\u043a\u0456\u043b\u044c\u043d\u043e\u0457 \u043b\u0456\u0442\u0435\u0440\u0430\u0442\u0443\u0440\u0438, \u044f\u043a\u0456 \u0437\u043d\u0430\u0445\u043e\u0434\u044f\u0442\u044c\u0441\u044f \u0432 \u0426\u0438\u0444\u0440\u043e\u0432\u0456\u0439 \u043d\u0430\u0446\u0456\u043e\u043d\u0430\u043b\u044c\u043d\u0456\u0439 \u0431\u0456\u0431\u043b\u0456\u043e\u0442\u0435\u0446\u0456 \u041f\u043e\u043b\u043e\u043d\u0430. \u0421\u043f\u0456\u043b\u044c\u043d\u043e \u0441\u0442\u0430\u0440\u0430\u0454\u043c\u043e\u0441\u044f, \u0449\u043e\u0431 \u0442\u0435\u043a\u0441\u0442\u0438 \u0448\u043a\u0456\u043b\u044c\u043d\u043e\u0457 \u043b\u0456\u0442\u0435\u0440\u0430\u0442\u0443\u0440\u0438 - \u043d\u0430\u0448\u0430 \u043a\u0443\u043b\u044c\u0442\u0443\u0440\u043d\u0430 \u0441\u043f\u0430\u0434\u0449\u0438\u043d\u0430 - \u0431\u0443\u043b\u0438 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u0456 \u0434\u043b\u044f \u0432\u0441\u0456\u0445, \u043d\u0435\u0437\u0430\u043b\u0435\u0436\u043d\u043e \u0432\u0456\u0434 \u043c\u0456\u0441\u0446\u044f \u043f\u0440\u043e\u0436\u0438\u0432\u0430\u043d\u043d\u044f, \u0444\u0456\u043d\u0430\u043d\u0441\u043e\u0432\u0438\u0445 \u0440\u0435\u0441\u0443\u0440\u0441\u0456\u0432, \u043e\u0431\u043c\u0435\u0436\u0435\u043d\u0438\u0445 \u0447\u0438 \u043d\u0435\u043e\u0431\u043c\u0435\u0436\u0435\u043d\u0438\u0445 \u043c\u043e\u0436\u043b\u0438\u0432\u043e\u0441\u0442\u0435\u0439. \u0426\u0435 \u043c\u043e\u0436\u043b\u0438\u0432\u043e \u0437\u0430\u0432\u0434\u044f\u043a\u0438 \u0456\u0441\u043d\u0443\u0432\u0430\u043d\u043d\u0456 \u0441\u0443\u0441\u043f\u0456\u043b\u044c\u043d\u043e\u0433\u043e \u043d\u0430\u0434\u0431\u0430\u043d\u043d\u044f, \u0442\u043e\u0431\u0442\u043e \u0441\u0443\u043a\u0443\u043f\u043d\u043e\u0441\u0442\u0456 \u0442\u0432\u043e\u0440\u0456\u0432, \u044f\u043a\u0456 \u043d\u0435 \u043e\u0445\u043e\u0440\u043e\u043d\u044f\u044e\u0442\u044c\u0441\u044f \u0430\u0432\u0442\u043e\u0440\u0441\u044c\u043a\u0438\u043c \u043f\u0440\u0430\u0432\u043e\u043c, \u0430 \u0442\u0430\u043a\u043e\u0436 \u0437\u0430\u0432\u0434\u044f\u043a\u0438 \u0441\u0443\u0447\u0430\u0441\u043d\u0438\u043c \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0456\u044f\u043c \u2013 \u0456\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430\u043c, \u044f\u043a\u0456 \u0434\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0442\u044c \u043c\u0443\u043b\u044c\u0442\u0438\u043f\u043b\u0456\u043a\u0443\u0432\u0430\u0442\u0438 \u0434\u043e\u0441\u0442\u0443\u043f \u0434\u043e \u0437\u043c\u0456\u0441\u0442\u0443 \u043e\u043f\u0443\u0431\u043b\u0456\u043a\u043e\u0432\u0430\u043d\u043e\u0433\u043e \u0432 \u0456\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0456.</p>\r\n\r\n \r\n\r\n <p>\u041f\u0440\u043e\u0435\u043a\u0442 Wolne Lektury \u0454 \u043f\u043e\u0432\u043d\u0456\u0441\u0442\u044e \u043d\u0435\u043a\u043e\u043c\u0435\u0440\u0446\u0456\u0439\u043d\u0438\u043c \u0456 \u0440\u0435\u0430\u043b\u0456\u0437\u0443\u0454\u0442\u044c\u0441\u044f \u0434\u043b\u044f \u0441\u0443\u0441\u043f\u0456\u043b\u044c\u043d\u043e\u0457 \u043a\u043e\u0440\u0438\u0441\u0442\u0456. \u0422\u043e\u043c\u0443 \u0434\u043b\u044f \u043d\u0430\u0441 \u0434\u0443\u0436\u0435 \u0432\u0430\u0436\u043b\u0438\u0432\u043e\u044e \u0454 \u043f\u0456\u0434\u0442\u0440\u0438\u043c\u043a\u0430 \u0437\u043d\u0430\u043c\u0435\u043d\u0438\u0442\u0438\u0445 \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0456\u0432 \u043d\u0430\u0443\u043a\u0438 \u0442\u0430 \u043a\u0443\u043b\u044c\u0442\u0443\u0440\u0438. \u041f\u043e\u0447\u0435\u0441\u043d\u0438\u0439 \u043f\u0430\u0442\u0440\u043e\u043d\u0430\u0442 \u043d\u0430\u0434 \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u043c Wolne Lektury \u0437\u0434\u0456\u0439\u0441\u043d\u044e\u0454 \u041c\u0456\u043d\u0456\u0441\u0442\u0435\u0440\u0441\u0442\u0432\u043e \u043a\u0443\u043b\u044c\u0442\u0443\u0440\u0438 \u0442\u0430 \u043d\u0430\u0446\u0456\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0457 \u0441\u043f\u0430\u0434\u0449\u0438\u043d\u0438, \u0430 \u0442\u0430\u043a\u043e\u0436 \u0421\u043f\u0456\u043b\u043a\u0430 \u041f\u043e\u043b\u044c\u0441\u044c\u043a\u0438\u0445 \u041f\u0438\u0441\u044c\u043c\u0435\u043d\u043d\u0438\u043a\u0456\u0432. \u0417\u0430\u0441\u0456\u0434\u0430\u0442\u0438 \u0432 \u041f\u043e\u0447\u0435\u0441\u043d\u043e\u043c\u0443 \u043a\u043e\u043c\u0456\u0442\u0435\u0442\u0456 \u043f\u0440\u043e\u0435\u043a\u0442\u0443 Wolne Lektury \u043f\u043e\u0433\u043e\u0434\u0438\u043b\u0438\u0441\u044f \u043f\u0440\u043e\u0444. \u041c\u0430\u0440\u0456\u044f \u042f\u043d\u0456\u043e\u043d, \u043f\u0440\u043e\u0444. \u0490\u0440\u0430\u0436\u0438\u043d\u0430 \u0411\u043e\u0440\u043a\u043e\u0432\u0441\u044c\u043a\u0430, \u043f\u0440\u043e\u0444. \u041f\u0448\u0435\u043c\u0438\u0441\u043b\u0430\u0432 \u0427\u0430\u043f\u043b\u0456\u043d\u0441\u044c\u043a\u0438\u0439, \u043f\u0440\u043e\u0444. \u041c\u2019\u0454\u0447\u0438\u0441\u043b\u0430\u0432 \u0414\u043e\u043c\u0431\u0440\u043e\u0432\u0441\u044c\u043a\u0438\u0439, \u043f\u0440\u043e\u0444. \u0415\u0432\u0430 \u041a\u0440\u0430\u0441\u043a\u043e\u0432\u0441\u044c\u043a\u0430, \u043f\u0440\u043e\u0444. \u041c\u0430\u043b\u0491\u043e\u0436\u0430\u0442\u0430 \u0427\u0435\u0440\u043c\u0456\u043d\u0441\u044c\u043a\u0430, \u043f\u0440\u043e\u0444. \u0404\u0436\u0438 \u042f\u0436\u0435\u043c\u0431\u0441\u044c\u043a\u0438\u0439 \u0442\u0430 \u043f\u0440\u043e\u0444. \u041f\u0456\u043e\u0442\u0440 \u0421\u043b\u0456\u0432\u0456\u043d\u0441\u044c\u043a\u0438\u0439.</p>\r\n\r\n\r\n\r\n \r\n\r\n <p>\u0414\u0438\u0433\u0456\u0442\u0430\u043b\u0456\u0437\u0430\u0446\u0456\u0454\u044e \u0442\u0430 \u043a\u043e\u0440\u0435\u043a\u0442\u043e\u044e \u0442\u0435\u043a\u0441\u0442\u0456\u0432 \u0437\u0430\u0439\u043c\u0430\u0454\u0442\u044c\u0441\u044f \u041d\u0430\u0446\u0456\u043e\u043d\u0430\u043b\u044c\u043d\u0430 \u0431\u0456\u0431\u043b\u0456\u043e\u0442\u0435\u043a\u0430. \u0406\u043d\u0442\u0435\u0440\u043d\u0435\u0442-\u0441\u0430\u0439\u0442 \u0437\u0430\u043f\u0440\u043e\u0435\u043a\u0442\u043e\u0432\u0430\u043d\u0438\u0439 2ia. \u0410\u0432\u0442\u043e\u0440\u043e\u043c \u043c\u043e\u0432\u0438 \u0441\u043a\u043b\u0430\u0434\u0443 \u0442\u0435\u043a\u0441\u0442\u0456\u0432 \u0443 Wolne Lektury, \u044f\u043a\u0430 \u0441\u043f\u0438\u0440\u0430\u0454\u0442\u044c\u0441\u044f \u043d\u0430 \u043c\u043e\u0432\u0456 XML, \u0454 \u0414\u0430\u0440\u044e\u0448 \u0490\u0430\u043b\u0435\u0446\u044c\u043a\u0438\u0439. \u042e\u0440\u0438\u0434\u0438\u0447\u043d\u0435 \u043e\u0431\u0441\u043b\u0443\u0433\u043e\u0432\u0443\u0432\u0430\u043d\u043d\u044f \u043f\u0440\u043e\u0435\u043a\u0442\u0443 Wolne Lektury \u0437\u0434\u0456\u0439\u0441\u043d\u044e\u0454\u0442\u044c\u0441\u044f \u041a\u0430\u043d\u0446\u0435\u043b\u0430\u0440\u0456\u0454\u044e \u0490\u0440\u0438\u043d\u0433\u043e\u0444\u0444, \u0412\u043e\u0437\u044c\u043d\u0438, \u041c\u0430\u043b\u0456\u043d\u0441\u044c\u043a\u0456. \u0425\u043e\u0441\u0442\u0438\u043d\u0433 \u0441\u0430\u0439\u0442\u0443 \u0437\u0430\u0431\u0435\u0437\u043f\u0435\u0447\u0443\u0454 \u043a\u043e\u043c\u043f\u0430\u043d\u0456\u044f EO Networks. \u0412 \u0442\u0435\u0445\u043d\u0456\u0447\u043d\u043e\u043c\u0443 \u0440\u0435\u0434\u0430\u0433\u0443\u0432\u0430\u043d\u043d\u0456 \u0442\u0435\u043a\u0441\u0442\u0456\u0432 \u0434\u043e\u043f\u043e\u043c\u0430\u0433\u0430\u0454 \u0432\u0438\u0434\u0430\u0432\u043d\u0438\u0446\u0442\u0432\u043e Korporacja Ha!Art. \u041b\u043e\u0433\u043e\u0442\u0438\u043f Wolne Lektury \u0454 \u0442\u0432\u043e\u0440\u043e\u043c \u0430\u0433\u0435\u043d\u0446\u0456\u0457 PZL. \u041f\u0440\u043e\u0435\u043a\u0442 \u0437\u0434\u0456\u0439\u0441\u043d\u044e\u0454\u0442\u044c\u0441\u044f \u043f\u0456\u0434 \u043c\u0435\u0434\u0456\u0430-\u043f\u0430\u0442\u0440\u043e\u043d\u0430\u0442\u043e\u043c \u043d\u0430\u0441\u0442\u0443\u043f\u043d\u0438\u0445 \u0417\u041c\u0406: Dziennik, Elle, Tok.fm, Biblioteka Analiz, Tygodnik Powszechny, Przekr\u00f3j \u0442\u0430 TVP Kultura.</p>\r\n\r\n \r\n\r\n <h2>\u042f\u043a \u043a\u043e\u0440\u0438\u0441\u0442\u0443\u0432\u0430\u0442\u0438\u0441\u044f \u0441\u0430\u0439\u0442\u043e\u043c Wolne Lektury?</h2>\r\n\r\n \r\n\r\n <p>\u041d\u0430\u0439\u0432\u0430\u0436\u043b\u0438\u0432\u0456\u0448\u043e\u044e \u0456\u043d\u043d\u043e\u0432\u0430\u0446\u0456\u0454\u044e Wolne Lektury, \u044f\u043a\u0430 \u0432\u0456\u0434\u0440\u0456\u0437\u043d\u044f\u0454 \u0446\u0435\u0439 \u043f\u0440\u043e\u0435\u043a\u0442 \u0432\u0456\u0434 \u0456\u043d\u0448\u0438\u0445 \u0456\u043d\u0442\u0435\u0440\u043d\u0435\u0442-\u0431\u0456\u0431\u043b\u0456\u043e\u0442\u0435\u043a \u0454 \u0437\u043c\u043e\u0433\u0430 \u0437\u0434\u0456\u0439\u0441\u043d\u044e\u0432\u0430\u0442\u0438 \u043f\u043e\u0448\u0443\u043a \u0443 \u0442\u0435\u043a\u0441\u0442\u0430\u0445 \u0437\u0430 \u0440\u0456\u0437\u043d\u0438\u043c\u0438 \u043a\u0440\u0438\u0442\u0435\u0440\u0456\u044f\u043c\u0438: \u0442\u0440\u0430\u0434\u0438\u0446\u0456\u0439\u043d\u0438\u043c\u0438, \u044f\u043a \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a, \u0430\u0432\u0442\u043e\u0440, \u0435\u043f\u043e\u0445\u0430, \u0440\u0456\u0434, \u043b\u0456\u0442\u0435\u0440\u0430\u0442\u0443\u0440\u043d\u0438\u0439 \u0436\u0430\u043d\u0440, \u0442\u0430 \u0456\u043d\u0448\u0438\u0445, \u044f\u043a\u0438\u0445 \u043d\u0435 \u043c\u043e\u0436\u043d\u0430 \u0437\u0443\u0441\u0442\u0440\u0456\u0442\u0438 \u0434\u0435\u0456\u043d\u0434\u0435, \u0442\u043e\u0431\u0442\u043e \u044f\u043a\u0456 \u043c\u0430\u044e\u0442\u044c \u0432\u0456\u0434\u043d\u043e\u0448\u0435\u043d\u043d\u044f \u0434\u043e \u0437\u043c\u0456\u0441\u0442\u0443 \u0431\u0430\u0433\u0430\u0442\u044c\u043e\u0445 \u0442\u0432\u043e\u0440\u0456\u0432 \u0432\u043e\u0434\u043d\u043e\u0447\u0430\u0441 \u2013 \u043b\u0456\u0442\u0435\u0440\u0430\u0442\u0443\u0440\u043d\u0438\u0445 \u043c\u043e\u0442\u0438\u0432\u0456\u0432 \u0442\u0430 \u0442\u0435\u043c. \u0422\u0430\u043a\u0438\u0439 \u043f\u043e\u0448\u0443\u043a \u043c\u043e\u0436\u043b\u0438\u0432\u0438\u0439 \u0437\u0430\u0432\u0434\u044f\u043a\u0438 \u0441\u043f\u0435\u0446\u0456\u0430\u043b\u044c\u043d\u0456\u0439 \u043f\u0456\u0434\u0433\u043e\u0442\u043e\u0432\u0446\u0456 \u0442\u0435\u043a\u0441\u0442\u0456\u0432 \u043b\u0456\u0442\u0435\u0440\u0430\u0442\u0443\u0440\u0438, \u0442\u043e\u0431\u0442\u043e \u043e\u043f\u0438\u0441\u0430\u043d\u043d\u0456 \u0457\u0445 \u0437\u0430 \u0434\u043e\u043f\u043e\u043c\u043e\u0433\u043e\u044e \u0432\u043a\u0430\u0437\u0430\u043d\u0438\u0445 \u043a\u0440\u0438\u0442\u0435\u0440\u0456\u0457\u0432. \u0421\u0430\u043c\u0435 \u0442\u0430\u043a\u0438\u043c \u0447\u0438\u043d\u043e\u043c Wolne Lektury \u0432\u0456\u0434\u0440\u0456\u0437\u043d\u044f\u0454\u0442\u044c\u0441\u044f \u0432\u0456\u0434 \u0431\u0430\u0433\u0430\u0442\u044c\u043e\u0445 \u0441\u0430\u0439\u0442\u0456\u0432 \u0437 \u043e\u043f\u0440\u0430\u0446\u044e\u0432\u0430\u043d\u043d\u044f\u043c\u0438 \u0448\u043a\u0456\u043b\u044c\u043d\u043e\u0457 \u043b\u0456\u0442\u0435\u0440\u0430\u0442\u0443\u0440\u0438 \u2013 Wolne Lektury \u043d\u0430\u0434\u0430\u0454 \u0456\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0438 \u0434\u043b\u044f \u0442\u0432\u043e\u0440\u0447\u043e\u0457 \u043f\u0440\u0430\u0446\u0456 \u0437 \u0442\u0435\u043a\u0441\u0442\u043e\u043c, \u0430 \u043d\u0435 \u0433\u043e\u0442\u043e\u0432\u0456 \u0448\u043f\u0430\u0440\u0433\u0430\u043b\u043a\u0438. \u042f\u043a\u0449\u043e \u043d\u0430\u043f\u0440\u0438\u043a\u043b\u0430\u0434 \u0443\u0447\u0435\u043d\u044c \u043e\u0442\u0440\u0438\u043c\u0443\u0454 \u0442\u0435\u043c\u0443 \u0434\u043e\u043c\u0430\u0448\u043d\u044c\u043e\u0433\u043e \u0437\u0430\u0432\u0434\u0430\u043d\u043d\u044f: \u00ab\u041c\u043e\u0442\u0438\u0432 \u0434\u0438\u0442\u0438\u043d\u0438 \u0432 \u0440\u043e\u043c\u0430\u043d\u0442\u0438\u0437\u043c\u0456 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0456 \u0432\u0438\u0431\u0440\u0430\u043d\u0438\u0445 \u0442\u0432\u043e\u0440\u0456\u0432\u00bb, \u043f\u0456\u0441\u043b\u044f \u0442\u0440\u044c\u043e\u0445 \u043a\u043b\u0430\u0446\u0430\u043d\u044c \u043d\u0430 \u043d\u0430\u0448\u043e\u043c\u0443 \u0441\u0430\u0439\u0442\u0456 \u0432\u0456\u043d \u043c\u0430\u0442\u0438\u043c\u0435 \u043d\u0430 \u0435\u043a\u0440\u0430\u043d\u0456 \u0441\u0432\u043e\u0433\u043e \u043a\u043e\u043c\u043f\u2019\u044e\u0442\u0435\u0440\u0430 \u043a\u043e\u043c\u043f\u043b\u0435\u043a\u0442 \u0442\u0435\u043a\u0441\u0442\u0456\u0432 \u0434\u043e \u0430\u043d\u0430\u043b\u0456\u0437\u0443. \u0417\u0430\u0432\u0434\u044f\u043a\u0438 \u0442\u0430\u043a\u0438\u043c \u0456\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430\u043c \u0447\u0438\u0442\u0430\u043d\u043d\u044f \u043b\u0456\u0442\u0435\u0440\u0430\u0442\u0443\u0440\u0438 \u0441\u0442\u0430\u0454 \u0437\u0430\u0445\u043e\u043f\u043b\u044e\u044e\u0447\u043e\u044e \u043f\u043e\u0434\u043e\u0440\u043e\u0436\u0436\u044e \u043f\u043e \u0441\u0432\u0456\u0442\u0456 \u043a\u0443\u043b\u044c\u0442\u0443\u0440\u0438.</p>\r\n\r\n \r\n\r\n <p>\u0427\u0435\u0440\u0433\u043e\u0432\u043e\u044e \u043a\u043e\u0440\u0438\u0441\u043d\u043e\u044e \u0445\u0430\u0440\u0430\u043a\u0442\u0435\u0440\u0438\u0441\u0442\u0438\u043a\u043e\u044e Wolne Lektury, \u044f\u043a\u0430 \u0441\u0442\u0430\u0454 \u0432 \u043f\u0440\u0438\u0433\u043e\u0434\u0456 \u0432 \u043f\u0440\u0430\u0446\u0456 \u0432 \u0448\u043a\u043e\u043b\u0456 \u0454 \u043c\u043e\u0436\u043b\u0438\u0432\u0456\u0441\u0442\u044c \u0441\u0442\u0432\u043e\u0440\u0435\u043d\u043d\u044f \u0446\u0456\u043b\u0438\u0445 \u0437\u0431\u0456\u0440\u043e\u043a \u0442\u0435\u043a\u0441\u0442\u0456\u0432, \u044f\u043a\u0456 \u043e\u0431\u0433\u043e\u0432\u043e\u0440\u044e\u0432\u0430\u043b\u0438\u0441\u044f \u043d\u0430\u043f\u0440\u0438\u043a\u043b\u0430\u0434 \u043f\u0440\u043e\u0442\u044f\u0433\u043e\u043c \u0440\u043e\u043a\u0443 \u0432 \u0434\u0430\u043d\u043e\u043c\u0443 \u043a\u043b\u0430\u0441\u0456. \u0422\u0430\u043a\u0456 \u043f\u043e\u043b\u0438\u0446\u0456 \u0442\u0435\u043a\u0441\u0442\u0456\u0432 \u043c\u043e\u0436\u0443\u0442\u044c \u0431\u0443\u0442\u0438 \u0441\u0442\u0432\u043e\u0440\u0435\u043d\u0456 \u0432\u0447\u0438\u0442\u0435\u043b\u0435\u043c/\u0432\u0447\u0438\u0442\u0435\u043b\u044c\u043a\u043e\u044e, \u044f\u043a\u0456 \u0434\u0430\u043b\u0456 \u043c\u043e\u0436\u0443\u0442\u044c \u0432\u0438\u0441\u043b\u0430\u0442\u0438 \u043f\u043e\u0441\u0438\u043b\u0430\u043d\u043d\u044f \u043d\u0430 \u043d\u0438\u0445 \u0441\u0432\u043e\u0457\u043c \u0443\u0447\u043d\u044f\u043c. \u0426\u0456 \u0432 \u0441\u0432\u043e\u044e \u0447\u0435\u0440\u0433\u0443, \u0437\u043c\u043e\u0436\u0443\u0442\u044c \u043e\u0434\u043d\u0438\u043c \u043a\u043b\u0430\u0446\u0430\u043d\u043d\u044f\u043c \u0437\u0430\u0432\u0430\u043d\u0442\u0430\u0436\u0438\u0442\u0438 \u0432\u0441\u044e \u0437\u0431\u0456\u0440\u043a\u0443 \u043d\u0430 \u0441\u0432\u0456\u0439 \u043a\u043e\u043c\u043f\u2019\u044e\u0442\u0435\u0440.</p>\r\n\r\n \r\n\r\n <p>\u0412\u0441\u0456 \u0442\u0435\u043a\u0441\u0442\u0438 \u0437 \u0441\u0430\u0439\u0442\u0443 Wolne Lektury (\u0443 \u0444\u043e\u0440\u043c\u0430\u0442\u0430\u0445 html, pdf, epub, txt) \u0454 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u0438\u043c\u0438 \u0431\u0435\u0437 \u043e\u0431\u043c\u0435\u0436\u0435\u043d\u044c \u0430\u0432\u0442\u043e\u0440\u0441\u044c\u043a\u043e\u0433\u043e \u043f\u0440\u0430\u0432\u0430 \u0456 \u043c\u043e\u0436\u043d\u0430 \u0432\u0456\u043b\u044c\u043d\u043e \u043d\u0438\u043c\u0438 \u043a\u043e\u0440\u0438\u0441\u0442\u0443\u0432\u0430\u0442\u0438\u0441\u044f \u0431\u0435\u0437 \u0436\u043e\u0434\u043d\u0438\u0445 \u0443\u043c\u043e\u0432.</p>\r\n\r\n\r\n\r\n <p>\u042f\u043a\u0449\u043e \u0442\u0435\u043a\u0441\u0442\u0438 \u0441\u0443\u043f\u0440\u043e\u0432\u043e\u0434\u0436\u0443\u044e\u0442\u044c\u0441\u044f \u0434\u043e\u0434\u0430\u0442\u043a\u043e\u0432\u0438\u043c\u0438 \u043c\u0430\u0442\u0435\u0440\u0456\u0430\u043b\u0430\u043c\u0438 (\u043f\u0440\u0438\u043c\u0456\u0442\u043a\u0430\u043c\u0438, \u043b\u0456\u0442\u0435\u0440\u0430\u0442\u0443\u0440\u043d\u0438\u043c\u0438 \u043c\u043e\u0442\u0438\u0432\u0430\u043c\u0438 \u0442\u043e\u0449\u043e), \u044f\u043a\u0456 \u043e\u0445\u043e\u0440\u043e\u043d\u044f\u044e\u0442\u044c\u0441\u044f \u0430\u0432\u0442\u043e\u0440\u0441\u044c\u043a\u0438\u043c \u043f\u0440\u0430\u0432\u043e\u043c, \u0434\u043e\u0441\u0442\u0443\u043f \u0434\u043e \u0446\u0438\u0445 \u0434\u043e\u0434\u0430\u0442\u043a\u043e\u0432\u0438\u0445 \u043c\u0430\u0442\u0435\u0440\u0456\u0430\u043b\u0456\u0432 \u043d\u0430\u0434\u0430\u0454\u0442\u044c\u0441\u044f \u043d\u0430 \u043b\u0456\u0446\u0435\u043d\u0437\u0456\u0457 Creative Commons Attribution \u2013 Share Alike 3.0 PL (<a href=\"http://creativecommons.org/licenses/by-sa/3.0/\">http://creativecommons.org/licenses/by-sa/3.0/</a>).</p>", 
+            "right_column_pl": "<h2>O Fundacji</h2>\r\n\r\n        <p>Fundacja Nowoczesna Polska powsta\u0142a, poniewa\u017c kszta\u0142cenie dzieci jest kluczem do przysz\u0142o\u015bci Polski. Jednym z\r\n        najwa\u017cniejszych zada\u0144, jakie stoj\u0105 przed polsk\u0105 edukacj\u0105, jest walka z cyfrowym wykluczeniem. Umiej\u0119tno\u015b\u0107\r\n        korzystania z komputera i internetu w czasach spo\u0142ecze\u0144stwa informacyjnego jest rodzajem elementarza. Ci, kt\u00f3rzy\r\n        go nie znaj\u0105, skazani s\u0105 na wegetacj\u0119 na obrze\u017cach nowoczesnego \u015bwiata. </p>\r\n        \r\n         <p>Dlatego od siedmiu lat pomagamy dzieciom zrozumie\u0107 i wykorzystywa\u0107 zaawansowane technologie. Fundacja\r\n        Nowoczesna Polska tysi\u0105com dzieci chce da\u0107 to, co najcenniejsze: wiedz\u0119 i umiej\u0119tno\u015bci pozwalaj\u0105ce rozumie\u0107\r\n        wsp\u00f3\u0142czesny \u015bwiat i wykorzystywa\u0107 mo\u017cliwo\u015bci, jakie on oferuje.</p>\r\n        \r\n         <p>Fundacja Nowoczesna Polska \u2013 poza projektem Wolne Lektury \u2013 koordynuje tak\u017ce projekt Wolne Podr\u0119czniki,\r\n        tworzony przez ruch spo\u0142eczny nauczycieli wolontariuszy, kt\u00f3rzy korzystaj\u0105c z Internetu pisz\u0105 nowe podr\u0119czniki\r\n        dla polskich uczni\u00f3w. Wolne Podr\u0119czniki s\u0105 publikowane na wolnych licencjach \u2013 czyli takich, kt\u00f3re zezwalaj\u0105\r\n        ka\u017cdemu na bezp\u0142atne kopiowanie, rozpowszechnianie i aktualizowanie ich bez konieczno\u015bci pytania o zgod\u0119 zespo\u0142u\r\n        autor\u00f3w. Ka\u017cdy nauczyciel b\u0119dzie m\u00f3g\u0142 te podr\u0119czniki uzupe\u0142nia\u0107, rozszerza\u0107 i poprawia\u0107 zgodnie z w\u0142asnymi\r\n        potrzebami i do\u015bwiadczeniem. Dzi\u0119ki wolnym licencjom mo\u017cna powa\u017cnie obni\u017cy\u0107 koszt podr\u0119cznik\u00f3w wydawanych w\r\n        tradycyjnej postaci ksi\u0105\u017cek drukowanych na papierze, a podr\u0119czniki rozpowszechniane w formie elektronicznej b\u0119d\u0105\r\n        dost\u0119pne za darmo.</p>\r\n\r\n        \r\n        <h2>O domenie publicznej</h2>\r\n        \r\n        <p>W serwisie Wolne Lektury mo\u017cemy zgodnie z prawem publikowa\u0107 tylko te ksi\u0105\u017cki, kt\u00f3re nale\u017c\u0105 do domeny\r\n        publicznej, a wi\u0119c te, kt\u00f3re wysz\u0142y ju\u017c spod dzia\u0142ania prawa autorskiego. Domena publiczna to rodzaj skarbca\r\n        kultury, wsp\u00f3lnego dobra, z kt\u00f3rego wszyscy mog\u0105 korzysta\u0107 na r\u00f3wnych prawach, bez ogranicze\u0144 i op\u0142at. Istnienie\r\n        domeny publicznej jest gwarantem dost\u0119pu do d\u00f3br kultury, ten za\u015b jest naszym obywatelskim prawem zapisanym w\r\n        konstytucji.</p>\r\n        \r\n         <p>Cho\u0107 zasad\u0105 jest, \u017ce po jakim\u015b czasie wszystkie dzie\u0142a maj\u0105 zasili\u0107 domen\u0119 publiczn\u0105, to czas dzia\u0142ania\r\n        polskiego prawa autorskiego zosta\u0142 w ci\u0105gu ostatnich kilkunastu lat znacznie wyd\u0142u\u017cony. Jeszcze na pocz\u0105tku lat\r\n        90. by\u0142o to 25 lat od \u015bmierci autora, potem ten czas wyd\u0142u\u017cono na 50 lat, dzi\u015b jest to ju\u017c lat 70. To oznacza,\r\n        \u017ce wielu pozycji z ministerialnych list lektur nie b\u0119dziemy mogli udost\u0119pni\u0107 jeszcze przez wiele lat. Dopiero w\r\n        2020 roku opublikujemy utwory Marka H\u0142aski i Witolda Gombrowicza. Powie\u015bci Kuncewiczowej zasil\u0105 domen\u0119 publiczn\u0105\r\n        w roku 2060, a poezje Mi\u0142osza w 2075 roku.</p>\r\n        \r\n         <p>Ograniczenia prawa autorskiego odnosz\u0105 si\u0119 tak\u017ce do wyda\u0144 krytycznych i t\u0142umacze\u0144. Do 1 stycznia 2012 roku\r\n        b\u0119dziemy czeka\u0107 na \"Wielki Testament\" Villona i inne utwory t\u0142umaczone przez Boya-\u017bele\u0144skiego, a do 2068 roku na\r\n        \u201eKubusia Puchatka\u201d Milne'a i inne przek\u0142ady Ireny Tuwim. Nie mamy tak\u017ce prawa upublicznia\u0107 wst\u0119p\u00f3w i przedm\u00f3w\r\n        napisanych przez autor\u00f3w, kt\u00f3rzy zmarli mniej ni\u017c 70 lat temu. Z tego w\u0142a\u015bnie powodu zdarza si\u0119 czasem, \u017ce jaki\u015b\r\n        utw\u00f3r znajduje si\u0119 na Wolnych Lekturach, ale link do odpowiadaj\u0105cej mu pozycji w Cyfrowej Bibliotece Narodowej\r\n        Polona odsy\u0142a do strony, kt\u00f3ra m\u00f3wi, \u017ce utw\u00f3r obj\u0119ty jest ochron\u0105 prawa autorskiego. Znaczy to, \u017ce cho\u0107 sam\r\n        tekst nale\u017cy do domeny publicznej i dlatego umieszczamy go w Wolnych Lekturach, to jego wydanie krytyczne,\r\n        kt\u00f3rym dysponuje CBN Polona (ze wszystkimi wst\u0119pami, przedmowami i komentarzami redaktor\u00f3w), wci\u0105\u017c jest obj\u0119te\r\n        dzia\u0142aniem prawa autorskiego.</p>\r\n        \r\n         <p>O domen\u0119 publiczn\u0105 nale\u017cy dba\u0107 i otacza\u0107 j\u0105 ochron\u0105. Kultura to misterny gmach, w kt\u00f3rym kolejne pi\u0119tra mog\u0105\r\n        by\u0107 budowane tylko na solidnych podstawach wypracowanych przez poprzednik\u00f3w. Kochanowski bezpo\u015brednio czerpa\u0142 z\r\n        tradycji antycznej. Mickiewicz tw\u00f3rczo\u015b\u0107 ludow\u0105 wykorzysta\u0142 do stworzenia najpi\u0119kniejszych polskich wierszy.\r\n        Ka\u017cde kolejne pokolenie mo\u017ce si\u0119ga\u0107 wzrokiem dalej, wypracowywa\u0107 w\u0142asny literacki j\u0119zyk i trwale wpisywa\u0107 si\u0119 w\r\n        histori\u0119 literatury tylko dzi\u0119ki osi\u0105gni\u0119ciom poprzednik\u00f3w. Dlatego tak wa\u017cna jest wolno\u015b\u0107 w udost\u0119pnianiu i\r\n        wykorzystywaniu najwa\u017cniejszych dzie\u0142 polskiej i \u015bwiatowej literatury. Bez domeny publicznej zbudowanie tego\r\n        wspania\u0142ego gmachu, jakim jest kultura, by\u0142oby niemo\u017cliwe.</p>\r\n", 
+            "page_title_en": "About Wolne Lektury project", 
+            "page_title_es": "Sobre el proyecto Wolne Lektury", 
+            "left_column_lt": "<h2>Laisvoji Literat\u016bra</h2> \r\n \r\n         \r\n         <p>Internetine biblioteka \"Laisvoji Literat\u016bra\" (www.laisvojiliteratura.lt) si\u016blanti mokyklin\u0119 literat\u016br\u0105 - \r\n         tai \u0160iuolaikines Lenkijos Fondo projektas. Fondas veikia nuo 2007 met\u0173 ir savo rinkiniuose turi mokyklin\u0119 literat\u016br\u0105, \r\n         kuria rekomenduoja \u0160vietimo ir Mokslo Ministerij\u0105 ir kuri jau\tpateko \u012f vie\u0161\u0105 Interneto svetain\u0119. Literat\u016bros \r\n         k\u016briniai yra apra\u0161yti, sukomentuoti ir yra galima juos parsisi\u0173sti i\u0161 Interneto \u0161iuose formatuose (html, epub, mp3, ogg, odt, txt i pdf). \r\n         Galima juos teis\u0117tai, nemokamai ap\u017ei\u016br\u0117ti, parsisi\u0173sti, persiusti kitiems ir cituoti.</p>\r\n        \r\n        \r\n          <p>Projekto Laisvoji Literat\u016bra nariai tai patyria redaktoriai ir mokytojai, d\u0117ka kuri\u0173  \u0161is portalas yra s\u0105\u017einingas.\r\n         Kuriant \u0161\u012f portal\u0105 bendradarbiavome su Lenkijos Nacionalin\u0119 Bibliotek\u0105, kuri pateik\u0117 mums geriausius\tknyg\u0173 leidinius, recenzijas \r\n         ir kritikas apie mokyklin\u0119 literat\u016br\u0105. K\u016briniu rinkinys yra pavie\u0161intas Skaitmenin\u0117je Lenkijos Nacionalin\u0117je Bibliotekoje Polona.\r\n         Kartu stengiam\u0117s kad mokyklin\u0119 literat\u016br\u0105 \u2013 m\u016bs\u0173 kult\u016bros na\u0161ta \u2013 b\u016bt\u0173 visiem prieinama, nepriklausomai nuo gyvenvietes, u\u017edarbi\u0173,\r\n         vikrumo ar ne\u012fgal\u0117jimo. Tai galima pasiekti d\u0117ka ve\u0161iai Interneto svetainei, tai yra rinkinio, kuris n\u0117ra\r\n         ribojamas autoriaus teis\u0117mis, o taip pat ir d\u0117ka naujausios technologijos \u012frankiais kurie pad\u0117da padauginti vie\u0161\u0105 turinio prieinamum\u0105\r\n         internete.</p>     \r\n        \r\n        <p>Laisvoji Literat\u016bra tai visi\u0161kai nekomercinis projektas realizuotas pro publico bono. Tod\u0117l labai svarbu yra kad projektu susidom\u0117tu \u017eymios kult\u016bros ir mokslo asmenyb\u0117s. \r\nLenkijoje projekt\u0105 globoj\u0105 Kult\u016bros Ministerija, \u0160vietimo ir Mokslo Ministerij\u0105, \r\nLenkijos Poetu Draugija. Garb\u0117s komitet\u0105 sudaro: prof. Maria\r\n        Janion, prof. Gra\u017cyna Borkowska, prof. Przemys\u0142aw\r\n        Czapli\u0144ski, prof. Mieczys\u0142aw D\u0105browski, prof. Ewa Kraskowska, prof. Ma\u0142gorzata Czermi\u0144ska, prof. Jerzy Jarz\u0119bski\r\n        i prof. Piotr \u015aliwi\u0144ski.</p>\r\n        \r\n         <p>Skaitmenines kopijas ruo\u0161ia Lenkijos Nacionalin\u0119 Bibliotek\u0105. Tinklap\u012f  projektavo 2ia. HTML versijos tekst\u0173  autorius tai Dariusz Ga\u0142ecki. Teisines paslaugas u\u017etikrina Kanceliarija  Grynhoff,\r\n        Pri\u017ei\u016br\u0117tojas, Mali\u0144ski. Hosting servis u\u017etikrina\r\n        \u012fmon\u0117 EO Networks. Techninius tekst\u0173 apra\u0161imus pad\u0117jo paruo\u0161ti leidykla Korporacija  Ha!Art. Logotipas Laisvoji Literat\u016bra tai\r\n        Agent\u016bros PZL k\u016brinys. Projekt\u0105 \u017einiasklaidoje remia: Dziennik, Elle, Tok.fm, Biblioteka Analiz,\r\n        Tygodnik Powszechny, Przekr\u00f3j ir TVP Kultura.</p>\r\n        \r\n        <h2>Kaip naudoti Laisv\u0105j\u0105 Literat\u016br\u0105?</h2>\r\n        \r\n         <p>Did\u017eiausia naujov\u0117 projekto Laisvoji Literat\u016bra, skirianti \u0161i projekt\u0105 nuo kitu internetiniu bibliotek\u0173 tai galimyb\u0117 ie\u0161koti teksto naudojant \u012fvairius kriterijus: tradicinius, pvz: k\u016brinio pavadinimas, autorius,\r\n        gaidyn\u0117, r\u016b\u0161is, literat\u016brin\u0117 paderm\u0117, bet ir niekur anks\u010diau nesutikti bet pritaikyti prie daugelio \u012fvairi\u0173 k\u016brini\u0173 ir turini\u0173\r\n        motyvai ir literat\u016brin\u0117s temos. Tokia paie\u0161ka yra galima d\u0117ka specjalaus -kruop\u0161\u010diai paruo\u0161to- mokyklin\u0117s literat\u016bros tekst\u0173 apra\u0161ymo, tai raiskia jie buvo/yra apra\u0161omi i\u0161 karto panaudojant daugel\u012f kriterij\u0173. Tai skiria Laisv\u0105j\u0105 Literat\u016br\u0105\r\n        nuo daugelio kitu apra\u0161ym\u0173 ir pateikia \u012frankius kokybi\u0161kam darbui su tekstu.\r\n        O tai skiriasi nuo paruo\u0161tuk\u0173 ar \u0161pargal\u0173. Jeigu mokynys tur\u0117s para\u0161yti namuose darb\u0105 tem\u0105  \u201eVaiko motyvas pagal i\u0161rinktus k\u016brinius ir romantizmo gaidyn\u0117s\u201c, tai paie\u0161ka galima padaryti pagal  3 kriterijus: vaiko motyvas, gaidyn\u0117, romatizmas ir vat pasirodis tekstas paruo\u0161tas analizei.\r\nD\u0117ka tokiu \u012frankiu skaitimas moklin\u0117s literat\u016bros gali b\u016bti \u012fsp\u016bdingas lyg kelion\u0117 per kult\u016bros pasauly.</p>\r\n        \r\n         <p>Dar vienas naudingumas -  Laisv\u0105ja Literat\u016bra galima pasinaudoti darbe ir mokykloje - tai galimyb\u0117 pasirinkti tekstus  paruo\u0161tus pavyzd\u017eiui paskutiniu metu per vien\u0105 klas\u0119.\r\nLentynos su mokykline literat\u016bra kuria mokytojai kurie veliau gali persiust mokiniams nurodym\u0105, o tie gali atsisi\u0173sti vis\u0105 katalog\u0105 \u012f savo disk\u0105. </p>\r\n        \r\n        <p>Visi knyg\u0173 tekstai i\u0161 Laisvosios Literat\u016bros tinklapio (\u0161iuose formatuose html, pdf, epub, txt) yra prieinami ne\u017eaid\u017eiant autori\u0173 teisi\u0173  ir galima juos laisvai ir nemokamai naudoti.</p>\r\n\r\n        <p>Jeigu tekstas turi dar pried\u0105 (i\u0161na\u0161\u0105 ir pana\u0161iai) kuris gal\u0117t\u0173 \u017eaisti autori\u0173  teises, med\u017eiagos prijungiamos d\u0117ka Creative Commons licencijos, kuri tuo pat pripa\u017eina autoriaus teises tomis pa\u010diomis s\u0105lygomis 3.0 PL (<a href=\"http://creativecommons.org/licenses/by-sa/3.0/\">http://creativecommons.org/licenses/by-sa/3.0/</a>).</p>\r\n", 
+            "title_fr": "Sur le projet Lectures libres", 
+            "right_column_ru": "<h2>\u041e \u0444\u043e\u043d\u0434\u0435</h2>\r\n\r\n        <p>\u0424\u043e\u043d\u0434 \u0421\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f \u041f\u043e\u043b\u044c\u0448\u0430 \u0431\u044b\u043b \u0441\u043e\u0437\u0434\u0430\u043d \u043d\u0430\u043c\u0438 \u043f\u043e\u0442\u043e\u043c\u0443, \u0447\u0442\u043e \u043e\u0431\u0443\u0447\u0435\u043d\u0438\u0435 \u0434\u0435\u0442\u0435\u0439 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043a\u043b\u044e\u0447\u0435\u043c \u043a \u0431\u0443\u0434\u0443\u0449\u0435\u043c\u0443 \u041f\u043e\u043b\u044c\u0448\u0438. \u041e\u0434\u043d\u043e\u0439 \u0438\u0437\r\n        \u0441\u0430\u043c\u044b\u0445 \u0432\u0430\u0436\u043d\u044b\u0445 \u0437\u0430\u0434\u0430\u0447, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u043e\u044f\u0442 \u043f\u043e\u043b\u044c\u0441\u043a\u043e\u043c\u0443 \u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u044e, \u0441\u0447\u0438\u0442\u0430\u0435\u0442\u0441\u044f \u0431\u043e\u0440\u044c\u0431\u0430 \u0441 \u0446\u0438\u0444\u0440\u043e\u0432\u044b\u043c \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435\u043c. \u0423\u043c\u0435\u043d\u0438\u0435\r\n        \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043a\u043e\u043c\u043f\u044c\u044e\u0442\u0435\u0440\u043e\u043c \u0438 \u0418\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u043e\u043c \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0433\u043e \u043e\u0431\u0449\u0435\u0441\u0442\u0432\u0430 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0444\u043e\u0440\u043c\u043e\u0439 \u0430\u0437\u0431\u0443\u043a\u0438. \u0422\u0435, \u043a\u043e\u0442\u043e\u0440\u044b\u0435\r\n        \u043d\u0435 \u0437\u043d\u0430\u044e\u0442 \u0435\u0435, \u043e\u0431\u0440\u0435\u0447\u0435\u043d\u044b \u043d\u0430 \u043f\u0440\u043e\u0437\u044f\u0431\u0430\u043d\u0438\u0435 \u043d\u0430 \u043e\u043a\u0440\u0430\u0438\u043d\u0430\u0445 \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0433\u043e \u043c\u0438\u0440\u0430. </p>\r\n        \r\n         <p>\u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u0441 \u0441\u0435\u043c\u0438 \u043b\u0435\u0442 \u043c\u044b \u043f\u043e\u043c\u043e\u0433\u0430\u0435\u043c \u0434\u0435\u0442\u044f\u043c \u043f\u043e\u043d\u044f\u0442\u044c \u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043d\u0430\u0443\u043a\u043e\u0435\u043c\u043a\u0438\u0435 \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0438. \u0424\u043e\u043d\u0434\r\n        \u0421\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f \u041f\u043e\u043b\u044c\u0448\u0430 \u0445\u043e\u0447\u0435\u0442 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0442\u044b\u0441\u044f\u0447\u0430\u043c \u0434\u0435\u0442\u0435\u0439 \u0441\u0430\u043c\u043e\u0435 \u0446\u0435\u043d\u043d\u043e\u0435, \u0442.\u0435. \u0437\u043d\u0430\u043d\u0438\u044f \u0438 \u0443\u043c\u0435\u043d\u0438\u044f, \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0449\u0438\u0435 \u043f\u043e\u043d\u044f\u0442\u044c\r\n        \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0439 \u043c\u0438\u0440 \u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u0435\u043c\u044b\u0435 \u0438\u043c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438.</p>\r\n        \r\n         <p>\u0424\u043e\u043d\u0434 \u0421\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f \u041f\u043e\u043b\u044c\u0448\u0430 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0438\u0440\u0443\u0435\u0442 \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u0440\u043e\u0435\u043a\u0442 Wolne Lektury, \u043d\u043e \u0442\u0430\u043a\u0436\u0435 \u043f\u0440\u043e\u0435\u043a\u0442 Wolne Podr\u0119czniki.\r\n        \u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0439 \u0436\u0435 \u0441\u043e\u0437\u0434\u0430\u044e\u0442 \u0443\u0447\u0438\u0442\u0435\u043b\u044f-\u0432\u043e\u043b\u043e\u043d\u0442\u0435\u0440\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u043e\u043b\u044c\u0437\u0443\u044f\u0441\u044c \u0418\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u043e\u043c, \u043f\u0438\u0448\u0443\u0442 \u043d\u043e\u0432\u044b\u0435 \u0443\u0447\u0435\u0431\u043d\u0438\u043a\u0438 \r\n        \u0434\u043b\u044f \u043f\u043e\u043b\u044c\u0441\u043a\u0438\u0445 \u0443\u0447\u0435\u043d\u0438\u043a\u043e\u0432. Wolne Podr\u0119czniki (\u0421\u0432\u043e\u0431\u043e\u0434\u043d\u044b\u0435 \u0443\u0447\u0435\u0431\u043d\u0438\u043a\u0438) \u0438\u0437\u0434\u0430\u044e\u0442\u0441\u044f \u043f\u043e \u0441\u0432\u043e\u0431\u043e\u0434\u043d\u044b\u043c \u043b\u0438\u0446\u0435\u043d\u0437\u0438\u044f\u043c, \u0442.\u0435. \u0442\u0430\u043a\u0438\u043c, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0440\u0430\u0437\u0440\u0435\u0448\u0430\u044e\u0442\r\n        \u043a\u0430\u0436\u0434\u043e\u043c\u0443 \u0431\u0435\u0441\u043f\u043b\u0430\u0442\u043d\u043e \u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u0442\u044c, \u0440\u0430\u0441\u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u044f\u0442\u044c \u0438 \u0430\u043a\u0442\u0443\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0438\u0445 \u043f\u0440\u0438 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u0438 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u043f\u0440\u043e\u0441\u0438\u0442\u044c \u0441\u043e\u0433\u043b\u0430\u0441\u0438\u044f\r\n        \u0430\u0432\u0442\u043e\u0440\u043e\u0432. \u041a\u0430\u0436\u0434\u044b\u0439 \u0443\u0447\u0438\u0442\u0435\u043b\u044c \u043c\u043e\u0436\u0435\u0442 \u044d\u0442\u0438 \u0443\u0447\u0435\u0431\u043d\u0438\u043a\u0438 \u0434\u043e\u043f\u043e\u043b\u043d\u044f\u0442\u044c, \u0440\u0430\u0441\u0448\u0438\u0440\u044f\u0442\u044c \u0438 \u0438\u0441\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0441\u043e\u0433\u043b\u0430\u0441\u043d\u043e \u0441\u0432\u043e\u0438\u043c\r\n        \u043f\u043e\u0442\u0440\u0435\u0431\u043d\u043e\u0441\u0442\u044f\u043c \u0438 \u043e\u043f\u044b\u0442\u0443. \u0411\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u044f \u0441\u0432\u043e\u0431\u043e\u0434\u043d\u044b\u043c \u043b\u0438\u0446\u0435\u043d\u0437\u0438\u044f\u043c \u043c\u043e\u0436\u043d\u043e \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043f\u043e\u043d\u0438\u0436\u0438\u0442\u044c \u0440\u0430\u0441\u0445\u043e\u0434\u044b \u043f\u043e \u0443\u0447\u0435\u0431\u043d\u0438\u043a\u0430\u043c, \u0438\u0437\u0434\u0430\u0432\u0430\u0435\u043c\u044b\u043c\r\n        \u0432 \u0442\u0440\u0430\u0434\u0438\u0446\u0438\u043e\u043d\u043d\u043e\u0439 \u0444\u043e\u0440\u043c\u0435 \u043a\u043d\u0438\u0433, \u043f\u0435\u0447\u0430\u0442\u0430\u043d\u043d\u044b\u0445 \u043d\u0430 \u0431\u0443\u043c\u0430\u0433\u0435, \u0442.\u043a. \u0443\u0447\u0435\u0431\u043d\u0438\u043a\u0438 \u0432 \u044d\u043b\u0435\u043a\u0442\u0440\u043e\u043d\u043d\u043e\u0439 \u0444\u043e\u0440\u043c\u0435 \u0431\u0443\u0434\u0443\u0442 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b \u0431\u0435\u0441\u043f\u043b\u0430\u0442\u043d\u043e.</p>\r\n\r\n        \r\n        <h2>\u041e \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u043e\u043c \u0434\u043e\u043c\u0435\u043d\u0435</h2>\r\n        \r\n        <p>\u0421\u043e\u0433\u043b\u0430\u0441\u043d\u043e \u0437\u0430\u043a\u043e\u043d\u0443, \u0432 \u0441\u0435\u0440\u0432\u0438\u0441\u0435 Wolne Lektury, \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u043f\u0443\u0431\u043b\u0438\u043a\u043e\u0432\u0430\u0442\u044c \u043b\u0438\u0448\u044c \u0442\u0435 \u043a\u043d\u0438\u0433\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u0440\u0438\u043d\u0430\u0434\u043b\u0435\u0436\u0430\u0442 \u043a \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u043e\u043c\u0443\r\n        \u0434\u043e\u043c\u0435\u043d\u0443, \u0442.\u0435. \u0442\u0435, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0443\u0436\u0435 \u043d\u0435 \u0440\u0430\u0441\u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u044f\u0435\u0442\u0441\u044f \u0430\u0432\u0442\u043e\u0440\u0441\u043a\u043e\u0435 \u043f\u0440\u0430\u0432\u043e. \u041f\u0443\u0431\u043b\u0438\u0447\u043d\u044b\u0439 \u0434\u043e\u043c\u0435\u043d - \u044d\u0442\u043e \u0432\u0438\u0434 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0430\r\n        \u043a\u0443\u043b\u044c\u0442\u0443\u0440\u044b, \u0441\u043e\u0432\u043c\u0435\u0441\u0442\u043d\u043e\u0433\u043e \u0431\u043b\u0430\u0433\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u043c \u043c\u043e\u0433\u0443\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0432\u0441\u0435 \u043d\u0430 \u0440\u0430\u0432\u043d\u044b\u0445 \u043f\u0440\u0430\u0432\u0430\u0445 \u0431\u0435\u0437\u0433\u0440\u0430\u043d\u0438\u0447\u043d\u043e \u0438 \u0431\u0435\u0441\u043f\u043b\u0430\u0442\u043d\u043e. \u0421\u0443\u0449\u0435\u0441\u0442\u0432\u043e\u0432\u0430\u043d\u0438\u0435\r\n        \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u043e\u0433\u043e \u0434\u043e\u043c\u0435\u043d\u0430 \u0441\u0447\u0438\u0442\u0430\u0435\u0442\u0441\u044f \u0433\u0430\u0440\u0430\u043d\u0442\u043e\u043c \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043a \u0446\u0435\u043d\u043d\u043e\u0441\u0442\u044f\u043c \u043a\u0443\u043b\u044c\u0442\u0443\u0440\u044b. \u041e\u043d \u0436\u0435 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043d\u0430\u0448\u0438\u043c \u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0441\u043a\u0438\u043c \u043f\u0440\u0430\u0432\u043e\u043c, \u0437\u0430\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u043c\r\n        \u0432 \u041a\u043e\u043d\u0441\u0442\u0438\u0442\u0443\u0446\u0438\u0438.</p>\r\n        \r\n         <p>\u041d\u0435\u0441\u043c\u043e\u0442\u0440\u044f \u043d\u0430 \u043f\u0440\u0438\u043d\u0446\u0438\u043f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e \u043f\u043e\u0441\u043b\u0435 \u043a\u0430\u043a\u043e\u0433\u043e-\u0442\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0432\u0441\u0435 \u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u044f \u043f\u043e\u043f\u043e\u043b\u043d\u044f\u0442 \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u044b\u0439 \u0434\u043e\u043c\u0435\u043d, \u0441\u0440\u043e\u043a \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f\r\n        \u043f\u043e\u043b\u044c\u0441\u043a\u043e\u0433\u043e \u0430\u0432\u0442\u043e\u0440\u0441\u043a\u043e\u0433\u043e \u043f\u0440\u0430\u0432\u0430 \u0432 \u0442\u0435\u0447\u0435\u043d\u0438\u0435 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0445 \u0434\u0435\u0441\u044f\u0442\u043e\u043a \u043b\u0435\u0442 \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0443\u0432\u0435\u043b\u0438\u0447\u0438\u043b\u0438\u0441\u044f. \u0415\u0449\u0435 \u0432 \u043d\u0430\u0447\u0430\u043b\u0435 90-\u044b\u0445 \u0433\u0433.\r\n        - \u044d\u0442\u043e \u0431\u044b\u043b\u043e 25 \u043b\u0435\u0442 \u0441\u043e \u0441\u043c\u0435\u0440\u0442\u0438 \u0430\u0432\u0442\u043e\u0440\u0430, \u043f\u043e\u0442\u043e\u043c \u044d\u0442\u043e\u0442 \u0441\u0440\u043e\u043a \u043f\u0440\u043e\u0434\u043b\u0438\u043b\u0441\u044f \u0434\u043e 50 \u043b\u0435\u0442, \u0441\u0435\u0433\u043e\u0434\u043d\u044f - \u044d\u0442\u043e \u0443\u0436\u0435 70 \u043b\u0435\u0442. \u042d\u0442\u043e \u043e\u0431\u043e\u0437\u043d\u0430\u0447\u0430\u0435\u0442,\r\n        \u0447\u0442\u043e \u043c\u043d\u043e\u0433\u0438\u0435 \u043f\u043e\u0437\u0438\u0446\u0438\u0438 \u043c\u0438\u043d\u0438\u0441\u0442\u0435\u0440\u0441\u043a\u0438\u0445 \u0441\u043f\u0438\u0441\u043a\u043e\u0432 \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u0447\u0442\u0435\u043d\u0438\u0439 \u043d\u0435 \u0431\u0443\u0434\u0443\u0442 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b \u0435\u0449\u0435 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043b\u0435\u0442. \u0422\u043e\u043b\u044c\u043a\u043e \u0432 \r\n        2020 \u0433\u043e\u0434\u0443 \u043c\u044b \u043e\u043f\u0443\u0431\u043b\u0438\u043a\u0443\u0435\u043c \u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u044f \u041c\u0430\u0440\u043a\u0430 \u0425\u043b\u0430\u0441\u043a\u043e \u0438 \u0412\u0438\u0442\u043e\u043b\u044c\u0434\u0430 \u0413\u043e\u043c\u0431\u0440\u043e\u0432\u0438\u0447\u0430. \u0420\u043e\u043c\u0430\u043d\u044b \u041a\u0443\u043d\u0446\u0435\u0432\u0438\u0447 \u043f\u043e\u043f\u043e\u043b\u043d\u044f\u0442 \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u044b\u0439 \u0434\u043e\u043c\u0435\u043d\r\n        \u0432 2060 \u0433\u043e\u0434\u0443, \u043f\u043e\u044d\u0437\u0438\u044f \u041c\u0438\u043b\u043e\u0448\u0430 \u0436\u0435 - \u0432 2075 \u0433\u043e\u0434\u0443.</p>\r\n        \r\n         <p>\u041e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u044f \u0430\u0432\u0442\u043e\u0440\u0441\u043a\u043e\u0433\u043e \u043f\u0440\u0430\u0432\u0430 \u0441\u0432\u044f\u0437\u0430\u043d\u044b \u0442\u0430\u043a\u0436\u0435 \u0441 \u043a\u0440\u0438\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0439 \u043b\u0438\u0442\u0435\u0440\u0430\u0442\u0443\u0440\u043e\u0439 \u0438 \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u0430\u043c\u0438. \u0414\u043e 1 \u044f\u043d\u0432\u0430\u0440\u044f 2012 \u0433\u043e\u0434\u0430\r\n        \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0436\u0434\u0430\u0442\u044c \"\u0411\u043e\u043b\u044c\u0448\u043e\u0433\u043e \u0437\u0430\u0432\u0435\u0449\u0430\u043d\u0438\u044f\" \u0412\u0438\u0439\u043e\u043d\u0430 \u0438 \u0434\u0440\u0443\u0433\u0438\u0445 \u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u0439, \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u0438\u043c\u044b\u0445 \u0411\u043e\u0439-\u0416\u0435\u043b\u0435\u043d\u0441\u043a\u0438\u043c. \u0414\u043e 2068 \u0433\u043e\u0434\u0430 \u0436\u0435 -\r\n        \u201e\u0412\u0438\u043d\u043d\u0438-\u041f\u0443\u0445\u0430\u201d \u041c\u0438\u043b\u043d\u0430 \u0438 \u0434\u0440\u0443\u0433\u0438\u0445 \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u043e\u0432 \u0418\u0440\u0435\u043d\u044b \u0422\u0443\u0432\u0438\u043c. \u0423 \u043d\u0430\u0441 \u043d\u0435\u0442 \u0442\u0430\u043a\u0436\u0435 \u043f\u0440\u0430\u0432\u0430 \u0434\u0435\u043b\u0430\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u043c\u0438 \u0432\u0432\u0435\u0434\u0435\u043d\u0438\u044f \u0438 \u043f\u0440\u0435\u0434\u0438\u0441\u043b\u043e\u0432\u0438\u044f,\r\n        \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u0435 \u0430\u0432\u0442\u043e\u0440\u0430\u043c\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0443\u043c\u0435\u0440\u043b\u0438 \u0440\u0430\u043d\u044c\u0448\u0435, \u0447\u0435\u043c 70 \u043b\u0435\u0442 \u0442\u043e\u043c\u0443 \u043d\u0430\u0437\u0430\u0434. \u041f\u043e \u044d\u0442\u043e\u0439 \u043f\u0440\u0438\u0447\u0438\u043d\u0435 \u0438\u043d\u043e\u0433\u0434\u0430 \u043a\u0430\u043a\u043e\u0435-\u0442\u043e\r\n        \u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0432 Wolne Lektury, \u043d\u043e \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0443\u044e \u0435\u043c\u0443 \u043f\u043e\u0437\u0438\u0446\u0438\u044e \u0432 \u0426\u0438\u0444\u0440\u043e\u0432\u043e\u0439 \u041d\u0430\u0440\u043e\u0434\u043d\u043e\u0439 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0435\r\n        Polona \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442 \u043d\u0430 \u0441\u0430\u0439\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e\u0434\u0441\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442, \u0447\u0442\u043e \u0434\u0430\u043d\u043d\u043e\u0435 \u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u0437\u0430\u0449\u0438\u0449\u0430\u0435\u0442\u0441\u044f \u0430\u0432\u0442\u043e\u0440\u0441\u043a\u0438\u043c \u043f\u0440\u0430\u0432\u043e\u043c.\r\n        \u0422\u0435\u043a\u0441\u0442 \u043f\u0440\u0438\u043d\u0430\u0434\u043b\u0435\u0436\u0438\u0442 \u043a \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u043e\u043c\u0443 \u0434\u043e\u043c\u0435\u043d\u0443 \u0438 \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043e\u043d \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0432 Wolne Lektury, \u043d\u043e \u043d\u0430 \u0435\u0433\u043e \u043a\u0440\u0438\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0435 \u0438\u0437\u0434\u0430\u043d\u0438\u0435, \u043a\u043e\u0442\u043e\u0440\u043e\u0435\r\n        \u0432\u0445\u043e\u0434\u0438\u0442 \u0432 \u0441\u043e\u0441\u0442\u0430\u0432 \u0426\u0438\u0444\u0440\u043e\u0432\u043e\u0439 \u041d\u0430\u0440\u043e\u0434\u043d\u043e\u0439 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 Polona (\u0441\u043e \u0432\u0441\u0435\u043c\u0438 \u0432\u0432\u0435\u0434\u0435\u043d\u0438\u044f\u043c\u0438, \u043f\u0440\u0435\u0434\u0438\u0441\u043b\u043e\u0432\u0438\u044f\u043c\u0438 \u0438 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u044f\u043c\u0438 \u0440\u0435\u0434\u0430\u043a\u0442\u043e\u0440\u043e\u0432), \r\n        \u0432\u0441\u0435-\u0442\u0430\u043a\u0438 \u0440\u0430\u0441\u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u044f\u0435\u0442\u0441\u044f \u0430\u0432\u0442\u043e\u0440\u0441\u043a\u043e\u0435 \u043f\u0440\u0430\u0432\u043e.</p>\r\n        \r\n         <p>\u041e \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u043e\u043c \u0434\u043e\u043c\u0435\u043d\u0435 \u043c\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u0437\u0430\u0431\u043e\u0442\u0438\u0442\u044c\u0441\u044f \u0438 \u043e\u0445\u0440\u0430\u043d\u044f\u0442\u044c \u0435\u0433\u043e. \u041a\u0443\u043b\u044c\u0442\u0443\u0440\u0430 - \u044d\u0442\u043e \u0438\u0441\u043a\u0443\u0441\u043d\u043e\u0435 \u0437\u0434\u0430\u043d\u0438\u0435, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u044d\u0442\u0430\u0436\u0438 \u043c\u043e\u0433\u0443\u0442\r\n        \u0441\u0442\u0440\u043e\u0438\u0442\u044c\u0441\u044f \u043b\u0438\u0448\u044c \u043d\u0430 \u0441\u043e\u043b\u0438\u0434\u043d\u044b\u0445 \u043e\u0441\u043d\u043e\u0432\u0430\u0445, \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u044b\u0445 \u043f\u0440\u0435\u0434\u0448\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u0438\u043a\u0430\u043c\u0438. \u041a\u043e\u0445\u0430\u043d\u043e\u0432\u0441\u043a\u0438\u0439 \u043d\u0435\u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0447\u0435\u0440\u043f\u0430\u043b\r\n        \u0438\u0437 \u0430\u043d\u0442\u0438\u0447\u043d\u043e\u0439 \u0442\u0440\u0430\u0434\u0438\u0446\u0438\u0438. \u041c\u0438\u0446\u043a\u0435\u0432\u0438\u0447 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b \u043d\u0430\u0440\u043e\u0434\u043d\u043e\u0435 \u0442\u0432\u043e\u0440\u0447\u0435\u0441\u0442\u0432\u043e \u0434\u043b\u044f \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u043a\u0440\u0430\u0441\u0438\u0432\u0435\u0439\u0448\u0438\u0445 \u043f\u043e\u043b\u044c\u0441\u043a\u0438\u0445 \u0441\u0442\u0438\u0445\u043e\u0442\u0432\u043e\u0440\u0435\u043d\u0438\u0439.\r\n        \u041a\u0430\u0436\u0434\u043e\u0435 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0435 \u043f\u043e\u043a\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u043c\u043e\u0436\u0435\u0442 \u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0434\u0430\u043b\u044c\u0448\u0435, \u0432\u044b\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0442\u044c \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u043b\u0438\u0442\u0435\u0440\u0430\u0442\u0443\u0440\u043d\u044b\u0439 \u044f\u0437\u044b\u043a, \u043f\u0440\u043e\u0447\u043d\u043e \u0432\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c\u0441\u044f\r\n        \u0432 \u0438\u0441\u0442\u043e\u0440\u0438\u044e \u043b\u0438\u0442\u0435\u0440\u0430\u0442\u0443\u0440\u044b \u043b\u0438\u0448\u044c \u0431\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u044f \u0434\u043e\u0441\u0442\u0438\u0436\u0435\u043d\u0438\u044f\u043c \u043f\u0440\u0435\u0434\u0448\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u0438\u043a\u043e\u0432. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u0442\u0430\u043a\u0438\u043c \u0436\u0435 \u0432\u0430\u0436\u043d\u044b\u043c \u0441\u0447\u0438\u0442\u0430\u0435\u0442\u0441\u044f \u0441\u0432\u043e\u0431\u043e\u0434\u0430 \u0434\u0435\u043b\u0430\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u043c\r\n        \u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0441\u0430\u043c\u044b\u0435 \u0433\u043b\u0430\u0432\u043d\u044b\u0435 \u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u044f \u043f\u043e\u043b\u044c\u0441\u043a\u043e\u0439 \u0438 \u043c\u0438\u0440\u043e\u0432\u043e\u0439 \u043b\u0438\u0442\u0435\u0440\u0430\u0442\u0443\u0440\u044b. \u0411\u0435\u0437 \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u043e\u0433\u043e \u0434\u043e\u043c\u0435\u043d\u0430 \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u0435 \u0442\u043e\u0433\u043e \u0436\u0435\r\n        \u0432\u0435\u043b\u0438\u043a\u043e\u043b\u0435\u043f\u043d\u043e\u0433\u043e \u0437\u0434\u0430\u043d\u0438\u044f, \u043a\u0430\u043a\u0438\u043c \u0441\u0447\u0438\u0442\u0430\u0435\u0442\u0441\u044f \u043a\u0443\u043b\u044c\u0442\u0443\u0440\u0430, \u044f\u0432\u043b\u044f\u043b\u043e\u0441\u044c \u0431\u044b \u043d\u0435\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u044b\u043c.</p>", 
+            "left_column_fr": "<h2>Lectures libres</h2>\r\n    \r\n        <p>La biblioth\u00e8que en ligne avec lectures scolaires \"Lectures libres\" (www.wolnelektury.pl) est un projet r\u00e9alis\u00e9 par la Fondation Pologne Moderne. Le projet a \u00e9t\u00e9 lanc\u00e9 en 2007. Dans son cadre, nous mettons \u00e0 la disposition du lecteur des lectures scolaires, recommend\u00e9es par le Minist\u00e8re de l'Education nationale, qui se trouvent d\u00e9j\u00e0 dans le domaine public. Elles sont prepar\u00e9es, accompagn\u00e9es d'un commentaire et mises \u00e0 la disposition au plusieurs formats (html, epub, mp3, ogg, odt, txt i pdf). Elles peuvent \u00eatre, tout en accord avec la loi, gratuitement lues, t\u00e9l\u00e9charg\u00e9es \u00e0 votre ordinateur, mises \u00e0 la disposition des autres et cit\u00e9es.</p>\r\n        \r\n         <p>L'\u00e9quipe du projet Lectures libres consiste des \u00e9ditrices et professeures experiment\u00e9es, ce qui garantit la fiabilit\u00e9 de notre portail. Dans sa cr\u00e9ation nous coop\u00e9rons avec la Biblioth\u00e8que nationale, qui nous fournit les meilleures \u00e9ditions et commentaires critiques des lectures scolaires accessibles, publi\u00e9es dans la Biblioteque nationale num\u00e9rique Polona. Ensemble, nous oeuvrons vers que les textes des lectures - notre h\u00e9ritage culturel - soient accessibles \u00e0 tous, o\u00f9 qu'ils vivent, m\u00eame s'ils ont des ressources limit\u00e9es ou  mobilite reduite. C'est possible gr\u00e2ce \u00e0 l'existence du domaine public - collection des oeuvres qui ne sont plus prot\u00e9g\u00e9es par le droit d'auteur, ainsi que gr\u00e2ce aux nouvelles technologies - des outils, qui permettent de multiplier l'accessibilit\u00e9 du mat\u00e9riaux publi\u00e9s dans l'internet.</p>\r\n        \r\n         <p>Le project Lectures libres est enti\u00e8rement non-commercial et r\u00e9alis\u00e9 pro publico bono. C'est pourquoi l' appui des personnages reconnus du monde de la culture et de la science est tellement important pour nous. Le projet est r\u00e9alis\u00e9 sous patronat du Minist\u00e8re de Culture et d'Heritage national, Minist\u00e8re de l'Education nationale et l'Association des \u00e9crivains polonais. Les personnes suivantes ont consent\u00e9es \u00e0 participer \u00e0 notre Comit\u00e9 d'honneur: prof. Maria\r\n        Janion, prof. Gra\u017cyna Borkowska, prof. Przemys\u0142aw\r\n        Czapli\u0144ski, prof. Mieczys\u0142aw D\u0105browski, prof. Ewa Kraskowska, prof. Ma\u0142gorzata Czermi\u0144ska, prof. Jerzy Jarz\u0119bski\r\n        et prof. Piotr \u015aliwi\u0144ski.</p>\r\n\r\n        \r\n         <p>La Biblioth\u00e8que nationale s'occupe de la num\u00e9risation et correcte des textes. Le site internet a \u00e9t\u00e9 mis en place par 2ia. L'auteur du langage de composition des textes sur Lectures libres, bas\u00e9 sur langage XML est Dariusz Ga\u0142ecki. Le service juridique autour de Lectures libres est assur\u00e9 par Kancelaria Grynhoff,\r\n Wo\u017any, Mali\u0144ski. Le hosting du site est assur\u00e9 par la soci\u00e9t\u00e9 EO Networks. La maison d'\u00e9dition Korporacja Ha!Art aide \u00e0 la r\u00e9daction technique des textes. Le logotype des Lectures libres a \u00e9t\u00e9 cr\u00e9\u00e9 par l'agence PZL. Le projet est r\u00e9alis\u00e9 sous le patronat m\u00e9dial de: Dziennik, Elle, Tok.fm, Biblioteka Analiz,\r\n Tygodnik Powszechny, Przekr\u00f3j et TVP Kultura.</p>\r\n        \r\n        <h2>Comment utiliser Lectures libres?</h2>\r\n        \r\n         <p>La plus grande innovation qui distingue ce projet des autres biblioth\u00e8ques en ligne est la possibilit\u00e9 d'ex\u00e9cuter la recherche dans les textes selon de diff\u00e9rents crit\u00e8res: traditionnels, tels que le titre, l'auteur, l'\u00e9poque, type et genre litt\u00e9raire, mais aussi d'autres, qu'on ne rencontre pas ailleurs, c'est \u00e0 dire qui ont r\u00e9f\u00e9rence au contenu des plusieurs oeuvres en m\u00eame temps - des motifs et th\u00e8mes litt\u00e9raires. Une telle recherche est possible gr\u00e2ce \u00e0 la pr\u00e9paration sp\u00e9ciale du texte des lectures scolaires, qui consiste \u00e0 les d\u00e9crire avec les crit\u00e8res \u00e9num\u00e9r\u00e9s. C'est la plus grande diff\u00e9rence entre Lectures libres et plusieurs sites consacr\u00e9s \u00e0 pr\u00e9senter les lectures scolaires - notre site vous fournit des instruments pour travailler cr\u00e9ativement avec le texte, et non pas de pompes toutes pr\u00eates. Par example, si un \u00e9l\u00e8ve obtient un travail maison \"Le motif de l'enfance dans l'\u00e9poque du romantisme, bas\u00e9 sur oeuvres choisies\", en trois clics sur notre site il pourra acc\u00e9der par son ordinateur \u00e0 la liste des textes \u00e0 analyser. C'est gr\u00e2ce au tels instruments que la lecture devient un voyage fascinant dans le monde de culture.</p>\r\n        \r\n         <p>Une autre caract\u00e9ristique de Lectures libres, tr\u00e8s utile dans le travail \u00e0 l'\u00e9cole, est la possiblit\u00e9 de cr\u00e9er toutes les s\u00e9ries des textes analys\u00e9s par example au cours de l'ann\u00e9e par une classe. De telles \u00e9tag\u00e8res sont cr\u00e9\u00e9es par un enseignant/une enseignante, qui peut ensuite envoyer un lien \u00e0 cette collection \u00e0 ses \u00e9l\u00e8ves. Ceux-ci peuvent ensuite t\u00e9l\u00e9charger toute la s\u00e9rie sur leurs oridinateurs avec un seul clic sur le site.</p>\r\n        \r\n        <p>Tous les textes des livres dans le site Lectures libres (au formats html, pdf, epub, txt) sont accessibles hors les restrictions du droit d'auteur et peuvent \u00eatre utilis\u00e9s librement sans aucunes conditions.</p>\r\n\r\n        <p>Si les textes sont accompagn\u00e9s par des mat\u00e9riaux additionnels (annotations, motifs litt\u00e9raires etc.), soumis \u00e0 la droit d'auteur, ces mat\u00e9riaux additionnels sont mis \u00e0 la disposition sous licence Creative Commons Paternite, Partage des conditions initiales \u00e0 l'identique 3.0 PL (<a href=\"http://creativecommons.org/licenses/by-sa/3.0/\">http://creativecommons.org/licenses/by-sa/3.0/</a>).</p>\r\n", 
+            "title": "About Wolne Lektury project", 
+            "title_lt": "Apie projekt\u00b9 Laisvoji Literatura", 
+            "right_column": "<h2>About the foundation</h2>\r\n\r\n        <p>Modern Poland Foundation was established because education of children is a key to the future. One of the most important objectives that Polish education has to approach is a struggle with digital retardation. The skill in using a computer and the Internet is a kind of elemental knowledge in the age of information society. One who does not have it, is condemned to a vegetative existence on the fringes of modern world. </p>\r\n        \r\n         <p>It is the reason why for seven years we have helped (and still do) the children in understanding and using the high technologies. Modern Poland Foundation wants to give a thousands of children what is the most valuable: knowledge and abilities letting them understand modern world and take advantage of its opportunities. </p>\r\n <p>Modern Poland Fundation - apart from Wolne Lektury project - is as well coordinating Wolne Podr\u0119czniki project. It is created by a social movement of voluteering teachers. With the use of the Internet, they are writing new coursebooks for Polish pupils. Wolne Podr\u0119czniki are published openly-licensed (meaning it gives the user certain copyright freedom i.e. the books can be copied, distributed and updated without the necessity of asking the team of authors for permission). Every teacher will be able to supplement, expand and improve the coursebooks in accordance with to their own needs and experience. Thanks to the open source the price of the traditional coursebooks published in printed format will seriously decrease and the access to the electronic coursebooks will be free. </p>\r\n\r\n\r\n\r\n<h2>About the public domain</h2>\r\n        \r\n        <p>On the Wolne Lektury website one can lawfully publish only these books that exist in the public domain, meaning the books  that are not covered by copyrigh law anymore.  Public domain is a kind of a treasure trove of culture, of public goods that everyone can draw from on equal rights, without restrictions and payments. The existence of public domain is a surety of the access to the cultural acheivments, and such an entitlement is our civil and constitutional right. .</p>\r\n <p>Albeit there is a rule that each and every literary work is to enter the public domain some day, the time period of validity of the Polish copyrights was considerably prolonged over the last dozen or so years. Only  in the early 90s the period was to last 25 years since the author's death, later on it was extended to 50 years and today the time period of copyrights' validity amounts 70 years. This means that a lot of literary works listed on departamental  list of obligatory readings will not be published for many years. Not until 2020 shall we be able to publish works of Marek H\u0142asko and Witold Gombrowicz. The novels of Kuncewiczowa will enter the public domain in 2060, and the poems of Mi\u0142osz - in 2075. </p>\r\n <p>The restrictions of copyrights apply as well to editions with critical apparatus and to translations. We will wait for Villon's \"Le grand testament\" and other poems untill January 1, 2012 as they were translated by Boy-\u017bele\u0144ski. Not until 2068 will we publish Milne's \"Winnie-the-Pooh\" and other translations by Irena Tuwim. Moreover, we do not have the right to publish the introductions and prefaces written by authors that died no sooner than 70 years ago.  It is the reason why sometimes a literary work is listed on Wolne Lektury but at the same time it is hyperlinked to a matching title in the Digital National Library Polona, directing the visitor to a website with information that the book is copyrighted. It means that even though the literary text is in the public domain - we listed it on Wolne Lektury - its edition with critical apparatus, DNL Polona property  (containing every introduction, preface and editorial comment) is still covered by the copyright law. </p>\r\n <p> The public domain should be looked after and protected. Culture is a fine edifice and the consecutive floors can be erected only when the base is built solidly by the predecessors. Kochanowski drew extensively on the classical literary tradition.  Mickiewicz used the folk works to create the most beautiful Polish poems. Every next generation can plan far into the future, develop their own literary language and permanently become part of the history of literature due to the achievments of their predecessors.   That is why the freedom of using and making available the most important works of Polish and world literature is so essential. Without the public domain it would be impossible to erect such a tremendous edifice of culture as it is. </p>", 
+            "right_column_es": "<h2>Sobre la Fundaci\u00f3n</h2>\r\n\r\n\r\n\r\n        <p>La Fundaci\u00f3n Polonia Moderna fue inventada con el fin de educar a los ni\u00f1os, asunto clave para el futuro de Polonia. Una de las tareas m\u00e1s importantes que la educaci\u00f3n polaca tiene que enfrentar es la lucha contra la exclusi\u00f3n virtual. La habilidad de usar el ordenador e internet en los tiempos de la sociedad de la informaci\u00f3n es una habilidad fundamental. Los que no la posean van a ser olvidados al margen del mundo moderno. </p>\r\n\r\n        \r\n\r\n         <p>Por lo tanto, desde hace siete a\u00f1os ayudamos a los ni\u00f1os a entender y usar las tecnolog\u00edas avanzadas. La Fundaci\u00f3n Polonia Moderna quiere dar a miles de ni\u00f1os lo m\u00e1s importante: el conocimiento y las habilidades que permiten a entender el mundo contempor\u00e1neo y hacer un buen uso de las posibilidades que nos ofrece. </p>\r\n\r\n        \r\n\r\n         <p>La fundaci\u00f3n Polonia Moderna, adem\u00e1s del proyecto Wolne Lektury, est\u00e1 coordinando el proyecto Wolne Podr\u0119czniki, creado por un movimiento social de profesofes-voluntarios quienes, usando internet, escriben nuevos manuales para los estudiantes. Wolne Podr\u0119czniki se publican bajo licencia libre, es decir, que se los puede copiar, diseminar y actualizar sin pedir permiso a los autores. Cada uno de los profesores los podr\u00e1 completar, ampliar i corregir seg\u00fan su propia experiencia y necesidades. Gracias a la licencia libre se puede reducir los precios de los manuales editados de forma tradicional en papel y proporcionar los manuales electr\u00f3nicos gratuitamente. </p>\r\n\r\n\r\n\r\n        \r\n\r\n        <h2>Sobre el dominio p\u00fablico</h2>\r\n\r\n        \r\n\r\n        <p>En la p\u00e1gina Wolne Lektury podemos publicar legalmente s\u00f3lo los libros que pertenecen al dominio p\u00fablico, es decir, estos que no est\u00e1n cubiertos por el derecho de autor. El dominio p\u00fablico es como un tesoro de la cultura, un bien com\u00fan del que todos pueden disfrutar con igualdad, sin restricciones y pagos. La existencia del dominio p\u00fablico garantiza el acceso a los bienes culturales que es nuestro derecho consagrado en la Constutuci\u00f3n. </p>\r\n\r\n                 <p> Seg\u00fan la regla general todas las obras, despu\u00e9s de un tiempo determinado, se incorporan al dominio p\u00fablico. Sin embargo, en Polonia el plazo de protecci\u00f3n del derecho de autor se ha extendido considerablemente en los \u00faltimos a\u00f1os. En los principios de los a\u00f1os 90 eran 25 a\u00f1os tras la muerte del autor, despu\u00e9s este periodo de tiempo se extendi\u00f3 hasta 50 a\u00f1os y hoy son 70 a\u00f1os. Esto significa que no podremos proporcionar muchas lecturas durante mucho tiempo. Las obras de Marek H\u0142asko o Witold Gombrowicz no las podremos publicar hasta el a\u00f1o 2020. Las novelas de Kuncewiczowa entrar\u00e1n en el dominio p\u00fablico en el a\u00f1o 2060 y los poemas de Mi\u0142osz en 2075. </p>\r\n\r\n        \r\n\r\n         <p> Las limitaciones del derecho de autor cubren tambi\u00e9n las ediciones cr\u00edticas y traducciones. Tenemos que esperar hasta el 1 de enero de 2012 para el \u201cGran Testamento\u201d de Villon y otras obras traducidas por Boy-\u017bele\u0144ski y hasta el a\u00f1o 2068 para \u201cWinnie the Pooh\u201d de Milne y otras traducciones de Irena Tuwim. Tampoco tenemos derecho para publicar introducciones o pr\u00f3logos escritos por autores que murieron hace menos de 70 a\u00f1os. Por eso puede ocurrir que una lectura se encontar\u00e1 en Wolne Lektury pero el enlace correspondiente en la electr\u00f3nica Biblioteca Nacional Polona nos lleva a otra p\u00e1gina informando que esta obra est\u00e1 cubierta por el derecho de autor. Esto significa que aunque el texto propiamente dicho sea del dominio p\u00fablico, y por eso lo publicamos en Wolne Lektury, su edici\u00f3n cr\u00edtica (con todos inicios, pr\u00f3logos y comentarios) todav\u00eda est\u00e1 cubierto por el derecho de autor. </p>        \r\n\r\n         <p>Se debe cuidar y proteger al dominio p\u00fablico. La cultura es un edificio sofisticado en \u00e9l que las plantas siguientes pueden ser construidas s\u00f3lo sobre bases s\u00f3lidas. Kochanowski se inspiraba directamente en la tradici\u00f3n cl\u00e1sica. Mickiewicz us\u00f3 la tradici\u00f3n del pueblo para escribir los mejores poemas en polaco. Cada siguiente generaci\u00f3n, gracias a los logros de sus antecedentes, puede ver m\u00e1s lejos, crear su propio lenguaje literario e inscribirse para siempre en la historia de la literatura. As\u00ed que es muy importante publicar libremente las obras m\u00e1s grandes tanto de la literatura polaca como la mundial. Sin el dominio p\u00fablico la construcci\u00f3n del maravilloso edificio de la cultura ser\u00eda imposible. </p>", 
+            "right_column_en": "<h2>About the foundation</h2>\r\n\r\n        <p>Modern Poland Foundation was established because education of children is a key to the future. One of the most important objectives that Polish education has to approach is a struggle with digital retardation. The skill in using a computer and the Internet is a kind of elemental knowledge in the age of information society. One who does not have it, is condemned to a vegetative existence on the fringes of modern world. </p>\r\n        \r\n         <p>It is the reason why for seven years we have helped (and still do) the children in understanding and using the high technologies. Modern Poland Foundation wants to give a thousands of children what is the most valuable: knowledge and abilities letting them understand modern world and take advantage of its opportunities. </p>\r\n <p>Modern Poland Fundation - apart from Wolne Lektury project - is as well coordinating Wolne Podr\u0119czniki project. It is created by a social movement of voluteering teachers. With the use of the Internet, they are writing new coursebooks for Polish pupils. Wolne Podr\u0119czniki are published openly-licensed (meaning it gives the user certain copyright freedom i.e. the books can be copied, distributed and updated without the necessity of asking the team of authors for permission). Every teacher will be able to supplement, expand and improve the coursebooks in accordance with to their own needs and experience. Thanks to the open source the price of the traditional coursebooks published in printed format will seriously decrease and the access to the electronic coursebooks will be free. </p>\r\n\r\n\r\n\r\n<h2>About the public domain</h2>\r\n        \r\n        <p>On the Wolne Lektury website one can lawfully publish only these books that exist in the public domain, meaning the books  that are not covered by copyrigh law anymore.  Public domain is a kind of a treasure trove of culture, of public goods that everyone can draw from on equal rights, without restrictions and payments. The existence of public domain is a surety of the access to the cultural acheivments, and such an entitlement is our civil and constitutional right. .</p>\r\n <p>Albeit there is a rule that each and every literary work is to enter the public domain some day, the time period of validity of the Polish copyrights was considerably prolonged over the last dozen or so years. Only  in the early 90s the period was to last 25 years since the author's death, later on it was extended to 50 years and today the time period of copyrights' validity amounts 70 years. This means that a lot of literary works listed on departamental  list of obligatory readings will not be published for many years. Not until 2020 shall we be able to publish works of Marek H\u0142asko and Witold Gombrowicz. The novels of Kuncewiczowa will enter the public domain in 2060, and the poems of Mi\u0142osz - in 2075. </p>\r\n <p>The restrictions of copyrights apply as well to editions with critical apparatus and to translations. We will wait for Villon's \"Le grand testament\" and other poems untill January 1, 2012 as they were translated by Boy-\u017bele\u0144ski. Not until 2068 will we publish Milne's \"Winnie-the-Pooh\" and other translations by Irena Tuwim. Moreover, we do not have the right to publish the introductions and prefaces written by authors that died no sooner than 70 years ago.  It is the reason why sometimes a literary work is listed on Wolne Lektury but at the same time it is hyperlinked to a matching title in the Digital National Library Polona, directing the visitor to a website with information that the book is copyrighted. It means that even though the literary text is in the public domain - we listed it on Wolne Lektury - its edition with critical apparatus, DNL Polona property  (containing every introduction, preface and editorial comment) is still covered by the copyright law. </p>\r\n <p> The public domain should be looked after and protected. Culture is a fine edifice and the consecutive floors can be erected only when the base is built solidly by the predecessors. Kochanowski drew extensively on the classical literary tradition.  Mickiewicz used the folk works to create the most beautiful Polish poems. Every next generation can plan far into the future, develop their own literary language and permanently become part of the history of literature due to the achievments of their predecessors.   That is why the freedom of using and making available the most important works of Polish and world literature is so essential. Without the public domain it would be impossible to erect such a tremendous edifice of culture as it is. </p>", 
+            "left_column_de": "\ufeff<h2>Freie Lekt\u00fcren</h2>\r\n    \r\n        <p>Internetbibliothek mit Schullekt\u00fcren \u201eFreie Lekt\u00fcren\u201d (www.wolnelektury.pl) ist ein Projekt, \r\n        das von der Stiftung Modernes Polen gef\u00f6rdert wird. Die Stiftung ist seit 2007 t\u00e4tig und hat bisher \r\n        viele Schullekt\u00fcren aus dem Bibliothekbestand zur \u00f6ffentlichen Nutzung freigestellt. Die gemeinfreien \r\n        Schullekt\u00fcren werden ausdr\u00fccklich vom Bildungsministerium empfohlen. Die B\u00fccher wurden bearbeitet, \r\n        mit Kommentaren versehen und sind in HTML-, EPUB-, MP3-, OGG-, ODT-, TXT- und PDF- Formaten zug\u00e4nglich. Inhalte \r\n        aus den B\u00fcchern d\u00fcrfen frei genutzt, gespeichert, zitiert und an Dritte (Freunde, Bekannte) weitergegeben werden.</p>\r\n        \r\n         <p>In der Projektgruppe Freie Lekt\u00fcren arbeiten erfahrene Redakteure und Lehrerinnen, die eine \r\n         professionelle Arbeit an der Mitgestaltung unseres Portals leisten. Hierbei arbeiten wir ganz \r\n         eng mit der Nationalbibliothek zusammen, die uns mit besten Buchausgaben und kritischen \r\n         Schulbuchanalysen beliefert, die bereits in Digitaler Nationalbibliothek Polona ver\u00f6ffentlicht wurden. \r\n         Wir sind stets bem\u00fcht, die Inhalte aus den Lekt\u00fcren - unsere Kulturerbe - f\u00fcr alle zug\u00e4nglich \r\n         zu machen und zwar unabh\u00e4ngig vom Wohnort und sozialer oder finanzieller Lage. Dies ist nur dank \r\n         dem Bestehen der Publik Domain \u2013 d.h. die hier ver\u00f6ffentlichten Werkbest\u00e4nde unterliegen \r\n         keinem Uhrheberrecht mehr-  und dank modernen Technologien m\u00f6glich, die den Zugang zu freien Medien wesentlich erleichtert haben. .</p>\r\n \r\n      \r\n         <p>Das Projekt Freie Lekt\u00fcren hat keinen kommerziellen Hintergrund und ist ein \"pro Bono publico\" Projekt \r\n         (zum Wohle der \u00d6ffentlichkeit). Die Unterst\u00fctzung von prominenten Pers\u00f6nlichkeiten aus dem Kultur- \r\n         und Wissenschaftsbereich ist uns sehr wichtig. Die Ehrenschirmherrschaft f\u00fcr das Projekt Freie Lekt\u00fcren \r\n         haben Ministerium f\u00fcr Kultur und Nationales Erbe, Ministerium f\u00fcr Bildung und der Polnische \r\n         Schriftstellerverband \u00fcbernommen. Ihre Mitgliedschaft im Ehrenkomitee Freie Lekt\u00fcren haben zugesagt:  prof. Maria\r\n         Janion, prof. Gra\u017cyna Borkowska, prof. Przemys\u0142aw Czapli\u0144ski, prof. Mieczys\u0142aw D\u0105browski, prof. Ewa Kraskowska, \r\n         prof. Ma\u0142gorzata Czermi\u0144ska, prof. Jerzy Jarz\u0119bski und prof. Piotr \u015aliwi\u0144ski.</p>\r\n\r\n\r\n         <p>Digitalisierung von Texten und Korrekturarbeiten leistet Nationalbibliothek. Die Webseite wurde von 2ia entworfen. \r\n         Dariusz Ga\u0142ecki ist f\u00fcr die Umsetzung von Inhalten und Struktur in HTML verantwortlich. Rechtliche Dienste \r\n         leistet Rechtskanzlei Grynhoff, Wo\u017any, Mali\u0144ski. F\u00fcr Webhosting ist Firma EO Networks zust\u00e4ndig. Der Verlag Ha!Art Korporation  \r\n         unterst\u00fctzt uns im Bereich der technischen Textverarbeitung. Das Logo der Freien Lekt\u00fcren wurde von PZL Agentur entworfen. \r\n         Mediale Schirmherrschaft \u00fcbernahmen: Dziennik, Elle, Tok.fm, Biblioteka Analiz, Tygodnik Powszechny, Przekr\u00f3j i TVP Kultura.</p>\r\n        \r\n        \r\n        \r\n        <h2>So nutzen Sie den Freie Lekt\u00fcren Service</h2>\r\n        \r\n         <p>Die wichtigste Innovation der Freien Lekt\u00fcren, die dieses Projekt von anderen Internetbibliotheken \r\n         so unterscheidet, ist die fortgeschrittene Suchfunktion, die die Suche nach unterschiedlichen Kriterien zul\u00e4sst. \r\n         Zum einen kann die Literaturrecherche nach traditionellen Suchkriterien wie Titel, Autor, Epoche, Art, \r\n         Gattung durchgef\u00fchrt werden, zum anderen l\u00e4sst sich das gesamte Archiv auf  literarische Motive und Themen durchsuchen. \r\n         Solche Suchdienste sind nur dank spezieller Textbearbeitung von Schullekt\u00fcren m\u00f6glich, die genau an erw\u00e4hnte Suchkriterien \r\n         angepasst wurden. Genau an dieser Stelle liegt der Unterschied unseres Services zu anderen Internetbibliotheken, \r\n         die Schullekt\u00fcren anbieten - wir stellen kreative Arbeitswerkzeuge f\u00fcr die Textverarbeitung bereit und keine blo\u00dfe Spickzettel. \r\n         Wenn z.B. ein Sch\u00fcller eine Hausaufgabe zum Thema \" Kindermotiv in der Epoche der Romantik in ausgew\u00e4hlten Werken\" bekommt, \r\n         so braucht er nur dreimal unsere Seite anzuklicken und schon kommt auf seinem Bildschirm eine zur Analyse vorbereitete Textsammlung.\r\n         So wird das B\u00fccherlesen zu der faszinierenden und bezaubernden Reise in der Kulturwelt.</p>\r\n        \r\n        \r\n       \r\n        \r\n        \r\n         \r\n         <p>Eine andere innovative Funktion, die unser Service Freie Lekt\u00fcren zur Verf\u00fcgung stellt und die in der Schularbeit \r\n         sehr n\u00fctzlich sein kann, ist die Sortierfunktion ganzer Textsammlungen, die z.B. j\u00e4hrlich von eine Schulgruppe \r\n         zu bearbeiten sind. Solche virtuelle Regale f\u00fcr Schullekt\u00fcren werden von der Lehrerin erstellt, die dann den link \r\n         mit ausgesuchten Textsammlungen an Sch\u00fcler versenden kann. Der Datensatz kann dann mit nur einem Klick heruntergeladen werden.</p>\r\n        \r\n        <p>Alle B\u00fccher in HTML, PDF, EPUB und TXT-Formaten, die sich auf dem Portal Freien Lekt\u00fcren befinden, sind frei zug\u00e4nglich und unterliegen keinem Urheberrecht.</p>\r\n\r\n\r\n\r\n        <p>Texte mit Zusatzmaterialien (Anmerkungen, literarische Motive u.a.), die urheberrechtlich gesch\u00fctzt sind, \r\n        werden unter der Lizenz Creative Commons (Anerkennung der Urheberschaft) unter gleichen Bedingungen \r\n        zur Verf\u00fcgung gestellt 3.0 PL (<a href=\"http://creativecommons.org/licenses/by-sa/3.0/\">http://creativecommons.org/licenses/by-sa/3.0/</a>).</p>\r\n", 
+            "title_uk": "\u041f\u0440\u043e \u043f\u0440\u043e\u0435\u043a\u0442 Wolne Lektury", 
+            "right_column_fr": "<h2>En savoir plus sur la Fondation</h2>\r\n\r\n        <p>La Fondation Pologne Moderne a \u00e9t\u00e9 cr\u00e9\u00e9e pour aider \u00e0 instruire les enfants, ce qui est indispensable pour l'avenir de Pologne. Un de plus grands d\u00e9fis devant l'\u00e9ducation polonaise est la lutte contre l'exclusion num\u00e9rique. Savoir utiliser l'ordinateur et l'internet est une comp\u00e9tence \u00e9l\u00e9mentaire dans la soci\u00e9t\u00e9 de l'information.  Ceux qui la manquent sont condamn\u00e9s \u00e0 vivre \u00e0 la marge du monde contemporain. </p>\r\n        \r\n         <p>C'est pourquoi, depuis sept ann\u00e9es, nous aidons les enfants \u00e0 comprendre et utiliser les TICE. La Fondation Pologne Moderne veut donner aux miliers des enfants ce qui est le plus pr\u00e9cieux: le savoir et les comp\u00e9tences qui permettent de comprendre le monde contemporain et de profiter des possibilit\u00e9s qui'il offre.</p>\r\n        \r\n         <p>La Fondation Pologne Moderne - hors du projet Lectures libres - coordone aussi le projet Manuels libres (Wolne Podr\u0119czniki),\r\n qui est un mouvement volontaire des enseignants, qui en utilisant l'internet, cr\u00e9ent de nouveaux manuels pour des \u00e9l\u00e8ves polonais. Manuels libres sont aussi publi\u00e9s sous licence libre - qui permet \u00e0 chacun de les copier, transmettre et actualiser gratuitement, sans \u00eatre oblig\u00e9 de demander la permission de l'\u00e9quipe des auteurs. Chaque enseignant pourra compl\u00e9ter, d\u00e9velopper et am\u00e9liorer ces manuels selon ses besoins et exp\u00e9rience. Gr\u00e2ce aux licences libres nous pouvons dramatiquement diminuer les prix des manuels publi\u00e9s au forme traditionnelle des livres imprim\u00e9s sur papier, et les manuels \u00e9lectroniques seront accessibles gratuitement.</p>\r\n\r\n        \r\n        <h2>Sur le domaine public</h2>\r\n        \r\n        <p>Sur le site Lectures libres, pour \u00eatre en accord avec la loi, nous ne pouvons publier que les livres qui sont dans le domaine public, c'est-\u00e0-dire ceux qui ne sont plus prot\u00e9g\u00e9s par le droit d'auteur. Le domaine public est un sorte de tr\u00e9sor de culture, dont tous peuvent profiter \u00e9galement, sans restrictions et paiements. L'existence du domaine public garantit notre acc\u00e8s au biens de la culture, qui est notre droit civique, inscrite dans la constitution.</p>\r\n        \r\n         <p> Bien qu'en principe avec le temps toutes les oeuvres entreront dans le domaine public, le terme de protection du droit d'auteur a \u00e9t\u00e9 prolong\u00e9 ces derni\u00e8res ann\u00e9es. Au d\u00e9but des ann\u00e9es 90, c'\u00e9tait 25 ans apr\u00e8s la mort de l'auteur, la p\u00e9riode prolong\u00e9e ensuite jusqu'\u00e0 50 ans, et aujourd'hui d\u00e9j\u00e0 70 ans. Cela veut dire que beaucoup des oeuvres inscrites surla liste minist\u00e9rielle de lectures scolaires ne seront mises \u00e0 la disposition du lecteur encore pendent une tr\u00e8s longue p\u00e9riode. Ce ne sera qu'en 2020 qu'on pourra publier les oeuvres de Marek H\u0142asko et Witold Gombrowicz. Les romans de Kuncewiczowa entreront dans le domaine public en 2060, et les po\u00e8mes de Mi\u0142osz en 2075.</p>\r\n        \r\n         <p>Les restrictions du droit d'auteur s'appliquent aussi aux publications critiques et traductions. Il nous faudra attendre jusqu'au 1er janvier 2012  pour \"Le Testament\" de Fran\u00e7ois Villon et autres oeuvres traduites par Boy-\u017bele\u0144ski, et jusqu'a 2068 pour \r\n        \u201eWinnie l'ourson\u201d de Milne et autres traductions d'Irena Tuwim. Nous ne pouvons non plus publier les introductions et avant propos \u00e9crits par auteurs qui sont morts moins de 70 ans avant. C'est pourquoi il arrive qu'une oeuvre se trouve sur Lectures libres, mais le lien \u00e0 la position dans la Biblioteque nationale num\u00e9rique Polona vous renvoie au page qui dit que l'oeuvre est prot\u00e9g\u00e9e par le droit d'auteur. Cela veut dire que m\u00eame si le texte lui-m\u00eame est dans le domaine public et peut \u00eatre publi\u00e9 sur Lectures libres, son \u00e9dition critique, dans la disposition de la Biblioteqhe num\u00e9rique (avec des introductions, avant propos et commentaires des \u00e9diteurs) est toujours prot\u00e9g\u00e9e par le droit d'auteur.</p>\r\n        \r\n         <p>Il faut s'occuper bien du domaine public et le prot\u00e9ger. La culture est un grand b\u00e2timent, o\u00f9 les \u00e9tages successives peuvent \u00eatre ajout\u00e9es seulement sur une base solide pr\u00e9par\u00e9e par nos pr\u00e9d\u00e9cesseurs. Kochanowski s'inspirait directement de la tradition antique. Mickiewicz a utilis\u00e9 le folklore pour cr\u00e9er de plus beaux po\u00e8mes polonais. Chaque g\u00e9n\u00e9ration peut voir plus loin, cr\u00e9er sa propre langue litt\u00e9raire et s'inscrire dans l'histoire de la litt\u00e9rature seulement gr\u00e2ce aux accomplissements de ses pr\u00e9d\u00e9cesseurs. C'est pourquoi la libert\u00e9 de rendre accessible et utiliser les chefs-d'oeuvre de la litt\u00e9rature polonaise et mondiale est si importante. Sans le domaine public, il serait impossible de construire ce b\u00e2timent magnifique qu'est la culture.</p>\r\n", 
+            "left_column": "<h2>Wolne Lektury</h2>\r\n    \r\n        <p>Web library with the school obligatory readings \"Wolne Lektury\" (www.wolnelektury.pl) is a project carried out by Modern Poland Foundation. Wolne Lektury website works since 2007. It provides the visitors with the school readings recommended Ministerstwo Edukacji Narodowej which entered the public domain.  The literary works are drawn up, annotated and available in several formats (html, epub, mp3, ogg, odt, txt and pdf). Under the Polish law, they can be read online, downloaded, cited and shared.</p>\r\n <p>Wolne Lektury project team comprises experienced editors and teachers so that our website content is solid and reliable. To create it, we cooperate with National Library which provides us with the best available editions of the books as well as the critical studies of the school readings, published in Digital National Library Polona. Together we try our best to make the texts of the books (our cultural legacy) available for everyone, regardless of where one is living, how much money does one have or whether one is handicapped or not. It is possible only due to the public domain concept, meaning a collection of literary works that are not copyrighted, as well as high technologies - tools that let us increase availability of the text published on the Internet.</p>\r\n  <p>Wolne Lektury project is completely uncommercial and it is carried out pro publico bono. Therefore the support of the eminent personages conncted with culture and sciences is very important for us. Wolne Lektury project is held under the honorary patronage of Ministerstwo Kultury i Dziedzictwa Narodowego, Ministerstwo Edukacji Narodowej and Polish Writers Association. In the Honorary Comitee of Wolne Lektury agreed to sit Professor Maria\r\n Janion, Professor Gra\u017cyna Borkowska, Professor Przemys\u0142aw\r\n Czapli\u0144ski, Professor Mieczys\u0142aw D\u0105browski, Professor Ewa Kraskowska, Professor Ma\u0142gorzata Czermi\u0144ska, Professor Jerzy Jarz\u0119bski\r\n  and Professor Piotr \u015aliwi\u0144ski.</p>\r\n\r\n <p>Digitalisation and proofreading is provided by the National Library. The website was designed by 2ia. The author of the programming language of the repository of Free Literature texts, based on the XML language is Dariusz Ga\u0142ecki. Grynhoff, Wo\u017any, Mali\u0144ski office provides us with the legal service. Web hosting is provided by EO Networks company. Publishing house Korporacja Ha!Art helps us in proofreading. The logo of Wolne Lektury is a creation of PZL agency.  The project is held under media patronage of: Dziennik, Elle, Tok.fm, Biblioteka Analiz,\r\n Tygodnik Powszechny, Przekr\u00f3j and TVP Kultura.</p>\r\n        \r\n    \r\n\r\n\r\n\r\n\r\n\r\n<h2>How should I use Wolne Lektury?</h2> <p>The most imporant innovation of Wolne Lektury that distinguishes this project from the others is the possibility of searching for the texts with the application of variety of criteria: traditional ones, such as the title, author, period, form and genre, as well as unusual ones, concerning many literary works at once, i.e. literary motifs and themes. This kind of serch is faesible due to special preparation of the books as they are now described with the parameters mentioned above. It is the element that differs Wolne Lektury  from the other editions of school readings. Wolne Lektury webiste provides the reader with devices that come in handy in when creative thinking is needed  whereas some editions of the readings are simply cribs. For instance, if a student is asked to prepare an essay on topic \"The child in Romantic literature\", when searching our website, he only must mouse-click three times to find a collection of necessary texts.  Due to this kind of tools reading books changes into fascinatng journey into the world of culture.</p>\r\n <p>Another useful function of Wolne Lektury that comes in handy when at home or at school is the possibility of combining the texts that are discussed during the school year into a list. The lists are called bookshelves and they are created by a teacher. Next the teacher may send the adequate hyperlink to his pupils and they can download the complete set of readings with one mouse click.</p>\r\n  <p>Every literary work available on Wolne Lektury website (in html, pdf, epub, txt formats) is not covered by copyright law and can be freely used with no legal consequences. </p>\r\n\r\n        <p>If the texts are provided with some extra materials (annotations, motifs) which are copyrighted, then the extras are accesible under Creative Commons Attribution - Share Alike 3.0 PL licence(<a href=\"http://creativecommons.org/licenses/by-sa/3.0/\">http://creativecommons.org/licenses/by-sa/3.0/</a>).</p>", 
+            "right_column_uk": "<h2>\u041f\u0440\u043e \u0424\u043e\u043d\u0434</h2>\r\n\r\n <p>\u0424\u043e\u043d\u0434 \u041c\u043e\u0434\u0435\u0440\u043d\u0430 \u041f\u043e\u043b\u044c\u0449\u0430 \u0431\u0443\u0432 \u0441\u0442\u0432\u043e\u0440\u0435\u043d\u0438\u0439, \u0442\u043e\u043c\u0443 \u0449\u043e \u043e\u0441\u0432\u0456\u0442\u0430 \u0434\u0456\u0442\u0435\u0439 \u0454 \u043a\u043b\u044e\u0447\u0435\u043c \u0434\u043e \u043c\u0430\u0439\u0431\u0443\u0442\u043d\u044c\u043e\u0433\u043e \u041f\u043e\u043b\u044c\u0449\u0456. \u041e\u0434\u043d\u0438\u043c \u0437 \u043d\u0430\u0439\u0432\u0430\u0436\u043b\u0438\u0432\u0456\u0448\u0438\u0445 \u0437\u0430\u0432\u0434\u0430\u043d\u044c, \u044f\u043a\u0456 \u0441\u0442\u043e\u044f\u0442\u044c \u043f\u0435\u0440\u0435\u0434 \u043f\u043e\u043b\u044c\u0441\u044c\u043a\u043e\u044e \u043e\u0441\u0432\u0456\u0442\u043e\u044e \u0454 \u0431\u043e\u0440\u043e\u0442\u044c\u0431\u0430 \u0437 \u0446\u0438\u0444\u0440\u043e\u0432\u0438\u043c \u0432\u0438\u043a\u043b\u044e\u0447\u0435\u043d\u043d\u044f\u043c. \u0412\u043c\u0456\u043d\u043d\u044f \u043a\u043e\u0440\u0438\u0441\u0442\u0443\u0432\u0430\u0442\u0438\u0441\u044f \u043a\u043e\u043c\u043f\u2019\u044e\u0442\u0435\u0440\u043e\u043c \u0442\u0430 \u0456\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u043e\u043c \u0432 \u0447\u0430\u0441\u0430\u0445 \u0456\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0456\u0439\u043d\u043e\u0433\u043e \u0441\u0443\u0441\u043f\u0456\u043b\u044c\u0441\u0442\u0432\u0430 \u0454 \u0441\u0432\u043e\u0433\u043e \u0440\u043e\u0434\u0443 \u0431\u0443\u043a\u0432\u0430\u0440\u0435\u043c. \u0426\u0456, \u044f\u043a\u0456 \u0439\u043e\u0433\u043e \u043d\u0435 \u0437\u043d\u0430\u044e\u0442\u044c, \u043f\u0440\u0438\u0440\u0435\u0447\u0435\u043d\u0456 \u043d\u0430 \u0432\u0435\u0433\u0435\u0442\u0430\u0446\u0456\u044e \u043d\u0430 \u043e\u0431\u0440\u0456\u044f\u0445 \u0441\u0443\u0447\u0430\u0441\u043d\u043e\u0433\u043e \u0441\u0432\u0456\u0442\u0443. </p>\r\n \r\n <p>\u0421\u0430\u043c\u0435 \u0442\u043e\u043c\u0443 \u0432\u0436\u0435 7 \u0440\u043e\u043a\u0456\u0432 \u043f\u043e\u043c\u0430\u0433\u0430\u0454\u043c\u043e \u0434\u0456\u0442\u044f\u043c \u0440\u043e\u0437\u0443\u043c\u0456\u0442\u0438 \u0456 \u0432\u0438\u043a\u043e\u0440\u0438\u0441\u0442\u043e\u0432\u0443\u0432\u0430\u0442\u0438 \u043f\u0440\u043e\u0441\u0443\u043d\u0443\u0442\u0456 \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0456\u0457. \u0424\u043e\u043d\u0434 \u041c\u043e\u0434\u0435\u0440\u043d\u0430 \u041f\u043e\u043b\u044c\u0449\u0430 \u0445\u043e\u0447\u0435 \u0437\u0430\u0431\u0435\u0437\u043f\u0435\u0447\u0438\u0442\u0438 \u0442\u0438\u0441\u044f\u0447\u0456 \u0434\u0456\u0442\u0435\u0439 \u0442\u0438\u043c, \u0449\u043e \u043d\u0430\u0439\u0432\u0430\u0436\u043b\u0438\u0432\u0456\u0448\u0435: \u0437\u043d\u0430\u043d\u043d\u044f\u043c \u0442\u0430 \u043d\u0430\u0432\u0438\u0447\u043a\u0430\u043c\u0438, \u044f\u043a\u0456 \u0434\u043e\u043f\u043e\u043c\u0430\u0433\u0430\u044e\u0442\u044c \u0440\u043e\u0437\u0443\u043c\u0456\u0442\u0438 \u0441\u0443\u0447\u0430\u0441\u043d\u0438\u0439 \u0441\u0432\u0456\u0442 \u0442\u0430 \u043a\u043e\u0440\u0438\u0441\u0443\u0432\u0430\u0442\u0438\u0441\u044f \u043c\u043e\u0436\u043b\u0438\u0432\u043e\u0441\u0442\u044f\u043c\u0438, \u044f\u043a\u0456 \u0432\u0456\u043d \u043f\u0440\u043e\u043f\u043e\u043d\u0443\u0454.</p>\r\n \r\n <p> \u0424\u043e\u043d\u0434 \u041c\u043e\u0434\u0435\u0440\u043d\u0430 \u041f\u043e\u043b\u044c\u0449\u0430 \u2013 \u043f\u043e\u0437\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u043c Wolne Lektury \u2013 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0443\u0454 \u0442\u0430\u043a\u043e\u0436 \u043f\u0440\u043e\u0435\u043a\u0442 Wolne Podr\u0119czniki (\u0412\u0456\u043b\u044c\u043d\u0456 \u043f\u0456\u0434\u0440\u0443\u0447\u043d\u0438\u043a\u0438), \u0441\u0442\u0432\u043e\u0440\u0435\u043d\u0438\u0439 \u0433\u0440\u043e\u043c\u0430\u0434\u0441\u044c\u043a\u0438\u043c \u0440\u0443\u0445\u043e\u043c \u0432\u0447\u0438\u0442\u0435\u043b\u0456\u0432-\u0432\u043e\u043b\u043e\u043d\u0442\u0435\u0440\u0456\u0432, \u044f\u043a\u0456 \u043f\u0440\u0438 \u0432\u0438\u043a\u043e\u0440\u0438\u0441\u0442\u0430\u043d\u043d\u0456 \u0456\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0443 \u043f\u0438\u0448\u0443\u0442\u044c \u043d\u043e\u0432\u0456 \u043f\u0456\u0434\u0440\u0443\u0447\u043d\u0438\u043a\u0438 \u0434\u043b\u044f \u043f\u043e\u043b\u044c\u0441\u044c\u043a\u0438\u0445 \u0443\u0447\u043d\u0456\u0432. Wolne Podr\u0119czniki \u043f\u0443\u0431\u043b\u0456\u043a\u0443\u044e\u0442\u044c\u0441\u044f \u043d\u0430 \u0432\u0456\u043b\u044c\u043d\u0438\u0445 \u043b\u0456\u0446\u0435\u043d\u0437\u0456\u044f\u0445, \u0442\u043e\u0431\u0442\u043e \u0442\u0430\u043a\u0438\u0445, \u044f\u043a\u0456 \u0434\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0442\u044c \u043a\u043e\u0436\u043d\u043e\u043c\u0443 \u0431\u0435\u0437\u043f\u043b\u0430\u0442\u043d\u043e \u043a\u043e\u043f\u0456\u044e\u0432\u0430\u0442\u0438, \u0440\u043e\u0437\u043f\u043e\u0432\u0441\u044e\u0434\u0436\u0443\u0432\u0430\u0442\u0438 \u0442\u0430 \u0430\u043a\u0442\u0443\u0430\u043b\u0456\u0437\u0443\u0432\u0430\u0442\u0438 \u0457\u0445, \u0431\u0435\u0437 \u043d\u0435\u043e\u0431\u0445\u0456\u0434\u043d\u043e\u0441\u0442\u0456 \u043f\u0440\u043e\u0441\u0438\u0442\u0438 \u0434\u043e\u0437\u0432\u043e\u043b\u0443 \u0432 \u0430\u0432\u0442\u043e\u0440\u0456\u0432. \u041a\u043e\u0436\u0435\u043d \u0432\u0447\u0438\u0442\u0435\u043b\u044c \u0437\u043c\u043e\u0436\u0435 \u0434\u043e\u043f\u043e\u0432\u043d\u044e\u0432\u0430\u0442\u0438, \u0440\u043e\u0437\u0432\u0438\u0432\u0430\u0442\u0438 \u0456 \u0432\u0438\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u0438 \u0446\u0456 \u043f\u0456\u0434\u0440\u0443\u0447\u043d\u0438\u043a\u0438 \u0432\u0456\u0434\u043f\u043e\u0432\u0456\u0434\u043d\u043e \u0434\u043e \u0441\u0432\u043e\u0457\u0445 \u043f\u043e\u0442\u0440\u0435\u0431 \u0442\u0430 \u0434\u043e\u0441\u0432\u0456\u0434\u0443. \u0417\u0430\u0432\u0434\u044f\u043a\u0438 \u0432\u0456\u043b\u044c\u043d\u0438\u043c \u043b\u0456\u0446\u0435\u043d\u0437\u0456\u044f\u043c \u043c\u043e\u0436\u043d\u0430 \u0437\u043d\u0430\u0447\u043d\u043e \u0437\u043c\u0435\u043d\u0448\u0438\u0442\u0438 \u0446\u0456\u043d\u0443 \u043f\u0456\u0434\u0440\u0443\u0447\u043d\u0438\u043a\u0456\u0432, \u044f\u043a\u0456 \u0432\u0438\u0434\u0430\u044e\u0442\u044c\u0441\u044f \u0443 \u0442\u0440\u0430\u0434\u0438\u0446\u0456\u0439\u043d\u043e\u043c\u0443 \u0432\u0438\u0433\u043b\u044f\u0434\u0456 \u043f\u0430\u043f\u0435\u0440\u043e\u0432\u0438\u0445, \u0434\u0440\u0443\u043a\u043e\u0432\u0430\u043d\u0438\u0445 \u043a\u043d\u0438\u0436\u043e\u043a, \u0430 \u043f\u0456\u0434\u0440\u0443\u0447\u043d\u0438\u043a\u0438, \u044f\u043a\u0456 \u0440\u043e\u0437\u043f\u043e\u0432\u0441\u044e\u0434\u0436\u0443\u044e\u0442\u044c\u0441\u044f \u0432 \u0435\u043b\u0435\u043a\u0442\u0440\u043e\u043d\u043d\u043e\u043c\u0443 \u0432\u0438\u0433\u043b\u044f\u0434\u0456, \u0431\u0443\u0434\u0443\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u0456 \u0431\u0435\u0437\u043a\u043e\u0448\u0442\u043e\u0432\u043d\u043e.</p>\r\n\r\n \r\n <h2>\u041f\u0440\u043e \u0441\u0443\u0441\u043f\u0456\u043b\u044c\u043d\u0435 \u043d\u0430\u0434\u0431\u0430\u043d\u043d\u044f</h2>\r\n \r\n <p>\u0412 \u0440\u0435\u0441\u0443\u0440\u0441\u0456 Wolne Lektury \u0437\u0433\u0456\u0434\u043d\u043e \u0437\u0430\u043a\u043e\u043d\u043e\u0434\u0430\u0432\u0441\u0442\u0432\u0430 \u043c\u043e\u0436\u0435\u043c\u043e \u043f\u0443\u0431\u043b\u0456\u043a\u0443\u0432\u0430\u0442\u0438 \u0442\u0456\u043b\u044c\u043a\u0438 \u0446\u0456 \u043a\u043d\u0438\u0436\u043a\u0438, \u044f\u043a\u0456 \u0437\u043d\u0430\u0445\u043e\u0434\u044f\u0442\u044c\u0441\u044f \u0432 \u0441\u0443\u0441\u043f\u0456\u043b\u044c\u043d\u043e\u043c\u0443 \u043d\u0430\u0434\u0431\u0430\u043d\u043d\u0456, \u0442\u043e\u0431\u0442\u043e \u0442\u0430\u043a\u0456, \u044f\u043a\u0456 \u0432\u0436\u0435 \u043d\u0435 \u043e\u0445\u043e\u0440\u043e\u043d\u044f\u044e\u0442\u044c\u0441\u044f \u0430\u0432\u0442\u043e\u0440\u0441\u044c\u043a\u0438\u043c \u043f\u0440\u0430\u0432\u043e\u043c. \u0421\u0443\u0441\u043f\u0456\u043b\u044c\u043d\u0435 \u043d\u0430\u0434\u0431\u0430\u043d\u043d\u044f \u0446\u0435 \u0441\u0432\u043e\u0454\u0440\u0456\u0434\u043d\u0430 \u0441\u043a\u0430\u0440\u0431\u043d\u0438\u0446\u044f \u043a\u0443\u043b\u044c\u0442\u0443\u0440\u0438, \u0441\u043f\u0456\u043b\u044c\u043d\u0435 \u0434\u043e\u0431\u0440\u043e, \u044f\u043a\u0438\u043c \u043c\u043e\u0436\u0443\u0442\u044c \u043a\u043e\u0440\u0438\u0441\u0442\u0443\u0432\u0430\u0442\u0438\u0441\u044f \u0443\u0441\u0456 \u043d\u0430 \u0440\u0456\u0432\u043d\u0438\u0445 \u043f\u0440\u0430\u0432\u0430\u0445, \u0431\u0435\u0437 \u043e\u0431\u043c\u0435\u0436\u0435\u043d\u044c \u0442\u0430 \u043f\u043b\u0430\u0442\u0438. \u0406\u0441\u043d\u0443\u0432\u0430\u043d\u043d\u044f \u0441\u0443\u0441\u043f\u0456\u043b\u044c\u043d\u043e\u0433\u043e \u043d\u0430\u0434\u0431\u0430\u043d\u043d\u044f \u0454 \u0433\u0430\u0440\u0430\u043d\u0442\u0456\u0454\u044e \u0434\u043e\u0441\u0442\u0443\u043f\u0443 \u0434\u043e \u0442\u0432\u043e\u0440\u0456\u0432 \u043a\u0443\u043b\u044c\u0442\u0443\u0440\u0438, \u044f\u043a\u0438\u0439 \u0454 \u043d\u0430\u0448\u0438\u043c \u0433\u0440\u043e\u043c\u0430\u0434\u044f\u043d\u0441\u044c\u043a\u0438\u043c \u043f\u0440\u0430\u0432\u043e\u043c, \u0437\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u043c \u0432 \u043a\u043e\u043d\u0441\u0442\u0438\u0442\u0443\u0446\u0456\u044e.</p>\r\n \r\n <p>\u0425\u043e\u0447\u0430 \u044f\u043a \u043f\u0440\u0430\u0432\u0438\u043b\u043e \u0432\u0441\u0456 \u0442\u0432\u043e\u0440\u0438 \u043a\u043e\u043b\u0438\u0441\u044c \u0441\u0442\u0430\u043d\u0443\u0442\u044c \u0447\u0430\u0441\u0442\u0438\u043d\u043e\u044e \u0441\u0443\u0441\u043f\u0456\u043b\u044c\u043d\u043e\u0433\u043e \u043d\u0430\u0434\u0431\u0430\u043d\u043d\u044f, \u0442\u043e \u0447\u0430\u0441 \u0434\u0456\u0457 \u0430\u0432\u0442\u043e\u0440\u0441\u044c\u043a\u043e\u0433\u043e \u043f\u0440\u0430\u0432\u0430 \u0432\u043f\u0440\u043e\u0434\u043e\u0432\u0436 \u043e\u0441\u0442\u0430\u043d\u043d\u0456\u0445 \u0434\u0435\u0441\u044f\u0442\u043a\u0456\u0432 \u043b\u0456\u0442 \u0431\u0443\u0432 \u043d\u0430\u0431\u0430\u0433\u0430\u0442\u043e \u043f\u0440\u043e\u0434\u043e\u0432\u0436\u0435\u043d\u0438\u043c. \u0429\u0435 \u043d\u0430\u043f\u043e\u0447\u0430\u0442\u043a\u0443 90-\u0445 \u0440\u043e\u043a\u0456\u0432 \u0446\u0435 \u0431\u0443\u043b\u043e 25 \u0440\u043e\u043a\u0456\u0432 \u043f\u0456\u0441\u043b\u044f \u0441\u043c\u0435\u0440\u0442\u0456 \u0430\u0432\u0442\u043e\u0440\u0430, \u043f\u043e\u0442\u0456\u043c \u0446\u0435\u0439 \u0442\u0435\u0440\u043c\u0456\u043d \u043f\u0440\u043e\u0434\u043e\u0432\u0436\u0435\u043d\u043e \u0434\u043e 50 \u0440\u043e\u043a\u0456\u0432, \u0441\u044c\u043e\u0433\u043e\u0434\u043d\u0456 \u0446\u0435 \u0432\u0436\u0435 70 \u0440\u043e\u043a\u0456\u0432. \u0426\u0435 \u043e\u0437\u043d\u0430\u0447\u0430\u0454 \u0449\u043e \u0447\u0438\u0441\u043b\u0435\u043d\u043d\u0456 \u043f\u043e\u0437\u0438\u0446\u0456\u0457 \u0437 \u043c\u0456\u043d\u0456\u0441\u0442\u0435\u0440\u0441\u044c\u043a\u043e\u0433\u043e \u0441\u043f\u0438\u0441\u043a\u0443 \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u043e\u0432\u0430\u043d\u043e\u0457 \u043b\u0456\u0442\u0435\u0440\u0430\u0442\u0443\u0440\u0438 \u043d\u0435 \u0437\u043c\u043e\u0436\u0443\u0442\u044c \u0431\u0443\u0442\u0438 \u043e\u043f\u0443\u0431\u043b\u0456\u043a\u043e\u0432\u0430\u043d\u0438\u043c\u0438 \u0449\u0435 \u0432\u043f\u0440\u043e\u0434\u043e\u0432\u0436 \u0431\u0430\u0433\u0430\u0442\u044c\u043e\u0445 \u0440\u043e\u043a\u0456\u0432. \u0429\u043e\u0439\u043d\u043e \u0432 2020 \u043e\u043f\u0443\u0431\u043b\u0456\u043a\u0443\u0454\u043c\u043e \u0442\u0432\u043e\u0440\u0438 \u041c\u0430\u0440\u043a\u0430 \u0425\u043b\u0430\u0441\u043a\u043e \u0442\u0430 \u0412\u0456\u0442\u043e\u043b\u044c\u0434\u0430 \u0413\u043e\u043c\u0431\u0440\u043e\u0432\u0456\u0447\u0430. \u0420\u043e\u043c\u0430\u043d\u0438 \u041a\u0443\u043d\u0446\u0435\u0432\u0456\u0447\u043e\u0432\u043e\u0457 \u0441\u0442\u0430\u043d\u0443\u0442\u044c \u0447\u0430\u0441\u0442\u0438\u043d\u043e\u044e \u0441\u0443\u0441\u043f\u0456\u043b\u044c\u043d\u043e\u0433\u043e \u043d\u0430\u0434\u0431\u0430\u043d\u043d\u044f \u0432 2060 \u0440\u043e\u0446\u0456, \u0430 \u043f\u043e\u0435\u0437\u0456\u0457 \u041c\u0456\u043b\u043e\u0448\u0430 \u0432 2075 \u0440\u043e\u0446\u0456.</p>\r\n \r\n <p>\u041e\u0431\u043c\u0435\u0436\u0435\u043d\u043d\u044f \u0430\u0432\u0442\u043e\u0440\u0441\u044c\u043a\u043e\u0433\u043e \u043f\u0440\u0430\u0432\u0430 \u043f\u043e\u0448\u0438\u0440\u044e\u044e\u0442\u044c\u0441\u044f \u0442\u0430\u043a\u043e\u0436 \u043d\u0430 \u043a\u0440\u0438\u0442\u0438\u0447\u043d\u0456 \u0432\u0438\u0434\u0430\u043d\u043d\u044f \u0442\u0430 \u043f\u0435\u0440\u0435\u043a\u043b\u0430\u0434\u0438. \u0414\u043e 1 \u0441\u0456\u0447\u043d\u044f 2012 \u0440\u043e\u043a\u0443 \u0431\u0443\u0434\u0435\u043c\u043e \u0447\u0435\u043a\u0430\u0442\u0438 \u043d\u0430 \u201c\u0412\u0435\u043b\u0438\u043a\u0438\u0439 \u0437\u0430\u043f\u043e\u0432\u0456\u0442\u201d \u0424\u0440\u0430\u043d\u0441\u0443\u0430 \u0412\u0456\u0439\u043e\u043d\u0430 \u0442\u0430 \u0456\u043d\u0448\u0456 \u0442\u0432\u043e\u0440\u0438 \u043f\u0435\u0440\u0435\u043a\u043b\u0430\u0434\u0435\u043d\u0456 \u0412\u043e\u0454\u043c-\u0416\u0435\u043b\u0435\u043d\u0441\u044c\u043a\u0438\u043c, \u0430 \u0434\u043e 2068 \u0440\u043e\u043a\u0443 \u043d\u0430 \u201c\u0412\u0456\u043d\u043d\u0456-\u041f\u0443\u0445\u0430\u201d \u041c\u0456\u043b\u043d\u0430 \u0442\u0430 \u0456\u043d\u0448\u0456 \u043f\u0435\u0440\u0435\u043a\u043b\u0430\u0434\u0438 \u0406\u0440\u0435\u043d\u0438 \u0422\u0443\u0432\u0456\u043c. \u041c\u0438 \u0442\u0430\u043a\u043e\u0436 \u043d\u0435 \u043c\u0430\u0454\u043c\u043e \u043f\u0440\u0430\u0432\u0430 \u043d\u0430\u0434\u0430\u0432\u0430\u0442\u0438 \u0434\u043e\u0441\u0442\u0443\u043f \u0434\u043e \u0437\u0430\u044f\u0432 \u0456 \u043f\u0440\u043e\u043c\u043e\u0432 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0445 \u0430\u0432\u0442\u043e\u0440\u0430\u043c\u0438, \u044f\u043a\u0456 \u043f\u043e\u043c\u0435\u0440\u043b\u0438 \u043c\u0435\u043d\u0448\u0435 \u043d\u0456\u0436 70 \u0440\u043e\u043a\u0456\u0432 \u0442\u043e\u043c\u0443. \u0417 \u0446\u0456\u0454\u0457 \u043f\u0440\u0438\u0447\u0438\u043d\u0438 \u0431\u0443\u0432\u0430\u0454 \u0442\u0430\u043a, \u0449\u043e \u044f\u043a\u0438\u0439\u0441\u044c \u0442\u0432\u0456\u0440 \u0454 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u0438\u043c \u0443 Wolne Lektury, \u0430\u043b\u0435 \u043f\u043e\u0441\u0438\u043b\u0430\u043d\u043d\u044f \u043d\u0430 \u0432\u0456\u0434\u043f\u043e\u0432\u0456\u0434\u043d\u0443 \u0434\u043b\u044f \u043d\u044c\u043e\u0433\u043e \u043f\u043e\u0437\u0438\u0446\u0456\u044e \u0432 \u0426\u0438\u0444\u0440\u043e\u0432\u0456\u0439 \u043d\u0430\u0446\u0456\u043e\u043d\u0430\u043b\u044c\u043d\u0456\u0439 \u0431\u0456\u0431\u043b\u0456\u043e\u0442\u0435\u0446\u0456 \u0432\u0456\u0434\u0441\u0438\u043b\u0430\u0454 \u043d\u0430 \u0441\u0442\u043e\u0440\u0456\u043d\u043a\u0443, \u044f\u043a\u0430 \u043f\u043e\u044f\u0441\u043d\u044e\u0454, \u0449\u043e \u0442\u0432\u0456\u0440 \u043e\u0445\u043e\u0440\u043e\u043d\u044f\u0454\u0442\u044c\u0441\u044f \u0430\u0432\u0442\u043e\u0440\u0441\u044c\u043a\u0438\u043c \u043f\u0440\u0430\u0432\u043e\u043c. \u0426\u0435 \u043e\u0437\u043d\u0430\u0447\u0430\u0454, \u0449\u043e \u0445\u043e\u0447\u0430 \u0441\u0430\u043c \u0442\u0435\u043a\u0441\u0442 \u0454 \u0447\u0430\u0441\u0442\u0438\u043d\u043e\u044e \u0441\u0443\u0441\u043f\u0456\u043b\u044c\u043d\u043e\u0433\u043e \u043d\u0430\u0434\u0431\u0430\u043d\u043d\u044f, \u0456 \u043c\u0438 \u0440\u043e\u0437\u043c\u0456\u0449\u0430\u0454\u043c\u043e \u0439\u043e\u0433\u043e \u0443 \u043d\u0430\u0448\u043e\u043c\u0443 \u0440\u0435\u0441\u0443\u0440\u0441\u0456, \u0442\u043e \u0439\u043e\u0433\u043e \u043a\u0440\u0438\u0442\u0438\u0447\u043d\u0435 \u0432\u0438\u0434\u0430\u043d\u043d\u044f, \u044f\u043a\u0435 \u0437\u043d\u0430\u0445\u043e\u0434\u0438\u0442\u044c\u0441\u044f \u0443 \u0426\u0438\u0444\u0440\u043e\u0432\u0456\u0439 \u0411\u0456\u0431\u043b\u0456\u043e\u0442\u0435\u0446\u0456 \u041f\u043e\u043b\u043e\u043d\u0430 (\u0437 \u0432\u0441\u0442\u0443\u043f\u043d\u0438\u043c \u0441\u043b\u043e\u0432\u043e\u043c, \u043f\u0435\u0440\u0435\u0434\u043c\u043e\u0432\u043e\u044e \u0442\u0430 \u043a\u043e\u043c\u0435\u043d\u0442\u0430\u0440\u044f\u043c\u0438), \u0434\u0430\u043b\u0456 \u043e\u0445\u043e\u0440\u043e\u043d\u044f\u0454\u0442\u044c\u0441\u044f \u0430\u0432\u0442\u043e\u0440\u0441\u044c\u043a\u0438\u043c \u043f\u0440\u0430\u0432\u043e\u043c. </p>\r\n \r\n <p>\u041f\u0440\u043e \u0441\u0443\u0441\u043f\u0456\u043b\u044c\u043d\u0435 \u043d\u0430\u0434\u0431\u0430\u043d\u043d\u044f \u0442\u0440\u0435\u0431\u0430 \u043f\u0456\u043a\u043b\u0443\u0432\u0430\u0442\u0438\u0441\u044f \u0456 \u0439\u043e\u0433\u043e \u0431\u0435\u0440\u0435\u0433\u0442\u0438. \u041a\u0443\u043b\u044c\u0442\u0443\u0440\u0430 \u0446\u0435 \u043c\u0430\u0439\u0441\u0442\u0435\u0440\u043d\u043e \u043f\u043e\u0431\u0443\u0434\u043e\u0432\u0430\u043d\u0430 \u0431\u0443\u0434\u0456\u0432\u043b\u044f, \u0432 \u044f\u043a\u0456\u0439 \u0447\u0435\u0440\u0433\u043e\u0432\u0456 \u043f\u043e\u0432\u0435\u0440\u0445\u0438 \u043c\u043e\u0436\u0443\u0442\u044c \u0441\u043f\u0438\u0440\u0430\u0442\u0438\u0441\u044f \u0442\u0456\u043b\u044c\u043a\u0438 \u043d\u0430 \u0441\u043e\u043b\u0456\u0434\u043d\u0456\u0439 \u043f\u0456\u0434\u0441\u0442\u0430\u0432\u0456, \u044f\u043a\u0443 \u0441\u0442\u0432\u043e\u0440\u0438\u043b\u0438 \u043f\u043e\u043f\u0435\u0440\u0435\u0434\u043d\u0438\u043a\u0438. \u041a\u043e\u0445\u0430\u043d\u043e\u0432\u0441\u044c\u043a\u0438\u0439 \u0431\u0435\u0437\u043f\u043e\u0441\u0435\u0440\u0435\u0434\u043d\u044c\u043e \u0447\u0435\u0440\u043f\u0430\u0432 \u0437 \u0430\u043d\u0442\u0438\u0447\u043d\u043e\u0457 \u0442\u0440\u0430\u0434\u0438\u0446\u0456\u0457. \u041c\u0456\u0446\u043a\u0435\u0432\u0438\u0447 \u0441\u043a\u043e\u0440\u0438\u0441\u0442\u0430\u0432\u0441\u044f \u043d\u0430\u0440\u043e\u0434\u043d\u043e\u044e \u0442\u0432\u043e\u0440\u0447\u0456\u0441\u0442\u044e \u0434\u043b\u044f \u0441\u0442\u0432\u043e\u0440\u0435\u043d\u043d\u044f \u043d\u0430\u0439\u0433\u0430\u0440\u043d\u0456\u0448\u0438\u0445 \u043f\u043e\u043b\u044c\u0441\u044c\u043a\u0438\u0445 \u043f\u043e\u0435\u043c. \u041a\u043e\u0436\u043d\u0435 \u043f\u043e\u043a\u043e\u043b\u0456\u043d\u043d\u044f \u043c\u043e\u0436\u0435 \u0441\u044f\u0433\u0430\u0442\u0438 \u0434\u0430\u043b\u0456 \u043f\u043e\u0433\u043b\u044f\u0434\u043e\u043c, \u0437\u0430\u0432\u0434\u044f\u043a\u0438 \u0434\u043e\u0441\u044f\u0433\u043d\u0435\u043d\u043d\u044f\u043c \u043f\u043e\u043f\u0435\u0440\u0435\u0434\u043d\u0438\u043a\u0456\u0432. \u0422\u043e\u043c\u0443 \u0442\u0430\u043a \u0441\u0443\u0442\u0442\u0454\u0432\u043e\u044e \u0454 \u0441\u0432\u043e\u0431\u043e\u0434\u0430 \u0432 \u043d\u0430\u0434\u0430\u0432\u0430\u043d\u043d\u0456 \u0434\u043e\u0441\u0442\u0443\u043f\u0443 \u0456 \u0432\u0438\u043a\u043e\u0440\u0438\u0441\u0442\u0430\u043d\u043d\u0456 \u0442\u0432\u043e\u0440\u0456\u0432 \u043f\u043e\u043b\u044c\u0441\u044c\u043a\u043e\u0457 \u0442\u0430 \u0441\u0432\u0456\u0442\u043e\u0432\u043e\u0457 \u043b\u0456\u0442\u0435\u0440\u0430\u0442\u0443\u0440\u0438. \u0411\u0435\u0437 \u0441\u0443\u0441\u043f\u0456\u043b\u044c\u043d\u043e\u0433\u043e \u043d\u0430\u0434\u0431\u0430\u043d\u043d\u044f, \u0441\u0442\u0432\u043e\u0440\u0435\u043d\u043d\u044f \u0442\u0430\u043a \u0447\u0443\u0434\u043e\u0432\u043e\u0457 \u0431\u0443\u0434\u0456\u0432\u043b\u0456 \u044f\u043a\u043e\u044e \u0454 \u043a\u0443\u043b\u044c\u0442\u0443\u0440\u0430, \u0431\u0443\u043b\u043e \u0431 \u043d\u0435\u043c\u043e\u0436\u043b\u0438\u0432\u0438\u043c. </p> ", 
+            "title_en": "About Wolne Lektury project", 
+            "left_column_pl": "<h2>Wolne Lektury</h2>\r\n    \r\n        <p>Biblioteka internetowa z lekturami szkolnymi \u201eWolne Lektury\u201d (www.wolnelektury.pl) to projekt realizowany\r\n        przez Fundacj\u0119 Nowoczesna Polska. Dzia\u0142a od 2007 roku i udost\u0119pnia w swoich zbiorach lektury szkolne, kt\u00f3re s\u0105\r\n        zalecane do u\u017cytku przez Ministerstwo Edukacji Narodowej i kt\u00f3re trafi\u0142y ju\u017c do domeny publicznej. S\u0105 one\r\n        opracowane, opatrzone komentarzem i udost\u0119pnione w kilku formatach (html, epub, mp3, ogg, odt, txt i pdf). Mo\u017cna je zgodnie z\r\n        prawem, bezp\u0142atnie przegl\u0105da\u0107, \u015bci\u0105ga\u0107 na sw\u00f3j komputer, a tak\u017ce udost\u0119pnia\u0107 innym i cytowa\u0107.</p>\r\n        \r\n         <p>Zesp\u00f3\u0142 projektu Wolne Lektury sk\u0142ada si\u0119 z do\u015bwiadczonych redaktorek i nauczycielek, co zapewnia rzetelno\u015b\u0107\r\n        naszego portalu. W tworzeniu go wsp\u00f3\u0142pracujemy z Bibliotek\u0105 Narodow\u0105, kt\u00f3ra dostarcza nam najlepszych dost\u0119pnych\r\n        wyda\u0144 i opracowa\u0144 krytycznych lektur szkolnych, opublikowanych w Cyfrowej Bibliotece Narodowej Polona. Wsp\u00f3lnie\r\n        staramy si\u0119, aby teksty lektur \u2013 nasze dziedzictwo kulturowe \u2013 by\u0142y dost\u0119pne dla wszystkich, niezale\u017cnie od\r\n        miejsca zamieszkania, zasobno\u015bci portfela, sprawno\u015bci lub jej braku. Jest to mo\u017cliwe dzi\u0119ki istnieniu domeny\r\n        publicznej, czyli zbioru dzie\u0142 nieobj\u0119tych restrykcjami prawa autorskiego, oraz dzi\u0119ki nowoczesnym technologiom\r\n        \u2013 narz\u0119dziom, kt\u00f3re pozwalaj\u0105 zwielokrotni\u0107 dost\u0119pno\u015b\u0107 tre\u015bci upublicznianych w Internecie.</p>\r\n        \r\n         <p>Projekt Wolne Lektury jest ca\u0142kowicie niekomercyjny i realizowany pro publico bono. Dlatego tak wa\u017cne jest\r\n        dla nas poparcie udzielone przez wybitne osobisto\u015bci kultury i nauki. Patronat honorowy nad projektem Wolne \r\n        Lektury sprawuje Ministerstwo Kultury i Dziedzictwa Narodowego, Ministerstwo Edukacji Narodowej oraz\r\n        Stowarzyszenie Pisarzy Polskich.. W Komitecie Honorowym Wolnych Lektur zgodzili si\u0119 uczestniczy\u0107 prof. Maria\r\n        Janion, prof. Gra\u017cyna Borkowska, prof. Przemys\u0142aw\r\n        Czapli\u0144ski, prof. Mieczys\u0142aw D\u0105browski, prof. Ewa Kraskowska, prof. Ma\u0142gorzata Czermi\u0144ska, prof. Jerzy Jarz\u0119bski\r\n        i prof. Piotr \u015aliwi\u0144ski.</p>\r\n\r\n        \r\n         <p>Digitalizacj\u0105 i korekt\u0105 tekst\u00f3w zajmuje si\u0119 Biblioteka Narodowa. Serwis internetowy zosta\u0142 zaprojektowany\r\n        przez 2ia. Autorem j\u0119zyka sk\u0142adu tekst\u00f3w Wolnych Lektur opartego na j\u0119zyku XML jest Dariusz Ga\u0142ecki. Obs\u0142ug\u0119\r\n        prawn\u0105 Wolnych Lektur zapewnia Kancelaria Grynhoff,\r\n        Wo\u017any, Mali\u0144ski. Hosting serwisu zapewnia\r\n        firma EO Networks. W opracowaniu technicznym tekst\u00f3w pomaga wydawnictwo Korporacja Ha!Art. Logo Wolne Lektury\r\n        jest dzie\u0142em agencji PZL. Projekt obj\u0119li patronatem medialnym: Dziennik, Elle, Tok.fm, Biblioteka Analiz,\r\n        Tygodnik Powszechny, Przekr\u00f3j i TVP Kultura.</p>\r\n        \r\n        <h2>Jak korzysta\u0107 z Wolnych Lektur?</h2>\r\n        \r\n         <p>Najwa\u017cniejsz\u0105 innowacj\u0105 Wolnych Lektur, odr\u00f3\u017cniaj\u0105c\u0105 ten projekt od innych bibliotek internetowych, jest\r\n        mo\u017cliwo\u015b\u0107 przeszukiwania tekst\u00f3w z zastosowaniem r\u00f3\u017cnych kryteri\u00f3w: tradycyjnych, takich jak tytu\u0142, autor,\r\n        epoka, rodzaj, gatunek literacki, ale i niespotykanych nigdzie indziej, to jest odnosz\u0105cych si\u0119 do tre\u015bci wielu\r\n        utwor\u00f3w naraz \u2013 motyw\u00f3w i temat\u00f3w literackich. Takie przeszukiwanie jest mo\u017cliwe dzi\u0119ki specjalnemu opracowaniu\r\n        tekst\u00f3w lektur szkolnych, to znaczy opisaniu ich za pomoc\u0105 wymienionych kryteri\u00f3w. Tym w\u0142a\u015bnie Wolne Lektury\r\n        r\u00f3\u017cni\u0105 si\u0119 od licznych stron z opracowaniami lektur szkolnych \u2013 dostarczaj\u0105 narz\u0119dzi do tw\u00f3rczej pracy z\r\n        tekstem, a nie gotowych \u015bci\u0105g. Je\u015bli np. ucze\u0144 dostanie temat pracy domowej: \u201eMotyw dziecka w romantyzmie na\r\n        podstawie wybranych utwor\u00f3w\u201c, to trzy klikni\u0119cia na naszej stronie sprawi\u0105, \u017ce na ekranie komputera pojawi mu\r\n        si\u0119 komplet tekst\u00f3w do analizy. Dzi\u0119ki takim narz\u0119dziom czytanie lektur staje si\u0119 fascynuj\u0105c\u0105 podr\u00f3\u017c\u0105 po \u015bwiecie\r\n        kultury.</p>\r\n        \r\n         <p>Kolejn\u0105 u\u017cyteczn\u0105 funkcjonalno\u015bci\u0105 Wolnych Lektur, przydatn\u0105 w pracy w szkole, jest mo\u017cliwo\u015b\u0107 uk\u0142adania\r\n        ca\u0142ych zestaw\u00f3w tekst\u00f3w przerabianych na przyk\u0142ad w ci\u0105gu roku przez dan\u0105 klas\u0119. Takie p\u00f3\u0142ki z lekturami s\u0105\r\n        tworzone przez nauczycielk\u0119/la, kt\u00f3ra/y mo\u017ce nast\u0119pnie wys\u0142a\u0107 swoim uczniom odno\u015bnik (link) do tego zbioru, a\r\n        oni jednym klikni\u0119ciem \u015bci\u0105gn\u0105 ca\u0142y zestaw na sw\u00f3j komputer.</p>\r\n        \r\n        <p>Wszystkie teksty ksi\u0105\u017cek ze stron Wolne Lektury (w postaci plik\u00f3w html, pdf, epub, txt) dost\u0119pne s\u0105 poza restrykcjami prawa autorskiego i mo\u017cna je swobodnie wykorzystywa\u0107 bez \u017cadnych warunk\u00f3w.</p>\r\n\r\n        <p>Je\u015bli teksty te s\u0105 opatrzone dodatkowymi materia\u0142ami (przypisy, motywy literackie etc.) kt\u00f3re podlegaj\u0105 prawu\r\n        autorskiemu, to te dodatkowe materia\u0142y udost\u0119pnione s\u0105 na licencji Creative Commons Uznanie Autorstwa - Na Tych\r\n        Samych Warunkach 3.0 PL (<a href=\"http://creativecommons.org/licenses/by-sa/3.0/\">http://creativecommons.org/licenses/by-sa/3.0/</a>).</p>\r\n", 
+            "left_column_ru": "<h2>Wolne Lektury</h2>\r\n    \r\n        <p>\u0418\u043d\u0442\u0435\u0440\u043d\u0435\u0442-\u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u0441\u043e \u0448\u043a\u043e\u043b\u044c\u043d\u044b\u043c\u0438 \u0447\u0442\u0435\u043d\u0438\u044f\u043c\u0438 \u201eWolne Lektury\u201d (www.wolnelektury.pl) - \u044d\u0442\u043e \u043f\u0440\u043e\u0435\u043a\u0442, \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u043c\u044b\u0439 \u0424\u043e\u043d\u0434\u043e\u043c \r\n        \u0421\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f \u041f\u043e\u043b\u044c\u0448\u0430. \u0424\u043e\u043d\u0434 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u0441 2007 \u0433\u043e\u0434\u0430 \u0438 \u0434\u0435\u043b\u0430\u0435\u0442 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u043c\u0438 \u0448\u043a\u043e\u043b\u044c\u043d\u044b\u0435 \u0447\u0442\u0435\u043d\u0438\u044f, \r\n        \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u0435\u0442 \u043c\u0438\u043d\u0438\u0441\u0442\u0440 \u043d\u0430\u0440\u043e\u0434\u043d\u043e\u0433\u043e \u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0438 \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u0443\u0436\u0435 \u0447\u0430\u0441\u0442\u044c\u044e \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u043e\u0433\u043e \u0434\u043e\u043c\u0435\u043d\u0430. \u0418\u0445 \u0440\u0430\u0437\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442\u0441\u044f,\r\n        \u0434\u0435\u043b\u0430\u0435\u0442\u0441\u044f \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0438 \u043a \u043d\u0438\u043c, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0432 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u0444\u043e\u0440\u043c\u0430\u0442\u0430\u0445 (html, epub, mp3, ogg, odt, txt i pdf). \u0421\u043e\u0433\u043b\u0430\u0441\u043d\u043e \u0437\u0430\u043a\u043e\u043d\u0443, \u0438\u0445 \u043c\u043e\u0436\u043d\u043e\r\n        \u0431\u0435\u0441\u043f\u043b\u0430\u0442\u043d\u043e \u043f\u0440\u043e\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u0442\u044c, \u0441\u043a\u0430\u0447\u0430\u0442\u044c \u043d\u0430 \u0441\u0432\u043e\u0439 \u043a\u043e\u043c\u043f\u044c\u044e\u0442\u0435\u0440, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0434\u0435\u043b\u0430\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u043c\u0438 \u0434\u043b\u044f \u0434\u0440\u0443\u0433\u0438\u0445 \u0438 \u0446\u0438\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c.</p>\r\n        \r\n         <p>\u041a\u043e\u043b\u043b\u0435\u043a\u0442\u0438\u0432 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 Wolne Lektury \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0438\u0437 \u043e\u043f\u044b\u0442\u043d\u044b\u0445 \u0440\u0435\u0434\u0430\u043a\u0442\u043e\u0440\u043e\u0432 \u0438 \u0443\u0447\u0442\u0435\u043b\u044c\u043d\u0438\u0446, \u0447\u0442\u043e \u0441\u043f\u043e\u0441\u043e\u0431\u0441\u0442\u0432\u0443\u0435\u0442 \u043f\u043e\u0434\u043b\u0438\u043d\u043d\u043e\u043c\u0443 \u0445\u0430\u0440\u0430\u043a\u0442\u0435\u0440\u0443\r\n        \u043d\u0430\u0448\u0435\u0433\u043e \u043f\u043e\u0440\u0442\u0430\u043b\u0430. \u0412\u043e \u0432\u0440\u0435\u043c\u044f \u0435\u0433\u043e \u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043c\u044b \u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u0447\u0430\u0435\u043c \u0441 \u041d\u0430\u0440\u043e\u0434\u043d\u043e\u0439 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u043e\u0439, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u043d\u0430\u043c \u043d\u0430\u0438\u043b\u0443\u0447\u0448\u0438\u0435\r\n        \u0438\u0437\u0434\u0430\u043d\u0438\u044f \u0438 \u043a\u0440\u0438\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u043f\u043e\u0437\u0438\u0446\u0438\u0438 \u0448\u043a\u043e\u043b\u044c\u043d\u044b\u0445 \u0447\u0442\u0435\u043d\u0438\u0439, \u043e\u043f\u0443\u0431\u043b\u0438\u043a\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0432 \u0426\u0438\u0444\u0440\u043e\u0432\u043e\u0439 \u041d\u0430\u0440\u043e\u0434\u043d\u043e\u0439 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0435 Polona. \u041c\u044b \u0432\u043c\u0435\u0441\u0442\u0435 \u043f\u044b\u0442\u0430\u0435\u043c\u0441\u044f, \u0447\u0442\u043e\u0431\u044b \u0442\u0435\u043a\u0441\u0442\u044b \u0447\u0442\u0435\u043d\u0438\u0439 \u2013 \u043d\u0430\u0448\u0435 \u043a\u0443\u043b\u044c\u0442\u0443\u0440\u043d\u043e\u0435 \u043d\u0430\u0441\u043b\u0435\u0434\u0441\u0442\u0432\u043e \u2013 \u0431\u044b\u043b\u0438 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b \u0432\u0441\u0435\u043c, \r\n        \u043d\u0435\u0441\u043c\u043e\u0442\u0440\u044f \u043d\u0430 \u043c\u0435\u0441\u0442\u043e\u0436\u0438\u0442\u0435\u043b\u044c\u0441\u0442\u0432\u043e, \u0442\u043e\u043b\u0449\u0438\u043d\u0443 \u043a\u043e\u0448\u0435\u043b\u044c\u043a\u0430, \u0443\u043c\u0435\u043d\u0438\u044f \u0438\u043b\u0438 \u0438\u0445 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u0435. \u042d\u0442\u043e \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u044b\u043c \u0431\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u044f \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043e\u0432\u0430\u043d\u0438\u044e \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u043e\u0433\u043e\r\n        \u0434\u043e\u043c\u0435\u043d\u0430, \u0442.\u0435. \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u0438 \u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u0439, \u043d\u0435\u043f\u043e\u0434\u0432\u0435\u0440\u0433\u0430\u044e\u0449\u0438\u0445\u0441\u044f \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u044f\u043c \u0430\u0432\u0442\u043e\u0440\u0441\u043a\u043e\u0433\u043e \u043f\u0440\u0430\u0432\u0430, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0431\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u044f \u043d\u043e\u0432\u0435\u0439\u0448\u0438\u043c \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u044f\u043c\r\n        \u2013 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430\u043c, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0442 \u0440\u0430\u0441\u0448\u0438\u0440\u0438\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u043d\u043e\u0433\u043e \u0432 \u0418\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u044f.</p>\r\n        \r\n         <p>\u041f\u0440\u043e\u0435\u043a\u0442 Wolne Lektury \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0432\u043f\u043e\u043b\u043d\u0435 \u043d\u0435\u043a\u043e\u043c\u043c\u0435\u0440\u0447\u0435\u0441\u043a\u0438\u043c \u0438 \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043b\u044f\u0435\u0442\u0441\u044f pro publico bono. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u0442\u0430\u043a\u0438\u043c \u0432\u0430\u0436\u043d\u044b\u043c \u0434\u043b\u044f \u043d\u0430\u0441\r\n        \u0441\u0447\u0438\u0442\u0430\u0435\u0442\u0441\u044f \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 \u0441\u043e \u0441\u0442\u043e\u0440\u043e\u043d\u044b \u0432\u044b\u0434\u0430\u044e\u0449\u0438\u0445\u0441\u044f \u043b\u0438\u0447\u043d\u043e\u0441\u0442\u0435\u0439 \u043a\u0443\u043b\u044c\u0442\u0443\u0440\u044b \u0438 \u043d\u0430\u0443\u043a\u0438. \u041f\u043e\u0447\u0435\u0442\u043d\u043e\u0435 \u043f\u043e\u043a\u0440\u043e\u0432\u0438\u0442\u0435\u043b\u044c\u0441\u0442\u0432\u043e \u043d\u0430\u0434 \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u043c Wolne \r\n        Lektury \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043b\u044f\u0435\u0442 \u041c\u0438\u043d\u0438\u0441\u0442\u0435\u0440\u0441\u0442\u0432\u043e \u043a\u0443\u043b\u044c\u0442\u0443\u0440\u044b \u0438 \u043d\u0430\u0440\u043e\u0434\u043d\u043e\u0433\u043e \u043d\u0430\u0441\u043b\u0435\u0434\u0441\u0442\u0432\u0430, \u041c\u0438\u043d\u0438\u0441\u0442\u0435\u0440\u0441\u0442\u0432\u043e \u043d\u0430\u0440\u043e\u0434\u043d\u043e\u0433\u043e \u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u0438\u044f, \u0430 \u0442\u0430\u043a\u0436\u0435\r\n        \u041e\u0431\u0449\u0435\u0441\u0442\u0432\u043e \u043f\u043e\u043b\u044c\u0441\u043a\u0438\u0445 \u043f\u0438\u0441\u0430\u0442\u0435\u043b\u0435\u0439. \u0412 \u0441\u043e\u0441\u0442\u0430\u0432 \u043f\u043e\u0447\u0435\u0442\u043d\u043e\u0433\u043e \u043a\u043e\u043c\u0438\u0442\u0435\u0442\u0430 \u0441\u043e\u0433\u043b\u0430\u0441\u0438\u043b\u0438\u0441\u044c \u0432\u043e\u0439\u0442\u0438 prof. Maria\r\n        Janion, prof. Gra\u017cyna Borkowska, prof. Przemys\u0142aw\r\n        Czapli\u0144ski, prof. Mieczys\u0142aw D\u0105browski, prof. Ewa Kraskowska, prof. Ma\u0142gorzata Czermi\u0144ska, prof. Jerzy Jarz\u0119bski\r\n        i prof. Piotr \u015aliwi\u0144ski.</p>\r\n\r\n        \r\n         <p>\u0414\u0438\u0433\u0438\u0442\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0435\u0439 \u0438 \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u0442\u0435\u043a\u0441\u0442\u043e\u0432 \u0437\u0430\u043d\u0438\u043c\u0430\u0435\u0442\u0441\u044f \u041d\u0430\u0440\u043e\u0434\u043d\u0430\u044f \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430. \u0418\u043d\u0442\u0435\u0440\u043d\u0435\u0442-\u0441\u0435\u0440\u0432\u0438\u0441 \u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043b\u0441\u044f\r\n        2ia. \u0410\u0432\u0442\u043e\u0440\u043e\u043c \u044f\u0437\u044b\u043a\u0430 Wolne Lektuy, \u043e\u0441\u0432\u043e\u0435\u043d\u043d\u043e\u0433\u043e \u043d\u0430 \u044f\u0437\u044b\u043a\u0435 XML, \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f Dariusz Ga\u0142ecki. \u042e\u0440\u0438\u0434\u0438\u0447\u0435\u0441\u043a\u0430\u044f \u0441\u043b\u0443\u0436\u0431\u0430\r\n        Wolne Lektury \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u043a\u043e\u043d\u0442\u043e\u0440\u043e\u0439 Grynhoff,\r\n        Wo\u017any, Mali\u0144ski. \u0425\u043e\u0441\u0442\u0438\u043d\u0433 \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u0435\u0442\r\n        \u0444\u0438\u0440\u043c\u0430 EO Networks. \u0412 \u0442\u0435\u0445\u043d\u0438\u0447\u0435\u0441\u043a\u043e\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u0442\u0435\u043a\u0441\u0442\u043e\u0432 \u043f\u043e\u043c\u043e\u0433\u0430\u0435\u0442 \u0438\u0437\u0434\u0430\u0442\u0435\u043b\u044c\u0441\u0442\u0432\u043e-\u043a\u043e\u0440\u043f\u043e\u0440\u0430\u0446\u0438\u044f Ha!Art. \u041b\u043e\u0433\u043e\u0442\u0438\u043f Wolne Lektury\r\n        \u0431\u044b\u043b \u0441\u043e\u0437\u0434\u0430\u043d \u0430\u0433\u0435\u043d\u0442\u0441\u0442\u0432\u043e\u043c PZL. \u041c\u0435\u0434\u0438\u0439\u043d\u043e\u0435 \u043f\u043e\u043a\u0440\u043e\u0432\u0438\u0442\u0435\u043b\u044c\u0441\u0442\u0432\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430: Dziennik, Elle, Tok.fm, Biblioteka Analiz,\r\n        Tygodnik Powszechny, Przekr\u00f3j i TVP Kultura.</p>\r\n        \r\n        <h2>\u041a\u0430\u043a \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f Wolne Lektury?</h2>\r\n        \r\n         <p>\u0421\u0430\u043c\u043e\u0439 \u0432\u0430\u0436\u043d\u043e\u0439 \u0438\u043d\u043d\u043e\u0432\u0430\u0446\u0438\u0435\u0439 Wolne Lektury, \u043e\u0442\u043b\u0438\u0447\u0430\u044e\u0449\u0435\u0439 \u044d\u0442\u043e\u0442 \u043f\u0440\u043e\u0435\u043a\u0442 \u043e\u0442 \u0434\u0440\u0443\u0433\u0438\u0445 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442-\u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a, \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \r\n        \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043e\u0431\u044b\u0441\u043a\u0430 \u0442\u0435\u043a\u0441\u0442\u043e\u0432 \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u0440\u0430\u0437\u043d\u044b\u0445 \u043a\u0440\u0438\u0442\u0435\u0440\u0438\u0435\u0432: \u0442\u0440\u0430\u0434\u0438\u0446\u0438\u043e\u043d\u043d\u044b\u0445 \u0442\u0430\u043a\u0438\u0445, \u043a\u0430\u043a \u0437\u0430\u0433\u043b\u0430\u0432\u0438\u0435, \u0430\u0432\u0442\u043e\u0440, \u044d\u043f\u043e\u0445\u0430, \u0444\u043e\u0440\u043c\u0430, \u043b\u0438\u0442\u0435\u0440\u0430\u0442\u0443\u0440\u043d\u044b\u0439 \u0436\u0430\u043d\u0440, \u043d\u043e \u0438 \u043d\u0435\u0432\u0441\u0442\u0440\u0435\u0447\u0430\u0435\u043c\u044b\u0445\r\n        \u0432 \u043d\u0438\u043a\u0430\u043a\u043e\u043c \u0434\u0440\u0443\u0433\u043e\u043c \u043c\u0435\u0441\u0442\u0435, \u0442.\u0435. \u043e\u0442\u043d\u043e\u0441\u044f\u0449\u0438\u0445\u0441\u044f \u0441\u0440\u0430\u0437\u0443 \u043a \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u044e \u043c\u043d\u043e\u0433\u0438\u0445\r\n        \u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u0439 \u2013 \u043b\u0438\u0442\u0435\u0440\u0430\u0442\u0443\u0440\u043d\u044b\u0445 \u0442\u0435\u043c \u0438 \u043c\u043e\u0442\u0438\u0432\u043e\u0432. \u0422\u0430\u043a\u043e\u0439 \u043e\u0431\u044b\u0441\u043a \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u044b\u043c \u0431\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u044f \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u043e\u0439 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435\r\n        \u0448\u043a\u043e\u043b\u044c\u043d\u044b\u0445 \u0447\u0442\u0435\u043d\u0438\u0439, \u0437\u043d\u0430\u0447\u0438\u0442 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0438 \u0438\u0445 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u0435\u043d\u043d\u044b\u0445 \u043a\u0440\u0438\u0442\u0435\u0440\u0438\u0435\u0432. \u0418\u043c\u0435\u043d\u043d\u043e \u044d\u0442\u043e\u043c Wolne Lektury\r\n        \u043e\u0442\u043b\u0438\u0447\u0430\u044e\u0442\u0441\u044f \u043e\u0442 \u043c\u043d\u043e\u0433\u0438\u0445 \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u043e\u0431\u0441\u0443\u0436\u0434\u0435\u043d\u0438\u044f\u043c\u0438 \u0448\u043a\u043e\u043b\u044c\u043d\u044b\u0445 \u0447\u0442\u0435\u043d\u0438\u0439 \u2013  \u043e\u043d\u0438 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0442 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b \u0434\u043b\u044f \u0442\u0432\u043e\u0440\u0447\u0435\u0441\u043a\u043e\u0439 \u0440\u0430\u0431\u043e\u0442\u044b \u0441\r\n        \u0442\u0435\u043a\u0441\u0442\u043e\u043c,- \u043d\u0435 \u0433\u043e\u0442\u043e\u0432\u044b\u0435 \u0448\u043f\u0430\u0440\u0433\u0430\u043b\u043a\u0438. \u0415\u0441\u043b\u0438 \u043d\u0430\u043f\u0440. \u0434\u043e\u043c\u0430\u0448\u043d\u044f\u044f \u0440\u0430\u0431\u043e\u0442\u0430 \u0443\u0447\u0435\u043d\u0438\u043a\u0430 \u0431\u0443\u0434\u0435\u0442 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0442\u044c\u0441\u044f \u043a\u0430\u043a: \u201e\u041c\u043e\u0442\u0438\u0432 \u0440\u0435\u0431\u0435\u043d\u043a\u0430 \u0432 \u0440\u043e\u043c\u0430\u043d\u0442\u0438\u0437\u043c\u0435 \u043d\u0430\r\n        \u043e\u0441\u043d\u043e\u0432\u0435 \u0438\u0437\u0431\u0440\u0430\u043d\u043d\u044b\u0445 \u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u0439\u201c, \u0442\u043e \u0442\u0440\u0438 \u0449\u0435\u043b\u043a\u0430 \u043d\u0430 \u043d\u0430\u0448\u0435\u043c \u0441\u0430\u0439\u0442\u0435 \u043f\u0440\u0438\u0432\u0435\u0434\u0443\u0442 \u043a \u043f\u043e\u044f\u0432\u043b\u0435\u043d\u0438\u044e \u043d\u0430\u0431\u043e\u0440\u0430 \u0442\u0435\u0441\u0442\u043e\u0432 \u0434\u043b\u044f \u0430\u043d\u0430\u043b\u0438\u0437\u0430 \r\n        \u043d\u0430 \u044d\u043a\u0440\u0430\u043d\u0435 \u043a\u043e\u043c\u043f\u044c\u044e\u0442\u0435\u0440\u0430. \u0411\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u044f \u0442\u0430\u043a\u0438\u043c \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430\u043c \u0447\u0442\u0435\u043d\u0438\u0435 \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u0448\u043a\u043e\u043b\u044c\u043d\u044b\u0445 \u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u0439 \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u0443\u0432\u043b\u0435\u043a\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u043c \u043f\u0443\u0442\u0435\u0448\u0435\u0441\u0442\u0432\u0438\u0435\u043c\r\n        \u043f\u043e \u043c\u0438\u0440\u0435 \u043a\u0443\u043b\u044c\u0442\u0443\u0440\u044b.</p>\r\n        \r\n         <p>\u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u043f\u043e\u043b\u0435\u0437\u043d\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c\u044e Wolne Lektury, \u043f\u0440\u0438\u0433\u043e\u0434\u043d\u043e\u0439 \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0432 \u0448\u043a\u043e\u043b\u0435, \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c\r\n        \u0441\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0446\u0435\u043b\u044b\u0445 \u043d\u0430\u0431\u043e\u0440\u043e\u0432 \u0442\u0435\u043a\u0441\u0442\u043e\u0432, \u043e\u0431\u0441\u0443\u0436\u0434\u0430\u0435\u043c\u044b\u0445 \u0432 \u0442\u0435\u0447\u0435\u043d\u0438\u0435 \u0433\u043e\u0434\u0430 \u0432\u0441\u0435\u043c \u043a\u043b\u0430\u0441\u0441\u043e\u043c. \u0422\u0430\u043a\u0438\u0435 \u043f\u043e\u043b\u043a\u0438 \u0441 \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u043c\u0438 \u0447\u0442\u0435\u043d\u0438\u044f\u043c\u0438\r\n        \u0441\u043e\u0437\u0434\u0430\u044e\u0442\u0441\u044f \u0443\u0447\u0438\u0442\u0435\u043b\u0435\u043c/\u0443\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u0438\u0446\u0435\u0439, \u043a\u043e\u0442\u043e\u0440\u044b\u0439/-\u0430\u044f \u0437\u0430\u0442\u0435\u043c \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u0441\u043b\u0430\u0442\u044c \u0441\u0432\u043e\u0438\u043c \u0443\u0447\u0435\u043d\u0438\u043a\u0430\u043c \u0441\u0441\u044b\u043b\u043a\u0443 \u043d\u0430 \u044d\u0442\u043e\u0442 \u043d\u0430\u0431\u043e\u0440.\r\n        \u041e\u043d\u0438 \u0436\u0435 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043e\u0434\u043d\u043e\u0433\u043e \u0449\u0435\u043b\u043a\u0430 \u0441\u043a\u0430\u0447\u0430\u044e\u0442 \u0432\u0435\u0441\u044c \u043d\u0430\u0431\u043e\u0440 \u043d\u0430 \u0441\u0432\u043e\u0439 \u043a\u043e\u043c\u043f\u044c\u044e\u0442\u0435\u0440.</p>\r\n        \r\n        <p>\u0412\u0441\u0435 \u0442\u0435\u043a\u0441\u0442\u044b \u043a\u043d\u0438\u0433 \u0441 \u0441\u0430\u0439\u0442\u0430 Wolne Lektury (\u0432 \u0432\u0438\u0434\u0435 \u0444\u0430\u0439\u043b\u043e\u0432 html, pdf, epub, txt) \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u043c\u0438 \u0432\u043d\u0435 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0439 \u0430\u0432\u0442\u043e\u0440\u0441\u043a\u043e\u0433\u043e \u043f\u0440\u0430\u0432\u0430. \u0418\u0445 \u043c\u043e\u0436\u043d\u043e \u0441\u0432\u043e\u0431\u043e\u0434\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043f\u0440\u0438 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u0438 \u043a\u0430\u043a\u0438\u0445-\u043b\u0438\u0431\u043e \u0443\u0441\u043b\u043e\u0432\u0438\u0439.</p>\r\n\r\n        <p>\u0415\u0441\u043b\u0438 \u044d\u0442\u0438 \u0442\u0435\u043a\u0441\u0442\u044b \u0441\u043e\u043f\u0440\u043e\u0432\u0430\u0436\u0434\u0430\u044e\u0442\u0441\u044f \u0434\u043e\u0431\u0430\u0432\u043e\u0447\u043d\u044b\u043c\u0438 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u0430\u043c\u0438 (\u0441\u043d\u043e\u0441\u043a\u0438, \u043b\u0438\u0442\u0435\u0440\u0430\u0442\u0443\u0440\u043d\u044b\u0435 \u043c\u043e\u0442\u0438\u0432\u044b \u0438 \u0442.\u0434.), \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0440\u0430\u0441\u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u044f\u0435\u0442\u0441\u044f \u0430\u0432\u0442\u043e\u0440\u0441\u043a\u043e\u0435 \u043f\u0440\u0430\u0432\u043e,\r\n        \u0442\u043e \u044d\u0442\u0438 \u0434\u043e\u0431\u0430\u0432\u043e\u0447\u043d\u044b\u0435 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u044b \u0441\u0447\u0438\u0442\u0430\u044e\u0442\u0441\u044f \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u043c\u0438 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u043b\u0438\u0446\u0435\u043d\u0437\u0438\u0438 Creative Commons Uznanie Autorstwa - \u043f\u0440\u0438 \u0443\u0447\u0430\u0441\u0442\u0438\u0438 \u0442\u0435\u0445 \u0436\u0435\r\n        \u0443\u0441\u043b\u043e\u0432\u0438\u0439 3.0 PL (<a href=\"http://creativecommons.org/licenses/by-sa/3.0/\">http://creativecommons.org/licenses/by-sa/3.0/</a>).</p>\r\n", 
+            "right_column_lt": "<h2>Apie Fond\u0105</h2>\r\n\r\n   \r\n           <p>\u0160iuolaikin\u0117s Lenkijos Fondas buvo \u012fkurtas nes vaik\u0173 lavinimas tai raktas \u012f Lenkijos ateit\u012f. Vienu i\u0161 svarbiausi\u0173 u\u017eduo\u010di\u0173 kurios i\u0161kilo prie\u0161 Lenkijos \u0161vietim\u0105 tai kova su skaitmeniniu i\u0161skyrimu. Geb\u0117jimas naudotis kompiuteriu ir internetu \u0161iuolaikiniame pasaulyje tai standartas. Tie kurie prie to neprisitaik\u0117 priteisti gyventi pasaulio pakra\u0161ty.</p>\r\n        \r\n <p>Tod\u0117l jau septynerius metus pad\u0117dam vaikams suprasti ir panaudoti pa\u017eangias technologijas. \u0160iuolaikines Lenkijos Fondas nori perduoti  t\u016bkstan\u010diams vaik\u0173 tai kas yra svarbiausia: \u017eines ir sugeb\u0117jimus, kurie pad\u0117s suprasti dabartin\u012f pasauly ir panaudoti galimybes kurias jis teikia.</p>\r\n\r\n         <p> \u0160iuolaikin\u0117s Lenkijos Fondas apart Projekto Laisvoji Literat\u016bra \u2013 veda taip pat projekt\u0105 Laisvieji Vadov\u0117liai,\r\n       sukurta savanori\u0173 - mokytoj\u0173 bendruomenin\u0117, kuri naudoja internet\u0105 ir ruo\u0161ia naujus vadov\u0117lius\r\n        Lenkijos moksleiviams. Laisvieji Vadov\u0117liai pavie\u0161inti su laisva licencija \u2013 tai rai\u0161kia kad kiekvienas gali teis\u0117tai ir nemokamai juos atsisi\u0173sti ir naudotis, nereikalaujant autoriaus darnos. \r\n        Kiekvienas mokytojas gali papildyti vadov\u0117ly, i\u0161pl\u0117sti ir pataisyti pagal savo nor\u0105 ir patyrim\u0105. D\u0117ka laisv\u0173j\u0173 licencij\u0173 galima numa\u017einti vadov\u0117li\u0173 kain\u0105 prilyginant su kaina vadov\u0117liu, kurie yra leid\u017eiami popierin\u0117s knygos formoje. Elektronin\u0117 j\u0173 versija yra platinama nemokamai.</p>\r\n\r\n        \r\n        <h2>Apie internetin\u0119 svetain\u0119</h2>\r\n        \r\n        <p>\r\nInterneto svetain\u0117je \u201eLaisvoji Literat\u016bra\u201c galima teis\u0117tai vie\u0161inti tik tas knygas, kurios priklauso  m\u016bs\u0173 tinklapiui.\r\n        Tai yra tos, kurioms autoriaus teis\u0117s negalioja. Internetin\u0117 svetain\u0117 tai kult\u016bros lobynas, bendra geryb\u0117, kuria visi lygiomis teis\u0117mis gali neribotai ir nemokamai naudotis.\r\nInternetin\u0117 svetain\u0117 tai garantas pri\u0117jimo prie kult\u016bros gerybi\u0173, k\u0105 mums u\u017etikrinta Konstitucijos \u012fstatymas.</p>\r\n        \r\n         <p>Principas yra toks kad po kiek laiko visi k\u016briniai atsirastu internetin\u0117s bibliot\u0117kos lentynose. Kada tai atsitiks priklauso nuo Lenkijos autori\u0173 teisi\u0173 galiojimo, kurios \u0161iuo metu yra prailgintos net kelesde\u0161imt met\u0173.\r\nPrad\u017eioje 90-t\u0173j\u0173 knyg\u0105 pavie\u0161inti galima buvo po 25 metu nuo autoriaus mirties met\u0173, veliau tas laikotarpis buvo prailgintas iki 50 met\u0173, dabar tai jau 70 met\u0173.\r\n        Tai rai\u0161kia kad m\u016bs\u0173 tinklapyje nesurasite visos mokyklines literat\u016bros ir deja tai greitai nepasikeis. Pavyzd\u017eiui net 2020 metais galima bus publikuoti k\u016brinius: Marek H\u0142aska arba Witold Gombrowicz. Romana Kuncewiczowej publikuosime 2060, o Czes\u0142owo Mi\u0142oszo net 2075 metais.</p>\r\n        \r\n         <p>Autori\u0173 teisi\u0173 apribojimai apima tuo pa\u010d ir vertimus ir kritikos leidinius. Iki 2012 sausio 1-sijos laukiame kad pavie\u0161inti k\u016briny \u201eTestamentai\u201c Fransua Vilono ir kitus k\u016brinius ver\u010diamus Boy-\u017bele\u0144skio, o net iki 2068 metu \u201eMik\u0117 P\u016bkuotukas\u201c Milne'o ir kitus vertimus Irenos Tuwim. Neturime teises publikuoti \u012f\u017eang\u0173 ir pratarmi\u0173 para\u0161yt\u0173 autori\u0173, kurie mir\u0117 nema\u017eiau nei prie\u0161 70 met\u0173. Tod\u0117l kartais taikosi kad ka\u017ekoks k\u016brinys pasirodo Laisvojoje Literat\u016broje bet nuoroda kuri veda mus i Skaitmenin\u0117je Lenkijos Nacionalin\u0119 Bibliotek\u0105 \u201ePolona\u201c primena mums kad \u0161iam k\u016briniui galioja autoriaus teis\u0117s.\r\n      Tai rai\u0161kia kad tekstas priklauso internetinei svetainei ir tod\u0117l yra Laisvojoje Literat\u016broje, bet tai tik tai kriti\u0161kas leidinys, kuris yra  Skaitmenin\u0117s Lenkijos Nacionalin\u0117s Bibliotekos \u201ePolona\u201c nuosavybe (su \u012f\u017eanga, komentarais ir pana\u0161ai) su vis galiojan\u010dioms autoriu teisemis.</p>\r\n        \r\n         <p> Internetin\u0117 svetain\u0117 tai kult\u016bros dalis kuri\u0105 reik\u0119 r\u016bpintis ir kuri\u0105 reik\u0119 saugoti. Kult\u016bra tai statinys kuriame sekantys auk\u0161tai gali b\u016bti statyti tik ant solidus pagrindo, paruo\u0161to pirmtaki\u0173. Kochanowsky s\u0117m\u0117  i\u0161 antikin\u0117s tradicijos, Mickiev\u010dius ir s\u0117m\u0117 i\u0161 liaudies tradicij\u0173. Kiekviena karta ap\u017evelgia  daugiau, gali i\u0161dirbti savo bendrin\u0117 kalb\u0105 ir tvirtai \u012fsira\u0161yti \u012f literat\u016bros istorij\u0105 d\u0117ka pirmtaki\u0173 pasiekim\u0173. \r\nTod\u0117l taip svarbu yra Laisv\u0117 ir prieinamumas naudotis svarbiausiais pasauliniais literat\u016briniais k\u016brinias. Be internetin\u0117s svetain\u0117s ne\u012fmanoma butu t\u0105 pasiekti.</p>\r\n\r\n \r\n\r\n", 
+            "title_es": "Sobre el proyecto Wolne Lektury", 
+            "page_title_fr": "Sur le projet Lectures libres", 
+            "page_title_uk": "\u041f\u0440\u043e \u043f\u0440\u043e\u0435\u043a\u0442 Wolne Lektury", 
+            "page_title_de": "\u00dcber das Projekt \"Freie Lekt\u00fcren\"", 
+            "slug": "about_us", 
+            "page_title_lt": "Apie projekt\u00b9 Laisvoji Literatura", 
+            "right_column_de": "\ufeff<h2>\u00dcber die Stiftung</h2>\r\n\r\n        <p>Die Stiftung Modernes Polen  ist als Reaktion auf Bildungsfragen der Kinder entstanden. \r\n        Eine der wichtigsten Aufgaben, die das polnische Bildungssystem zu bew\u00e4ltigen hat, \r\n        ist der Kampf gegen den digitalen Ausschluss. Computer- und Internetkompetenz sind \r\n        elementare F\u00e4higkeiten, die in einer Informationsgesellschaft eine Wissensgrundlage bilden. \r\n        Diejenigen, die Probleme mit Computer- und Internetnutzung haben, sind zum Leben eines Outsiders verurteilt. </p>\r\n        \r\n     \r\n        \r\n         <p>Aus diesem Grunde helfen wir den Kindern seit 7 Jahren, die fortschrittlichen Technologien zu verstehen und zu nutzen. \r\n         Die Stiftung Modernes Polen m\u00f6chte Tausenden von Kindern das geben, was f\u00fcr ihre Entwicklung die h\u00f6chste Priorit\u00e4t hat: \r\n         Wissen und F\u00e4higkeiten, die zum besserem Weltverst\u00e4ndnis f\u00fchren.</p>        \r\n        \r\n       \r\n        \r\n         <p>Die Stiftung koordiniert \u2013 vom Projekt Freie Lekt\u00fcren abgesehen \u2013 auch das Projekt Freie Schulb\u00fccher, \r\n         das von Lehrer- und Volont\u00e4rgruppierungen unterst\u00fctzt wird. Unsere Kollegen arbeiten per Internet an neuen Schulb\u00fcchern, \r\n         die an polnische Sch\u00fcller adressiert sind. Freie Schulb\u00fccher werden unter freien Lizenzen ver\u00f6ffentlicht, also solchen, \r\n         die das kostenfreie Kopieren, Aktualisierungen und Verbreiten - ohne Erlaubnisanfrage der Autorengruppe - zulassen.  \r\n         Jeder Lehrer kann diese Schulb\u00fccher nach eigenem Ermessen vervollst\u00e4ndigen, verbreiten und korrigieren. \r\n         Dabei k\u00f6nnen die Kosten von lizenzfreien Printmedien deutlich gesenkt werden. Zugleich werden die digitalen Schulb\u00fccher \r\n         kostenlos zur Verf\u00fcgung gestellt.</p>\r\n\r\n        \r\n        <h2>\u00dcber die Public Domain</h2>\r\n        \r\n        <p>Auf der Plattform der Freien Lekt\u00fcren d\u00fcrfen jene B\u00fccher ver\u00f6ffentlicht werden, die der Public Domain angeh\u00f6ren. \r\n        Gemeint sind hier B\u00fccher, die keinem Uhrheberrecht mehr unterliegen. Publik Domain wird als eine Art von Kulturschatzkammer \r\n        angesehen, also ein Gemeingut, von dem alle mit gleichen Rechten, ohne jegliche Einschr\u00e4nkungen und v\u00f6llig kostenfrei profitieren k\u00f6nnen. \r\n        Das Vorhandensein der Public Domain wird zum Garant des freien Zugangs zu Kultursch\u00e4tzen. Die Nutzung von gemeinfreien \r\n        B\u00fcchern steht uns als B\u00fcrgerrecht zu und ist in der Verfassung verankert.</p>\r\n        \r\n        \r\n         <p>Obwohl hier der Grundsatz gilt, dass nach bestimmter Zeit alle Werke in die Public Domain gestellt werden d\u00fcrfen, \r\n         so wurde die Schutzfrist im polnischen Urheberrecht in den letzen Jahren wesentlich verl\u00e4ngert. Anfang der 90er Jahre \r\n         waren es 25 Jahre nach dem Tod des Urhebers, sp\u00e4ter wurde die Schutzfrist auf 50 Jahr verl\u00e4ngert, heute sind es schon 70 Jahre. \r\n         Dies hat zur Folge, dass viele Werke, die auf einer Ministerliste als Lekt\u00fcren verzeichnet sind, d\u00fcrfen \u00fcber \r\n         viele Jahre nicht ver\u00f6ffentlicht werden. Erst im Jahr 2020 d\u00fcrfen wir Werke von Marek H\u0142asko und Witold Gombrowicz ver\u00f6ffentlichen. \r\n         Die Werke von Kuncewiczow erscheinen in der Public Domain in 2060 und Poeme von Milosz in 2075.</p>\r\n        \r\n         <p>Unter den Schutz des Urheberrechts fallen kritische Ausgaben und \u00dcbersetzungen. Bis zum 1. Januar 2012 warten wir \r\n         auf \"Wielki Testament\" von Villon sowie andere Schriften, die von Boy-\u017bele\u0144ski \u00fcbersetzt wurden, und bis 2068 auf  \r\n         \"Kubu\u015b Puchatek\" von Milen und andere \u00dcbersetzungen von Julian Tuwim. Gem\u00e4\u00df dem Urheberschutzgesetz d\u00fcrfen wir \r\n         keine Einleitungen und Vorreden von Autoren ver\u00f6ffentlichen, nach deren Todesdatum keine 70 Jahre vergangen sind. \r\n         Es kann also passieren, dass ein bestimmtes Schriftst\u00fcck auf dem Portal der Freien Lekt\u00fcren verf\u00fcgbar ist, jedoch der link, \r\n         der auf die Quelldatei in digitaler Nationalbibliothek Polona verweist, f\u00fchr uns direkt zur Seite mit dem Kommentar: \r\n         Das urheberrechtlich gesch\u00fctzte Werk. Das bedeutet, dass obwohl das Werk in der Public Domain steht und deswegen \r\n         auf dem Portal Freie Lekt\u00fcren ver\u00f6ffentlicht ist, so ist dessen kritische Ausgabe, \u00fcber die DNB Polona verf\u00fcgt \r\n         (einschlie\u00dflich Einleitungen, Vorreden und Redakteurkommentaren) urheberrechtlich gesch\u00fctzt.</p>\r\n        \r\n       \r\n         <p>Um die Public Domain muss gesorgt werden. Kultur ist ein kunstvolles Bauwerk, dessen Stockwerke von seinen Vorg\u00e4nger \r\n         auf einem soliden Fundament gebaut wurden. Kochanowski sch\u00f6pfte aus der Antiktradition. Die Volkskunst war die Inspiration \r\n         f\u00fcr Mickiewicz sch\u00f6nste, polnische Gedichte. Jede kommende Generation kann noch weiterblicken, eigene literarische Sprache \r\n         schaffen und sich dank den Leistungen der Vorg\u00e4nger dauerhaft in die Literaturgeschichte einschreiben. Der freie Zugang \r\n         zu den wichtigsten Werken aus der polnisch- und fremdsprachigen Literatur ist deswegen so wichtig. Ohne Public Domain w\u00e4re \r\n         die Errichtung solch eines Kunstgeb\u00e4udes wie Literatur gar nicht m\u00f6glich.</p>\r\n        \r\n        \r\n        ", 
+            "page_title_pl": "O projekcie Wolne Lektury", 
+            "left_column_es": "<h2>Wolne Lektury</h2>\r\n\r\n        <p>La biblioteca virtual con lecturas \u201cWolne Lektury\u201d (www.wolnelektury.pl) es un proyecto realizado por la Fundaci\u00f3n Polonia Moderna. La Fundaci\u00f3n hab\u00eda comenzado su actividad en el a\u00f1o 2007 y est\u00e1 compartiendo las lecturas recomendadas por el Ministerio de la Educaci\u00f3n Nacional y que ya forman parte del dominio p\u00fablico. Las lecturas, elaboradas y comentadas, est\u00e1n disponibles en diferentes formatos (html, epub, mp3, ogg, odt, txt i pdf). Se las puede legal y gratuitamente leer, descargar, citar y compartir con otros.</p>\r\n\r\n        \r\n\r\n         <p>El equipo del proyecto Wolne Lektury consta de redactores y profesores con experiencia, que garantiza la fiabilidad de nuestra p\u00e1gina. Estamos cooperando con la Biblioteca Nacional que nos proporciona las mejores ediciones de las lecturas cl\u00e1sicas, que fueron publicadas en la Electr\u00f3nica Biblioteca Nacional Polona. Juntos queremos que las lecturas \u2013 nuestro patrimonio cultural \u2013 est\u00e9n disponibles para todos, independientemente de su lugar de residencia, posesiones materiales, eficiencia o su falta. Esto es posible gracias a la existencia del dominio p\u00fablico, es decir, una colecci\u00f3n de obras no cubiertas por el derecho de autor, y tambi\u00e9n gracias a las nuevas tecnolog\u00edas  \u2013 herramientas que permiten aumentar la disponibilidad del contenido publicado en internet. </p>\r\n\r\n        \r\n\r\n         <p>El proyecto Wolne Lektury es completamente no comercial y realizado pro publico bono. As\u00ed que el apoyo de los personajes excepcionales de la cultura y las ciencias es tan importante para nosotros. El Ministerio de la Cultura y Patrimonio Cultural y La Asociaci\u00f3n de Escritores Polacos tienen el patrocinio de honor sobre el proyecto Wolne Lektury.        \r\n\r\n       El Comit\u00e9 de Honor de Wolne Lektury re\u00fane a los profesores: Maria Janion, Gra\u017cyna Borkowska,  Przemys\u0142aw  Czapli\u0144ski, Mieczys\u0142aw D\u0105browski, Ewa Kraskowska, Ma\u0142gorzata Czermi\u0144ska,  Jerzy Jarz\u0119bski  y Piotr \u015aliwi\u0144ski.</p>\r\n\r\n\r\n\r\n        \r\n\r\n         <p>La Biblioteca Nacional de ocupa de la digitalizaci\u00f3n y correcci\u00f3n de los textos. La p\u00e1gina fue dise\u00f1ada\r\n\r\n        por 2ia. Dariusz Ga\u0142ecki es el autor del lenguaje de marcos de Wolne Lektury basado en el lenguaje XML. La oficina Grynhoff, Wo\u017any, Mali\u0144ski presta el servcio legal. El hosting de la p\u00e1gina lo proporciona EO Networks. En la edici\u00f3n t\u00e9cnica de los textos ayuda la editorial Korporacja Ha!Art. El logotipo de Wolne Lektury fue dise\u00f1ado por la agencia de publicidad PZL. El patrocinio medial: Dziennik, Elle, Tok.fm, Biblioteka Analiz, Tygodnik Powszechny, Przekr\u00f3j y TVP Kultura.</p>\r\n\r\n        \r\n\r\n        <h2>\u00bfC\u00f3mo usar Wolne Lektury?</h2>\r\n\r\n        \r\n\r\n         <p>La innovaci\u00f3n m\u00e1s importante de Wolne Lektury, que distingue este proyecto de otras bibliotecas virtuales, es la posibilidad de buscar los textos usando varios criterios: tradicionales, como el t\u00edtulo, el autor,\r\n\r\n       la \u00e9poca, el subg\u00e9nero; pero tambi\u00e9n los que no se puede encontrar en otras bibliotecas, es decir los que se pueden aplicar a varias\r\n\r\n        obras \u2013 los motivos y temas literarios. Este tipo de b\u00fasqueda es posible gracias a la preparaci\u00f3n especial \r\n\r\n        de las lecturas, su la descripci\u00f3n a trav\u00e9s de los criterios anteriormente mencionados. Es el rasgo caracter\u00edstico de Wolne Lektury que lo distingue de otras p\u00e1ginas en las que aparecen res\u00famenes de lecturas. Nuestro servicio proporciona instrumentos para trabajo creativo con el texto y no res\u00famenes hechos. Si el estudiante tiene que escribir un trabajo: \u201cEl motivo del ni\u00f1o en el romanticismo bas\u00e1ndose en obras elegidas\u201d, basta con s\u00f3lo tres clics en nuestra p\u00e1gina para ver una colecci\u00f3n de textos para analizar. Gracias a aquellos instrumentos la lectura se puede convertir en un viaje fascinante por el mundo de la cultura. </p>\r\n\r\n        \r\n\r\n         <p>Otra funci\u00f3n de Wolne Lektury, \u00fatil en el trabajo en la escuela, es la posibilidad de completar colecciones de textos que la clase leer\u00e1 durante el a\u00f1o. Aquellos estantes con lecturas pueden ser creados por el profesor y luego compartidos con sus estudiantes. Los estudiantes, con un solo clic, podr\u00e1n descargar todas las lecturas a sus ordenadores. </p>\r\n\r\n        \r\n\r\n        <p> Ninguno de los textos en Wolne Lektury (en formatos: html, pdf, epub, txt) est\u00e1 cubierto por el derecho de autor de all\u00ed que se les pueda usar libremente.  </p>\r\n\r\n\r\n\r\n        <p>Si un texto contiene materiales adicionales (notas a pie de p\u00e1gina, motivos literarios etc.) que est\u00e1n cubiertos por el derecho de autor, estos materiales est\u00e1n publicados bajo la licencia Creative Commons Reconocimiento-Compartir bajo la misma licencia 3.0 (<a href=\"http://creativecommons.org/licenses/by-sa/3.0/deed.es/\">http://creativecommons.org/licenses/by-sa/3.0/deed.es/</a>).</p>", 
+            "left_column_en": "<h2>Wolne Lektury</h2>\r\n    \r\n        <p>Web library with the school obligatory readings \"Wolne Lektury\" (www.wolnelektury.pl) is a project carried out by Modern Poland Foundation. Wolne Lektury website works since 2007. It provides the visitors with the school readings recommended Ministerstwo Edukacji Narodowej which entered the public domain.  The literary works are drawn up, annotated and available in several formats (html, epub, mp3, ogg, odt, txt and pdf). Under the Polish law, they can be read online, downloaded, cited and shared.</p>\r\n <p>Wolne Lektury project team comprises experienced editors and teachers so that our website content is solid and reliable. To create it, we cooperate with National Library which provides us with the best available editions of the books as well as the critical studies of the school readings, published in Digital National Library Polona. Together we try our best to make the texts of the books (our cultural legacy) available for everyone, regardless of where one is living, how much money does one have or whether one is handicapped or not. It is possible only due to the public domain concept, meaning a collection of literary works that are not copyrighted, as well as high technologies - tools that let us increase availability of the text published on the Internet.</p>\r\n  <p>Wolne Lektury project is completely uncommercial and it is carried out pro publico bono. Therefore the support of the eminent personages conncted with culture and sciences is very important for us. Wolne Lektury project is held under the honorary patronage of Ministerstwo Kultury i Dziedzictwa Narodowego, Ministerstwo Edukacji Narodowej and Polish Writers Association. In the Honorary Comitee of Wolne Lektury agreed to sit Professor Maria\r\n Janion, Professor Gra\u017cyna Borkowska, Professor Przemys\u0142aw\r\n Czapli\u0144ski, Professor Mieczys\u0142aw D\u0105browski, Professor Ewa Kraskowska, Professor Ma\u0142gorzata Czermi\u0144ska, Professor Jerzy Jarz\u0119bski\r\n  and Professor Piotr \u015aliwi\u0144ski.</p>\r\n\r\n <p>Digitalisation and proofreading is provided by the National Library. The website was designed by 2ia. The author of the programming language of the repository of Free Literature texts, based on the XML language is Dariusz Ga\u0142ecki. Grynhoff, Wo\u017any, Mali\u0144ski office provides us with the legal service. Web hosting is provided by EO Networks company. Publishing house Korporacja Ha!Art helps us in proofreading. The logo of Wolne Lektury is a creation of PZL agency.  The project is held under media patronage of: Dziennik, Elle, Tok.fm, Biblioteka Analiz,\r\n Tygodnik Powszechny, Przekr\u00f3j and TVP Kultura.</p>\r\n        \r\n    \r\n\r\n\r\n\r\n\r\n\r\n<h2>How should I use Wolne Lektury?</h2> <p>The most imporant innovation of Wolne Lektury that distinguishes this project from the others is the possibility of searching for the texts with the application of variety of criteria: traditional ones, such as the title, author, period, form and genre, as well as unusual ones, concerning many literary works at once, i.e. literary motifs and themes. This kind of serch is faesible due to special preparation of the books as they are now described with the parameters mentioned above. It is the element that differs Wolne Lektury  from the other editions of school readings. Wolne Lektury webiste provides the reader with devices that come in handy in when creative thinking is needed  whereas some editions of the readings are simply cribs. For instance, if a student is asked to prepare an essay on topic \"The child in Romantic literature\", when searching our website, he only must mouse-click three times to find a collection of necessary texts.  Due to this kind of tools reading books changes into fascinatng journey into the world of culture.</p>\r\n <p>Another useful function of Wolne Lektury that comes in handy when at home or at school is the possibility of combining the texts that are discussed during the school year into a list. The lists are called bookshelves and they are created by a teacher. Next the teacher may send the adequate hyperlink to his pupils and they can download the complete set of readings with one mouse click.</p>\r\n  <p>Every literary work available on Wolne Lektury website (in html, pdf, epub, txt formats) is not covered by copyright law and can be freely used with no legal consequences. </p>\r\n\r\n        <p>If the texts are provided with some extra materials (annotations, motifs) which are copyrighted, then the extras are accesible under Creative Commons Attribution - Share Alike 3.0 PL licence(<a href=\"http://creativecommons.org/licenses/by-sa/3.0/\">http://creativecommons.org/licenses/by-sa/3.0/</a>).</p>", 
+            "title_pl": "O projekcie Wolne Lektury", 
+            "title_ru": "\u041e \u043f\u0440\u043e\u0435\u043a\u0442\u0435 Wolne Lektury", 
+            "page_title_ru": "\u041e \u043f\u0440\u043e\u0435\u043a\u0442\u0435 Wolne Lektury"
+        }
+    }, 
+    {
+        "pk": 2, 
+        "model": "infopages.infopage", 
+        "fields": {
+            "title_de": "\ufeffDu kannst uns helfen", 
+            "page_title": "You can help us on WolneLektury.pl", 
+            "left_column_uk": "<h2>\u0412\u043e\u043b\u043e\u043d\u0442\u0435\u0440\u0441\u0442\u0432\u043e</h2>\r\n\r\n\r\n\r\n <p>\u041c\u0438 \u043d\u0430\u043c\u0430\u0433\u0430\u0454\u043c\u043e\u0441\u044f \u044f\u043a\u043e\u043c\u043e\u0433\u0430 \u043a\u0440\u0430\u0449\u0435 \u043f\u0456\u0434\u0433\u043e\u0442\u0443\u0432\u0430\u0442\u0438 \u0442\u0432\u043e\u0440\u0438, \u044f\u043a\u0456 \u043f\u043e\u0441\u0442\u0443\u043f\u043e\u0432\u043e \u0434\u043e\u0434\u0430\u044e\u0442\u044c\u0441\u044f \u0434\u043e \u043d\u0430\u0448\u043e\u0457 \u0431\u0456\u0431\u043b\u0456\u043e\u0442\u0435\u043a\u0438. \u0426\u0435 \u043c\u043e\u0436\u043b\u0438\u0432\u043e \u0442\u0456\u043b\u044c\u043a\u0438 \u0437\u0430\u0432\u0434\u044f\u043a\u0438 \u043d\u0430\u0448\u0438\u043c \u0432\u043e\u043b\u043e\u043d\u0442\u0435\u0440\u0430\u043c.</p>\r\n\r\n\r\n\r\n \r\n\r\n <p>\u0417\u0430\u043f\u0440\u043e\u0448\u0443\u0454\u043c\u043e \u0443\u0441\u0456\u0445, \u0445\u0442\u043e \u0445\u043e\u0447\u0435 \u0434\u043e\u043f\u043e\u043c\u043e\u0433\u0442\u0438 \u0443 \u0442\u0432\u043e\u0440\u0435\u043d\u043d\u0456 \u0448\u043a\u0456\u043b\u044c\u043d\u043e\u0457 \u0456\u043d\u0442\u0435\u0440\u043d\u0435\u0442-\u0431\u0456\u0431\u043b\u0456\u043e\u0442\u0435\u043a\u0438 Wolne Lektury.</p>\r\n\r\n \r\n\r\n <p>\u0412\u0441\u0456\u043c \u0432\u043e\u043b\u043e\u043d\u0442\u0435\u0440\u0430\u043c \u043c\u0438 \u043f\u0440\u043e\u043f\u043e\u043d\u0443\u0454\u043c\u043e \u0442\u0440\u0435\u043d\u0456\u043d\u0433\u0438 \u0456 \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u043d\u0438\u0439 \u0434\u043e\u0441\u0432\u0456\u0434 \u043e\u0431\u0440\u043e\u0431\u043a\u0438 \u0442\u0435\u043a\u0441\u0442\u0443: \u0437\u043c\u0456\u0441\u0442\u043e\u0432\u043d\u0435 \u0442\u0430 \u0442\u0435\u0445\u043d\u0456\u0447\u043d\u0435 \u0440\u0435\u0434\u0430\u0433\u0443\u0432\u0430\u043d\u043d\u044f. \u0412\u043e\u043b\u043e\u043d\u0442\u0435\u0440\u0438 \u043c\u043e\u0436\u0443\u0442\u044c \u043e\u0437\u043d\u0430\u0439\u043e\u043c\u0438\u0442\u0438\u0441\u044f \u0437 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430\u043c\u0438 \u0442\u0430 \u043c\u043e\u0436\u043b\u0438\u0432\u043e\u0441\u0442\u044f\u043c\u0438, \u043f\u043e\u0432\u2019\u044f\u0437\u0430\u043d\u0438\u043c\u0438 \u0437 \u0456\u043d\u0442\u0435\u0440\u043d\u0435\u0442-\u043f\u0443\u0431\u043b\u0456\u043a\u0430\u0446\u0456\u044f\u043c\u0438.\r\n\r\n \u0421\u043f\u0456\u043b\u044c\u043d\u043e \u0437 \u043d\u0430\u043c\u0438 \u0432\u043e\u043b\u043e\u043d\u0442\u0435\u0440\u0438 \u043e\u0440\u0433\u0430\u043d\u0456\u0437\u0443\u044e\u0442\u044c \u0442\u0440\u0435\u043d\u0456\u043d\u0433\u0438 \u0442\u0430 \u043a\u043e\u043d\u0444\u0435\u0440\u0435\u043d\u0446\u0456\u0457, \u0434\u043e\u043f\u043e\u043c\u0430\u0433\u0430\u044e\u0442\u044c \u0432 \u043f\u0456\u0434\u0433\u043e\u0442\u043e\u0432\u043b\u0435\u043d\u043d\u0456 \u0442\u0435\u043a\u0441\u0442\u0456\u0432 \u0434\u043b\u044f \u0441\u043b\u0443\u0445\u0430\u043d\u043d\u044f (\u0442\u0430\u043a \u0437\u0432\u0430\u043d\u0438\u0445 \u0430\u0443\u0434\u0456\u043e-\u043a\u043d\u0438\u0433). \u041c\u0438 \u043f\u0456\u0434\u043f\u0438\u0441\u0443\u0454\u043c\u043e \u0437 \u0432\u043e\u043b\u043e\u043d\u0442\u0435\u0440\u0430\u043c\u0438 \u0443\u0433\u043e\u0434\u0438 \u0442\u0430 \u043d\u0430\u0434\u0430\u0454\u043c\u043e \u0457\u043c \u043f\u043e\u0441\u0432\u0456\u0434\u0447\u0435\u043d\u043d\u044f \u043f\u0440\u043e \u0446\u0435 \u043a\u043e\u043b\u0438 \u0456 \u044f\u043a\u0456 \u043f\u0440\u0430\u0446\u0456 \u0432\u0438\u043a\u043e\u043d\u0443\u0432\u0430\u0432 \u0434\u043b\u044f \u043d\u0430\u0448\u043e\u0433\u043e \u0444\u043e\u043d\u0434\u0443 \u0432\u043e\u043b\u043e\u043d\u0442\u0435\u0440. \u0422\u0440\u0435\u043d\u0456\u043d\u0433\u0438, \u0434\u043e\u0441\u0432\u0456\u0434 \u0440\u0435\u0434\u0430\u0433\u0443\u0432\u0430\u043d\u043d\u044f \u0442\u0430 \u0441\u0435\u0440\u0442\u0438\u0444\u0456\u043a\u0430\u0442\u0438, \u044f\u043a\u0456 \u0446\u0435 \u0437\u0430\u0441\u0432\u0456\u0434\u0447\u0443\u044e\u0442\u044c, \u043c\u043e\u0436\u0443\u0442\u044c \u0431\u0443\u0442\u0438 \u0446\u0456\u043d\u043d\u0438\u043c\u0438 \u0432 \u043f\u0440\u043e\u0446\u0435\u0441\u0456 \u043f\u0456\u0434\u0432\u0438\u0449\u0435\u043d\u043d\u044f \u043a\u0432\u0430\u043b\u0456\u0444\u0456\u043a\u0430\u0446\u0456\u0439 \u0456 \u043f\u0440\u043e\u0444\u0435\u0441\u0456\u0439\u043d\u0456\u0439 \u043a\u0430\u0440'\u0454\u0440\u0456.</p>\r\n\r\n\r\n\r\n \r\n\r\n <h2>\u0429\u043e \u043c\u043e\u0436\u043d\u0430 \u0440\u043e\u0431\u0438\u0442\u0438?</h2>\r\n\r\n \r\n\r\n <p>\u041d\u0430\u0439\u0431\u0456\u043b\u044c\u0448\u0435 \u0440\u043e\u0431\u043e\u0442\u0438 \u043f\u0440\u0438\u0441\u0432\u044f\u0447\u0443\u0454\u0442\u044c\u0441\u044f \u043f\u0456\u0434\u0433\u043e\u0442\u043e\u0432\u043b\u0435\u043d\u043d\u044e \u0442\u0435\u043a\u0441\u0442\u0443 \u0434\u043b\u044f \u043f\u0443\u0431\u043b\u0456\u043a\u0430\u0446\u0456\u0457. \u0412 \u0442\u0435\u043a\u0441\u0442\u0456, \u044f\u043a\u0438\u0439 \u043c\u0438 \u043e\u0442\u0440\u0438\u043c\u0443\u0454\u043c\u043e \u0432\u0456\u0434 \u041d\u0430\u0446\u0456\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0457 \u0431\u0456\u0431\u043b\u0456\u043e\u0442\u0435\u043a\u0438 \u0442\u0440\u0435\u0431\u0430 \u0432\u0438\u043f\u0440\u0430\u0432\u0438\u0442\u0438 \u043e\u0440\u0444\u043e\u0433\u0440\u0430\u0444\u0456\u0447\u043d\u0456 \u0442\u0430 \u0456\u043d\u0448\u0456 \u043c\u0435\u0445\u0430\u043d\u0456\u0447\u043d\u0456 \u043f\u043e\u043c\u0438\u043b\u043a\u0438, \u0430 \u043f\u043e\u0442\u0456\u043c \u0434\u043e\u0434\u0430\u0442\u0438 \u0432 \u0442\u0435\u043a\u0441\u0442\u0456 \u043f\u0440\u0438\u043c\u0456\u0442\u043a\u0438, \u043f\u0430\u043c\u2019\u044f\u0442\u0430\u044e\u0447\u0438 \u043f\u0440\u043e \u0446\u0435, \u0449\u043e \u043d\u0430\u0448\u0430 \u043f\u0440\u043e\u043f\u043e\u0437\u0438\u0446\u0456\u044f \u0441\u043a\u0435\u0440\u043e\u0432\u0430\u043d\u0430 \u043f\u0435\u0440\u0448 \u0437\u0430 \u0432\u0441\u0435 \u0434\u043e \u0443\u0447\u043d\u0456\u0432, \u0434\u043b\u044f \u044f\u043a\u0438\u0445 \u0431\u0430\u0433\u0430\u0442\u043e \u0441\u043b\u0456\u0432 \u0442\u0430 \u0444\u0440\u0430\u0437 \u0437\u0432\u0443\u0447\u0430\u0442\u0438\u043c\u0435 \u0430\u043d\u0430\u0445\u0440\u043e\u043d\u0456\u0447\u043d\u043e. \u0414\u0430\u0432\u043d\u0456\u0448\u0456 \u043f\u0443\u0431\u043b\u0456\u043a\u0430\u0446\u0456\u0457 (\u0432\u0441\u0435 \u0437\u0430\u043b\u0435\u0436\u0438\u0442\u044c \u0442\u0443\u0442 \u0432\u0456\u0434 \u0430\u0432\u0442\u043e\u0440\u0441\u044c\u043a\u043e\u0433\u043e \u043f\u0440\u0430\u0432\u0430) \u043f\u0456\u0434\u0434\u0430\u044e\u0442\u044c\u0441\u044f \u043d\u0435\u043e\u0431\u0445\u0456\u0434\u043d\u043e\u043c\u0443 \u043c\u043e\u0432\u043d\u043e\u043c\u0443 \u043e\u0441\u0443\u0447\u0430\u0441\u043d\u0435\u043d\u043d\u044e, \u043d\u0430 \u043f\u0440\u0438\u043a\u043b\u0430\u0434 \u0449\u043e\u0434\u043e \u043f\u0440\u0430\u0432\u043e\u043f\u0438\u0441\u0443 \u0447\u0438 \u0444\u043b\u0435\u043a\u0441\u0456\u0457, \u043f\u0440\u0438 \u0447\u043e\u043c\u0443 \u043c\u0438 \u0434\u0431\u0430\u0454\u043c\u043e \u043f\u0440\u043e \u0446\u0435 \u0449\u043e\u0431 \u043d\u0435 \u043f\u043e\u0440\u0443\u0448\u0443\u0432\u0430\u0442\u0438 \u0430\u0440\u0442\u0438\u0441\u0442\u0438\u0447\u043d\u043e\u0433\u043e \u0445\u0430\u0440\u0430\u043a\u0442\u0435\u0440\u0443 \u0442\u0435\u043a\u0441\u0442\u0443. \u041e\u0441\u0442\u0430\u043d\u043d\u0456\u043c \u0435\u0442\u0430\u043f\u043e\u043c \u0454 \u043f\u043e\u0448\u0443\u043a \u043b\u0456\u0442\u0435\u0440\u0430\u0442\u0443\u0440\u043d\u0438\u0445 \u043c\u043e\u0442\u0438\u0432\u0456\u0432 \u0442\u0430 \u0442\u0435\u043c, \u044f\u043a\u0456 \u043c\u0430\u044e\u0442\u044c \u0434\u043e\u043f\u043e\u043c\u043e\u0433\u0442\u0438 \u0432 \u0433\u043b\u0438\u0431\u0438\u043d\u043d\u043e\u043c\u0443 \u043f\u0456\u0437\u043d\u0430\u043d\u043d\u0456 \u043b\u0456\u0442\u0435\u0440\u0430\u0442\u0443\u0440\u0438. \u0412 \u0443\u0441\u0456\u0445 \u0446\u0438\u0445 \u043f\u0440\u0430\u0446\u044f\u0445 \u043d\u0430\u0441 \u043f\u0456\u0434\u0442\u0440\u0438\u043c\u0443\u044e\u0442\u044c \u0432\u043e\u043b\u043e\u043d\u0442\u0435\u0440\u0438 - \u0432\u0447\u0438\u0442\u0435\u043b\u0456 \u0442\u0430 \u0441\u0442\u0443\u0434\u0435\u043d\u0442\u0438 - \u044f\u043a\u0456 \u0447\u0430\u0441\u0442\u043e \u0434\u043e\u043f\u043e\u043c\u0430\u0433\u0430\u044e\u0442\u044c \u0442\u0430\u043a\u043e\u0436 \u043f\u043e\u0440\u0430\u0434\u043e\u044e \u0442\u0430 \u0437\u0430\u0443\u0432\u0430\u0436\u0435\u043d\u043d\u044f\u043c\u0438 \u043f\u0440\u0438 \u043f\u0440\u0438\u0439\u043d\u044f\u0442\u0442\u0456 \u0432\u0430\u0436\u043b\u0438\u0432\u0438\u0445 \u0440\u0456\u0448\u0435\u043d\u044c.</p>\r\n\r\n \r\n\r\n <h2>\u042f\u043a \u0434\u043e \u043d\u0430\u0441 \u0437\u0433\u043e\u043b\u043e\u0441\u0438\u0442\u0438\u0441\u044f?</h2>\r\n\r\n \r\n\r\n <p>\u0423\u0441\u0456\u0445 \u0437\u0430\u0446\u0456\u043a\u0430\u0432\u043b\u0435\u043d\u0438\u0445 \u043f\u0440\u043e\u0441\u0438\u043c\u043e \u0432\u0438\u0441\u043b\u0430\u0442\u0438 \u043b\u0438\u0441\u0442\u0430 \u043d\u0430 \u0430\u0434\u0440\u0435\u0441\u0443 <a href=\"mail:fundacja@nowoczesnapolska.org.pl\">fundacja@nowoczesnapolska.org.pl</a>.</p>\r\n\r\n\r\n\r\n <p>\u0417\u0430\u043f\u0440\u043e\u0448\u0443\u0454\u043c\u043e \u0442\u0430\u043a\u043e\u0436 \u043d\u0430 <a href=\"http://redmine.nowoczesnapolska.org.pl/projects/wl-publikacje\">\u0441\u0430\u0439\u0442 \u0440\u0435\u0434\u0430\u043a\u0446\u0456\u0457 Wolne Lektury</a>, \u0434\u0435 \u043c\u043e\u0436\u043d\u0430 \u0437\u043d\u0430\u0439\u0442\u0438 \u0443\u0441\u044e \u043d\u0435\u043e\u0431\u0445\u0456\u0434\u043d\u0443 \u0456\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0456\u044e \u043f\u0440\u043e \u0446\u0435, \u044f\u043a \u0437\u0430\u043b\u0443\u0447\u0438\u0442\u0438\u0441\u044c \u0443 \u0440\u0435\u0434\u0430\u043a\u0446\u0456\u0439\u043d\u0443 \u0440\u043e\u0431\u043e\u0442\u0443.</p>", 
+            "right_column_pl": "<h2>Najbardziej zas\u0142u\u017ceni wolontariusze</h2>\r\n\r\n\t<h3>Agatapaszkowska (wsp\u00f3\u0142pracuje z nami od 15 marca 2008)</h3>\r\n\r\n        <p>m.in. opracowywa\u0142a \u201eW pustyni i w puszczy\u201d Sienkiewicza ; zob. te\u017c na naszej stronie \u201ewk\u0142ad u\u017cytkownika\u201d: <a href=\"http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Agatapaszkowska\">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Agatapaszkowska</a></p>\r\n\r\n\t<h3>AgnieszkaKappa (wsp\u00f3\u0142pracuje z nami od 16 marca 2008)</h3>\r\n\r\n        <p>m.in. bra\u0142a udzia\u0142 w tworzeniu listy i opisie u\u017cycia motyw\u00f3w i temat\u00f3w literackich; opracowywa\u0142a teksty Sienkiewicza (Latarnik, Janko Muzykant, Quo vadis); zob. te\u017c na naszej stronie \u201ewk\u0142ad u\u017cytkownika\u201d: <a href=\"http://wiki.wolnepodreczniki.pl/index.php?title=Specjalna:Wk%C5%82ad&amp;limit=500&amp;target=AgnieszkaKappa\">http://wiki.wolnepodreczniki.pl/index.php?title=Specjalna:Wk%C5%82ad&amp;limit=500&amp;target=AgnieszkaKappa</a></p>\r\n\r\n\r\n        <h3>Anerys (wsp\u00f3\u0142pracuje z nami od 5 lipca 2007)</h3>\r\n\r\n        <p>m.in. bra\u0142a udzia\u0142 w tworzeniu listy motyw\u00f3w i temat\u00f3w literackich, dyskusji o gatunkach literackich, opracowywa\u0142a Bogurodzic\u0119, \u201eFraszki\u201d i \u201eTreny\u201d Kochanowskiego; wiersze S\u0142owackiego (Gr\u00f3b Agamemnona), \u201e\u015awi\u0119toszka\u201d Moliere'a, czy poezje Kasprowicza (w tym hymn \u201eDies Irae\u201d); zob. te\u017c na naszej stronie \u201ewk\u0142ad u\u017cytkownika\u201d: <a href=\"http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Anerys\">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Anerys</a></p>\r\n\r\n\r\n\t<h3>EmiliaZdankiewicz (wsp\u00f3\u0142pracuje z nami od 17 marca 2008)</h3>\r\n\r\n        <p>m.in. motywy literackie dyskusja i opisywanie, S\u0142owacki, Kordian; Konopnicka, Nasza szkapa; Mickiewicz, Dziady cz. III; zob. te\u017c na naszej stronie \u201ewk\u0142ad u\u017cytkownika\u201d: <a href=\"http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/EmiliaZdankiewicz\">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/EmiliaZdankiewicz</a></p>\r\n\r\n\r\n\t<h3>Ewa_Serafin (wsp\u00f3\u0142pracuje z nami od 15 marca 2008)</h3>\r\n\r\n        <p>m.in. bra\u0142a udzia\u0142 w tworzeniu listy i opisie u\u017cycia motyw\u00f3w i temat\u00f3w literackich, opracowywa\u0142a poezje Kasprowicza (\u201eZ wichr\u00f3w i hal\u201d, \u201eNad przepa\u015bciami\u201d, \u201eW ciemno\u015bci schodzi moja dusza\u201d oraz \u201eNad Niemnem\u201d Orzeszkowej; zob. te\u017c na naszej stronie \u201ewk\u0142ad u\u017cytkownika\u201d: <a href=\"http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Ewa_Serafi\">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Ewa_Serafi</a>n</p>\r\n\r\n\r\n    \t<h3>Hanna_Golab (wsp\u00f3\u0142pracuje z nami od 15 marca 2008)</h3>\r\n\r\n        <p>opracowywa\u0142a \u201eKr\u00f3la Edypa\u201d Sofoklesa oraz \u201eDusio\u0142ka\u201d Le\u015bmiana; zob. te\u017c na naszej stronie \u201ewk\u0142ad u\u017cytkownika\u201d: <a href=\"http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Hanna_Golab\">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Hanna_Golab</a></p>\r\n\r\n\t<h3>Ingene (wsp\u00f3\u0142pracuje z nami od 16 lipca 2008)</h3>\r\n\r\n        <p>m.in. opracowywa\u0142a \u201eSi\u0142aczk\u0119\u201d \u017beromskiego, \u201eQuo vadis\u201d Sienkiewicza oraz \u201eTreny\u201d Kochanowskiego; zob. te\u017c na naszej stronie \u201ewk\u0142ad u\u017cytkownika\u201d: <a href=\"http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Ingene\">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Ingene</a></p>\r\n    \r\n\t<h3>Jmyszkowska (wsp\u00f3\u0142pracuje z nami od 26 marca 2008)</h3>\r\n\r\n        <p>m. in. opracowywa\u0142a \u201eGiaura\u201d Byrona oraz \u201eQuo vadis\u201d Sienkiewicza; zob. te\u017c na naszej stronie \u201ewk\u0142ad u\u017cytkownika\u201d: <a href=\"http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Jmyszkowska\">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Jmyszkowska</a></p>\r\n\r\n\r\n        <h3>Marysiabailey (wsp\u00f3\u0142pracuje z nami od 1 pa\u017adziernika 2007)</h3>\r\n\r\n        <p>m.in. bra\u0142a udzia\u0142 w tworzeniu listy motyw\u00f3w i temat\u00f3w literackich oraz opisywaniu ich u\u017cycia; opracowywa\u0142a \u201eCh\u0142op\u00f3w\u201d Reymonta, \u201eLalk\u0119\u201d Prusa, \u201eNie-Bosk\u0105 komedi\u0119\u201d Krasi\u0144skiego, \u201eBajki\u201d i \u201eSatyry\u201d Krasickiego, \u201eAntygon\u0119\u201d Sofoklesa oraz utwory Kochanowskiego, Morsztyna, Mickiewicza, Kasprowicza, Goethego, Oppmana, Kasprowicza; zob. te\u017c na naszej stronie \u201ewk\u0142ad u\u017cytkownika\u201d: <a href=\"http://wiki.wolnepodreczniki.pl/index.php?title=Specjalna:Wk%C5%82ad&amp;limit=500&amp;target=Marysiabailey\">http://wiki.wolnepodreczniki.pl/index.php?title=Specjalna:Wk%C5%82ad&amp;limit=500&amp;target=Marysiabailey</a>; ponadto przygotowywa\u0142a i prowadzi\u0142a szkolenie dla wolontariuszy 15 marca 2008; zajmowa\u0142a si\u0119 proofreadingiem, a obecnie kieruje pracami nad audiobookami.</p>\r\n\r\n\r\n        <h3>Olga_Wojtczak (wsp\u00f3\u0142pracuje z nami od 21 pa\u017adziernika 2008)</h3>\r\n\r\n        <p>m.in. opracowywa\u0142a powie\u015bci Sienkiewicza (Trylogia), Reymonta, \u017beromskiego, dramaty Shakespeare'a; zob. te\u017c na naszej stronie \u201ewk\u0142ad u\u017cytkownika\u201d: <a href=\"http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Olga_Wojtczak\">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Olga_Wojtczak</a></p>\r\n\r\n\r\n        <h3>Renataml (wsp\u00f3\u0142pracuje z nami od 30 czerwca 2007)</h3>\r\n\r\n        <p>bra\u0142a udzia\u0142 w dyskusji na temat listy motyw\u00f3w, wspomaga\u0142a nas radami jako do\u015bwiadczona nauczycielka, edytowa\u0142a \u201eLalk\u0119\u201d Prusa, \u201eBalladyn\u0119\u201d S\u0142owackiego, \u201eSi\u0142aczk\u0119\u201d \u017beromskiego.\r\n\r\n        <a href=\"http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Renataml\">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Renataml</a></p>\r\n", 
+            "page_title_en": "You can help us on WolneLektury.pl", 
+            "page_title_es": "\ufeffPuedes ayudarnos en WolneLektury.pl", 
+            "left_column_lt": "<h2>Savanori\u0161ka veikla</h2>\r\n\r\n        <p>D\u0117ka savanori\u0173 k\u016brini\u0173 apra\u0161ymai, kurie yra \u012fjungiami \u012f m\u016bs\u0173 bibliotek\u0105 yra kiekvien\u0105 kart\u0105 kruop\u0161\u010diai paruo\u0161iami.</p>\r\n        \r\n       \r\n        <p>Kvie\u010diame visus, kurie nori kartu su mumis kurti mokykline internetine bibliotek\u0105 Laisvoji Literat\u016bra.</p>\r\n              \r\n        <p>Visiem savanoriams teikiame apmokym\u0105 ir praktik\u0105 suri\u0161ta su teksto editavimu: techninis ir esminis teksto redagavimas. \r\n        Savanoriai gali susipa\u017einti su problemom suri\u0161tomis su teksto platinimu internete, bet ir su galimybe juos i\u0161ri\u0161ti.\r\n        Savanoriai padeda mums organizuoti apmokymus ir konferencijas, taip pat padeda paruo\u0161ti knyg\u0173 garso \u012fra\u0161us (taip vadinamos: audio knygos). \r\n       Kiekvienam savanoriui kuris nori parvirtimo bei paliudijimo, kad dirbo (ir k\u0105 veik\u0117) m\u016bs\u0173 fonde, suteikiame tokia galimyb\u0119.\r\n        Apmokymai, praktika ir paliudijimas gali prisid\u0117ti prie darbo kvalifikacij\u0173 pak\u0117limo.</p>\r\n\r\n        <h2>K\u0105 dar galima padaryti?</h2>\r\n        \r\n        <p>Daug darbo yra ruo\u0161iant mokyklin\u0119 literat\u016br\u0105 leidimui. Perdirbti reikia tekst\u0105, kuri gauname i\u0161  Lenkijos Nacionalines\r\n         Bibliotekos reikia pa\u0161alinti korekt\u016bros ir kitas klaidas, o veliau sukurti i\u0161na\u0161as, vis\u0105 laik\u0105 reikia tur\u0117ti omeny kad \r\n         m\u016bs\u0173 svetain\u0119 aplanko da\u017eniausiai jaunimas ir visu pirma jiems tekstas turi b\u016bti \u012fdomus. \r\n        Ankstesnieji knyg\u0173 ledinei turi pereiti kalbos modernizacij\u0105 (tai diktuoja autori\u0173 teis\u0117s) pvz.: ra\u0161ybos ar kaitybos kartu \r\n        raikia stengtis kad nepa\u017eeisti menini\u0173 teksto savybi\u0173. Paskutinis etapas tai ie\u0161kojimas literat\u016brini\u0173 motyv\u0173 ir tem\u0173\r\n        kurie per\u017eiures kuriny perd\u0117m. Visuose \u0161iouse darbuose rame mus savanoriai  - mokytojai ir studentai - da\u017enai pataria atkreipia d\u0117mesy, padeda nuspr\u0119sti.</p>\r\n        \r\n        <h2>Kaip prie m\u016bs prisijungti?</h2>\r\n        \r\n        <p>Susidomejusius kvie\u010diame ra\u0161yti: e-pa\u0161tas <a href=\"mail:fundacja@nowoczesnapolska.org.pl\">fundacja@nowoczesnapolska.org.pl</a>.</p>\r\n\r\n        <p>Kvie\u010diame tai pat aplankyti  <a href=\"http://redmine.nowoczesnapolska.org.pl/projects/wl-publikacje\">redakcijos Laisvoji Literatura tinklap\u012f</a>, \r\n        kur galim surasti visas raikalingas \u017einias apie tai kaip prisijungi i redakciny darb\u0105.</p>", 
+            "title_fr": "Vous pouvez nous aider", 
+            "right_column_ru": "<h2>\u0421\u0430\u043c\u044b\u0435 \u0434\u043e\u0441\u0442\u043e\u0439\u043d\u044b\u0435 \u0432\u043e\u043b\u043e\u043d\u0442\u0435\u0440\u044b</h2>\r\n\r\n\t<h3>Agatapaszkowska (\u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u0447\u0430\u0435\u0442 \u0441 \u043d\u0430\u043c\u0438 \u0441 15 \u043c\u0430\u0440\u0442\u0430 2008)</h3>\r\n\r\n        <p>\u0441\u0440\u0435\u0434\u0438 \u0434\u0440\u0443\u0433\u0438\u0445 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u043b\u0430 \u201e\u0412 \u043f\u0443\u0441\u0442\u044b\u043d\u0435 \u0438 \u043f\u0443\u0449\u0435\u201d \u0421\u0435\u043d\u043a\u0435\u0432\u0438\u0447\u0430 ; \u0441\u043c. \u0442\u0430\u043a\u0436\u0435 \u043d\u0430 \u043d\u0430\u0448\u0435\u043c \u0441\u0430\u0439\u0442\u0435 \u201e\u0432\u043a\u043b\u0430\u0434 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f\u201d: <a href=\"http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Agatapaszkowska\">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Agatapaszkowska</a></p>\r\n\r\n\r\n\t<h3>AgnieszkaKappa (\u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u0447\u0430\u0435\u0442 \u0441 \u043d\u0430\u043c\u0438 \u0441 16 \u043c\u0430\u0440\u0442\u0430 2008)</h3>\r\n\r\n        <p> \u0441\u0440\u0435\u0434\u0438 \u0434\u0440\u0443\u0433\u0438\u0445 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u043b\u0430 \u0443\u0447\u0430\u0441\u0442\u0438\u0435 \u0432 \u0441\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0438 \u0441\u043f\u0438\u0441\u043a\u0430 \u0438 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0438 \u0443\u043f\u043e\u0442\u0440\u0435\u0431\u043b\u0435\u043d\u0438\u044f \u043b\u0438\u0442\u0435\u0440\u0430\u0442\u0443\u0440\u043d\u044b\u0445 \u043c\u043e\u0442\u0438\u0432\u043e\u0432 \u0438 \u0442\u0435\u043c; \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u043b\u0430 \u0421\u0435\u043d\u043a\u0435\u0432\u0438\u0447\u0430 (\"\u041c\u0430\u044f\u0447\u043d\u0438\u043a\", \"\u042f\u043d\u043a\u043e-\u043c\u0443\u0437\u044b\u043a\u0430\u043d\u0442\", \"\u041a\u0430\u043c\u043e \u0433\u0440\u044f\u0434\u0435\u0448\u0438\"); \u0441\u043c. \u0442\u0430\u043a\u0436\u0435 \u043d\u0430 \u043d\u0430\u0448\u0435\u043c \u0441\u0430\u0439\u0442\u0435 \u201e\u0432\u043a\u043b\u0430\u0434 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f\u201d: <a href=\"http://wiki.wolnepodreczniki.pl/index.php?title=Specjalna:Wk%C5%82ad&amp;limit=500&amp;target=AgnieszkaKappa\">http://wiki.wolnepodreczniki.pl/index.php?title=Specjalna:Wk%C5%82ad&amp;limit=500&amp;target=AgnieszkaKappa</a></p>\r\n\r\n\r\n        <h3>Anerys (\u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u0447\u0430\u0435\u0442 \u0441 \u043d\u0430\u043c\u0438 \u0441 5 \u0438\u044e\u043b\u044f 2007)</h3>\r\n\r\n        <p> \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u043b\u0430 \u0443\u0447\u0430\u0441\u0442\u0438\u0435 \u0432 \u0441\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0438 \u0441\u043f\u0438\u0441\u043a\u0430 \u043b\u0438\u0442\u0435\u0440\u0430\u0442\u0443\u0440\u043d\u044b\u0445 \u043c\u043e\u0442\u0438\u0432\u043e\u0432 \u0438 \u0442\u0435\u043c, \u043e\u0431\u0441\u0443\u0436\u0434\u0435\u043d\u0438\u0439 \u043b\u0438\u0442\u0435\u0440\u0430\u0442\u0443\u0440\u043d\u044b\u0445 \u0436\u0430\u043d\u0440\u043e\u0432, \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u043b\u0430 \u0411\u043e\u0433\u043e\u0440\u043e\u0434\u0438\u0446\u0443, \u201e\u042d\u043f\u0438\u0433\u0440\u0430\u043c\u043c\u044b\u201d \u0438 \u201e\u0422\u0440\u0435\u043d\u044b\u201d \u041a\u043e\u0445\u0430\u043d\u043e\u0432\u0441\u043a\u043e\u0433\u043e; \u0441\u0442\u0438\u0445\u043e\u0442\u0432\u043e\u0440\u0435\u043d\u0438\u044f \u0421\u043b\u043e\u0432\u0430\u0446\u043a\u043e\u0433\u043e (Gr\u00f3b Agamemnona), \u201e\u041e\u0431\u043c\u0430\u043d\u0449\u0438\u043a\u0430\u201d \u041c\u043e\u043b\u044c\u0435\u0440\u0430, \u043f\u043e\u044d\u0437\u0438\u044e \u041a\u0430\u0441\u043f\u0440\u043e\u0432\u0438\u0447\u0430 (\u0432 \u0442.\u0447. \u0433\u0438\u043c\u043d \u201eDies Irae\u201d) \u0438 \u0434\u0440.; \u0441\u043c. \u0442\u0430\u043a\u0436\u0435 \u043d\u0430 \u043d\u0430\u0448\u0435\u043c \u0441\u0430\u0439\u0442\u0435 \u201e\u0432\u043a\u043b\u0430\u0434 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f\u201d: <a href=\"http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Anerys\">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Anerys</a></p>\r\n\r\n\r\n\t<h3>EmiliaZdankiewicz (\u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u0447\u0430\u0435\u0442 \u0441 \u043d\u0430\u043c\u0438 \u0441  17 \u043c\u0430\u0440\u0442\u0430 2008)</h3>\r\n\r\n        <p> \u043b\u0438\u0442\u0435\u0440\u0430\u0442\u0443\u0440\u043d\u044b\u0435 \u043c\u043e\u0442\u0438\u0432\u044b: \u0434\u0438\u0441\u043a\u0443\u0441\u0441\u0438\u044f \u0438 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435, \u0421\u043b\u043e\u0432\u0430\u0446\u043a\u0438\u0439 \"\u041a\u043e\u0440\u0434\u0438\u0430\u043d\"; \u041a\u043e\u043d\u043e\u043f\u043d\u0438\u0446\u043a\u0430\u044f \"Nasza szkapa\"; \u041c\u0438\u0446\u0435\u043a\u0432\u0438\u0447 \"\u0414\u0437\u044f\u0434\u044b \u0447. III\" \u0438 \u0434\u0440.; \u0441\u043c. \u0442\u0430\u043a\u0436\u0435 \u043d\u0430 \u043d\u0430\u0448\u0435\u043c \u0441\u0430\u0439\u0442\u0435 \u201e\u0432\u043a\u043b\u0430\u0434 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f\u201d: <a href=\"http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/EmiliaZdankiewicz\">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/EmiliaZdankiewicz</a></p>\r\n\r\n\r\n\t<h3>Ewa_Serafin (\u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u0447\u0430\u0435\u0442 \u0441 \u043d\u0430\u043c\u0438 \u0441 15 \u043c\u0430\u0440\u0442\u0430 2008)</h3>\r\n\r\n        <p> \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u043b\u0430 \u0443\u0447\u0430\u0441\u0442\u0438\u0435 \u0432 \u0441\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0438 \u0441\u043f\u0438\u0441\u043a\u0430 \u0438 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0438 \u0443\u043f\u043e\u0442\u0440\u0435\u0431\u043b\u0435\u043d\u0438\u044f \u043b\u0438\u0442\u0435\u0440\u0430\u0442\u0443\u0440\u043d\u044b\u0445 \u043c\u043e\u0442\u0438\u0432\u043e\u0432 \u0438 \u0442\u0435\u043c, \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u043b\u0430 \u043f\u043e\u044d\u0437\u0438\u044e \u041a\u0430\u0441\u043f\u0440\u043e\u0432\u0438\u0447\u0430 (\u201eZ wichr\u00f3w i hal\u201d, \u201eNad przepa\u015bciami\u201d, \u201eW ciemno\u015bci schodzi moja dusza\u201d), \u0430 \u0442\u0430\u043a\u0436\u0435 \u201eNad Niemnem\u201d \u041e\u0436\u0435\u0448\u043a\u043e; \u0441\u043c. \u0442\u0430\u043a\u0436\u0435 \u043d\u0430 \u043d\u0430\u0448\u0435\u043c \u0441\u0430\u0439\u0442\u0435 \u201e\u0432\u043a\u043b\u0430\u0434 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f\u201d: <a href=\"http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Ewa_Serafi\">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Ewa_Serafi</a>n</p>\r\n\r\n\r\n    \t<h3>Hanna_Golab (\u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u0447\u0430\u0435\u0442 \u0441 \u043d\u0430\u043c\u0438 \u0441  15 \u043c\u0430\u0440\u0442\u0430 2008)</h3>\r\n\r\n        <p>\u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u043b\u0430 \u201e\u0426\u0430\u0440\u044f \u042d\u0434\u0438\u043f\u0430\u201d \u0421\u043e\u0444\u043e\u043a\u043b\u0430, \u0432 \u0442\u0430\u043a\u0436\u0435 \u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u201eDusio\u0142ek\u201d \u041b\u0435\u0441\u044c\u043c\u044f\u043d\u0430; \u0441\u043c. \u0442\u0430\u043a\u0436\u0435 \u043d\u0430 \u043d\u0430\u0448\u0435\u043c \u0441\u0430\u0439\u0442\u0435 \u201e\u0432\u043a\u043b\u0430\u0434 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f\u201d: <a href=\"http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Hanna_Golab\">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Hanna_Golab</a></p>\r\n\r\n\r\n\t<h3>Ingene (\u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u0447\u0430\u0435\u0442 \u0441 \u043d\u0430\u043c\u0438 \u0441  16 \u0438\u044e\u043b\u044f 2008)</h3>\r\n\r\n        <p> \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u043b\u0430 \u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u201eSi\u0142aczka\u201d \u0416\u0435\u0440\u043e\u043c\u0441\u043a\u043e\u0433\u043e, \u201e\u041a\u0430\u043c\u043e \u0433\u0440\u044f\u0434\u0435\u0448\u0438\u201d \u0421\u0435\u043d\u043a\u0435\u0432\u0438\u0447\u0430, \u201e\u0422\u0440\u0435\u043d\u044b\u201d \u041a\u043e\u0445\u0430\u043d\u043e\u0432\u0441\u043a\u043e\u0433\u043e \u0438 \u0434\u0440.; \u0441\u043c. \u0442\u0430\u043a\u0436\u0435 \u043d\u0430 \u043d\u0430\u0448\u0435\u043c \u0441\u0430\u0439\u0442\u0435 \u201e\u0432\u043a\u043b\u0430\u0434 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f\u201d: <a href=\"http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Ingene\">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Ingene</a></p>\r\n    \r\n\t<h3>Jmyszkowska (\u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u0447\u0430\u0435\u0442 \u0441 \u043d\u0430\u043c\u0438 \u0441  26 \u043c\u0430\u0440\u0442\u0430 2008)</h3>\r\n\r\n        <p>\u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u043b\u0430 \u0441\u0440\u0435\u0434\u0438 \u0434\u0440\u0443\u0433\u0438\u0445 \u201e\u0413\u044f\u0443\u0440\u0430\u201d \u0411\u0430\u0439\u0440\u043e\u043d\u0430, \u0430 \u0442\u0430\u043a\u0436\u0435 \u201e\u041a\u0430\u043c\u043e \u0433\u0440\u044f\u0434\u0435\u0448\u0438\u201d \u0421\u0435\u043d\u043a\u0435\u0432\u0438\u0447\u0430; \u0441\u043c. \u0442\u0430\u043a\u0436\u0435 \u043d\u0430 \u043d\u0430\u0448\u0435\u043c \u0441\u0430\u0439\u0442\u0435 \u201e\u0432\u043a\u043b\u0430\u0434 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f\u201d: <a href=\"http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Jmyszkowska\">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Jmyszkowska</a></p>\r\n\r\n\r\n        <h3>Marysiabailey (\u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u0447\u0430\u0435\u0442 \u0441 \u043d\u0430\u043c\u0438 \u0441  1 \u043e\u043a\u0442\u0430\u0431\u0440\u044f 2007)</h3>\r\n\r\n        <p>\u043f\u0440\u0438\u043d\u0438\u043c\u0430\u043b\u0430 \u0443\u0447\u0430\u0441\u0442\u0438\u0435 \u0432 \u0441\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0438 \u0441\u043f\u0438\u0441\u043a\u0430 \u043b\u0438\u0442\u0435\u0440\u0430\u0442\u0443\u0440\u043d\u044b\u0445 \u043c\u043e\u0442\u0438\u0432\u043e\u0432 \u0438 \u0442\u0435\u043c, \u0430 \u0442\u0430\u043a\u0436\u0435 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0438 \u0438\u0445 \u0443\u043f\u043e\u0442\u0440\u0435\u0431\u043b\u0435\u043d\u0438\u044f; \u043e\u0431\u0441\u0443\u0436\u0434\u0430\u043b\u0430 \u201e\u041c\u0443\u0436\u0438\u043a\u043e\u0432\u201d \u0420\u0435\u0439\u043c\u043e\u043d\u0442\u0430, \u201e\u041a\u0443\u043a\u043b\u0443\u201d \u041f\u0440\u0443\u0441\u0430, \u201e\u041d\u0435\u0431\u043e\u0436\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u0443\u044e \u043a\u043e\u043c\u0435\u0434\u0438\u044e\u201d \u041a\u0440\u0430\u0441\u0438\u043d\u044c\u0441\u043a\u043e\u0433\u043e, \u201eBajki\u201d \u0438 \u201eSatyry\u201d \u041a\u0440\u0430\u0441\u0438\u0446\u043a\u043e\u0433\u043e, \u201e\u0410\u043d\u0442\u0438\u0433\u043e\u043d\u0443\u201d \u0421\u043e\u0444\u043e\u043a\u043b\u0430, \u0430 \u0442\u0430\u043a\u0436\u0435 \u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u044f \u041a\u043e\u0445\u0430\u043d\u043e\u0432\u0441\u043a\u043e\u0433\u043e, \u041c\u043e\u0440\u0448\u0442\u0438\u043d\u0430, \u041c\u0438\u0446\u043a\u0435\u0432\u0438\u0447\u0430, \u041a\u0430\u0441\u043f\u0440\u043e\u0432\u0438\u0447\u0430, \u0413\u0435\u0442\u0435, \u041e\u043f\u043f\u043c\u0430\u043d\u0430; \u0441\u043c. \u0442\u0430\u043a\u0436\u0435 \u043d\u0430 \u043d\u0430\u0448\u0435\u043c \u0441\u0430\u0439\u0442\u0435 \u201e\u0432\u043a\u043b\u0430\u0434 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f\u201d: <a href=\"http://wiki.wolnepodreczniki.pl/index.php?title=Specjalna:Wk%C5%82ad&amp;limit=500&amp;target=Marysiabailey\">http://wiki.wolnepodreczniki.pl/index.php?title=Specjalna:Wk%C5%82ad&amp;limit=500&amp;target=Marysiabailey</a>; \u043a\u0440\u043e\u043c\u0435 \u0442\u043e\u0433\u043e \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u0438\u043b\u0430 \u0438 \u0432\u0435\u043b\u0430 \u0443\u0447\u0435\u0431\u0443 \u0434\u043b\u044f \u0432\u043e\u043b\u043e\u043d\u0442\u0435\u0440\u043e\u0432 15 \u043c\u0430\u0440\u0442\u0430 2008; \u0437\u0430\u043d\u0438\u043c\u0430\u043b\u0430\u0441\u044c \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u0443\u0440\u043e\u0439, \u0441\u0435\u0439\u0447\u0430\u0441 \u0436\u0435 \u0440\u0443\u043a\u043e\u0432\u043e\u0434\u0438\u0442 \u0440\u0430\u0431\u043e\u0442\u043e\u0439 \u043d\u0430\u0434 \u0430\u0443\u0434\u0438\u043e\u043a\u043d\u0438\u0433\u0430\u043c\u0438.</p>\r\n\r\n\r\n        <h3>Olga_Wojtczak (\u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u0447\u0430\u0435\u0442 \u0441 \u043d\u0430\u043c\u0438 \u0441  21 \u043e\u043a\u0442\u0430\u0431\u0440\u044f 2008)</h3>\r\n\r\n        <p>\u043e\u0431\u0441\u0443\u0436\u0434\u0430\u043b\u0430 \u0441\u0440\u0435\u0434\u0438 \u0434\u0440\u0443\u0433\u0438\u0445 \u0440\u043e\u043c\u0430\u043d\u044b \u0421\u0435\u043d\u043a\u0435\u0432\u0438\u0447\u0430 (\"\u0422\u0440\u0438\u043b\u043e\u0433\u0438\u044f\"), \u0420\u0435\u0439\u043c\u043e\u043d\u0442\u0430, \u0416\u0435\u0440\u043e\u043c\u0441\u043a\u043e\u0433\u043e, \u0434\u0440\u0430\u043c\u044b \u0428\u0435\u043a\u0441\u043f\u0438\u0440\u0430; \u0441\u043c. \u0442\u0430\u043a\u0436\u0435 \u043d\u0430 \u043d\u0430\u0448\u0435\u043c \u0441\u0430\u0439\u0442\u0435 \u201e\u0432\u043a\u043b\u0430\u0434 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f\u201d: <a href=\"http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Olga_Wojtczak\">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Olga_Wojtczak</a></p>\r\n\r\n\r\n        <h3>Renataml (\u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u0447\u0430\u0435\u0442 \u0441 \u043d\u0430\u043c\u0438 \u0441  30 \u0438\u044e\u043d\u044f 2007)</h3>\r\n\r\n        <p>\u043f\u0440\u0438\u043d\u0438\u043c\u0430\u043b\u0430 \u0443\u0447\u0430\u0441\u0442\u0438\u0435 \u0432 \u0434\u0438\u0441\u043a\u0443\u0441\u0441\u0438\u0438 \u043d\u0430\u0441\u0447\u0435\u0442 \u0441\u043f\u0438\u0441\u043a\u0430 \u043c\u043e\u0442\u0438\u0432\u043e\u0432; \u043a\u0430\u043a \u043e\u043f\u044b\u0442\u043d\u044b\u0439 \u0443\u0447\u0438\u0442\u0435\u043b\u044c, \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u043b\u0430 \u043d\u0430\u0441 \u0441\u043e\u0432\u0435\u0442\u0430\u043c\u0438, \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043b\u0430 \u201e\u041a\u0443\u043a\u043b\u0443\u201d \u041f\u0440\u0443\u0441\u0430, \u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u201eBalladyn\u0430\u201d \u0421\u043b\u043e\u0432\u0430\u0446\u043a\u043e\u0433\u043e, \u201eSi\u0142aczk\u0119\u201d \u0416\u0435\u0440\u043e\u043c\u0441\u043a\u043e\u0433\u043e.\r\n\r\n        <a href=\"http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Renataml\">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Renataml</a></p>", 
+            "left_column_fr": "<h2>B\u00e9n\u00e9volat</h2>\r\n\r\n        <p>Nous essayons de r\u00e9diger les oeuvres ajout\u00e9es successivement \u00e0 notre biblioth\u00e8que le mieux possible. Ce n'est possible que gr\u00e2ce \u00e0 nos b\u00e9n\u00e9voles.</p>\r\n\r\n        \r\n        <p>Nous invitons tous ceux qui veulent contribuer \u00e0 la cr\u00e9ation de la biblioth\u00e8que en ligne Lectures libres \u00e0 coop\u00e9rer avec nous.</p>\r\n        \r\n        <p>Tous les b\u00e9n\u00e9voles peuvent profiter de l'apprentissage et gagner de la pratique en \u00e9dition du texte: r\u00e9daction technique et du contenu. Les b\u00e9n\u00e9voles ont la possibilit\u00e9 de d\u00e9couvrir les probl\u00e8mes, mais aussi les possibilit\u00e9s li\u00e9es avec les publications en ligne. Ils co-organisent des entra\u00eenements et des conf\u00e9rences, aident \u00e0 pr\u00e9parer des versions des textes \u00e0 \u00e9couter (livres audio). Les b\u00e9n\u00e9voles obtiennent un contrat et un certificat pr\u00e9cisant quand et en quelle qualit\u00e9 ils ont aid\u00e9 notre fondation. Des entra\u00eenements, la pratique de l'\u00e9dition et les c\u00e9rtificats qui les confirment peuvent vous aider \u00e0 d\u00e9montrer vos comp\u00e9tences et peuvent \u00eatre tr\u00e8s precieux pour votre d\u00e9veloppement professionnel.</p>\r\n\r\n        \r\n        <h2>Qu'est-ce qu'il y a \u00e0 faire?</h2>\r\n        \r\n        <p>Le plus de travail est consacr\u00e9 \u00e0 pr\u00e9parer le texte pour la publication. Dans le texte qu'on re\u00e7oit de la Biblioth\u00e8que nationale il faut corriger les fautes de frappe ou autres erreurs m\u00e9caniques, et puis ajouter des annotations tout en sachant que norte offre est cibl\u00e9e aux \u00e9l\u00e8ves, pour lesquels beaucoup des mots sembleront anachroniques. Dans les \u00e9ditions plus anciennes (tout en vue du droit d'auteur) on introduit des modernisations de la langue par exemple en ce qui concerne l'orthographe ou flexion, tout en prenant soin \u00e0 ne pas d\u00e9former la sp\u00e9cificit\u00e9 artistique du texte. Derni\u00e8re \u00e9tape c'est la recherche des motifs et th\u00e8mes litt\u00e9raires, pour aider \u00e0 conna\u00eetre la litt\u00e9rature d'une fa\u00e7on r\u00e9element profonde. Dans tous ces travaux nous sommes aid\u00e9s par les b\u00e9n\u00e9voles - professeurs et \u00e9tudiants - dont les conseils et commentaires nous aident fr\u00e9quemment \u00e0 prendre des d\u00e9cisions importantes.</p>\r\n        \r\n        <h2>Comment nous contacter?</h2>\r\n        \r\n        <p>Toutes les personnes int\u00e9ress\u00e9es sont invit\u00e9es \u00e0 envoyer un message \u00e0 l'adresse <a href=\"mail:fundacja@nowoczesnapolska.org.pl\">fundacja@nowoczesnapolska.org.pl</a>.</p>\r\n\r\n        <p>Vous pouvez aussi visiter <a href=\"http://redmine.nowoczesnapolska.org.pl/projects/wl-publikacje\">le site de la r\u00e9daction Lectures Libres</a>, o\u00f9 on peut trouver toutes les informations n\u00e9cessaires, expliquant comment se joindre \u00e0 nos travaux de r\u00e9daction.</p>", 
+            "title": "You can help us", 
+            "title_lt": "Gali mums padeti", 
+            "right_column": "<h2>The most noteworthy volunteers</h2>\r\n\r\n\t\r\n\r\n<h3>AgataPaszkowska (contributes to the website since March 15, 2008)</h3>\r\n\r\n        <p>Among the others, she worked on Henryk Sienkiewicz's \"In Desert nad Wilderness\"; cf. \"User's contribution\" on our website: <a href=\"http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Agatapaszkowska\">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Agatapaszkowska</a></p>\r\n\r\n\r\n\t\r\n\r\n\r\n\r\n<h3>AgnieszkaKappa (contributes to the website since March 16, 2008)</h3>\r\n\r\n        <p>Among the others, she participated in creating the booklist and descritpion of the usage of the motifs and themes; worked on Henryk Sienkiewicz's works (\"The Lighthouse Keeper\", \"Janko Muzykant\", \"Quo vadis\"); cf. \"User's contribution\" on our website: <a href=\"http://wiki.wolnepodreczniki.pl/index.php?title=Specjalna:Wk%C5%82ad&amp;limit=500&amp;target=AgnieszkaKappa\">http://wiki.wolnepodreczniki.pl/index.php?title=Specjalna:Wk%C5%82ad&amp;limit=500&amp;target=AgnieszkaKappa</a></p>\r\n\r\n\r\n        \r\n\r\n\r\n\r\n<h3>Anerys (contributes to the website since July 5, 2007)</h3>\r\n\r\n   <p>Among the others, she took part in creating the list of literary motifs and themes, and dicussion on the literary genres, she worked on Bogurodzica, Jan Kochanowski's \"Fraszki\" and \"Laments\"; Juliusz S\u0142owacki's poems (\"Gr\u00f3b Agamemnona\"), Moliere's \"Tartuffe\" and Jan Kasprowicz's poems (together with \"Dies Irae\" hymn); cf. \"User's contribution\" on our website: <a href=\"http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Anerys\">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Anerys</a></p>\r\n\r\n\r\n\r\n\r\n\r\n\r\n<h3>EmiliaZdankiewicz (contributes to the website since March 17, 2008)</h3>\r\n\r\n        <p>Among the others: literary motifs, discussion and descriptions; Juliusz S\u0142owacki's \"Kordian\"; Maria Konopnicka's \"Nasza Szkapa\"; Adam Mickiewicz's \"Dziady, part III); cf. \"User's contribution\" on our website: <a href=\"http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/EmiliaZdankiewicz\">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/EmiliaZdankiewicz</a></p>\r\n\r\n\r\n\r\n<h3>Ewa_Serafin (contributes to the website since March 15, 2008)</h3>\r\n\r\n        <p>Among the others, she participated in creating list and usage description of literary motifsand themes; she worked on Jan Kasprowicz poems (\"Z wichr\u00f3w i hal\", \"Nad przepa\u015bciami\", \"W ciemno\u015bci schodzi moja dusza\") and Eliza Orzeszkowa's \"On the Niemen\";  cf. \"User's contribution\" on our website: <a href=\"http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Ewa_Serafi\">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Ewa_Serafi</a>n</p>\r\n\r\n\r\n    \r\n\r\n\r\n\r\n<h3>Hanna_Golab (contributes to the website since March 15, 2008)</h3>\r\n\r\n  <p>She worked on Sophocles' \"Oedipus the King\" and Boles\u0142aw Le\u015bmian's \"Dusio\u0142ek\"; cf. \"User's contribution\" on our website: <a href=\"http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Hanna_Golab\">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Hanna_Golab</a></p>\r\n\r\n\r\n\r\n<h3>Ingene (contributes to the website since July 16, 2008) </h3>\r\n\r\n        <p>Among the others, she worked on Stefan \u017beromski's \"Si\u0142aczka\", Henryk Sienkiewicz's \"Quo vadis\" and Jan Kochanowski's \"Laments\"; cf. \"User's contribution\" on our website:   <a href=\"http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Ingene\">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Ingene</a></p>\r\n \r\n\r\n\r\n\r\n<h3>Jmyszkowska (contributes to the website since March 26, 2008)</h3>  <p>Among the others, she worked on Byron's \"Giaour\" and Henryk Sienkiewicz's \"Quo vadis\"; cf. \"User's contribution\" on our website:  <a href=\"http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Jmyszkowska\">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Jmyszkowska</a></p>\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n<h3>Marysiabailey (contributes to the website since October 1, 2007)</h3>\r\n\r\n        <p>Among the others, she took part in creating the list of literary themes and motifs and description of usage of those bra\u0142a udzia\u0142; worked on W\u0142adys\u0142aw Reymont's \"Ch\u0142opi\", Boles\u0142aw Prus' \"The Doll\", Zygmunt Krasi\u0144ski's \"Nie-boska komedia\", Ignacy Krasicki's \"Fables\" and \"Satires\", Sophocles' \"Antigone\" and poems of Kochanowski, Morsztyn, Mickiewicz, Kasprowicz, Geothe and Oppman; cf. \"User's contribution\" on our website:  <a href=\"http://wiki.wolnepodreczniki.pl/index.php?title=Specjalna:Wk%C5%82ad&amp;limit=500&amp;target=Marysiabailey\">http://wiki.wolnepodreczniki.pl/index.php?title=Specjalna:Wk%C5%82ad&amp;limit=500&amp;target=Marysiabailey</a>; Furthermore, she prepared and carried on the training for volunteers and took care of proofreading. Currently she's managing the works on audiobooks.</p>\r\n\r\n\r\n   \r\n\r\n\r\n\r\n<h3>Olga_Wojtczak (contributes to the website since October 21, 2008)</h3>\r\n\r\n       <p>Among the others, she worked on Henryk Sienkiewicz's novels (The Trilogy), the works of W\u0142adys\u0142aw Reymont and Stefan \u017beromski, as well as Shakespeare's dramas;cf. \"User's contribution\" on our website:  <a href=\"http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Olga_Wojtczak\">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Olga_Wojtczak</a></p>\r\n\r\n\r\n  \r\n\r\n\r\n\r\n<h3>Renataml (contributes to the website since June 30, 2007)</h3>\r\n\r\n        <p>She took part in the discussion on list of motifs, as a experienced teacher she supported us with pieces of advice; edited Boles\u0142aw Prus' \"The Doll\", Juliusz S\u0142owacki's \"Balladyna\", Stefan \u017beromski's \"Si\u0142aczka\".  <a href=\"http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Renataml\">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Renataml</a></p>", 
+            "right_column_es": "<h2> Los voluntarios a los que merecemos mucho  </h2>\r\n\r\n\r\n\r\n\t<h3>Agatapaszkowska (trabaja con nosotros desde el 15 de marzo 2008)</h3>\r\n\r\n\r\n\r\n        <p> edit\u00f3, entre otros, \u201cW pustynii i w puszczy\u201d  de Sienkiewicz ; ved tambi\u00e9n \u201ccontribuci\u00f3n del usuario\u201d en nuestra p\u00e1gina: <a href=\"http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Agatapaszkowska\">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Agatapaszkowska</a></p>\r\n\r\n\r\n\r\n\r\n\r\n\t<h3>AgnieszkaKappa (trabaja con nosotros desde el 16 de marzo 2008) </h3>\r\n\r\n\r\n\r\n        <p>particip\u00f3 en la creaci\u00f3n de la lista y la descripci\u00f3n del uso de los motivos y temas literarios, edit\u00f3 los textos de Sienkiewicz (\u201cFarero\u201d, \u201cJanko Muzykant\u201d, \u201cQuo vadis\u201d); ved tambi\u00e9n \u201ccontribuci\u00f3n del usuario\u201d en nuestra p\u00e1gina: <a href=\"http://wiki.wolnepodreczniki.pl/index.php?title=Specjalna:Wk%C5%82ad&amp;limit=500&amp;target=AgnieszkaKappa\">http://wiki.wolnepodreczniki.pl/index.php?title=Specjalna:Wk%C5%82ad&amp;limit=500&amp;target=AgnieszkaKappa</a></p>\r\n\r\n\r\n\r\n\r\n\r\n        <h3>Anerys (trabaja con nosotros desde el 5 de julio 2007)</h3>\r\n\r\n\r\n\r\n        <p> particip\u00f3 en la creaci\u00f3nn de la lista de los motivos y temas literarios y la debate sobre los g\u00e9neros literarios, edit\u00f3 Bogurodzica, \u201cFraszki\u201d y \u201cTreny\u201d de Kochanowski,  poemas de S\u0142owacki (\u201cLa tumba de Agamemnon\u201d), \u201cTartufo\u201d de Moliere y los poemas de Kasprowicz (el himno \u201cDies Irae\u201d); ved tambi\u00e9n \u201ccontribuci\u00f3n del usuario\u201d en nuestra p\u00e1gina: <a href=\"http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Anerys\">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Anerys</a></p>\r\n\r\n\r\n\r\n\r\n\r\n\t<h3>EmiliaZdankiewicz (trabaja con nosotros desde el 17 de marzo 2008)</h3>\r\n\r\n\r\n\r\n        <p>edit\u00f3 y discut\u00f3 sobre los motivos literarios, \u201cKordian\u201d de S\u0142owacki, \u201cNasza Szkapa\u201d de Konopnicka,\u201dDziady\u201d parte III de Mickiewicz; ved tambi\u00e9n \u201ccontribuci\u00f3n del usuario\u201d en nuestra p\u00e1gina: <a href=\"http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/EmiliaZdankiewicz\">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/EmiliaZdankiewicz</a></p>\r\n\r\n\r\n\r\n\r\n\r\n\t<h3>Ewa_Serafin (trabaja con nosotros desde el 15 de marzo 2008)</h3>\r\n\r\n\r\n\r\n        <p> particip\u00f3 en la creaci\u00f3n de la lista y la descripci\u00f3n del uso de los motivos y temas literarios, edit\u00f3 los poemas de Kasprowicz (\u201cZ wichr\u00f3w i hal\u201d, \u201cNad przepa\u015bciami\u201d, \u201cW ciemno\u015bci schodzi moja dusza\u201d) y \u201cNad Niemnem\u201d de Orzeszkowa; ved tambi\u00e9n \u201ccontribuci\u00f3n del usuario\u201d en nuestra p\u00e1gina: <a href=\"http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Ewa_Serafi\">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Ewa_Serafi</a>n</p>\r\n\r\n\r\n\r\n\r\n\r\n    \t<h3>Hanna_Golab (trabaja con nosotros desde el 15 de marzo 2008)</h3>\r\n\r\n\r\n\r\n        <p> edit\u00f3 \u201cEdipo Rey\u201d de S\u00f3focles y \u201cDusio\u0142ek\u201d de Le\u015bmian; ved tambi\u00e9n \u201ccontribuci\u00f3n del usuario\u201d en nuestra p\u00e1gina: <a href=\"http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Hanna_Golab\">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Hanna_Golab</a></p>\r\n\r\n\r\n\r\n\r\n\r\n\t<h3>Ingene (trabaja con nosotros desde el 16 de julio 2008)</h3>\r\n\r\n\r\n\r\n        <p>edit\u00f3 \u201eSi\u0142aczka\u201dde  \u017beromski, \u201eQuo vadis\u201d de Sienkiewicz y \u201eTreny\u201d de Kochanowski; ved tambi\u00e9n \u201ccontribuci\u00f3n del usuario\u201d en nuestra p\u00e1gina: <a href=\"http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Ingene\">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Ingene</a></p>\r\n\r\n    \r\n\r\n\t<h3>Jmyszkowska (trabaja con nosotros desde el 26 de marzo 2008)</h3>\r\n\r\n\r\n\r\n        <p> edit\u00f3 \u201cGiaur\u201d de Byron y \u201cQuo vadis\u201d de Sienkiewicz; ved tambi\u00e9n \u201ccontribuci\u00f3n del usuario\u201d en nuestra p\u00e1gina: <a href=\"http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Jmyszkowska\">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Jmyszkowska</a></p>\r\n\r\n\r\n\r\n\r\n\r\n        <h3>Marysiabailey (trabaja con nosotros desde el 1 de octubre 2007)</h3>\r\n\r\n\r\n\r\n        <p> partici\u00f3 en la creaci\u00f3n de la lista de motivos y temas literarios y la descripci\u00f3n de su uso, edit\u00f3 \u201cLos campesinos\u201d de Reymont, \u201cLa mu\u00f1eca\u201d de Prus, \u201cNie-boska komedia\u201d de Krasi\u0144ski, \u201cFabulas\u201d y \u201cS\u00e1tiras\u201d de Krasicki, \u201cAnt\u00edgona\u201d de S\u00f3focles y las obras de Kochanowski, Morsztyn, Mickiewicz, Kasprowicz, Goethe, Oppman; ved tambi\u00e9n \u201ccontribuci\u00f3n del usuario\u201d en nuestra p\u00e1gina: <a href=\"http://wiki.wolnepodreczniki.pl/index.php?title=Specjalna:Wk%C5%82ad&amp;limit=500&amp;target=Marysiabailey\">http://wiki.wolnepodreczniki.pl/index.php?title=Specjalna:Wk%C5%82ad&amp;limit=500&amp;target=Marysiabailey</a>; adem\u00e1s prepar\u00f3 y condujo el curso para voluntarios el 15 de marzo 2008; se ocupaba de proofreading y actualmente  coordina los trabajos sobre los audiolibros.</p>\r\n\r\n\r\n\r\n\r\n\r\n        <h3>Olga_Wojtczak (trabaja con nosotros desde el 21 de octubre 2008)</h3>\r\n\r\n\r\n\r\n        <p> edit\u00f3 las novelas de Sienkiewicz (\u201cLa Trilogia\u201d), Reymont, \u017beromski, las dramas de Shakespeare; ved tambi\u00e9n \u201ccontribuci\u00f3n del usuario\u201d en nuestra p\u00e1gina: <a href=\"http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Olga_Wojtczak\">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Olga_Wojtczak</a></p>\r\n\r\n\r\n\r\n\r\n\r\n        <h3>Renataml (trabaja con nosotros desde el 30 de junio 2007)</h3>\r\n\r\n\r\n\r\n        <p>particip\u00f3 en la debate sobre la lista de motivos literarios, nos ayud\u00f3 con sus consejos de profesora con experiencia, edit\u00f3 \u201cLa mu\u00f1eca\u201d de Prus, \u201cBalladyna\u201d de S\u0142owacki, \u201cSi\u0142aczka\u201d de \u017beromski. <a href=\"http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Renataml\">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Renataml</a></p>", 
+            "right_column_en": "<h2>The most noteworthy volunteers</h2>\r\n\r\n\t\r\n\r\n<h3>AgataPaszkowska (contributes to the website since March 15, 2008)</h3>\r\n\r\n        <p>Among the others, she worked on Henryk Sienkiewicz's \"In Desert nad Wilderness\"; cf. \"User's contribution\" on our website: <a href=\"http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Agatapaszkowska\">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Agatapaszkowska</a></p>\r\n\r\n\r\n\t\r\n\r\n\r\n\r\n<h3>AgnieszkaKappa (contributes to the website since March 16, 2008)</h3>\r\n\r\n        <p>Among the others, she participated in creating the booklist and descritpion of the usage of the motifs and themes; worked on Henryk Sienkiewicz's works (\"The Lighthouse Keeper\", \"Janko Muzykant\", \"Quo vadis\"); cf. \"User's contribution\" on our website: <a href=\"http://wiki.wolnepodreczniki.pl/index.php?title=Specjalna:Wk%C5%82ad&amp;limit=500&amp;target=AgnieszkaKappa\">http://wiki.wolnepodreczniki.pl/index.php?title=Specjalna:Wk%C5%82ad&amp;limit=500&amp;target=AgnieszkaKappa</a></p>\r\n\r\n\r\n        \r\n\r\n\r\n\r\n<h3>Anerys (contributes to the website since July 5, 2007)</h3>\r\n\r\n   <p>Among the others, she took part in creating the list of literary motifs and themes, and dicussion on the literary genres, she worked on Bogurodzica, Jan Kochanowski's \"Fraszki\" and \"Laments\"; Juliusz S\u0142owacki's poems (\"Gr\u00f3b Agamemnona\"), Moliere's \"Tartuffe\" and Jan Kasprowicz's poems (together with \"Dies Irae\" hymn); cf. \"User's contribution\" on our website: <a href=\"http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Anerys\">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Anerys</a></p>\r\n\r\n\r\n\r\n\r\n\r\n\r\n<h3>EmiliaZdankiewicz (contributes to the website since March 17, 2008)</h3>\r\n\r\n        <p>Among the others: literary motifs, discussion and descriptions; Juliusz S\u0142owacki's \"Kordian\"; Maria Konopnicka's \"Nasza Szkapa\"; Adam Mickiewicz's \"Dziady, part III); cf. \"User's contribution\" on our website: <a href=\"http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/EmiliaZdankiewicz\">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/EmiliaZdankiewicz</a></p>\r\n\r\n\r\n\r\n<h3>Ewa_Serafin (contributes to the website since March 15, 2008)</h3>\r\n\r\n        <p>Among the others, she participated in creating list and usage description of literary motifsand themes; she worked on Jan Kasprowicz poems (\"Z wichr\u00f3w i hal\", \"Nad przepa\u015bciami\", \"W ciemno\u015bci schodzi moja dusza\") and Eliza Orzeszkowa's \"On the Niemen\";  cf. \"User's contribution\" on our website: <a href=\"http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Ewa_Serafi\">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Ewa_Serafi</a>n</p>\r\n\r\n\r\n    \r\n\r\n\r\n\r\n<h3>Hanna_Golab (contributes to the website since March 15, 2008)</h3>\r\n\r\n  <p>She worked on Sophocles' \"Oedipus the King\" and Boles\u0142aw Le\u015bmian's \"Dusio\u0142ek\"; cf. \"User's contribution\" on our website: <a href=\"http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Hanna_Golab\">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Hanna_Golab</a></p>\r\n\r\n\r\n\r\n<h3>Ingene (contributes to the website since July 16, 2008) </h3>\r\n\r\n        <p>Among the others, she worked on Stefan \u017beromski's \"Si\u0142aczka\", Henryk Sienkiewicz's \"Quo vadis\" and Jan Kochanowski's \"Laments\"; cf. \"User's contribution\" on our website:   <a href=\"http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Ingene\">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Ingene</a></p>\r\n \r\n\r\n\r\n\r\n<h3>Jmyszkowska (contributes to the website since March 26, 2008)</h3>  <p>Among the others, she worked on Byron's \"Giaour\" and Henryk Sienkiewicz's \"Quo vadis\"; cf. \"User's contribution\" on our website:  <a href=\"http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Jmyszkowska\">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Jmyszkowska</a></p>\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n<h3>Marysiabailey (contributes to the website since October 1, 2007)</h3>\r\n\r\n        <p>Among the others, she took part in creating the list of literary themes and motifs and description of usage of those bra\u0142a udzia\u0142; worked on W\u0142adys\u0142aw Reymont's \"Ch\u0142opi\", Boles\u0142aw Prus' \"The Doll\", Zygmunt Krasi\u0144ski's \"Nie-boska komedia\", Ignacy Krasicki's \"Fables\" and \"Satires\", Sophocles' \"Antigone\" and poems of Kochanowski, Morsztyn, Mickiewicz, Kasprowicz, Geothe and Oppman; cf. \"User's contribution\" on our website:  <a href=\"http://wiki.wolnepodreczniki.pl/index.php?title=Specjalna:Wk%C5%82ad&amp;limit=500&amp;target=Marysiabailey\">http://wiki.wolnepodreczniki.pl/index.php?title=Specjalna:Wk%C5%82ad&amp;limit=500&amp;target=Marysiabailey</a>; Furthermore, she prepared and carried on the training for volunteers and took care of proofreading. Currently she's managing the works on audiobooks.</p>\r\n\r\n\r\n   \r\n\r\n\r\n\r\n<h3>Olga_Wojtczak (contributes to the website since October 21, 2008)</h3>\r\n\r\n       <p>Among the others, she worked on Henryk Sienkiewicz's novels (The Trilogy), the works of W\u0142adys\u0142aw Reymont and Stefan \u017beromski, as well as Shakespeare's dramas;cf. \"User's contribution\" on our website:  <a href=\"http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Olga_Wojtczak\">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Olga_Wojtczak</a></p>\r\n\r\n\r\n  \r\n\r\n\r\n\r\n<h3>Renataml (contributes to the website since June 30, 2007)</h3>\r\n\r\n        <p>She took part in the discussion on list of motifs, as a experienced teacher she supported us with pieces of advice; edited Boles\u0142aw Prus' \"The Doll\", Juliusz S\u0142owacki's \"Balladyna\", Stefan \u017beromski's \"Si\u0142aczka\".  <a href=\"http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Renataml\">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Renataml</a></p>", 
+            "left_column_de": "<h2>Volontariat</h2>\r\n\r\n        <p>Wir sind stets bem\u00fcht, unseren Bibliothekbestand st\u00e4ndig um neue Werke zu erweitern. Dies ist nur \r\n        dank der Hilfe unserer Volont\u00e4re m\u00f6glich.</p>\r\n\r\n        <p>Wir laden herzlich alle Menschen ein, die sich an der Mitgestaltung unserer Internet-Schulbibliothek beteiligen wollen.</p>\r\n        \r\n        \r\n        \r\n        <p>Allen Volont\u00e4ren bieten wir Schulungen und Praktikum im Bereich der Textverarbeitung an: \r\n        technische und sachliche Redaktion. Volont\u00e4re k\u00f6nnen mehr \u00fcber Probleme und M\u00f6glichkeiten erfahren, \r\n        die mit der Ver\u00f6ffentlichung von Internetpublikationen verbunden sind. Unsere Volont\u00e4re beteiligen \r\n        sich zudem an der Organisation von Schulungen und Konferenzen, helfen bei der Vorbereitung \r\n        von H\u00f6rtexten (sog. Audiobooks). Wir stellen Vertr\u00e4ge und Bescheinigungen unseren Volont\u00e4ren \r\n        bez\u00fcglich der Art der T\u00e4tigkeit und deren Zeitrahmen aus. Schulungen, Verlagspraktikum sowie \r\n        w\u00e4hrend des Volontariats erworbene Erfahrungen und Kompetenzen k\u00f6nnen ganz gewiss zum beruflichen Aufstieg verhelfen.</p>   \r\n        \r\n        \r\n        <h2>Was zu tun ist?</h2>\r\n        \r\n        <p>Der Gro\u00dfteil der Arbeit liegt in der Vorbereitung der Lekt\u00fcren zur Ver\u00f6ffentlichung. Die Texte, die wir \r\n        von der Nationalbibliothek bekommen, m\u00fcssen auf Tipp- und andere mechanische Fehler \u00fcberpr\u00fcft werden. \r\n        Die Anmerkungen m\u00fcssen in den Text eingef\u00fcgt werden. Es sei zu bedenken, dass unsere Zielgruppe Sch\u00fcler sind, \r\n        so m\u00fcssen dementsprechend die W\u00f6rter und Wendungen an diese Altersgruppe angepasst werden. \u00c4ltere Ausgaben \r\n        (hier gilt das strenge Uhrheberrecht) werden stets in Hinblick auf Rechtsschreibung und Flexion an die \r\n        Gegenwartssprache angepasst und zwar unter gleichzeitiger Beachtung der Einheit von Form und literarischen Stilen. \r\n        Das Aussuchen von literarischen Motiven und Themen, die uns helfen sollen, Literaturinhalte tiefgreifend zu verstehen, \r\n        schlie\u00dfen unsere Projektarbeiten ab. Bei allen diesen Unternehmungen helfen uns Volont\u00e4re - Lehrer sowie Sch\u00fcller - \r\n        die uns mit eigenen Ratschl\u00e4gen und Bemerkungen bei der Entscheidungsfindung unterst\u00fctzen.</p>\r\n        \r\n       \r\n        <h2>Wie Sie uns erreichen?</h2>\r\n        \r\n        <p>Personen, die an der Zusammenarbeit interessiert sind, bitten wir um eine E-Mail an folgende Adresse zu richten: <a href=\"mail:fundacja@nowoczesnapolska.org.pl\">fundacja@nowoczesnapolska.org.pl</a>.</p>\r\n\r\n        <p>Wir laden Sie auch ein unter <a href=\"http://redmine.nowoczesnapolska.org.pl/projects/wl-publikacje\">Redaktonseite der Freien Lekt\u00fcren</a>, auf unserer Hompage finden Sie n\u00fctzliche Informationen rund um das Thema Redaktionsarbeit.</p>", 
+            "title_uk": "\u041c\u043e\u0436\u0435\u0442\u0435 \u043d\u0430\u043c \u0434\u043e\u043f\u043e\u043c\u043e\u0433\u0442\u0438", 
+            "right_column_fr": "<h2>Nos b\u00e9n\u00e9voles les plus m\u00e9ritants</h2>\r\n\r\n\t<h3>Agatapaszkowska (coop\u00e8re avec nous depuis le 15 mars 2008)</h3>\r\n\r\n        <p>entre autres, elle a r\u00e9dig\u00e9 \"W pustyni i w puszczy\u201d de Henryk Sienkiewicz; voir aussi \"contribution de l'utilisateur\u201d sur notre site: <a href=\"http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Agatapaszkowska\">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Agatapaszkowska</a></p>\r\n\r\n\r\n\t<h3>AgnieszkaKappa (coop\u00e8re avec nous depuis le 16 mars 2008)</h3>\r\n\r\n        <p>entre autres, elle a particip\u00e9 \u00e0 la pr\u00e9paration de la liste des motifs et th\u00e8mes litt\u00e9raires et leurs descriptions, a r\u00e9dig\u00e9 les textes de Sienkiewicz (\"Latarnik\", \"Janko Muzykant\", \"Quo vadis\"); voir aussi \"contribution de l'utilisateur\u201d sur notre site: <a href=\"http://wiki.wolnepodreczniki.pl/index.php?title=Specjalna:Wk%C5%82ad&amp;limit=500&amp;target=AgnieszkaKappa\">http://wiki.wolnepodreczniki.pl/index.php?title=Specjalna:Wk%C5%82ad&amp;limit=500&amp;target=AgnieszkaKappa</a></p>\r\n\r\n\r\n        <h3>Anerys (coop\u00e8re avec nous depuis le 5 juillet 2007)</h3>\r\n\r\n        <p>entre autres, elle a particip\u00e9 \u00e0 la pr\u00e9paration de la liste des motifs et th\u00e8mes litt\u00e9raires, dans la discussion sur les genres litt\u00e9raires, elle \u00e0 r\u00e9dig\u00e9 \"Bogurodzica\", \"Fraszki\u201d et \"Treny\u201d de Kochanowski; les po\u00e8mes de S\u0142owacki (\"Gr\u00f3b Agamemnona\"), \"Tartuffe, ou l'Imposteur\" de Moli\u00e8re, les po\u00e8mes de Kasprowicz (entre autres le hymne \"Dies Irae\u201d); voir aussi \"contribution de l'utilisateur\u201d sur notre site: <a href=\"http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Anerys\">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Anerys</a></p>\r\n\r\n\r\n\t<h3>EmiliaZdankiewicz (coop\u00e8re avec nous depuis le 17 mars 2008)</h3>\r\n\r\n        <p>entre autres, les motifs litt\u00e9raires - discussion et description, \"Kordian\" de S\u0142owacki; \"Nasza szkapa\" de Konopnicka; \"A\u00efeux p.III\" de Mickiewicz; voir aussi \"contribution de l'utilisateur\u201d sur notre site: <a href=\"http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/EmiliaZdankiewicz\">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/EmiliaZdankiewicz</a></p>\r\n\r\n\r\n\t<h3>Ewa_Serafin (coop\u00e8re avec nous depuis le 15 mars 2008)</h3>\r\n\r\n        <p>entre autres a particip\u00e9 \u00e0 la cr\u00e9ation de la liste et de la description de l'utilisation des motifs et th\u00e8mes litt\u00e9raires, a r\u00e9dig\u00e9 les po\u00e8mes de Kasprowicz (\"Z wichr\u00f3w i hal\u201d, \"Nad przepa\u015bciami\u201d, \"W ciemno\u015bci schodzi moja dusza\u201d ainsi que \u201eNad Niemnem\u201d d'Orzeszkowa; voir aussi \"contribution de l'utilisateur\u201d sur notre site: <a href=\"http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Ewa_Serafi\">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Ewa_Serafi</a>n</p>\r\n\r\n\r\n    \t<h3>Hanna_Golab (coop\u00e8re avec nous depuis le 15 juillet 2008)</h3>\r\n\r\n        <p>elle a r\u00e9dig\u00e9 \"Oedipe roi\u201d de Sophocle et \"Dusio\u0142ek\u201d de Le\u015bmian; voir aussi \"contribution de l'utilisateur\u201d sur notre site: <a href=\"http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Hanna_Golab\">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Hanna_Golab</a></p>\r\n\r\n\r\n\t<h3>Ingene (coop\u00e8re avec nous depuis le 16 juillet 2008)</h3>\r\n\r\n        <p>elle a r\u00e9dig\u00e9 \"Si\u0142aczka\u201d de \u017beromski, \"Quo vadis\u201d de Sienkiewicz ainsi que \"Treny\u201d de Kochanowski; voir aussi \"contribution de l'utilisateur\u201d sur notre site: <a href=\"http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Ingene\">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Ingene</a></p>\r\n    \r\n\t<h3>Jmyszkowska (coop\u00e8re avec nous depuis le 26 mars 2008)</h3>\r\n\r\n        <p>entre autres, elle a r\u00e9dig\u00e9 \"Giaour\u201d de Byron et \"Quo vadis\u201d de Sienkiewicz; voir aussi \"contribution de l'utilisateur\u201d sur notre site: <a href=\"http://wiki.wolnepodreczniki.pl/S pecjalna:Wk%C5%82ad/Jmyszkowska\">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Jmyszkowska</a></p>\r\n\r\n\r\n        <h3>Marysiabailey (coop\u00e8re avec nous depuis le 1 octobre 2007)</h3>\r\n\r\n        <p>elle a particip\u00e9 \u00e0 la pr\u00e9paration de la liste des motifs et th\u00e8mes litt\u00e9raires et de la description de leur utilisation; elle a r\u00e9dig\u00e9 \"Les Paysans\u201d de Reymont, \"La poup\u00e9e\u201d de Prus, \"Nie-Boska komedia\u201d de Krasi\u0144ski, \"Bajki\u201d et \"Satyry\u201d de Krasicki, \"Antigone\u201d de Sophocle et les oeuvres de Kochanowski, Morsztyn, Mickiewicz, Kasprowicz, Goethe, Oppman, Kasprowicz; voir aussi \"contribution de l'utilisateur\u201d sur notre site: <a href=\"http://wiki.wolnepodreczniki.pl/index.php?title=Specjalna:Wk%C5%82ad&amp;limit=500&amp;target=Marysiabailey\">http://wiki.wolnepodreczniki.pl/index.php?title=Specjalna:Wk%C5%82ad&amp;limit=500&amp;target=Marysiabailey</a>; elle a en plus pr\u00e9par\u00e9 et conduit l'entra\u00eenement pour les b\u00e9n\u00e9voles le 15 mars 2008; elle a fait la correcte des textes et est coordinatrice du travail sur les livres audio.</p>\r\n\r\n\r\n        <h3>Olga_Wojtczak (coop\u00e8re avec nous depuis le 21 octobre 2008)</h3>\r\n\r\n        <p>entre autres, elle a r\u00e9dig\u00e9 les romans de Sienkiewicz (la Trilogie), de Reymont, \u017beromski, les oeuvres de Shakespeare; voir aussi \"contribution de l'utilisateur\u201d sur notre site: <a href=\"http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Olga_Wojtczak\">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Olga_Wojtczak</a></p>\r\n\r\n\r\n        <h3>Renataml (coop\u00e8re avec nous depuis le 30 juin 2007)</h3>\r\n\r\n        <p>a particip\u00e9 \u00e0 la discussion sur la liste des motifs, en tant qu'enseignante experiment\u00e9e, elle nous a donn\u00e9 des conseils pr\u00e9cieux, a \u00e9dit\u00e9 \"La poup\u00e9e\u201d de Prus, \"Balladyna\u201d de S\u0142owacki, \"Si\u0142aczka\u201d de \u017beromski.\r\n\r\n        <a href=\"http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Renataml\">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Renataml</a></p>\r\n", 
+            "left_column": "<h2>Volunteering</h2>\r\n\r\n        <p>We try our best to elaborate works appended to our library. It is possible only thanks to the support of our volunteers.</p>\r\n\r\n        \r\n        <p>We invite every person who wants to take part in developing the web school library Wolne Lektury.</p>\r\n     <p>We offer trainings and traineeships in proofreading and copy-editing for every and each volunteer. Our volunteers can learn not only about the problems, but also the opportunities concerning web publishing.  They organize the trainings and conferences together with us, as well as they help in preparing the audio versions ob books (so called audiobooks). We are also able to issue voluneering contracts and certificates regarding sort and duration of  volunteer's work for our foundation. The traineeships, proofreading and copywriting practice as well as the certificates confirming those may be found vital in acquiring professional qualifications and promotion.  .</p>\r\n\r\n        \r\n\r\n\r\n\r\n\r\n\r\n\r\n<h2>What else is there to be done?</h2>\r\n        \r\n        <p>Preparing the reading for publishing demands the most effort. One has to correct the typos nad other errors of this kind in the texts we receive from the National Library. Next, one needs to provide the book with the annotations, at the same time bearing in mind that our offering is addressed to the pupils, for whom many words and collocations may sound out of date.  The older editions (the rule is determined by copyrights) are subject to essential lingustic modernisations, i.e. in spelling or inflection but we pay attention to not to violate the artistic specifity of the literary works. The last stage of the preparation is searching for literary motfis and themes, so the text is examined thoroughly.  In each and every phase we are supported by the volunteers - teachers and students - who often advise us point out crucial matters as we take important decisions.  </p>\r\n    \r\n\r\n\r\n\r\n\r\n\r\n<h2>How to contact us?</h2>\r\n        \r\n        <p>We ask every interested person to send us an e-mail: <a href=\"mail:fundacja@nowoczesnapolska.org.pl\">fundacja@nowoczesnapolska.org.pl</a>.</p>\r\n\r\n        <p>Please, visit also the editorial website of Wolne Lektury<a href=\"http://redmine.nowoczesnapolska.org.pl/projects/wl-publikacje\"></a>. There you will find essential information on how to involve yourself in editorial works.</p>\r\n\r\n", 
+            "right_column_uk": "<h2>\u041d\u0430\u0439\u0431\u0456\u043b\u044c\u0448 \u0437\u0430\u0441\u043b\u0443\u0436\u0435\u043d\u0456 \u0432\u043e\u043b\u043e\u043d\u0442\u0435\u0440\u0438</h2>\r\n\r\n\r\n\r\n\t<h3>Agatapaszkowska (\u0441\u043f\u0456\u0432\u043f\u0440\u0430\u0446\u044e\u0454 \u0437 \u043d\u0430\u043c\u0438 \u0432\u0456\u0434 15 \u0431\u0435\u0440\u0435\u0437\u043d\u044f 2008)</h3>\r\n\r\n\r\n\r\n        <p>\u043c\u0456\u0436 \u0456\u043d\u0448\u0438\u043c\u0438, \u043e\u043f\u0440\u0430\u0446\u044e\u0432\u0430\u043b\u0430 \u00ab\u0412 \u043f\u0443\u0441\u0442\u0435\u043b\u0456 \u0456 \u0432 \u0434\u0436\u0443\u043d\u0433\u043b\u044f\u0445\u00bb \u0421\u0435\u043d\u043a\u0435\u0432\u0438\u0447\u0430 ; \u0434\u0438\u0432\u0438\u0441\u044c \u0442\u0430\u043a\u043e\u0436 \u043d\u0430 \u043d\u0430\u0448\u043e\u043c\u0443 \u0441\u0430\u0439\u0442\u0456 \u00ab\u0432\u043a\u043b\u0430\u0434 \u043a\u043e\u0440\u0438\u0441\u0442\u0443\u0432\u0430\u0447\u0430\u00bb: <a href=\"http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Agatapaszkowska\">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Agatapaszkowska</a></p>\r\n\r\n\r\n\r\n\r\n\r\n\t<h3>AgnieszkaKappa (\u0441\u043f\u0456\u0432\u043f\u0440\u0430\u0446\u044e\u0454 \u0437 \u043d\u0430\u043c\u0438 \u0432\u0456\u0434 16 \u0431\u0435\u0440\u0435\u0437\u043d\u044f 2008)</h3>\r\n\r\n\r\n\r\n        <p>\u043c\u0456\u0436 \u0456\u043d\u0448\u0438\u043c\u0438, \u0431\u0440\u0430\u043b\u0430 \u0443\u0447\u0430\u0441\u0442\u044c \u0432 \u0442\u0432\u043e\u0440\u0435\u043d\u043d\u0456 \u0441\u043f\u0438\u0441\u043a\u0443 \u0442\u0430 \u043e\u043f\u0438\u0441\u0443 \u0432\u0438\u043a\u043e\u0440\u0438\u0441\u0442\u0430\u043d\u043d\u044f \u043b\u0456\u0442\u0435\u0440\u0430\u0442\u0443\u0440\u043d\u0438\u0445 \u043c\u043e\u0442\u0438\u0432\u0456\u0432 \u0442\u0430 \u0442\u0435\u043c; \u043e\u043f\u0440\u0430\u0446\u044e\u0432\u0430\u043b\u0430 \u0442\u0435\u043a\u0441\u0442\u0438 \u0421\u0435\u043d\u043a\u0435\u0432\u0438\u0447\u0430 (Latarnik,\u042f\u043d\u043a\u043e \u041c\u0443\u0437\u0438\u043a\u0430\u043d\u0442, Quo vadis); \u0434\u0438\u0432\u0438\u0441\u044c \u0442\u0430\u043a\u043e\u0436 \u043d\u0430 \u043d\u0430\u0448\u043e\u043c\u0443 \u0441\u0430\u0439\u0442\u0456 \u00ab\u0432\u043a\u043b\u0430\u0434 \u043a\u043e\u0440\u0438\u0441\u0442\u0443\u0432\u0430\u0447\u0430\u00bb: <a href=\"http://wiki.wolnepodreczniki.pl/index.php?title=Specjalna:Wk%C5%82ad&amp;limit=500&amp;target=AgnieszkaKappa\">http://wiki.wolnepodreczniki.pl/index.php?title=Specjalna:Wk%C5%82ad&amp;limit=500&amp;target=AgnieszkaKappa</a></p>\r\n\r\n\r\n\r\n\r\n\r\n        <h3>Anerys (\u0441\u043f\u0456\u0432\u043f\u0440\u0430\u0446\u044e\u0454 \u0437 \u043d\u0430\u043c\u0438 \u0432\u0456\u0434 5 \u043b\u0438\u043f\u043d\u044f 2007)</h3>\r\n\r\n\r\n\r\n        <p> \u043c\u0456\u0436 \u0456\u043d\u0448\u0438\u043c\u0438, \u0431\u0440\u0430\u043b\u0430 \u0443\u0447\u0430\u0441\u0442\u044c \u0432 \u0442\u0432\u043e\u0440\u0435\u043d\u043d\u0456 \u0441\u043f\u0438\u0441\u043a\u0443 \u043b\u0456\u0442\u0435\u0440\u0430\u0442\u0443\u0440\u043d\u0438\u0445 \u043c\u043e\u0442\u0438\u0432\u0456\u0432 \u0442\u0430 \u0442\u0435\u043c, \u0434\u0438\u0441\u043a\u0443\u0441\u0456\u0457 \u043d\u0430 \u0442\u0435\u043c\u0443 \u043b\u0456\u0442\u0435\u0440\u0430\u0442\u0443\u0440\u043d\u0438\u0445 \u0436\u0430\u043d\u0440\u0456\u0432, \u043e\u043f\u0440\u0430\u0446\u044e\u0432\u0430\u043b\u0430 \u0433\u0456\u043c\u043d \u0411\u043e\u0433\u043e\u0440\u043e\u0434\u0438\u0446\u044f, \u00ab\u0424\u0440\u0430\u0448\u043a\u0438\u00bb \u0442\u0430 \u00ab\u0422\u0440\u0435\u043d\u0438\u00bb \u041a\u043e\u0445\u0430\u043d\u043e\u0432\u0441\u044c\u043a\u043e\u0433\u043e; \u0432\u0456\u0440\u0448\u0456 \u0421\u043b\u043e\u0432\u0430\u0446\u044c\u043a\u043e\u0433\u043e (Gr\u00f3b Agamemnona), \u00ab\u0422\u0430\u0440\u0442\u044e\u0444\u0430\u00bb \u041c\u043e\u043b\u044c\u0454\u0440\u0430, \u0442\u0430 \u043f\u043e\u0435\u0437\u0456\u0457 \u041a\u0430\u0441\u043f\u0440\u043e\u0432\u0456\u0447\u0430 (\u0432 \u0446\u044c\u043e\u043c\u0443 \u0447\u0438\u0441\u043b\u0456 \u0433\u0456\u043c\u043d \u201eDies Irae\u201d); \u0434\u0438\u0432\u0438\u0441\u044c \u0442\u0430\u043a\u043e\u0436 \u043d\u0430 \u043d\u0430\u0448\u043e\u043c\u0443 \u0441\u0430\u0439\u0442\u0456 \u00ab\u0432\u043a\u043b\u0430\u0434 \u043a\u043e\u0440\u0438\u0441\u0442\u0443\u0432\u0430\u0447\u0430\u00bb: <a href=\"http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Anerys\">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Anerys</a></p>\r\n\r\n\r\n\r\n\r\n\r\n\t<h3>EmiliaZdankiewicz (\u0441\u043f\u0456\u0432\u043f\u0440\u0430\u0446\u044e\u0454 \u0437 \u043d\u0430\u043c\u0438 \u0432\u0456\u0434 17 \u0431\u0435\u0440\u0435\u0437\u043d\u044f 2008)</h3>\r\n\r\n\r\n\r\n        <p>\u043c\u0456\u0436 \u0456\u043d\u0448\u0438\u043c\u0438, \u043b\u0456\u0442\u0435\u0440\u0430\u0442\u0443\u0440\u043d\u0456 \u043c\u043e\u0442\u0438\u0432\u0438 \u2014 \u0434\u0438\u0441\u043a\u0443\u0441\u0456\u044f \u0442\u0430 \u043e\u043f\u0438\u0441, \u0421\u043b\u043e\u0432\u0430\u0446\u044c\u043a\u0438\u0439, \u041a\u043e\u0440\u0434\u0456\u0430\u043d; \u041a\u043e\u043d\u043e\u043f\u043d\u0456\u0446\u044c\u043a\u0430, Nasza szkapa; \u041c\u0456\u0446\u043a\u0435\u0432\u0438\u0447, \u0414\u0437\u044f\u0434\u0438 \u0447. III; \u0434\u0438\u0432\u0438\u0441\u044c \u0442\u0430\u043a\u043e\u0436 \u043d\u0430 \u043d\u0430\u0448\u043e\u043c\u0443 \u0441\u0430\u0439\u0442\u0456 \u00ab\u0432\u043a\u043b\u0430\u0434 \u043a\u043e\u0440\u0438\u0441\u0442\u0443\u0432\u0430\u0447\u0430\u00bb: <a href=\"http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/EmiliaZdankiewicz\">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/EmiliaZdankiewicz</a></p>\r\n\r\n\r\n\r\n\r\n\r\n\t<h3>Ewa_Serafin (\u0441\u043f\u0456\u0432\u043f\u0440\u0430\u0446\u044e\u0454 \u0437 \u043d\u0430\u043c\u0438 \u0432\u0456\u0434 15 \u0431\u0435\u0440\u0435\u0437\u043d\u044f 2008)</h3>\r\n\r\n\r\n\r\n        <p>\u043c\u0456\u0436 \u0456\u043d\u0448\u0438\u043c\u0438, \u0431\u0440\u0430\u043b\u0430 \u0443\u0447\u0430\u0441\u0442\u044c \u0432 \u0442\u0432\u043e\u0440\u0435\u043d\u043d\u0456 \u0441\u043f\u0438\u0441\u043a\u0443 \u0442\u0430 \u043e\u043f\u0438\u0441\u0443 \u0432\u0438\u043a\u043e\u0440\u0438\u0441\u0442\u0430\u043d\u043d\u044f \u043b\u0456\u0442\u0435\u0440\u0430\u0442\u0443\u0440\u043d\u0438\u0445 \u043c\u043e\u0442\u0438\u0432\u0456\u0432 \u0442\u0430 \u0442\u0435\u043c, \u043e\u043f\u0440\u0430\u0446\u044e\u0432\u0430\u043b\u0430 \u043f\u043e\u0435\u0437\u0456\u0457 \u041a\u0430\u0441\u043f\u0440\u043e\u0432\u0456\u0447\u0430(\u201cZ wichr\u00f3w i hal\u201d, \u201cNad przepa\u015bciami\u201d, \u201cW ciemno\u015bci schodzi moja dusza\u201d), \u0430 \u0442\u0430\u043a\u043e\u0436 \u201cNad Niemnem\u201d \u0415\u043b\u0456\u0437\u0438 \u041e\u0436\u0435\u0448\u043a\u043e; \u0434\u0438\u0432\u0438\u0441\u044c \u0442\u0430\u043a\u043e\u0436 \u043d\u0430 \u043d\u0430\u0448\u043e\u043c\u0443 \u0441\u0430\u0439\u0442\u0456 \u00ab\u0432\u043a\u043b\u0430\u0434 \u043a\u043e\u0440\u0438\u0441\u0442\u0443\u0432\u0430\u0447\u0430\u00bb: <a href=\"http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Ewa_Serafi\">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Ewa_Serafi</a>n</p>\r\n\r\n\r\n\r\n\r\n\r\n    \t<h3>Hanna_Golab (\u0441\u043f\u0456\u0432\u043f\u0440\u0430\u0446\u044e\u0454 \u0437 \u043d\u0430\u043c\u0438 \u0432\u0456\u0434 15 \u0431\u0435\u0440\u0435\u0437\u043d\u044f 2008)</h3>\r\n\r\n\r\n\r\n        <p>\u043e\u043f\u0440\u0430\u0446\u044e\u0432\u0430\u043b\u0430 \u201c\u0426\u0430\u0440\u044f \u0415\u0434\u0456\u043f\u0430\u201d \u0421\u043e\u0444\u043e\u043a\u043b\u0430 \u0442\u0430 \u0432\u0456\u0440\u0448 \u201cDusio\u0142ek\u201d \u041b\u0435\u0441\u044c\u043c\u044f\u043d\u0430; \u0434\u0438\u0432\u0438\u0441\u044c \u0442\u0430\u043a\u043e\u0436 \u043d\u0430 \u043d\u0430\u0448\u043e\u043c\u0443 \u0441\u0430\u0439\u0442\u0456 \u00ab\u0432\u043a\u043b\u0430\u0434 \u043a\u043e\u0440\u0438\u0441\u0442\u0443\u0432\u0430\u0447\u0430\u00bb: <a href=\"http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Hanna_Golab\">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Hanna_Golab</a></p>\r\n\r\n\r\n\r\n\r\n\r\n\t<h3>Ingene (\u0441\u043f\u0456\u0432\u043f\u0440\u0430\u0446\u044e\u0454 \u0437 \u043d\u0430\u043c\u0438 \u0432\u0456\u0434 16 \u043b\u0438\u043f\u043d\u044f 2008)</h3>\r\n\r\n\r\n\r\n        <p> \u043c\u0456\u0436 \u0456\u043d\u0448\u0438\u043c\u0438, \u043e\u043f\u0440\u0430\u0446\u044e\u0432\u0430\u043b\u0430 \u043e\u043f\u043e\u0432\u0456\u0434\u0430\u043d\u043d\u044f \u201cSi\u0142aczk\u0119\u201d \u0416\u0435\u0440\u043e\u043c\u0441\u044c\u043a\u043e\u0433\u043e, \u201cQuo vadis\u201d \u0421\u0435\u043d\u043a\u0435\u0432\u0438\u0447\u0430 \u0442\u0430 \u201c\u0422\u0440\u0435\u043d\u0438\u201d \u041a\u043e\u0445\u0430\u043d\u043e\u0432\u0441\u044c\u043a\u043e\u0433\u043e; \u0434\u0438\u0432\u0438\u0441\u044c \u0442\u0430\u043a\u043e\u0436 \u043d\u0430 \u043d\u0430\u0448\u043e\u043c\u0443 \u0441\u0430\u0439\u0442\u0456 \u00ab\u0432\u043a\u043b\u0430\u0434 \u043a\u043e\u0440\u0438\u0441\u0442\u0443\u0432\u0430\u0447\u0430\u00bb: <a href=\"http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Ingene\">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Ingene</a></p>\r\n\r\n    \r\n\r\n\t<h3>Jmyszkowska (\u0441\u043f\u0456\u0432\u043f\u0440\u0430\u0446\u044e\u0454 \u0437 \u043d\u0430\u043c\u0438 \u0432\u0456\u0434 26 \u0431\u0435\u0440\u0435\u0437\u043d\u044f 2008)</h3>\r\n\r\n\r\n\r\n        <p>\u043c\u0456\u0436 \u0456\u043d\u0448\u0438\u043c\u0438, \u043e\u043f\u0440\u0430\u0446\u044e\u0432\u0430\u043b\u0430 \u201c\u0413\u044f\u0443\u0440\u0430\u201d \u0411\u0430\u0439\u0440\u043e\u043d\u0430 \u0442\u0430 \u201cQuo vadis\u201d \u0421\u0435\u043d\u043a\u0435\u0432\u0438\u0447\u0430; \u0434\u0438\u0432\u0438\u0441\u044c \u0442\u0430\u043a\u043e\u0436 \u043d\u0430 \u043d\u0430\u0448\u043e\u043c\u0443 \u0441\u0430\u0439\u0442\u0456 \u00ab\u0432\u043a\u043b\u0430\u0434 \u043a\u043e\u0440\u0438\u0441\u0442\u0443\u0432\u0430\u0447\u0430\u00bb: <a href=\"http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Jmyszkowska\">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Jmyszkowska</a></p>\r\n\r\n\r\n\r\n\r\n\r\n        <h3>Marysiabailey (\u0441\u043f\u0456\u0432\u043f\u0440\u0430\u0446\u044e\u0454 \u0437 \u043d\u0430\u043c\u0438 \u0432\u0456\u0434 1 \u0436\u043e\u0432\u0442\u043d\u044f 2007)</h3>\r\n\r\n\r\n\r\n        <p>\u043c\u0456\u0436 \u0456\u043d\u0448\u0438\u043c\u0438, \u0431\u0440\u0430\u043b\u0430 \u0443\u0447\u0430\u0441\u0442\u044c \u0443 \u0442\u0432\u043e\u0440\u0435\u043d\u043d\u0456 \u0441\u043f\u0438\u0441\u043a\u0443 \u043b\u0456\u0442\u0435\u0440\u0430\u0442\u0443\u0440\u043d\u0438\u0445 \u0442\u0435\u043c \u0442\u0430 \u043e\u043f\u0438\u0441\u0456 \u0457\u0445 \u0437\u0430\u0441\u0442\u043e\u0441\u0443\u0432\u0430\u043d\u043d\u044f; \u043e\u043f\u0440\u0430\u0446\u044e\u0432\u0430\u043b\u0430 \u0442\u0432\u043e\u0440\u0438: \u201c\u0421\u0435\u043b\u044f\u043d\u0438\u201d \u0420\u0435\u0439\u043c\u043e\u043d\u0442\u0430 , \u201cLalka\u201d \u041f\u0440\u0443\u0441\u0430, \u201cNie-Boska komedia\u201d \u041a\u0440\u0430\u0441\u0456\u043d\u0441\u044c\u043a\u043e\u0433\u043e, \u201eBajki\u201d \u0442\u0430 \u201eSatyry\u201d \u041a\u0440\u0430\u0441\u0456\u0446\u044c\u043a\u043e\u0433\u043e, \u201c\u0410\u043d\u0442\u0438\u0433\u043e\u043d\u0430\u201d \u0421\u043e\u0444\u043e\u043a\u043b\u0430, \u0430 \u0442\u0430\u043a\u043e\u0436 \u0442\u0432\u043e\u0440\u0438 \u041a\u043e\u0445\u0430\u043d\u043e\u0432\u0441\u044c\u043a\u043e\u0433\u043e, \u041c\u043e\u0440\u0448\u0442\u0438\u043d\u0430, \u041c\u0456\u0446\u043a\u0435\u0432\u0438\u0447\u0430, \u0490\u0435\u0442\u0435, \u041e\u043f\u043f\u043c\u0430\u043d\u0430, \u041a\u0430\u0441\u043f\u0440\u043e\u0432\u0456\u0447\u0430; \u0434\u0438\u0432\u0438\u0441\u044c \u0442\u0430\u043a\u043e\u0436 \u043d\u0430 \u043d\u0430\u0448\u043e\u043c\u0443 \u0441\u0430\u0439\u0442\u0456 \u00ab\u0432\u043a\u043b\u0430\u0434 \u043a\u043e\u0440\u0438\u0441\u0442\u0443\u0432\u0430\u0447\u0430\u00bb: <a href=\"http://wiki.wolnepodreczniki.pl/index.php?title=Specjalna:Wk%C5%82ad&amp;limit=500&amp;target=Marysiabailey\">http://wiki.wolnepodreczniki.pl/index.php?title=Specjalna:Wk%C5%82ad&amp;limit=500&amp;target=Marysiabailey</a>; \u043a\u0440\u0456\u043c \u0442\u043e\u0433\u043e, \u043f\u0456\u0434\u0433\u043e\u0442\u0443\u0432\u0430\u043b\u0430 \u0456 \u043f\u0440\u043e\u0432\u0435\u043b\u0430 \u0442\u0440\u0435\u043d\u0456\u043d\u0433 \u0434\u043b\u044f \u0432\u043e\u043b\u043e\u043d\u0442\u0435\u0440\u0456\u0432 15 \u0431\u0435\u0440\u0435\u0437\u043d\u044f 2008; \u0437\u0430\u044f\u043c\u0430\u043b\u0430\u0441\u044f \u0442\u0430\u043a\u043e\u0434 \u043a\u043e\u0440\u0435\u043a\u0442\u043e\u044e, \u0430 \u043d\u0430 \u0434\u0430\u043d\u0438\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u043f\u0440\u0430\u0446\u044e\u0454 \u043d\u0430\u0434 \u0430\u0443\u0434\u0456\u043e-\u043a\u043d\u0438\u0433\u0430\u043c\u0438.</p>\r\n\r\n\r\n\r\n\r\n\r\n        <h3>Olga_Wojtczak (\u0441\u043f\u0456\u0432\u043f\u0440\u0430\u0446\u044e\u0454 \u0437 \u043d\u0430\u043c\u0438 \u0432\u0456\u0434 21 \u0436\u043e\u0432\u0442\u043d\u044f 2008)</h3>\r\n\r\n\r\n\r\n        <p> \u043c\u0456\u0436 \u0456\u043d\u0448\u0438\u043c\u0438, \u043e\u043f\u0440\u0430\u0446\u044e\u0432\u0430\u043b\u0430 \u0440\u043e\u043c\u0430\u043d\u0438 \u0421\u0435\u043d\u043a\u0435\u0432\u0438\u0447\u0430 (\u0422\u0440\u0438\u043b\u043e\u0433\u0456\u044f), \u0420\u0435\u0439\u043c\u043e\u043d\u0442\u0430, \u0416\u0435\u0440\u043e\u043c\u0441\u044c\u043a\u043e\u0433\u043e, \u0434\u0440\u0430\u043c\u0438 \u0428\u0435\u043a\u0441\u043f\u0456\u0440\u0430; \u0434\u0438\u0432\u0438\u0441\u044c \u0442\u0430\u043a\u043e\u0436 \u043d\u0430 \u043d\u0430\u0448\u043e\u043c\u0443 \u0441\u0430\u0439\u0442\u0456 \u00ab\u0432\u043a\u043b\u0430\u0434 \u043a\u043e\u0440\u0438\u0441\u0442\u0443\u0432\u0430\u0447\u0430\u00bb: <a href=\"http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Olga_Wojtczak\">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Olga_Wojtczak</a></p>\r\n\r\n\r\n\r\n\r\n\r\n        <h3>Renataml (\u0441\u043f\u0456\u0432\u043f\u0440\u0430\u0446\u044e\u0454 \u0437 \u043d\u0430\u043c\u0438 \u0432\u0456\u0434 30 \u0447\u0435\u0440\u0432\u043d\u044f 2007)</h3>\r\n\r\n\r\n\r\n        <p>\u0431\u0440\u0430\u043b\u0430 \u0443\u0447\u0430\u0441\u0442\u044c \u0432 \u0434\u0438\u0441\u043a\u0443\u0441\u0456\u0457 \u043d\u0430 \u0442\u0435\u043c\u0443 \u0441\u043f\u0438\u0441\u043a\u0443 \u043c\u043e\u0442\u0438\u0432\u0456\u0432; \u044f\u043a \u0434\u043e\u0441\u0432\u0456\u0434\u0447\u0435\u043d\u0430 \u0432\u0447\u0438\u0442\u0435\u043b\u044c\u043a\u0430, \u043d\u0430\u0434\u0430\u0432\u0430\u043b\u0430 \u043f\u0456\u0434\u0442\u0440\u0438\u043c\u043a\u0443 \u0442\u0430 \u043f\u043e\u0440\u0430\u0434\u0438, \u0440\u0435\u0434\u0430\u0433\u0443\u0432\u0430\u043b\u0430 \u0440\u043e\u043c\u0430\u043d \u00abLalka\u00bb \u041f\u0440\u0443\u0441\u0430, \u0434\u0440\u0430\u043c\u0443 \u00ab\u0411\u0430\u043b\u043b\u0430\u0434\u0438\u043d\u0430\u00bb \u0421\u043b\u043e\u0432\u0430\u0446\u044c\u043a\u043e\u0433\u043e, \u043e\u043f\u043e\u0432\u0456\u0434\u0430\u043d\u043d\u044f \u00abSi\u0142aczka\u00bb \u0416\u0435\u0440\u043e\u043c\u0441\u044c\u043a\u043e\u0433\u043e.\r\n\r\n\r\n\r\n        <a href=\"http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Renataml\">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Renataml</a></p>", 
+            "title_en": "You can help us", 
+            "left_column_pl": "<h2>Wolontariat</h2>\r\n\r\n        <p>Utwory w\u0142\u0105czane sukcesywnie do naszej biblioteki staramy si\u0119 opracowywa\u0107 jak najdok\u0142adniej. Jest to mo\u017cliwe\r\n        tylko dzi\u0119ki wsp\u00f3\u0142pracuj\u0105cym z nami wolontariuszom.</p>\r\n        \r\n        <p>Zapraszamy wszystkie osoby, kt\u00f3re chc\u0105 wsp\u00f3\u0142tworzy\u0107 szkoln\u0105 bibliotek\u0119 internetow\u0105 Wolne Lektury.</p>\r\n        \r\n        <p>Wszystkim wolontariuszom oferujemy szkolenia i praktyk\u0119 w zakresie edycji tekst\u00f3w: redakcji technicznej i\r\n        merytorycznej. Wolontariusze mog\u0105 pozna\u0107 problemy, ale i mo\u017cliwo\u015bci, jakie wi\u0105\u017c\u0105 si\u0119 z publikacjami internetowymi.\r\n        Wsp\u00f3\u0142organizuj\u0105 z nami szkolenia i konferencje, pomagaj\u0105 w przygotowaniu wersji tekst\u00f3w do s\u0142uchania (tzw.\r\n        audiobook\u00f3w). Wystawiamy umowy i za\u015bwiadczenia o tym, kiedy i jakie prace wykonywa\u0142 wolontariusz na rzecz naszej\r\n        fundacji. Szkolenia, praktyka edytorska i potwierdzaj\u0105ce je za\u015bwiadczenia mog\u0105 si\u0119 okaza\u0107 istotne w procesie\r\n        podnoszenia kwalifikacji i awansu zawodowego.</p>\r\n\r\n        \r\n        <h2>Co jest do zrobienia?</h2>\r\n        \r\n        <p>Najwi\u0119cej pracy mamy przy przygotowaniu lektur do publikacji. Z tekstu, kt\u00f3ry otrzymujemy z Biblioteki\r\n        Narodowej, nale\u017cy usun\u0105\u0107 liter\u00f3wki i inne mechaniczne b\u0142\u0119dy, a nast\u0119pnie opatrzy\u0107 tekst przypisami, pami\u0119taj\u0105c o\r\n        tym, \u017ce nasza oferta skierowana jest przede wszystkim do uczni\u00f3w, dla kt\u00f3rych wiele s\u0142\u00f3w i zwrot\u00f3w b\u0119dzie brzmia\u0142o\r\n        anachronicznie. Wydania dawniejsze (rygor wyznacza tu prawo autorskie) poddawane s\u0105 koniecznym uwsp\u00f3\u0142cze\u015bnieniom\r\n        j\u0119zykowym, np. w zakresie ortografii lub fleksji, przy czym pilnujemy, aby nie narusza\u0107 artystycznej swoisto\u015bci\r\n        tekstu. Ostatnim etapem jest wyszukiwanie motyw\u00f3w i temat\u00f3w literackich, maj\u0105ce pom\u00f3c przejrze\u0107 literatur\u0119 \"na\r\n        wskro\u015b\". We wszystkich tych pracach wspomagaj\u0105 nas wolontariusze \u2013 nauczyciele i studenci \u2013 cz\u0119sto s\u0142u\u017c\u0105c r\u00f3wnie\u017c\r\n        radami i uwagami przy podejmowaniu wa\u017cnych decyzji.</p>\r\n        \r\n        <h2>Jak si\u0119 do nas zg\u0142osi\u0107?</h2>\r\n        \r\n        <p>Wszystkie zainteresowane osoby prosimy o przys\u0142anie maila na adres <a href=\"mail:fundacja@nowoczesnapolska.org.pl\">fundacja@nowoczesnapolska.org.pl</a>.</p>\r\n\r\n        <p>Zapraszamy tak\u017ce na <a href=\"http://redmine.nowoczesnapolska.org.pl/projects/wl-publikacje\">stron\u0119 redakcji Wolnych Lektur</a>, na kt\u00f3rej znajduj\u0105 si\u0119 wszystkie niezb\u0119dne informacje o tym, jak w\u0142\u0105czy\u0107 si\u0119 w prace redakcyjne.</p>\r\n", 
+            "left_column_ru": "<h2>\u0412\u043e\u043b\u043e\u043d\u0442\u0435\u0440\u0441\u0442\u0432\u043e</h2>\r\n\r\n        <p>\u041f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u044f, \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u043f\u043e\u043f\u043e\u043b\u043d\u044f\u044e\u0449\u0438\u0435 \u043d\u0430\u0448\u0443 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 \u043c\u044b \u043f\u044b\u0442\u0430\u0435\u043c\u0441\u044f \u0442\u0449\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u0440\u0430\u0437\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0442\u044c. \u042d\u0442\u043e \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u044b\u043c\r\n        \u0442\u043e\u043b\u044c\u043a\u043e \u0431\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u044f \u043d\u0430\u0448\u0438\u043c \u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a\u0430\u043c-\u0432\u043e\u043b\u043e\u043d\u0442\u0435\u0440\u0430\u043c.</p>\r\n\r\n        \r\n        <p>\u041c\u044b \u043f\u0440\u0438\u0433\u043b\u0430\u0448\u0430\u0435\u043c \u0432\u0441\u0435\u0445 \u0436\u0435\u043b\u0430\u044e\u0449\u0438\u0445 \u0441\u043e\u0434\u0430\u0432\u0430\u0442\u044c \u0448\u043a\u043e\u043b\u044c\u043d\u0443\u044e \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442-\u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 Wolne Lektury \u0432\u043c\u0435\u0441\u0442\u0435 \u0441 \u043d\u0430\u043c\u0438.</p>\r\n        \r\n        <p>\u041c\u044b \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c \u0432\u0441\u0435\u043c \u0432\u043e\u043b\u043e\u043d\u0442\u0435\u0440\u0430\u043c \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0443 \u0438 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0443 \u043f\u043e \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044e \u0442\u0435\u043a\u0441\u0442\u043e\u0432: \u0442\u0435\u0445\u043d\u0438\u0447\u0435\u0441\u043a\u043e\u0439 \u0440\u0435\u0434\u0430\u043a\u0446\u0438\u0438 \u0438\r\n        \u0440\u0435\u0434\u0430\u043a\u0446\u0438\u0438 \u043f\u043e \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443. \u0412\u043e\u043b\u043e\u043d\u0442\u0435\u0440\u044b \u043c\u043e\u0433\u0443\u0442 \u043f\u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u044c\u0441\u044f \u043a\u0430\u043a \u0441 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430\u043c\u0438, \u0442\u0430\u043a \u0438 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044f\u043c\u0438, \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u043c\u0438 \u0441 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442-\u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u044f\u043c\u0438.\r\n        \u041e\u043d\u0438, \u0432\u043c\u0435\u0441\u0442\u0435 \u0441 \u043d\u0430\u043c\u0438, \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u0443\u044e\u0442 \u0443\u0447\u0435\u0431\u0443 \u0438 \u043a\u043e\u043d\u0444\u0435\u0440\u0435\u043d\u0446\u0438\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u043e\u043c\u0430\u0433\u0430\u044e\u0442 \u0432 \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0435 \u0442\u0435\u043a\u0441\u0442\u043e\u0432 \u0434\u043b\u044f \u0441\u043b\u0443\u0448\u0430\u043d\u0438\u044f (\u0442.\u043d.\r\n        \u0430\u0443\u0434\u0438\u043e\u043a\u043d\u0438\u0433). \u041c\u044b \u0432\u044b\u0434\u0430\u0435\u043c \u0434\u043e\u0433\u043e\u0432\u043e\u0440\u044b \u0438 \u0441\u043f\u0440\u0430\u0432\u043a\u0438 \u043d\u0430\u0441\u0447\u0435\u0442 \u0442\u043e\u0433\u043e, \u043a\u043e\u0433\u0434\u0430 \r\n        \u0438 \u043a\u0430\u043a\u0438\u0435 \u0440\u0430\u0431\u043e\u0442\u044b \u0431\u044b\u043b\u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u044b \u0432\u043e\u043b\u043e\u043d\u0442\u0435\u0440\u043e\u043c \u0432 \u043f\u043e\u043b\u044c\u0437\u0443 \u043d\u0430\u0448\u0435\u0433\u043e \r\n        \u0444\u043e\u043d\u0434\u0430. \u0423\u0447\u0435\u0431\u0430, \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0430 \u043f\u043e \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044e \u0438 \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0430\u044e\u0449\u0438\u0435 \u0438\u0445 \u0441\u043f\u0440\u0430\u0432\u043a\u0438 \u043c\u043e\u0433\u0443\u0442 \u044f\u0432\u043b\u044f\u0442\u044c\u0441\u044f \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u043c\u0438 \u0432 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435\r\n        \u043f\u043e\u0432\u044b\u0448\u0435\u043d\u0438\u044f \u043a\u0432\u0430\u043b\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 \u0438 \u043f\u0440\u043e\u0434\u0432\u0438\u0436\u0435\u043d\u0438\u044f \u043f\u043e \u0441\u043b\u0443\u0436\u0431\u0435.</p>\r\n\r\n        \r\n        <h2>\u0427\u0442\u043e \u043d\u0430\u043c \u043d\u0430\u0434\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c?</h2>\r\n        \r\n        <p>\u0421\u0430\u043c\u043e\u0439 \u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u0440\u0430\u0431\u043e\u0442\u043e\u0439 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0430 \u0447\u0442\u0435\u043d\u0438\u0439 \u0434\u043b\u044f \u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u0438. \u0412 \u0442\u0435\u043a\u0441\u0442\u0430\u0445 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0445 \u043d\u0430\u043c\u0438 \u0438\u0437 \u041d\u0430\u0440\u043e\u0434\u043d\u043e\u0439 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u0441\u043b\u0435\u0434\u0443\u0435\u0442 \u0443\u0434\u0430\u043b\u0438\u0442\u044c \u043e\u043f\u0435\u0447\u0430\u0442\u043a\u0438 \u0438 \u0434\u0440\u0443\u0433\u0438\u0435 \u043c\u0435\u0445\u0430\u043d\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u043e\u0448\u0438\u0431\u043a\u0438. \r\n        \u0417\u0430\u0442\u0435\u043c \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0441\u043d\u043e\u0441\u043a\u0438, \u043d\u0435 \u0437\u0430\u0431\u044b\u0432\u0430\u044f \u043e \u0442\u043e\u043c, \u0447\u0442\u043e \u043d\u0430\u0448\u0435 \u043f\u0440\u0435\u0434\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043e\u0431\u0440\u0430\u0449\u0435\u043d\u043e \u043a \u0443\u0447\u0435\u043d\u0438\u043a\u0430\u043c, \u0434\u043b\u044f \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043c\u043d\u043e\u0433\u043e \u0441\u043b\u043e\u0432 \u0438 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0439 \u0437\u0432\u0443\u0447\u0438\u0442 \u0430\u043d\u0430\u0445\u0440\u043e\u043d\u0438\u0447\u043d\u043e.\r\n         \u041f\u0440\u0435\u0436\u043d\u0438\u0435 \u0438\u0437\u0434\u0430\u043d\u0438\u044f (\u0440\u0435\u0436\u0438\u043c \u0430\u0432\u0442\u043e\u0440\u0441\u043a\u043e\u0433\u043e \u043f\u0440\u0430\u0432\u0430) \u043f\u043e\u0434\u0432\u0435\u0440\u0433\u0430\u044e\u0442\u0441\u044f \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0439 \u044f\u0437\u044b\u043a\u043e\u0432\u043e\u0439 \u0430\u043a\u0442\u0443\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438, \u043d\u0430\u043f\u0440. \u043f\u043e \u043e\u0440\u0444\u043e\u0433\u0440\u0430\u0444\u0438\u0438 \u0438\u043b\u0438 \u0444\u043b\u0435\u043a\u0441\u0438\u0438. \u041f\u0440\u0438\u0447\u0435\u043c, \u043c\u044b \u0437\u0430\u0431\u043e\u0442\u0438\u043c\u0441\u044f \u043e \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0438\r\n        \u0445\u0443\u0434\u043e\u0436\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0433\u043e \u0441\u0432\u043e\u0435\u043e\u0431\u0440\u0430\u0437\u0438\u044f \u0442\u0435\u043a\u0441\u0442\u0430. \u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u043c \u044d\u0442\u0430\u043f\u043e\u043c \u0441\u0447\u0438\u0442\u0430\u0435\u0442\u0441\u044f \u043f\u043e\u0438\u0441\u043a \u043b\u0438\u0442\u0435\u0440\u0430\u0442\u0443\u0440\u043d\u044b\u0445 \u043c\u043e\u0442\u0438\u0432\u043e\u0432 \u0438 \u0442\u0435\u043c, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0434\u043e\u043b\u0436\u0435\u043d \u043f\u043e\u043c\u043e\u0447\u044c \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u043b\u0438\u0442\u0435\u0440\u0430\u0442\u0443\u0440\u0443 \"\u043d\u0430\u0441\u043a\u0432\u043e\u0437\u044c\".\r\n        \u0412\u043e \u0432\u0441\u0435\u0445 \u044d\u0442\u0438\u0445 \u0440\u0430\u0431\u043e\u0442\u0430\u0445 \u0441\u0432\u043e\u044e \u043f\u043e\u043c\u043e\u0449\u044c \u043e\u043a\u0430\u0437\u044b\u0432\u0430\u044e\u0442 \u043d\u0430\u043c \u0432\u043e\u043b\u043e\u043d\u0442\u0435\u0440\u044b - \u0443\u0447\u0438\u0442\u0435\u043b\u044f \u0438 \u0441\u0442\u0443\u0434\u0435\u043d\u0442\u044b, \u0447\u0430\u0441\u0442\u043e \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0449\u0438\u0435 \u0441\u0432\u043e\u0438 \u0441\u043e\u0432\u0435\u0442\u044b \u0438 \u0437\u0430\u043c\u0435\u0447\u0430\u043d\u0438\u044f \u0432\u043e \u0432\u0440\u0435\u043c\u044f\r\n        \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u043d\u0438\u044f \u0432\u0430\u0436\u043d\u044b\u0445 \u0440\u0435\u0448\u0435\u043d\u0438\u0439.</p>\r\n        \r\n        <h2>\u041a\u0430\u043a \u043f\u043e\u0441\u0442\u0443\u043f\u0438\u0442\u044c \u0432 \u043d\u0430\u0448 \u0444\u043e\u043d\u0434?</h2>\r\n        \r\n        <p>\u0412\u0441\u0435\u0445 \u0436\u0435\u043b\u0430\u044e\u0449\u0438\u0445 \u043f\u0440\u043e\u0441\u0438\u043c \u043f\u043e\u0441\u043b\u0430\u0442\u044c \u0438-\u043c\u0435\u0439\u043b \u043f\u043e \u0430\u0434\u0440\u0435\u0441\u0443 <a href=\"mail:fundacja@nowoczesnapolska.org.pl\">fundacja@nowoczesnapolska.org.pl</a>.</p>\r\n\r\n        <p>\u041c\u044b \u043f\u0440\u0438\u0433\u043b\u0430\u0448\u0430\u0435\u043c \u0442\u0430\u043a\u0436\u0435 \u043d\u0430 <a href=\"http://redmine.nowoczesnapolska.org.pl/projects/wl-publikacje\">\u0441\u0430\u0439\u0442 \u0440\u0435\u0434\u0430\u043a\u0446\u0438\u0438 Wolne Lektury</a>, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u0439\u0442\u0438 \u0432\u0441\u044e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u0442\u043e\u043c, \u043a\u0430\u043a \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u0442\u044c \u043a \u0440\u0435\u0434\u0430\u043a\u0446\u0438\u043e\u043d\u043d\u044b\u043c \u0440\u0430\u0431\u043e\u0442\u0430\u043c.</p>", 
+            "right_column_lt": "<h2>Labiausiai nusipeln\u0119 savanoriai</h2>\r\n\r\n\t<h3>Agatapaszkowska (bendradarbiauja su mumis nuo 2008 m. kovo 15 d.)</h3>\r\n\r\n        <p>tarp kitko pareng\u0117 \u201eW pustyni i w puszczy\u201d Sienkiewicza ; aplankyk taip pat tinklap\u012f \u201evartotojo \u012fna\u0161\u0105\u201d: <a href=\"http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Agatapaszkowska\">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Agatapaszkowska</a></p>\r\n\r\n\r\n\t<h3>AgnieszkaKappa (bendradarbiauja su mumis nuo 2008 m. kovo 16 d.)</h3>\r\n\r\n        <p>tarp kitko pad\u0117jo paruo\u0161ti literat\u016bros tem\u0173  ir motyv\u0173  s\u0105ra\u0161\u0105; parsiuo\u0161\u0117 teksto apra\u0161ymus: Sienkiewicz (Latarnik, Janko Muzykant, Quo vadis); aplankyk taip pat tinklap\u012f \u201evartotojo \u012fna\u0161\u0105\u201d: <a href=\"http://wiki.wolnepodreczniki.pl/index.php?title=Specjalna:Wk%C5%82ad&amp;limit=500&amp;target=AgnieszkaKappa\">http://wiki.wolnepodreczniki.pl/index.php?title=Specjalna:Wk%C5%82ad&amp;limit=500&amp;target=AgnieszkaKappa</a></p>\r\n\r\n\r\n        <h3>Anerys (bendradarbiauja su mumis nuo 2007 m. liepos 5 d.)</h3>\r\n\r\n        <p>tarp kitko pad\u0117jo paruo\u0161ti literat\u016bros tem\u0173  ir motyv\u0173  s\u0105ra\u0161\u0105, diskusija apie literat\u016brin\u0119s r\u016b\u0161is, parsiuo\u0161\u0117 \u0161iu tekstu apra\u0161ymus; BogurodzicA, \u201eFraszki\u201d i \u201eTreny\u201d Kochanowskiego; eil\u0117ra\u0161\u010diai: S\u0142owacki (Gr\u00f3b Agamemnona), \u201e\u015awi\u0119toszek\u201d Molier, ar poezija Kasprowicz (himnas  \u201eDies Irae\u201d);aplankyk taip pat tinklap\u012f \u201evartotojo \u012fna\u0161\u0105\u201d:\r\n <a href=\"http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Anerys\">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Anerys</a></p>\r\n\r\n\r\n\t<h3>EmiliaZdankiewicz (bendradarbiauja su mumis nuo  2008 m. kovo 17 d.</h3>\r\n\r\n        <p>tarp kitko literat\u016brinai motyvai, diskusijos, apra\u0161ymai: S\u0142owacki, Kordian; Konopnicka, Nasza szkapa; Mickiewicz, Dziady cz. III; aplankyk taip pat tinklap\u012f \u201evartotojo \u012fna\u0161\u0105\u201d: <a href=\"http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/EmiliaZdankiewicz\">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/EmiliaZdankiewicz</a></p>\r\n\r\n\r\n\t<h3>Ewa_Serafin (bendradarbiauja su mumis nuo 2008 m. kovo 15 d.)</h3>\r\n\r\n        <p>tarp kitko pad\u0117jo paruo\u0161ti literat\u016bros tem\u0173  ir motyv\u0173  s\u0105ra\u0161\u0105, parsiuo\u0161\u0117 \u0161iu poeti\u0161ku tekstu apra\u0161ymus: Kasprowicz (\u201eZ wichr\u00f3w i hal\u201d, \u201eNad przepa\u015bciami\u201d, \u201eW ciemno\u015bci schodzi moja dusza\u201d oraz \u201eNad Niemnem\u201d Orzeszkowej; aplankyk taip pat tinklap\u012f \u201evartotojo \u012fna\u0161\u0105\u201d: <a href=\"http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Ewa_Serafi\">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Ewa_Serafi</a>n</p>\r\n\r\n\r\n    \t<h3>Hanna_Golab (bendradarbiauja su mumis nuo 2008 m. kovo 15 d.)</h3>\r\n\r\n        <p>apra\u0161\u0117:\u201eKr\u00f3la Edypa\u201d Sofoklesa ir \u201eDusio\u0142k\u201d Le\u015bmian; aplankyk taip pat tinklap\u012f \u201evartotojo \u012fna\u0161\u0105\u201d: <a href=\"http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Hanna_Golab\">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Hanna_Golab</a></p>\r\n\r\n\r\n\t<h3>Ingene (bendradarbiauja su mumis nuo  2008 m. liepos 16 d.)</h3>\r\n\r\n        <p>tarp kitko apra\u0161\u0117: \u201eSi\u0142aczka\u201d \u017beromski, \u201eQuo vadis\u201d Sienkiewicz ir \u201eTreny\u201d Kochanowski; aplankyk taip pat tinklap\u012f \u201evartotojo \u012fna\u0161\u0105\u201d: <a href=\"http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Ingene\">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Ingene</a></p>\r\n    \r\n\t<h3>Jmyszkowska (bendradarbiauja su mumis nuo 2008 m. kovo 26 d.)</h3>\r\n\r\n        <p>tarp kitko apra\u0161\u0117 \u201eGiaura\u201d Byron ir \u201eQuo vadis\u201d Sienkiewicz; aplankyk taip pat tinklap\u012f \u201evartotojo \u012fna\u0161\u0105\u201d: <a href=\"http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Jmyszkowska\">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Jmyszkowska</a></p>\r\n\r\n\r\n        <h3>Marysiabailey (bendradarbiauja su mumis nuo 2007 m. spalio 1 d.)</h3>\r\n\r\n        <p>tarp kitko pad\u0117jo paruo\u0161ti literat\u016bros tem\u0173  ir motyv\u0173  s\u0105ra\u0161\u0105; apra\u0161\u0117 \u201eCh\u0142opi\u201d Reymont, \u201eLalka\u201d Prus, \u201eNie-Bosk\u0105 komedia\u201d Krasi\u0144skie, \u201eBajki\u201d ir \u201eSatyry\u201d Krasicki, \u201eAntygona\u201d Sofokles ir k\u016brinius: Kochanowski, Morsztyn, Mickiewicz, Kasprowicz, Goethe, Oppman, Kasprowicz; zob. ;aplankyk taip pat tinklap\u012f \u201evartotojo \u012fna\u0161\u0105\u201d: <a href=\"http://wiki.wolnepodreczniki.pl/index.php?title=Specjalna:Wk%C5%82ad&amp;limit=500&amp;target=Marysiabailey\">http://wiki.wolnepodreczniki.pl/index.php?title=Specjalna:Wk%C5%82ad&amp;limit=500&amp;target=Marysiabailey</a>; parose ir ved\u0117 apmokymus savanoriams 2008 m. kovo 15 d.; u\u017esiimin\u0117jo  proofreading, o dabartiniu metu vadovauja darbams susijusiems su audio knyg\u0173 ruo\u0161imu.</p>\r\n\r\n\r\n        <h3>Olga_Wojtczak (bendradarbiauja su mumis nuo 2008 m. spalio 21 d.)</h3>\r\n\r\n        <p>tarp kitko apra\u0161e roman\u0105 Sienkiewicz (Trilogija), Reymont, \u017beromski, dramos Shakespear; ;aplankyk taip pat tinklap\u012f \u201evartotojo \u012fna\u0161\u0105\u201d: <a href=\"http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Olga_Wojtczak\">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Olga_Wojtczak</a></p>\r\n\r\n\r\n        <h3>Renataml (bendradarbiauja su mumis nuo 2007 m. bir\u017eelio 30 d.)</h3>\r\n\r\n        <p>pad\u0117jo parsiuo\u0161ti diskusij\u0105 apie motyv\u0173  s\u0105ra\u0161\u0105, patar\u0117  mums, nes tai patyrusi mokytoja,  \u201eLalk\u0119\u201d Prusa, \u201eBalladyn\u0119\u201d S\u0142owackiego, \u201eSi\u0142aczk\u0119\u201d \u017beromskiego.\r\n\r\n        <a href=\"http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Renataml\">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Renataml</a></p>\r\n", 
+            "title_es": "\ufeffPuedes ayudarnos", 
+            "page_title_fr": "Vous pouvez nous aider avec WolneLektury.pl", 
+            "page_title_uk": "\u041c\u043e\u0436\u0435\u0442\u0435 \u043d\u0430\u043c \u0434\u043e\u043f\u043e\u043c\u043e\u0433\u0442\u0438 \u0443 WolneLektury.pl", 
+            "page_title_de": "Du kannst uns helfen unter WolneLektury.pl", 
+            "slug": "help_us", 
+            "page_title_lt": "Gali mums pad\u0117ti LaisvojiLiteratura.lt", 
+            "right_column_de": "<h2>Wohlverdiente Volont\u00e4re</h2>\r\n\r\n\t<h3>Agatapaszkowska (Mitarbeit seit 15. M\u00e4rz 2008)</h3>\r\n\r\n        <p>bearbeitete u.a. \"Durch W\u00fcste und Wildnis\" von Sienkiewicz; s. auf unserer Website die \"Benutzerbeitr\u00e4ge\": <a href=\"http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Agatapaszkowska\">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Agatapaszkowska</a></p>\r\n\r\n\r\n\t<h3>AgnieszkaKappa (Mitarbeit seit 16. M\u00e4rz 2008)</h3>\r\n\r\n        <p>arbeitete u.a. an der Erstellung der Liste und Beschreibung der literarischen Themen und Motive;bearbeitete Texten von Sienkiewicz ( Der Leuchtturmw\u00e4rter, Janko der Musikant, Quo vadis);s. auf unserer Website die \"Benutzerbeitr\u00e4ge\": <a href=\"http://wiki.wolnepodreczniki.pl/index.php?title=Specjalna:Wk%C5%82ad&amp;limit=500&amp;target=AgnieszkaKappa\">http://wiki.wolnepodreczniki.pl/index.php?title=Specjalna:Wk%C5%82ad&amp;limit=500&amp;target=AgnieszkaKappa</a></p>\r\n\r\n\r\n        \r\n        \r\n\r\n        <h3>Anerys (Mitarbeit seit 5. Juli 2007)</h3>\r\n\r\n        <p>arbeitete u.a. an der Erstellung der Liste und Beschreibung der literarischen Themen und Motive;nahm an der Diskussion \u00fcber Literaturgattungen teil, bearbeitete folgende Werke: Bogurodzica, \"Spruchgedichte\" und \"Klagelieder\"  von Kochanowski; Gedichte von  Slowacki ( Agamemnons Grab), \"Tartuffe oder der Betr\u00fcger\" von  Moliere, ob Poesien  von Kasprowicz (u.a. eine Hymne \"Dies Irae\"); s. auf unserer Website die \"Benutzerbeitr\u00e4ge\": <a href=\"http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Anerys\">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Anerys</a></p>\r\n         \r\n\r\n\t<h3>EmiliaZdankiewicz (Mitarbeit seit 17. M\u00e4rz 2008)</h3>\r\n\r\n        <p>nahm u.a. an der Diskussion und Beschreibung literarischer Motive teil, S\u0142owacki, Kordian; Konopnicka, Unsere M\u00e4hre; Mickiewicz, Totenfeier Teil III; s. auf unserer Website die \"Benutzerbeitr\u00e4ge\": <a href=\"http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/EmiliaZdankiewicz\">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/EmiliaZdankiewicz</a></p>\r\n\r\n    \r\n\t\r\n\t<h3>Ewa_Serafin (Mitarbeit seit 15. M\u00e4rz 2008)</h3>\r\n\r\n        <p>arbeitete u.a. an der Erstellung der Liste und Beschreibung der literarischen Themen und Motive, bearbeitete Kasprowicz Gedichte  (\u201eZ wichr\u00f3w i hal\u201d, \u201eNad przepa\u015bciami\u201d, \u201eW ciemno\u015bci schodzi moja dusza\u201d oraz \u201eNad Niemnem\u201d Orzeszkowej; s. auf unserer Website die \"Benutzerbeitr\u00e4ge\": <a href=\"http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Ewa_Serafi\">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Ewa_Serafi</a>n</p>\r\n\r\n\r\n    \t<h3>Hanna_Golab (Mitarbeit seit 15. M\u00e4rz 2008)</h3>\r\n\r\n        <p>bearbeitete \" K\u00f6nig \u00d6dipus\" von Sophokles sowie \"Dusio\u0142ek\"  von Lesmian; s. auf unserer Website die \"Benutzerbeitr\u00e4ge\": <a href=\"http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Hanna_Golab\">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Hanna_Golab</a></p>\r\n\r\n\r\n\t<h3>Ingene (Mitarbeit seit 16. Juli 2008)</h3>\r\n\r\n        <p>bearbeitete u.a. \u201eSi\u0142aczka\u201d von \u017beromski, \u201eQuo vadis\u201d von Sienkiewicz sowie \u201eKlagelieder\u201d von Kochanowski; s. auf unserer Website die \"Benutzerbeitr\u00e4ge\": <a href=\"http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Ingene\">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Ingene</a></p>\r\n    \r\n\t<h3>Jmyszkowska (Mitarbeit seit 26. M\u00e4rz 2008)</h3>\r\n\r\n        <p>bearbeitete u.a. \u201eGiaur\u201d von Byron sowie \u201eQuo vadis\u201d von Sienkiewicz; s. auf unserer Website die \"Benutzerbeitr\u00e4ge\": <a href=\"http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Jmyszkowska\">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Jmyszkowska</a></p>\r\n\r\n\r\n        <h3>Marysiabailey (Mitarbeit seit 1. Oktober 2007)</h3>\r\n\r\n        <p>arbeitete u.a. an der Erstellung der Liste und Beschreibung der literarischen Themen und Motive sowie deren Benutzung; bearbeitete folgende Werke: \"Die Bauern\"  von Reymont, \"Die Puppe\" von Prus, \"Un-g\u00f6ttliche Kom\u00f6die\" von Krasinski, \"M\u00e4rchens\" und \"Satire\" von Krasickiego, \"Antigone\" von Sophokles sowie Werke von Kochanowski, Morsztyn, Mickiewicz, Kasprowicz, Goethe, Oppman, Kasprowicz; s. auf unserer Website die \"Benutzerbeitr\u00e4ge\u201c: <a href=\"http://wiki.wolnepodreczniki.pl/index.php?title=Specjalna:Wk%C5%82ad&amp;limit=500&amp;target=Marysiabailey\">http://wiki.wolnepodreczniki.pl/index.php?title=Specjalna:Wk%C5%82ad&amp;limit=500&amp;target=Marysiabailey</a zus\u00e4tzlich beteiligte sie sich am 15. M\u00e4rz 2008 an der Organisation von Volont\u00e4r-Schulungen, besch\u00e4ftigte sich mit proofreading, gegenw\u00e4rtig arbeitet sie an H\u00f6rb\u00fcchern.</p>\r\n\r\n\r\n        <h3>Olga_Wojtczak (Mitarbeit seit 21. Oktober 2008)</h3>\r\n\r\n        <p>bearbeitete u.a. Romane von  Sienkiewicz ( Die Trilogie), Reymont, \u017beromski und Dramen von Shakespeare; s. auf unserer Website die \"Benutzerbeitr\u00e4ge\": <a href=\"http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Olga_Wojtczak\">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Olga_Wojtczak</a></p>\r\n\r\n        <h3>Renataml (Mitarbeit seit 30. Juni 2007)</h3>\r\n\r\n        <p>nahm an der Diskussion \u00fcber Motivlisten teil, als erfahrene Lehrerin unterst\u00fctzte sie uns mit vielen Ratschl\u00e4gen, bearbeitete folgende Werke: \"Die Puppe\" von Prus, \"Balladyna\"  von Slowacki, \"Si\u0142aczka\"  \u017beromski.\r\n\r\n        <a href=\"http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Renataml\">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Renataml</a></p>\r\n", 
+            "page_title_pl": "Mo\u017cesz nam pom\u00f3c w WolneLektury.pl", 
+            "left_column_es": "<h2>Voluntariado</h2>\r\n\r\n\r\n\r\n        <p> Hacemos todo lo posible para elaborar las obras de nuestra biblioteca con la mayor perfecci\u00f3n. Esto es posible s\u00f3lo gracias al apoyo de nuestros voluntarios. </p>\r\n\r\n\r\n\r\n        \r\n\r\n        <p> Invitamos a todos quienes quieren formar parte en el desarrollo de la biblioteca virtual de Wolne Lektury. </p>\r\n\r\n        \r\n\r\n        <p> A todos los voluntarios les ofrecemos cursos y pr\u00e1cticas en cuanto a la redacci\u00f3n t\u00e9cnica y pr\u00e1ctica. Los voluntarios tienen la posibilidad de conocer tanto los problemas como las oportunidades relacionadas con las publicaciones virtuales. Nos ayudan en la organizaci\u00f3n de conferencias y cursos de formaci\u00f3n, asimismo asisten en la edici\u00f3n de los textos en forma auditiva (audiolibros). Los proporcionamos contratos y certificados con los detalles del trabajo y tipo de tareas realizadas para nuestra fundaci\u00f3n. Los cursos, las pr\u00e1cticas realizadas y los certificados correspondientes podr\u00e1n resultar \u00fatiles en el proceso del desarrollo profesional y para el futuro trabajo profesional. </p>\r\n\r\n      \r\n\r\n        <h2>\u00bfEn qu\u00e9 nos puedes ayudar? </h2>\r\n\r\n        La Biblioteca\r\n\r\n        Nacional proporciona textos, pero hay que eliminar las faltas de ortograf\u00eda y otros errores mec\u00e1nicos y, a continuaci\u00f3n, a\u00f1adir glosas.\r\n\r\n        <p>La mayor\u00eda de trabajo la tenemos con la preparaci\u00f3n de los libros para la publicaci\u00f3n. La Biblioteca Nacional proporciona textos pero hay que corregir las erratas y otros errores, despu\u00e9s a\u00f1adir las anotaciones a pie de p\u00e1gina teniendo en cuenta que nuestra oferta es dirigida especialmente a estudiantes para quienes muchas palabras o expresiones pueden ser anacr\u00f3nicas. Tratamos de modernizar las ediciones antiguas (respetando el derecho de autor) respecto a la ortograf\u00eda o la inflexi\u00f3n pero cuidamos para no violar el valor art\u00edstico del texto. La \u00faltima etapa es buscar todos los motivos y temas literarios que ayudar\u00e1n en conocer la lectura totalmente. En todos los trabajos nos ayudan los voluntarios, profesores y estudiantes, a menudo ayudando tambi\u00e9n en la toma de decisiones importantes. </p>\r\n\r\n        \r\n\r\n        <h2> \u00bfC\u00f3mo inscribirse?</h2>\r\n\r\n        \r\n\r\n        <p>Todos que est\u00e9n interesados enviad un mail a <a href=\"mail:fundacja@nowoczesnapolska.org.pl\">fundacja@nowoczesnapolska.org.pl</a>.</p>\r\n\r\n\r\n\r\n        <p> Os invitamos tambi\u00e9n a visitar <a href=\"http://redmine.nowoczesnapolska.org.pl/projects/wl-publikacje\"> la p\u00e1gina de la redacci\u00f3n de Wolne Lektury </a> donde hay todas las informaciones necesarias para empezar el trabajo editorial. </p>\r\n\r\n", 
+            "left_column_en": "<h2>Volunteering</h2>\r\n\r\n        <p>We try our best to elaborate works appended to our library. It is possible only thanks to the support of our volunteers.</p>\r\n\r\n        \r\n        <p>We invite every person who wants to take part in developing the web school library Wolne Lektury.</p>\r\n     <p>We offer trainings and traineeships in proofreading and copy-editing for every and each volunteer. Our volunteers can learn not only about the problems, but also the opportunities concerning web publishing.  They organize the trainings and conferences together with us, as well as they help in preparing the audio versions ob books (so called audiobooks). We are also able to issue voluneering contracts and certificates regarding sort and duration of  volunteer's work for our foundation. The traineeships, proofreading and copywriting practice as well as the certificates confirming those may be found vital in acquiring professional qualifications and promotion.  .</p>\r\n\r\n        \r\n\r\n\r\n\r\n\r\n\r\n\r\n<h2>What else is there to be done?</h2>\r\n        \r\n        <p>Preparing the reading for publishing demands the most effort. One has to correct the typos nad other errors of this kind in the texts we receive from the National Library. Next, one needs to provide the book with the annotations, at the same time bearing in mind that our offering is addressed to the pupils, for whom many words and collocations may sound out of date.  The older editions (the rule is determined by copyrights) are subject to essential lingustic modernisations, i.e. in spelling or inflection but we pay attention to not to violate the artistic specifity of the literary works. The last stage of the preparation is searching for literary motfis and themes, so the text is examined thoroughly.  In each and every phase we are supported by the volunteers - teachers and students - who often advise us point out crucial matters as we take important decisions.  </p>\r\n    \r\n\r\n\r\n\r\n\r\n\r\n<h2>How to contact us?</h2>\r\n        \r\n        <p>We ask every interested person to send us an e-mail: <a href=\"mail:fundacja@nowoczesnapolska.org.pl\">fundacja@nowoczesnapolska.org.pl</a>.</p>\r\n\r\n        <p>Please, visit also the editorial website of Wolne Lektury<a href=\"http://redmine.nowoczesnapolska.org.pl/projects/wl-publikacje\"></a>. There you will find essential information on how to involve yourself in editorial works.</p>\r\n\r\n", 
+            "title_pl": "Mo\u017cesz nam pom\u00f3c", 
+            "title_ru": "\u0412\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043d\u0430\u043c \u043f\u043e\u043c\u043e\u0447\u044c", 
+            "page_title_ru": "\u0412\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043d\u0430\u043c \u043f\u043e\u043c\u043e\u0447\u044c \u0432 WolneLektury.pl"
+        }
+    }, 
+    {
+        "pk": 1, 
+        "model": "infopages.infopage", 
+        "fields": {
+            "title_de": "Volontariat f\u00fcr Wissen", 
+            "page_title": "Volunteering for knowledge on WolneLektury.pl", 
+            "left_column_uk": "<h2>\u0412\u043e\u043b\u043e\u043d\u0442\u0435\u0440\u0441\u0442\u0432\u043e</h2>\r\n <p>\r\n \u0411\u0456\u043e\u0433\u0440\u0430\u043c\u0438 \u043f\u0438\u0441\u044c\u043c\u0435\u043d\u043d\u0438\u043a\u0456\u0432 \u0442\u0430 \u0434\u0435\u0444\u0456\u043d\u0456\u0446\u0456\u0457 \u0435\u043f\u043e\u0445 \u0442\u0430 \u043b\u0456\u0442\u0435\u0440\u0430\u0442\u0443\u0440\u043d\u0438\u0445 \u0436\u0430\u043d\u0440\u0456\u0432 \u0432 \u0456\u043d\u0442\u0435\u0440\u043d\u0435\u0442-\u0431\u0456\u0431\u043b\u0456\u043e\u0442\u0435\u0446\u0456 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0456 \u0443\u0447\u043d\u044f\u043c\u0438 \u0447\u043e\u0442\u0438\u0440\u044c\u043e\u0445 \u0448\u043a\u0456\u043b \u043f\u0456\u0434\u0447\u0430\u0441 \u043c\u0430\u0439\u0441\u0442\u0435\u0440-\u043a\u043b\u0430\u0441\u0456\u0432 \u201c\u0412\u043e\u043b\u043e\u043d\u0442\u0435\u0440\u0441\u0442\u0432\u043e \u0432 \u043e\u0441\u0432\u0456\u0442\u0456\u201d.\r\n </p>\r\n\r\n <p>\r\n \u0423\u0447\u043d\u0456 \u0441\u043f\u0456\u043b\u044c\u043d\u043e \u043f\u0440\u0430\u0446\u044e\u0432\u0430\u043b\u0438 \u0432\u0456\u0434 \u0434\u043e\u0433\u043b\u044f\u0434\u043e\u043c \u0432\u0447\u0438\u0442\u0435\u043b\u0456\u0432 \u0442\u0430 \u0441\u043f\u0435\u0446\u0456\u0430\u043b\u0456\u0441\u0442\u0456\u0432 \u2014 \u043b\u0456\u0442\u0435\u0440\u0430\u0442\u0443\u0440\u043e\u0437\u043d\u0430\u0432\u0446\u0456\u0432 \u043d\u0430 <a href=\"http://wolnepodreczniki.pl/wolontariat/\">\r\n\r\n \u0456\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u043e\u0432\u0456\u0439 \u0432\u0456\u043a\u0456-\u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0456</a>\r\n \u0432\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0456\u0439 \u043a\u043e\u043c\u0430\u043d\u0434\u043e\u044e\r\n <a href=\"http://2ia.pl/\">2ia</a>. \u0420\u043e\u0431\u043e\u0442\u0430 \u043d\u0430\u0434 \u0446\u0438\u043c\u0438 \u0442\u0435\u043a\u0441\u0442\u0430\u043c\u0438 \u0431\u0443\u043b\u0430 \u0432\u043e\u0434\u043d\u043e\u0447\u0430\u0441 \u043d\u0430\u0443\u043a\u043e\u044e \u043a\u043e\u0440\u0438\u0441\u0442\u0443\u0432\u0430\u0442\u0438\u0441\u044f \u043a\u043e\u043c\u043f\u2019\u044e\u0442\u0435\u0440\u043e\u043c \u0442\u0430 \u0456\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u043e\u043c \u0434\u043b\u044f \u043f\u043e\u0448\u0443\u043a\u0443 \u0456\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0456\u0457, \u0430 \u0442\u0430\u043a\u043e\u0436 \u043f\u0435\u0440\u0435\u0432\u0456\u0440\u043a\u0438 \u0457\u0457 \u0432\u0456\u0440\u043e\u0433\u0456\u0434\u043d\u043e\u0441\u0442\u0456.\r\n </p>\r\n\r\n <p>\r\n \u041f\u0440\u043e\u0435\u043a\u0442 \"\u0412\u043e\u043b\u043e\u043d\u0442\u0435\u0440\u0441\u0442\u0432\u043e \u0432 \u043e\u0441\u0432\u0456\u0442\u0456\" \u0437\u0434\u0456\u0439\u0441\u043d\u0435\u043d\u043e \u0437\u0430\u0432\u0434\u044f\u043a\u0438 \u043f\u0456\u0434\u0442\u0440\u0438\u043c\u0446\u0456 \r\n <a href=\"http://www.menis.gov.pl/\">\r\n \u041c\u0456\u043d\u0456\u0441\u0442\u0435\u0440\u0441\u0442\u0432\u0430 \u043d\u0430\u0446\u0456\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0457 \u043e\u0441\u0432\u0456\u0442\u0438</a>. \u041f\u0440\u0438\u0437\u0438 \u0434\u043b\u044f \u0443\u0447\u043d\u0456\u0432 \u043f\u0440\u0438\u0433\u043e\u0442\u0443\u0432\u0430\u043b\u0438 <a href=\"http://www.nk.com.pl/engine/index.php?page=glowna\">\r\n\r\n \u0412\u0438\u0434\u0430\u0432\u043d\u0438\u0446\u0442\u0432\u043e Nasza Ksi\u0119garnia</a>\r\n \u0442\u0430\r\n <a href=\"http://helion.pl/\">\u0412\u0438\u0434\u0430\u0432\u043d\u0438\u0446\u0442\u0432\u043e Helion</a>. \u0422\u0435\u043a\u0441\u0442\u0438 \u043f\u0435\u0440\u0435\u0432\u0456\u0440\u0435\u043d\u043e \u0432 \u0440\u0435\u0441\u0443\u0440\u0441\u0456 <a href=\"http://www.plagiat.pl/webplagiat/main.action\">\r\n Plagiat.pl</a>.\r\n </p>\r\n\r\n <p>\r\n <a href=\"/static/wolontariat.pdf\">\u0417\u0432\u0456\u0442 \u0437 \u0440\u0435\u0430\u043b\u0456\u0437\u0430\u0446\u0456\u0457 \u043f\u0440\u043e\u0435\u043a\u0442\u0443 \"\u0412\u043e\u043b\u043e\u043d\u0442\u0435\u0440\u0441\u0442\u0432\u043e \u0432 \u043e\u0441\u0432\u0456\u0442\u0456\"</a>.\r\n </p>\r\n\r\n <p>\r\n <img src=\"/static/img/wolontariat/okladka.jpg\" style='margin: 10px' />\r\n <img src=\"/static/img/wolontariat/01.jpg\" style='margin: 10px' />\r\n <img src=\"/static/img/wolontariat/02.jpg\" style='margin: 10px' />\r\n <img src=\"/static/img/wolontariat/03.jpg\" style='margin: 10px' />\r\n <img src=\"/static/img/wolontariat/04.jpg\" style='margin: 10px' />\r\n </p> ", 
+            "right_column_pl": "\t<h2>Autorzy</h2>\r\n\r\n\t<ol>\r\n\t\t<li>\r\n\t\t\t<p>\r\n\t\t\t\tGimnazjum nr 40 z Oddzia\u0142ami Integracyjnymi w Zespole\r\n\t\t\t\tSzk\u00f3\u0142 nr 69 im. Armii Krajowej Grupy Bojowej \u201eKRYBAR\u201d,\r\n\t\t\t\tul. Drewniana 8, 00-345 Warszawa; klasa druga pod opiek\u0105\r\n\t\t\t\tAnny Budziarek-Friedrich:\r\n\t\t\t</p>\r\n\r\n\t\t\t<ul>\r\n\t\t\t\t<li>Burdon Filip;</li>\r\n\r\n\t\t\t\t<li>D\u0119bski Bartek;</li>\r\n\t\t\t\t<li>Jackowicz Kamil;</li>\r\n\t\t\t\t<li>Kurek Pawe\u0142;</li>\r\n\t\t\t\t<li>Makles Bartosz;</li>\r\n\t\t\t\t<li>Markiewicz Jeremiasz;</li>\r\n\t\t\t\t<li>Migda\u0142 Katarzyna;</li>\r\n\r\n\t\t\t\t<li>Mioduszewski Micha\u0142;</li>\r\n\t\t\t\t<li>Pfeiffer Ida;</li>\r\n\t\t\t\t<li>P\u0142askowicka Karolina;</li>\r\n\t\t\t\t<li>Sailer Ewa.</li>\r\n\t\t\t</ul>\r\n\t\t</li>\r\n\r\n\t\t<li>\r\n\t\t\t<p>\r\n\t\t\t\tXXXIII Liceum Og\u00f3lnokszta\u0142c\u0105ce im. Miko\u0142aja Kopernika,\r\n\t\t\t\tul. Bema 76, 01-225 Warszawa; klasa pierwsza o profilu\r\n\t\t\t\tbiologiczno-chemicznym pod opiek\u0105 El\u017cbiety Konkowskiej:\r\n\t\t\t</p>\r\n\r\n\t\t\t<ul>\r\n\t\t\t\t<li>Chwil Bart\u0142omiej;</li>\r\n\t\t\t\t<li>Czarnecka Natalia;</li>\r\n\t\t\t\t<li>Gawro\u0144ska Iga;</li>\r\n\r\n\t\t\t\t<li>Grabarczyk Marta;</li>\r\n\t\t\t\t<li>Jastrz\u0105b Katarzyna;</li>\r\n\t\t\t\t<li>Krawczak Olga;</li>\r\n\t\t\t\t<li>Krawczyk Marianna;</li>\r\n\t\t\t\t<li>Kur Natalia;</li>\r\n\t\t\t\t<li>Kwiatek Marta;</li>\r\n\r\n\t\t\t\t<li>La\u015bkiewicz Joanna;</li>\r\n\t\t\t\t<li>Machczy\u0144ska Daria;</li>\r\n\t\t\t\t<li>Miecznikowska Izabela;</li>\r\n\t\t\t\t<li>Moczulska Karolina;</li>\r\n\t\t\t\t<li>Mo\u015bcicka Aneta;</li>\r\n\t\t\t\t<li>Narloch Sabina;</li>\r\n\r\n\t\t\t\t<li>Przybysz Pawe\u0142;</li>\r\n\t\t\t\t<li>Puchta Marek;</li>\r\n\t\t\t\t<li>Ryska Cezary;</li>\r\n\t\t\t\t<li>Sandomierski Bart\u0142omiej;</li>\r\n\t\t\t\t<li>S\u0142awi\u0144ski Tomasz;</li>\r\n\t\t\t\t<li>S\u0142owik Olga;</li>\r\n\r\n\t\t\t\t<li>Starzycka Katarzyna;</li>\r\n\t\t\t\t<li>Strzelczak Karolina;</li>\r\n\t\t\t\t<li>Szafran Danuta;</li>\r\n\t\t\t\t<li>Szmigielska Magdalena;</li>\r\n\t\t\t\t<li>Szulkowska Alicja;</li>\r\n\t\t\t\t<li>\u015alusarczyk Anna;</li>\r\n\r\n\t\t\t\t<li>Tytkowska Anna.</li>\r\n\t\t\t</ul>\r\n\t\t\t<li>\r\n\t\t\t\t<p>\r\n\t\t\t\t\tAutorskie Niepubliczne Liceum Og\u00f3lnokszta\u0142c\u0105ce nr\r\n\t\t\t\t\t42, ul. Iwicka 47 B, 00-735 Warszawa; klasa pierwsza\r\n\t\t\t\t\to profilu og\u00f3lnym pod opiek\u0105 Micha\u0142a Friedricha:\r\n\t\t\t\t</p>\r\n\r\n\t\t\t\t<ul>\r\n\t\t\t\t\t<li>Baraniecka Marta;</li>\r\n\r\n\t\t\t\t\t<li>Go\u0142aszewska Ewa;</li>\r\n\t\t\t\t\t<li>Kwiatkowski Micha\u0142;</li>\r\n\t\t\t\t\t<li>Machnikowska Monika;</li>\r\n\t\t\t\t\t<li>Pietrzak Bartosz;</li>\r\n\t\t\t\t\t<li>Przespolewski Przemys\u0142aw;</li>\r\n\t\t\t\t\t<li>Rosi\u0144ska Zuzanna;</li>\r\n\r\n\t\t\t\t\t<li>Sibiga Magdalena.</li>\r\n\t\t\t\t</ul>\r\n\t\t\t</li>\r\n\t\t\t<li>\r\n\t\t\t\t<p>\r\n\t\t\t\t\tLXIV Liceum Og\u00f3lnokszta\u0142c\u0105ce im. St. I. Witkiewicza,\r\n\t\t\t\t\tul. Elbl\u0105ska 51, 01-737 Warszawa; klasa pierwsza o\r\n\t\t\t\t\tprofilu og\u00f3lnym pod opiek\u0105 Daniela Zycha:\r\n\t\t\t\t</p>\r\n\r\n\t\t\t\t<ul>\r\n\r\n\t\t\t\t\t<li>Andrzejczak Kamil;</li>\r\n\t\t\t\t\t<li>Czubaj Konrad;</li>\r\n\t\t\t\t\t<li>Dr\u0105gowska Katarzyna;</li>\r\n\t\t\t\t\t<li>Gajewska Magdalena;</li>\r\n\t\t\t\t\t<li>G\u0142owacki Jan;</li>\r\n\t\t\t\t\t<li>Grad Pawe\u0142;</li>\r\n\r\n\t\t\t\t\t<li>Hnatowski Bartek;</li>\r\n\t\t\t\t\t<li>Karwowski Marcin;</li>\r\n\t\t\t\t\t<li>K\u0142os Aneta;</li>\r\n\t\t\t\t\t<li>Kozie\u0142 Barbara;</li>\r\n\t\t\t\t\t<li>Koz\u0142owska Anna;</li>\r\n\t\t\t\t\t<li>Krug Pamela;</li>\r\n\r\n\t\t\t\t\t<li>Krzosek Jakub;</li>\r\n\t\t\t\t\t<li>Luba\u015b Micha\u0142;</li>\r\n\t\t\t\t\t<li>Masewicz Natalia;</li>\r\n\t\t\t\t\t<li>Mastalerz Agnieszka;</li>\r\n\t\t\t\t\t<li>Modelska Marta;</li>\r\n\t\t\t\t\t<li>Nowak Aleksandra;</li>\r\n\r\n\t\t\t\t\t<li>Pabian Agnieszka;</li>\r\n\t\t\t\t\t<li>Paszkowska Aleksandra;</li>\r\n\t\t\t\t\t<li>Pielat Zofia;</li>\r\n\t\t\t\t\t<li>Poniecka Agnieszka;</li>\r\n\t\t\t\t\t<li>Pytlak Urszula;</li>\r\n\t\t\t\t\t<li>Rosa Karolina;</li>\r\n\r\n\t\t\t\t\t<li>Smyczy\u0144ska Kamila;</li>\r\n\t\t\t\t\t<li>Stoli\u0144ska Barbara;</li>\r\n\t\t\t\t\t<li>Szyma\u0144ska Katarzyna;</li>\r\n\t\t\t\t\t<li>\u015acibior Ewa;</li>\r\n\t\t\t\t\t<li>Witczak Magda;</li>\r\n\t\t\t\t\t<li>Witkowska Justyna;</li>\r\n\r\n\t\t\t\t\t<li>Wyrzykowska Jowita;</li>\r\n\t\t\t\t\t<li>Zi\u00f3\u0142kowska Adrianna.</li>\r\n\t\t\t\t</ul>\r\n\t\t\t</li>\r\n\t  </li>\r\n\t  </ol>\r\n", 
+            "page_title_en": "Volunteering for knowledge on WolneLektury.pl", 
+            "page_title_es": "Voluntariado para el conocimiento en WolneLektury.pl", 
+            "left_column_lt": "<h2>Savanoriai</h2>\r\n\t<p>\r\n\t\tAutoriu biografijos ir literat\u016brinis r\u016b\u0161i\u0173 apra\u0161ymus \r\n\t\tinternetineje bibliotekoje Laisvoji Literatura paruo\u0161e mokiniai\r\n\t\ti\u0161 keturi\u0173 mokykl\u0173 seminarijos \u201eLik savanoriu kad su\u017einoti daugiau\u201d.\r\n\t</p>\r\n\r\n\t<p>\r\n\t\tMokiniai dirbo visi kartu globojami mokytoj\u0173 ir literaturos \u017einov\u0173.\r\n\t\t<a href=\"http://wolnepodreczniki.pl/wolontariat/\">\r\n\r\n\t\t\tinternetine platforma viki</a>\r\n\t\tparuo\u0161ta grup\u0117s\r\n\t\t<a href=\"http://2ia.pl/\">2ia</a>. Kuriant apra\u0161ymus naudojo kompiuterius, internet\u0105 tamkad\r\n\t\t surasti informacij\u0105 ir patikrinti jos tik\u0117tingum\u0105.\r\n\t</p>\r\n\r\n\t<p>\r\n\t\tProjektas \"Lik savanoriu kad su\u017einoti daugiau\" buvo \u012fvykdytas\r\n\t\t d\u0117ka\r\n\t\t<a href=\"http://www.menis.gov.pl/\">\r\n\t\t\tMinisterstwa Edukacji Narodowej</a>. Dovanas mokiniams \u012fsteig\u0117\r\n\t\t<a href=\"http://www.nk.com.pl/engine/index.php?page=glowna\">\r\n\r\n\t\t\tLeidykla M\u016bs\u016b Knygynas</a>\r\n\t\ti\r\n\t\t<a href=\"http://helion.pl/\">Wydawnictwo Helion</a>. Patikrinta servise.\r\n\t\t<a href=\"http://www.plagiat.pl/webplagiat/main.action\">\r\n\t\t\tPlagiat.pl</a>.\r\n\t</p>\r\n\r\n\t<p>\r\n\t\t<a href=\"/static/wolontariat.pdf\">Raportas suristas su \u012fgyvendinimu projekto \u201eLik savanoriu kad su\u017einoti daugiau\"</a>.\r\n\t</p>\r\n\r\n\t<p>\r\n\t<img src=\"/static/img/wolontariat/okladka.jpg\" style='margin: 10px' />\r\n\t<img src=\"/static/img/wolontariat/01.jpg\" style='margin: 10px' />\r\n\t<img src=\"/static/img/wolontariat/02.jpg\" style='margin: 10px' />\r\n    <img src=\"/static/img/wolontariat/03.jpg\" style='margin: 10px' />\r\n    <img src=\"/static/img/wolontariat/04.jpg\" style='margin: 10px' />\r\n\t</p>\r\n", 
+            "title_fr": "B\u00e9n\u00e9volat pour le savoir", 
+            "right_column_ru": "\t<h2>\u0410\u0432\u0442\u043e\u0440\u044b</h2>\r\n\r\n\t<ol>\r\n\t\t<li>\r\n\t\t\t<p>\r\n\t\t\t\t\u0413\u0438\u043c\u043d\u0430\u0437\u0438\u0439 \u043d\u043e\u043c\u0435\u0440 40 \u0441 \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u043c\u0438 \u043e\u0442\u0434\u0435\u043b\u0435\u043d\u0438\u044f\u043c\u0438 \u0432 \u043a\u043e\u043c\u043f\u043b\u0435\u043a\u0441\u0435\r\n\t\t\t\t\u0448\u043a\u043e\u043b \u043d\u043e\u043c\u0435\u0440 69 \u0438\u043c. \u0410\u0440\u0438\u043c\u0438\u0438 \u043a\u0440\u0430\u0439\u043e\u0432\u043e\u0439 \u0431\u043e\u0435\u0432\u043e\u0439 \u0433\u0440\u0443\u043f\u043f\u044b \u201eKRYBAR\u201d,\r\n\t\t\t\tul. Drewniana 8, 00-345 Warszawa; \u0432\u0442\u043e\u0440\u043e\u0439 \u043a\u043b\u0430\u0441\u0441 \u043f\u043e\u0434 \u0440\u0443\u043a\u043e\u0432\u043e\u0434\u0441\u0442\u0432\u043e\u043c\r\n\t\t\t\tAnny Budziarek-Friedrich:\r\n\t\t\t</p>\r\n\r\n\t\t\t<ul>\r\n\t\t\t\t<li>Burdon Filip;</li>\r\n\r\n\t\t\t\t<li>D\u0119bski Bartek;</li>\r\n\t\t\t\t<li>Jackowicz Kamil;</li>\r\n\t\t\t\t<li>Kurek Pawe\u0142;</li>\r\n\t\t\t\t<li>Makles Bartosz;</li>\r\n\t\t\t\t<li>Markiewicz Jeremiasz;</li>\r\n\t\t\t\t<li>Migda\u0142 Katarzyna;</li>\r\n\r\n\t\t\t\t<li>Mioduszewski Micha\u0142;</li>\r\n\t\t\t\t<li>Pfeiffer Ida;</li>\r\n\t\t\t\t<li>P\u0142askowicka Karolina;</li>\r\n\t\t\t\t<li>Sailer Ewa.</li>\r\n\t\t\t</ul>\r\n\t\t</li>\r\n\r\n\t\t<li>\r\n\t\t\t<p>\r\n\t\t\t\tXXXIII \u041e\u0431\u0449\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u043b\u0438\u0446\u0435\u0439 \u0438\u043c. \u041d\u0438\u043a\u043e\u043b\u0430\u044f \u041a\u043e\u043f\u0435\u0440\u043d\u0438\u043a\u0430,\r\n\t\t\t\tul. Bema 76, 01-225 Warszawa; \u043f\u0435\u0440\u0432\u044b\u0439 \u043a\u043b\u0430\u0441\u0441 \u0431\u0438\u043e\u043b\u043e\u0433\u0438\u0447\u0435\u0441\u043a\u043e-\u0445\u0438\u043c\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e\r\n\t\t\t\t\u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043f\u043e\u0434 \u0440\u0443\u043a\u043e\u0432\u043e\u0434\u0441\u0442\u0432\u043e\u043c El\u017cbiety Konkowskiej:\r\n\t\t\t</p>\r\n\r\n\t\t\t<ul>\r\n\t\t\t\t<li>Chwil Bart\u0142omiej;</li>\r\n\t\t\t\t<li>Czarnecka Natalia;</li>\r\n\t\t\t\t<li>Gawro\u0144ska Iga;</li>\r\n\r\n\t\t\t\t<li>Grabarczyk Marta;</li>\r\n\t\t\t\t<li>Jastrz\u0105b Katarzyna;</li>\r\n\t\t\t\t<li>Krawczak Olga;</li>\r\n\t\t\t\t<li>Krawczyk Marianna;</li>\r\n\t\t\t\t<li>Kur Natalia;</li>\r\n\t\t\t\t<li>Kwiatek Marta;</li>\r\n\r\n\t\t\t\t<li>La\u015bkiewicz Joanna;</li>\r\n\t\t\t\t<li>Machczy\u0144ska Daria;</li>\r\n\t\t\t\t<li>Miecznikowska Izabela;</li>\r\n\t\t\t\t<li>Moczulska Karolina;</li>\r\n\t\t\t\t<li>Mo\u015bcicka Aneta;</li>\r\n\t\t\t\t<li>Narloch Sabina;</li>\r\n\r\n\t\t\t\t<li>Przybysz Pawe\u0142;</li>\r\n\t\t\t\t<li>Puchta Marek;</li>\r\n\t\t\t\t<li>Ryska Cezary;</li>\r\n\t\t\t\t<li>Sandomierski Bart\u0142omiej;</li>\r\n\t\t\t\t<li>S\u0142awi\u0144ski Tomasz;</li>\r\n\t\t\t\t<li>S\u0142owik Olga;</li>\r\n\r\n\t\t\t\t<li>Starzycka Katarzyna;</li>\r\n\t\t\t\t<li>Strzelczak Karolina;</li>\r\n\t\t\t\t<li>Szafran Danuta;</li>\r\n\t\t\t\t<li>Szmigielska Magdalena;</li>\r\n\t\t\t\t<li>Szulkowska Alicja;</li>\r\n\t\t\t\t<li>\u015alusarczyk Anna;</li>\r\n\r\n\t\t\t\t<li>Tytkowska Anna.</li>\r\n\t\t\t</ul>\r\n\t\t\t<li>\r\n\t\t\t\t<p>\r\n\t\t\t\t\t\u0410\u0432\u0442\u043e\u0440\u0441\u043a\u0438\u0439 \u043d\u0435\u043f\u0443\u0431\u043b\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u043e\u0431\u0449\u0435\u043e\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u043b\u0438\u0446\u0435\u0439 \u043d\u043e\u043c\u0435\u0440\r\n\t\t\t\t\t42, ul. Iwicka 47 B, 00-735 Warszawa;\u043f\u0435\u0440\u0432\u044b\u0439 \u043a\u043b\u0430\u0441\u0441\r\n\t\t\t\t\t\u043e\u0431\u0449\u0435\u0433\u043e \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043f\u043e\u0434 \u0440\u0443\u043a\u043e\u0432\u043e\u0434\u0441\u0442\u0432\u043e\u043c Micha\u0142a Friedricha:\r\n\t\t\t\t</p>\r\n\r\n\t\t\t\t<ul>\r\n\t\t\t\t\t<li>Baraniecka Marta;</li>\r\n\r\n\t\t\t\t\t<li>Go\u0142aszewska Ewa;</li>\r\n\t\t\t\t\t<li>Kwiatkowski Micha\u0142;</li>\r\n\t\t\t\t\t<li>Machnikowska Monika;</li>\r\n\t\t\t\t\t<li>Pietrzak Bartosz;</li>\r\n\t\t\t\t\t<li>Przespolewski Przemys\u0142aw;</li>\r\n\t\t\t\t\t<li>Rosi\u0144ska Zuzanna;</li>\r\n\r\n\t\t\t\t\t<li>Sibiga Magdalena.</li>\r\n\t\t\t\t</ul>\r\n\t\t\t</li>\r\n\t\t\t<li>\r\n\t\t\t\t<p>\r\n\t\t\t\t\tLXIV \u041e\u0431\u0449\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u043b\u0438\u0446\u0435\u0439 \u0438\u043c. \u0421. \u0418. \u0412\u0438\u0442\u043a\u0435\u0432\u0438\u0447\u0430,\r\n\t\t\t\t\tul. Elbl\u0105ska 51, 01-737 Warszawa; \u043f\u0435\u0440\u0432\u044b\u0439 \u043a\u043b\u0430\u0441\u0441\r\n\t\t\t\t\t\u043e\u0431\u0449\u0435\u0433\u043e \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043f\u043e\u0434 \u0440\u0443\u043a\u043e\u0432\u043e\u0434\u0441\u0442\u0432\u043e\u043c Daniela Zycha:\r\n\t\t\t\t</p>\r\n\r\n\t\t\t\t<ul>\r\n\r\n\t\t\t\t\t<li>Andrzejczak Kamil;</li>\r\n\t\t\t\t\t<li>Czubaj Konrad;</li>\r\n\t\t\t\t\t<li>Dr\u0105gowska Katarzyna;</li>\r\n\t\t\t\t\t<li>Gajewska Magdalena;</li>\r\n\t\t\t\t\t<li>G\u0142owacki Jan;</li>\r\n\t\t\t\t\t<li>Grad Pawe\u0142;</li>\r\n\r\n\t\t\t\t\t<li>Hnatowski Bartek;</li>\r\n\t\t\t\t\t<li>Karwowski Marcin;</li>\r\n\t\t\t\t\t<li>K\u0142os Aneta;</li>\r\n\t\t\t\t\t<li>Kozie\u0142 Barbara;</li>\r\n\t\t\t\t\t<li>Koz\u0142owska Anna;</li>\r\n\t\t\t\t\t<li>Krug Pamela;</li>\r\n\r\n\t\t\t\t\t<li>Krzosek Jakub;</li>\r\n\t\t\t\t\t<li>Luba\u015b Micha\u0142;</li>\r\n\t\t\t\t\t<li>Masewicz Natalia;</li>\r\n\t\t\t\t\t<li>Mastalerz Agnieszka;</li>\r\n\t\t\t\t\t<li>Modelska Marta;</li>\r\n\t\t\t\t\t<li>Nowak Aleksandra;</li>\r\n\r\n\t\t\t\t\t<li>Pabian Agnieszka;</li>\r\n\t\t\t\t\t<li>Paszkowska Aleksandra;</li>\r\n\t\t\t\t\t<li>Pielat Zofia;</li>\r\n\t\t\t\t\t<li>Poniecka Agnieszka;</li>\r\n\t\t\t\t\t<li>Pytlak Urszula;</li>\r\n\t\t\t\t\t<li>Rosa Karolina;</li>\r\n\r\n\t\t\t\t\t<li>Smyczy\u0144ska Kamila;</li>\r\n\t\t\t\t\t<li>Stoli\u0144ska Barbara;</li>\r\n\t\t\t\t\t<li>Szyma\u0144ska Katarzyna;</li>\r\n\t\t\t\t\t<li>\u015acibior Ewa;</li>\r\n\t\t\t\t\t<li>Witczak Magda;</li>\r\n\t\t\t\t\t<li>Witkowska Justyna;</li>\r\n\r\n\t\t\t\t\t<li>Wyrzykowska Jowita;</li>\r\n\t\t\t\t\t<li>Zi\u00f3\u0142kowska Adrianna.</li>\r\n\t\t\t\t</ul>\r\n\t\t\t</li>\r\n\t  </li>\r\n\t  </ol>", 
+            "left_column_fr": "<h2>B\u00e9n\u00e9volat</h2>\r\n\t<p>\r\n\t\tLes histoires de vie des auteurs ainsi que les d\u00e9finitions des \u00e9poques et genres litt\u00e9raires dans la biblioth\u00e8que en ligne Lectures libres ont \u00e9t\u00e9 \u00e9crites par les \u00e9l\u00e8ves des quatre \u00e9coles pendant les ateliers \"B\u00e9n\u00e9volat pour le savoir\"\r\n\t</p>\r\n\r\n\t<p>\r\n\t\tLes \u00e9l\u00e8ves ont travaill\u00e9 ensemble sous la supervision des professeurs et sp\u00e9cialistes \u2013 hommes des lettres sur\r\n\t\t<a href=\"http://wolnepodreczniki.pl/wolontariat/\">\r\n\r\n\t\tune platforme en ligne wiki</a>\r\n\t\tmise en place par l'\u00e9quipe\r\n\t\t<a href=\"http://2ia.pl/\">2ia</a>. Le travail sur les fiches comprenait aussi la ma\u00eetrise de l'ordinateur et de l'internet pour chercher des informations, ainsi que pour v\u00e9rifier leur fiabilit\u00e9.\r\n\t</p>\r\n\r\n\t<p>\r\n\t\tLe projet \"B\u00e9n\u00e9volat pour le savoir\" a \u00e9t\u00e9 r\u00e9alis\u00e9 gr\u00e2ce \u00e0 l'appui \t<a href=\"http://www.menis.gov.pl/\">\r\n\t\tdu Minist\u00e8re de l'Education nationale\t</a>. Des r\u00e9compenses pour les \u00e9l\u00e8ves ont \u00e9t\u00e9 fond\u00e9es par <a href=\"http://www.nk.com.pl/engine/index.php?page=glowna\">\r\n\r\n\t\t\tla Maison d'\u00e9dition Nasza Ksi\u0119garnia</a>\r\n\t\tet\r\n\t\t<a href=\"http://helion.pl/\">la Maison d'\u00e9dition Helion</a>. Les fiches ont \u00e9t\u00e9 v\u00e9rifi\u00e9es sur le site\r\n\t\t<a href=\"http://www.plagiat.pl/webplagiat/main.action\">\r\n\t\t\tPlagiat.pl</a>.\r\n\t</p>\r\n\r\n\t<p>\r\n\t\t<a href=\"/static/wolontariat.pdf\"> Le rapport sur la r\u00e9alisation du projet \"B\u00e9n\u00e9volat pour le savoir\"\r\n</a>.\r\n\t</p>\r\n\r\n\t<p>\r\n\t<img src=\"/static/img/wolontariat/okladka.jpg\" style='margin: 10px' />\r\n\t<img src=\"/static/img/wolontariat/01.jpg\" style='margin: 10px' />\r\n\t<img src=\"/static/img/wolontariat/02.jpg\" style='margin: 10px' />\r\n    <img src=\"/static/img/wolontariat/03.jpg\" style='margin: 10px' />\r\n    <img src=\"/static/img/wolontariat/04.jpg\" style='margin: 10px' />\r\n\t</p>", 
+            "title": "Volunteering for knowledge", 
+            "title_lt": "Lik savanoriu kad su\u009einoti daugiau", 
+            "right_column": "<h2>Authors</h2>\r\n\r\n\t<ol>\r\n\t\t<li>\r\n\t\t\tGimnazjum nr 40 z Oddzia\u0142ami Integracyjnymi w Zespole\r\n\t\t\t\tSzk\u00f3\u0142 nr 69 im. Armii Krajowej Grupy Bojowej \u201eKRYBAR\u201d,\r\n\t\t\t\tul. Drewniana 8, 00-345 Warszawa; second form attented by\t\t\t\tAnna Budziarek-Friedrich:\r\n\t\t\t</p>\r\n\r\n\t\t\t<ul>\r\n\t\t\t\t<li>Burdon Filip;</li>\r\n\r\n\t\t\t\t<li>D\u0119bski Bartek;</li>\r\n\t\t\t\t<li>Jackowicz Kamil;</li>\r\n\t\t\t\t<li>Kurek Pawe\u0142;</li>\r\n\t\t\t\t<li>Makles Bartosz;</li>\r\n\t\t\t\t<li>Markiewicz Jeremiasz;</li>\r\n\t\t\t\t<li>Migda\u0142 Katarzyna;</li>\r\n\r\n\t\t\t\t<li>Mioduszewski Micha\u0142;</li>\r\n\t\t\t\t<li>Pfeiffer Ida;</li>\r\n\t\t\t\t<li>P\u0142askowicka Karolina;</li>\r\n\t\t\t\t<li>Sailer Ewa.</li>\r\n\t\t\t</ul>\r\n\t\t</li>\r\n\r\n\t\t<li>\r\n\t\t\t<p>\r\n\t\t\t\tXXXIII Liceum Og\u00f3lnokszta\u0142c\u0105ce im. Miko\u0142aja Kopernika,\r\n\t\t\t\tul. Bema 76, 01-225 Warszawa; first year, biologyoriented class attented by  El\u017cbieta Konkowskiej:\r\n\t\t\t</p>\r\n\r\n\t\t\t<ul>\r\n\t\t\t\t<li>Chwil Bart\u0142omiej;</li>\r\n\t\t\t\t<li>Czarnecka Natalia;</li>\r\n\t\t\t\t<li>Gawro\u0144ska Iga;</li>\r\n\r\n\t\t\t\t<li>Grabarczyk Marta;</li>\r\n\t\t\t\t<li>Jastrz\u0105b Katarzyna;</li>\r\n\t\t\t\t<li>Krawczak Olga;</li>\r\n\t\t\t\t<li>Krawczyk Marianna;</li>\r\n\t\t\t\t<li>Kur Natalia;</li>\r\n\t\t\t\t<li>Kwiatek Marta;</li>\r\n\r\n\t\t\t\t<li>La\u015bkiewicz Joanna;</li>\r\n\t\t\t\t<li>Machczy\u0144ska Daria;</li>\r\n\t\t\t\t<li>Miecznikowska Izabela;</li>\r\n\t\t\t\t<li>Moczulska Karolina;</li>\r\n\t\t\t\t<li>Mo\u015bcicka Aneta;</li>\r\n\t\t\t\t<li>Narloch Sabina;</li>\r\n\r\n\t\t\t\t<li>Przybysz Pawe\u0142;</li>\r\n\t\t\t\t<li>Puchta Marek;</li>\r\n\t\t\t\t<li>Ryska Cezary;</li>\r\n\t\t\t\t<li>Sandomierski Bart\u0142omiej;</li>\r\n\t\t\t\t<li>S\u0142awi\u0144ski Tomasz;</li>\r\n\t\t\t\t<li>S\u0142owik Olga;</li>\r\n\r\n\t\t\t\t<li>Starzycka Katarzyna;</li>\r\n\t\t\t\t<li>Strzelczak Karolina;</li>\r\n\t\t\t\t<li>Szafran Danuta;</li>\r\n\t\t\t\t<li>Szmigielska Magdalena;</li>\r\n\t\t\t\t<li>Szulkowska Alicja;</li>\r\n\t\t\t\t<li>\u015alusarczyk Anna;</li>\r\n\r\n\t\t\t\t<li>Tytkowska Anna.</li>\r\n\t\t\t</ul>\r\n\t\t\t<li>\r\n\t\t\t\t<p>\r\n\t\t\t\t\tAutorskie Niepubliczne Liceum Og\u00f3lnokszta\u0142c\u0105ce nr\r\n\t\t\t\t\t42, ul. Iwicka 47 B, 00-735 Warszawa; first year, general education class attented by Micha\u0142 Friedrich:\r\n\t\t\t\t</p>\r\n\r\n\t\t\t\t<ul>\r\n\t\t\t\t\t<li>Baraniecka Marta;</li>\r\n\r\n\t\t\t\t\t<li>Go\u0142aszewska Ewa;</li>\r\n\t\t\t\t\t<li>Kwiatkowski Micha\u0142;</li>\r\n\t\t\t\t\t<li>Machnikowska Monika;</li>\r\n\t\t\t\t\t<li>Pietrzak Bartosz;</li>\r\n\t\t\t\t\t<li>Przespolewski Przemys\u0142aw;</li>\r\n\t\t\t\t\t<li>Rosi\u0144ska Zuzanna;</li>\r\n\r\n\t\t\t\t\t<li>Sibiga Magdalena.</li>\r\n\t\t\t\t</ul>\r\n\t\t\t</li>\r\n\t\t\t<li>\r\n\t\t\t\t<p>\r\n\t\t\t\t\tLXIV Liceum Og\u00f3lnokszta\u0142c\u0105ce im. St. I. Witkiewicza,\r\n\t\t\t\t\tul. Elbl\u0105ska 51, 01-737 Warszawa; first year, general education class attented by Daniel Zych:\r\n\t\t\t\t</p>\r\n\r\n\t\t\t\t<ul>\r\n\r\n\t\t\t\t\t<li>Andrzejczak Kamil;</li>\r\n\t\t\t\t\t<li>Czubaj Konrad;</li>\r\n\t\t\t\t\t<li>Dr\u0105gowska Katarzyna;</li>\r\n\t\t\t\t\t<li>Gajewska Magdalena;</li>\r\n\t\t\t\t\t<li>G\u0142owacki Jan;</li>\r\n\t\t\t\t\t<li>Grad Pawe\u0142;</li>\r\n\r\n\t\t\t\t\t<li>Hnatowski Bartek;</li>\r\n\t\t\t\t\t<li>Karwowski Marcin;</li>\r\n\t\t\t\t\t<li>K\u0142os Aneta;</li>\r\n\t\t\t\t\t<li>Kozie\u0142 Barbara;</li>\r\n\t\t\t\t\t<li>Koz\u0142owska Anna;</li>\r\n\t\t\t\t\t<li>Krug Pamela;</li>\r\n\r\n\t\t\t\t\t<li>Krzosek Jakub;</li>\r\n\t\t\t\t\t<li>Luba\u015b Micha\u0142;</li>\r\n\t\t\t\t\t<li>Masewicz Natalia;</li>\r\n\t\t\t\t\t<li>Mastalerz Agnieszka;</li>\r\n\t\t\t\t\t<li>Modelska Marta;</li>\r\n\t\t\t\t\t<li>Nowak Aleksandra;</li>\r\n\r\n\t\t\t\t\t<li>Pabian Agnieszka;</li>\r\n\t\t\t\t\t<li>Paszkowska Aleksandra;</li>\r\n\t\t\t\t\t<li>Pielat Zofia;</li>\r\n\t\t\t\t\t<li>Poniecka Agnieszka;</li>\r\n\t\t\t\t\t<li>Pytlak Urszula;</li>\r\n\t\t\t\t\t<li>Rosa Karolina;</li>\r\n\r\n\t\t\t\t\t<li>Smyczy\u0144ska Kamila;</li>\r\n\t\t\t\t\t<li>Stoli\u0144ska Barbara;</li>\r\n\t\t\t\t\t<li>Szyma\u0144ska Katarzyna;</li>\r\n\t\t\t\t\t<li>\u015acibior Ewa;</li>\r\n\t\t\t\t\t<li>Witczak Magda;</li>\r\n\t\t\t\t\t<li>Witkowska Justyna;</li>\r\n\r\n\t\t\t\t\t<li>Wyrzykowska Jowita;</li>\r\n\t\t\t\t\t<li>Zi\u00f3\u0142kowska Adrianna.</li>\r\n\t\t\t\t</ul>\r\n\t\t\t</li>\r\n\t  </li>\r\n\t  </ol>", 
+            "right_column_es": "\t<h2>Autores</h2>\r\n\r\n\r\n\r\n\t<ol>\r\n\r\n\t\t<li>\r\n\r\n\t\t\t<p>\r\n\r\n\t\t\t\tGimnazjum nr 40 z Oddzia\u0142ami Integracyjnymi w Zespole\r\n\r\n\t\t\t\tSzk\u00f3\u0142 nr 69 im. Armii Krajowej Grupy Bojowej \u201eKRYBAR\u201d,\r\n\r\n\t\t\t\tC/ Drewniana 8, 00-345 Varsovia; segundo curso bajo la supervisi\u00f3n de\r\n\r\n\t\t\t\tAnna Budziarek-Friedrich:\r\n\r\n\t\t\t</p>\r\n\r\n\r\n\r\n\t\t\t<ul>\r\n\r\n\t\t\t\t<li>Burdon Filip;</li>\r\n\r\n\r\n\r\n\t\t\t\t<li>D\u0119bski Bartek;</li>\r\n\r\n\t\t\t\t<li>Jackowicz Kamil;</li>\r\n\r\n\t\t\t\t<li>Kurek Pawe\u0142;</li>\r\n\r\n\t\t\t\t<li>Makles Bartosz;</li>\r\n\r\n\t\t\t\t<li>Markiewicz Jeremiasz;</li>\r\n\r\n\t\t\t\t<li>Migda\u0142 Katarzyna;</li>\r\n\r\n\r\n\r\n\t\t\t\t<li>Mioduszewski Micha\u0142;</li>\r\n\r\n\t\t\t\t<li>Pfeiffer Ida;</li>\r\n\r\n\t\t\t\t<li>P\u0142askowicka Karolina;</li>\r\n\r\n\t\t\t\t<li>Sailer Ewa.</li>\r\n\r\n\t\t\t</ul>\r\n\r\n\t\t</li>\r\n\r\n\r\n\r\n\t\t<li>\r\n\r\n\t\t\t<p>\r\n\r\n\t\t\t\tXXXIII Liceum Og\u00f3lnokszta\u0142c\u0105ce im. Miko\u0142aja Kopernika,\r\n\r\n\t\t\t\tC/ Bema 76, 01-225 Varsovia; primer curso de perfil biol\u00f3gico-qu\u00edmico bajo la supervisi\u00f3n de El\u017cbieta Konkowska:\r\n\r\n\t\t\t</p>\r\n\r\n\r\n\r\n\t\t\t<ul>\r\n\r\n\t\t\t\t<li>Chwil Bart\u0142omiej;</li>\r\n\r\n\t\t\t\t<li>Czarnecka Natalia;</li>\r\n\r\n\t\t\t\t<li>Gawro\u0144ska Iga;</li>\r\n\r\n\r\n\r\n\t\t\t\t<li>Grabarczyk Marta;</li>\r\n\r\n\t\t\t\t<li>Jastrz\u0105b Katarzyna;</li>\r\n\r\n\t\t\t\t<li>Krawczak Olga;</li>\r\n\r\n\t\t\t\t<li>Krawczyk Marianna;</li>\r\n\r\n\t\t\t\t<li>Kur Natalia;</li>\r\n\r\n\t\t\t\t<li>Kwiatek Marta;</li>\r\n\r\n\r\n\r\n\t\t\t\t<li>La\u015bkiewicz Joanna;</li>\r\n\r\n\t\t\t\t<li>Machczy\u0144ska Daria;</li>\r\n\r\n\t\t\t\t<li>Miecznikowska Izabela;</li>\r\n\r\n\t\t\t\t<li>Moczulska Karolina;</li>\r\n\r\n\t\t\t\t<li>Mo\u015bcicka Aneta;</li>\r\n\r\n\t\t\t\t<li>Narloch Sabina;</li>\r\n\r\n\r\n\r\n\t\t\t\t<li>Przybysz Pawe\u0142;</li>\r\n\r\n\t\t\t\t<li>Puchta Marek;</li>\r\n\r\n\t\t\t\t<li>Ryska Cezary;</li>\r\n\r\n\t\t\t\t<li>Sandomierski Bart\u0142omiej;</li>\r\n\r\n\t\t\t\t<li>S\u0142awi\u0144ski Tomasz;</li>\r\n\r\n\t\t\t\t<li>S\u0142owik Olga;</li>\r\n\r\n\r\n\r\n\t\t\t\t<li>Starzycka Katarzyna;</li>\r\n\r\n\t\t\t\t<li>Strzelczak Karolina;</li>\r\n\r\n\t\t\t\t<li>Szafran Danuta;</li>\r\n\r\n\t\t\t\t<li>Szmigielska Magdalena;</li>\r\n\r\n\t\t\t\t<li>Szulkowska Alicja;</li>\r\n\r\n\t\t\t\t<li>\u015alusarczyk Anna;</li>\r\n\r\n\r\n\r\n\t\t\t\t<li>Tytkowska Anna.</li>\r\n\r\n\t\t\t</ul>\r\n\r\n\t\t\t<li>\r\n\r\n\t\t\t\t<p>\r\n\r\n\t\t\t\t\tAutorskie Niepubliczne Liceum Og\u00f3lnokszta\u0142c\u0105ce nr\r\n\r\n\t\t\t\t\t42, C/ Iwicka 47 B, 00-735 Varsovia; primer curso\r\n\r\n\t\t\t\t\tbajo la supervisi\u00f3n de Micha\u0142 Friedrich:\r\n\r\n\t\t\t\t</p>\r\n\r\n\r\n\r\n\t\t\t\t<ul>\r\n\r\n\t\t\t\t\t<li>Baraniecka Marta;</li>\r\n\r\n\r\n\r\n\t\t\t\t\t<li>Go\u0142aszewska Ewa;</li>\r\n\r\n\t\t\t\t\t<li>Kwiatkowski Micha\u0142;</li>\r\n\r\n\t\t\t\t\t<li>Machnikowska Monika;</li>\r\n\r\n\t\t\t\t\t<li>Pietrzak Bartosz;</li>\r\n\r\n\t\t\t\t\t<li>Przespolewski Przemys\u0142aw;</li>\r\n\r\n\t\t\t\t\t<li>Rosi\u0144ska Zuzanna;</li>\r\n\r\n\r\n\r\n\t\t\t\t\t<li>Sibiga Magdalena.</li>\r\n\r\n\t\t\t\t</ul>\r\n\r\n\t\t\t</li>\r\n\r\n\t\t\t<li>\r\n\r\n\t\t\t\t<p>\r\n\r\n\t\t\t\t\tLXIV Liceum Og\u00f3lnokszta\u0142c\u0105ce im. St. I. Witkiewicza,\r\n\r\n\t\t\t\t\tC/ Elbl\u0105ska 51, 01-737 Varsovia; primer curso bajo la supervisi\u00f3n de Daniel Zych:\r\n\r\n\t\t\t\t</p>\r\n\r\n\r\n\r\n\t\t\t\t<ul>\r\n\r\n\r\n\r\n\t\t\t\t\t<li>Andrzejczak Kamil;</li>\r\n\r\n\t\t\t\t\t<li>Czubaj Konrad;</li>\r\n\r\n\t\t\t\t\t<li>Dr\u0105gowska Katarzyna;</li>\r\n\r\n\t\t\t\t\t<li>Gajewska Magdalena;</li>\r\n\r\n\t\t\t\t\t<li>G\u0142owacki Jan;</li>\r\n\r\n\t\t\t\t\t<li>Grad Pawe\u0142;</li>\r\n\r\n\r\n\r\n\t\t\t\t\t<li>Hnatowski Bartek;</li>\r\n\r\n\t\t\t\t\t<li>Karwowski Marcin;</li>\r\n\r\n\t\t\t\t\t<li>K\u0142os Aneta;</li>\r\n\r\n\t\t\t\t\t<li>Kozie\u0142 Barbara;</li>\r\n\r\n\t\t\t\t\t<li>Koz\u0142owska Anna;</li>\r\n\r\n\t\t\t\t\t<li>Krug Pamela;</li>\r\n\r\n\r\n\r\n\t\t\t\t\t<li>Krzosek Jakub;</li>\r\n\r\n\t\t\t\t\t<li>Luba\u015b Micha\u0142;</li>\r\n\r\n\t\t\t\t\t<li>Masewicz Natalia;</li>\r\n\r\n\t\t\t\t\t<li>Mastalerz Agnieszka;</li>\r\n\r\n\t\t\t\t\t<li>Modelska Marta;</li>\r\n\r\n\t\t\t\t\t<li>Nowak Aleksandra;</li>\r\n\r\n\r\n\r\n\t\t\t\t\t<li>Pabian Agnieszka;</li>\r\n\r\n\t\t\t\t\t<li>Paszkowska Aleksandra;</li>\r\n\r\n\t\t\t\t\t<li>Pielat Zofia;</li>\r\n\r\n\t\t\t\t\t<li>Poniecka Agnieszka;</li>\r\n\r\n\t\t\t\t\t<li>Pytlak Urszula;</li>\r\n\r\n\t\t\t\t\t<li>Rosa Karolina;</li>\r\n\r\n\r\n\r\n\t\t\t\t\t<li>Smyczy\u0144ska Kamila;</li>\r\n\r\n\t\t\t\t\t<li>Stoli\u0144ska Barbara;</li>\r\n\r\n\t\t\t\t\t<li>Szyma\u0144ska Katarzyna;</li>\r\n\r\n\t\t\t\t\t<li>\u015acibior Ewa;</li>\r\n\r\n\t\t\t\t\t<li>Witczak Magda;</li>\r\n\r\n\t\t\t\t\t<li>Witkowska Justyna;</li>\r\n\r\n\r\n\r\n\t\t\t\t\t<li>Wyrzykowska Jowita;</li>\r\n\r\n\t\t\t\t\t<li>Zi\u00f3\u0142kowska Adrianna.</li>\r\n\r\n\t\t\t\t</ul>\r\n\r\n\t\t\t</li>\r\n\r\n\t  </li>\r\n\r\n\t  </ol>", 
+            "right_column_en": "<h2>Authors</h2>\r\n\r\n\t<ol>\r\n\t\t<li>\r\n\t\t\tGimnazjum nr 40 z Oddzia\u0142ami Integracyjnymi w Zespole\r\n\t\t\t\tSzk\u00f3\u0142 nr 69 im. Armii Krajowej Grupy Bojowej \u201eKRYBAR\u201d,\r\n\t\t\t\tul. Drewniana 8, 00-345 Warszawa; second form attented by\t\t\t\tAnna Budziarek-Friedrich:\r\n\t\t\t</p>\r\n\r\n\t\t\t<ul>\r\n\t\t\t\t<li>Burdon Filip;</li>\r\n\r\n\t\t\t\t<li>D\u0119bski Bartek;</li>\r\n\t\t\t\t<li>Jackowicz Kamil;</li>\r\n\t\t\t\t<li>Kurek Pawe\u0142;</li>\r\n\t\t\t\t<li>Makles Bartosz;</li>\r\n\t\t\t\t<li>Markiewicz Jeremiasz;</li>\r\n\t\t\t\t<li>Migda\u0142 Katarzyna;</li>\r\n\r\n\t\t\t\t<li>Mioduszewski Micha\u0142;</li>\r\n\t\t\t\t<li>Pfeiffer Ida;</li>\r\n\t\t\t\t<li>P\u0142askowicka Karolina;</li>\r\n\t\t\t\t<li>Sailer Ewa.</li>\r\n\t\t\t</ul>\r\n\t\t</li>\r\n\r\n\t\t<li>\r\n\t\t\t<p>\r\n\t\t\t\tXXXIII Liceum Og\u00f3lnokszta\u0142c\u0105ce im. Miko\u0142aja Kopernika,\r\n\t\t\t\tul. Bema 76, 01-225 Warszawa; first year, biologyoriented class attented by  El\u017cbieta Konkowskiej:\r\n\t\t\t</p>\r\n\r\n\t\t\t<ul>\r\n\t\t\t\t<li>Chwil Bart\u0142omiej;</li>\r\n\t\t\t\t<li>Czarnecka Natalia;</li>\r\n\t\t\t\t<li>Gawro\u0144ska Iga;</li>\r\n\r\n\t\t\t\t<li>Grabarczyk Marta;</li>\r\n\t\t\t\t<li>Jastrz\u0105b Katarzyna;</li>\r\n\t\t\t\t<li>Krawczak Olga;</li>\r\n\t\t\t\t<li>Krawczyk Marianna;</li>\r\n\t\t\t\t<li>Kur Natalia;</li>\r\n\t\t\t\t<li>Kwiatek Marta;</li>\r\n\r\n\t\t\t\t<li>La\u015bkiewicz Joanna;</li>\r\n\t\t\t\t<li>Machczy\u0144ska Daria;</li>\r\n\t\t\t\t<li>Miecznikowska Izabela;</li>\r\n\t\t\t\t<li>Moczulska Karolina;</li>\r\n\t\t\t\t<li>Mo\u015bcicka Aneta;</li>\r\n\t\t\t\t<li>Narloch Sabina;</li>\r\n\r\n\t\t\t\t<li>Przybysz Pawe\u0142;</li>\r\n\t\t\t\t<li>Puchta Marek;</li>\r\n\t\t\t\t<li>Ryska Cezary;</li>\r\n\t\t\t\t<li>Sandomierski Bart\u0142omiej;</li>\r\n\t\t\t\t<li>S\u0142awi\u0144ski Tomasz;</li>\r\n\t\t\t\t<li>S\u0142owik Olga;</li>\r\n\r\n\t\t\t\t<li>Starzycka Katarzyna;</li>\r\n\t\t\t\t<li>Strzelczak Karolina;</li>\r\n\t\t\t\t<li>Szafran Danuta;</li>\r\n\t\t\t\t<li>Szmigielska Magdalena;</li>\r\n\t\t\t\t<li>Szulkowska Alicja;</li>\r\n\t\t\t\t<li>\u015alusarczyk Anna;</li>\r\n\r\n\t\t\t\t<li>Tytkowska Anna.</li>\r\n\t\t\t</ul>\r\n\t\t\t<li>\r\n\t\t\t\t<p>\r\n\t\t\t\t\tAutorskie Niepubliczne Liceum Og\u00f3lnokszta\u0142c\u0105ce nr\r\n\t\t\t\t\t42, ul. Iwicka 47 B, 00-735 Warszawa; first year, general education class attented by Micha\u0142 Friedrich:\r\n\t\t\t\t</p>\r\n\r\n\t\t\t\t<ul>\r\n\t\t\t\t\t<li>Baraniecka Marta;</li>\r\n\r\n\t\t\t\t\t<li>Go\u0142aszewska Ewa;</li>\r\n\t\t\t\t\t<li>Kwiatkowski Micha\u0142;</li>\r\n\t\t\t\t\t<li>Machnikowska Monika;</li>\r\n\t\t\t\t\t<li>Pietrzak Bartosz;</li>\r\n\t\t\t\t\t<li>Przespolewski Przemys\u0142aw;</li>\r\n\t\t\t\t\t<li>Rosi\u0144ska Zuzanna;</li>\r\n\r\n\t\t\t\t\t<li>Sibiga Magdalena.</li>\r\n\t\t\t\t</ul>\r\n\t\t\t</li>\r\n\t\t\t<li>\r\n\t\t\t\t<p>\r\n\t\t\t\t\tLXIV Liceum Og\u00f3lnokszta\u0142c\u0105ce im. St. I. Witkiewicza,\r\n\t\t\t\t\tul. Elbl\u0105ska 51, 01-737 Warszawa; first year, general education class attented by Daniel Zych:\r\n\t\t\t\t</p>\r\n\r\n\t\t\t\t<ul>\r\n\r\n\t\t\t\t\t<li>Andrzejczak Kamil;</li>\r\n\t\t\t\t\t<li>Czubaj Konrad;</li>\r\n\t\t\t\t\t<li>Dr\u0105gowska Katarzyna;</li>\r\n\t\t\t\t\t<li>Gajewska Magdalena;</li>\r\n\t\t\t\t\t<li>G\u0142owacki Jan;</li>\r\n\t\t\t\t\t<li>Grad Pawe\u0142;</li>\r\n\r\n\t\t\t\t\t<li>Hnatowski Bartek;</li>\r\n\t\t\t\t\t<li>Karwowski Marcin;</li>\r\n\t\t\t\t\t<li>K\u0142os Aneta;</li>\r\n\t\t\t\t\t<li>Kozie\u0142 Barbara;</li>\r\n\t\t\t\t\t<li>Koz\u0142owska Anna;</li>\r\n\t\t\t\t\t<li>Krug Pamela;</li>\r\n\r\n\t\t\t\t\t<li>Krzosek Jakub;</li>\r\n\t\t\t\t\t<li>Luba\u015b Micha\u0142;</li>\r\n\t\t\t\t\t<li>Masewicz Natalia;</li>\r\n\t\t\t\t\t<li>Mastalerz Agnieszka;</li>\r\n\t\t\t\t\t<li>Modelska Marta;</li>\r\n\t\t\t\t\t<li>Nowak Aleksandra;</li>\r\n\r\n\t\t\t\t\t<li>Pabian Agnieszka;</li>\r\n\t\t\t\t\t<li>Paszkowska Aleksandra;</li>\r\n\t\t\t\t\t<li>Pielat Zofia;</li>\r\n\t\t\t\t\t<li>Poniecka Agnieszka;</li>\r\n\t\t\t\t\t<li>Pytlak Urszula;</li>\r\n\t\t\t\t\t<li>Rosa Karolina;</li>\r\n\r\n\t\t\t\t\t<li>Smyczy\u0144ska Kamila;</li>\r\n\t\t\t\t\t<li>Stoli\u0144ska Barbara;</li>\r\n\t\t\t\t\t<li>Szyma\u0144ska Katarzyna;</li>\r\n\t\t\t\t\t<li>\u015acibior Ewa;</li>\r\n\t\t\t\t\t<li>Witczak Magda;</li>\r\n\t\t\t\t\t<li>Witkowska Justyna;</li>\r\n\r\n\t\t\t\t\t<li>Wyrzykowska Jowita;</li>\r\n\t\t\t\t\t<li>Zi\u00f3\u0142kowska Adrianna.</li>\r\n\t\t\t\t</ul>\r\n\t\t\t</li>\r\n\t  </li>\r\n\t  </ol>", 
+            "left_column_de": "<h2>Volontariat</h2>\r\n\t<p>\r\n\t\tSchriftsteller-Biographien und Definitionen von Epochen und Literaturgattungen\r\n    in der Internetbibliothek Freie Lekt\u00fcren haben unsere Sch\u00fcler aus vier\r\n    Schulen w\u00e4hrend Workshops \"Volontariat f\u00fcr Wissen\" geschrieben.\r\n\t</p>\r\n\r\n\t<p>\r\n\t\tDie Sch\u00fcler haben gemeinsam unter Aufsicht der Lehrer\r\n\t\tund Spezialisten -Literaturwissenschaftler - gearbeitet\r\n\t\t<a href=\"http://wolnepodreczniki.pl/wolontariat/\">\r\n\r\n\t\t\tauf \"wiki\" Internetplattform</a>\r\n\t\tvorbereitet von unserem Team\r\n\t\t<a href=\"http://2ia.pl/\">2ia</a>. Der Einsatz von Computer und Internet wurde\r\n\t\t- w\u00e4hrend der Arbeiten an Noten - f\u00fcr die Informationssuche und Informationspr\u00fcfung genutzt\r\n\t\tund gleichzeitig als notwendiges Werkzeug in den Lernprozess einbezogen.\r\n\t</p>\r\n    \r\n\t<p>\r\n\t\tDas Projekt \"Volontariat f\u00fcr Wissen\" wurde dank der Unterst\u00fctzung umgesetzt, von\r\n\t\t<a href=\"http://www.menis.gov.pl/\">\r\n\t\t\tMinisterium f\u00fcr Bildung</a>. Preise f\u00fcr Sch\u00fcler spendeten\r\n\t\t<a href=\"http://www.nk.com.pl/engine/index.php?page=glowna\">\r\n\r\n\t\t\tVerlag unsere Buchhandlung</a>\r\n\t\tund\r\n\t\t<a href=\"http://helion.pl/\">Wydawnictwo Helion</a>. Noten wurden im Service verifiziert\r\n\t\t<a href=\"http://www.plagiat.pl/webplagiat/main.action\">\r\n\t\t\tPlagiat.pl</a>.\r\n\t</p>\r\n\r\n\t<p>\r\n\t\t<a href=\"/static/wolontariat.pdf\">der Bericht \u00fcber das Projekt \"Volontariat f\u00fcr Wissen\"</a>.\r\n\t</p>\r\n\r\n\t<p>\r\n\t<img src=\"/static/img/wolontariat/okladka.jpg\" style='margin: 10px' />\r\n\t<img src=\"/static/img/wolontariat/01.jpg\" style='margin: 10px' />\r\n\t<img src=\"/static/img/wolontariat/02.jpg\" style='margin: 10px' />\r\n    <img src=\"/static/img/wolontariat/03.jpg\" style='margin: 10px' />\r\n    <img src=\"/static/img/wolontariat/04.jpg\" style='margin: 10px' />\r\n\t</p>\r\n", 
+            "title_uk": "\u0412\u043e\u043b\u043e\u043d\u0442\u0435\u0440\u0441\u0442\u0432\u043e \u0432 \u043e\u0441\u0432\u0456\u0442\u0456", 
+            "right_column_fr": "\t<h2>Auteurs</h2>\r\n\r\n\t<ol>\r\n\t\t<li>\r\n\t\t\t<p>\r\n\t\t\t\tColl\u00e8ge no. 40 avec classes d'int\u00e9gration dans l'Ensemble Scolaire no. 69 de Armia Krajowa Grupa Bojowa \u201eKRYBAR\u201d,\r\n\t\t\t\tul. Drewniana 8, 00-345 Warszawa; classe seconde sous la supervision de\r\n\tAnna Budziarek-Friedrich:\r\n\t\t\t</p>\r\n\r\n\t\t\t<ul>\r\n\t\t\t\t<li>Burdon Filip;</li>\r\n\r\n\t\t\t\t<li>D\u0119bski Bartek;</li>\r\n\t\t\t\t<li>Jackowicz Kamil;</li>\r\n\t\t\t\t<li>Kurek Pawe\u0142;</li>\r\n\t\t\t\t<li>Makles Bartosz;</li>\r\n\t\t\t\t<li>Markiewicz Jeremiasz;</li>\r\n\t\t\t\t<li>Migda\u0142 Katarzyna;</li>\r\n\r\n\t\t\t\t<li>Mioduszewski Micha\u0142;</li>\r\n\t\t\t\t<li>Pfeiffer Ida;</li>\r\n\t\t\t\t<li>P\u0142askowicka Karolina;</li>\r\n\t\t\t\t<li>Sailer Ewa.</li>\r\n\t\t\t</ul>\r\n\t\t</li>\r\n\r\n\t\t<li>\r\n\t\t\t<p>\r\n\t\t\t\tXXXIII Lyc\u00e9e g\u00e9n\u00e9ral de Miko\u0142aj Kopernik,\r\n\t\t\t\tul. Bema 76, 01-225 Warszawa; classe premi\u00e8re, orientation biologie-chimique\r\n sous la supervision de El\u017cbieta Konkowska:\r\n\t\t\t</p>\r\n\r\n\t\t\t<ul>\r\n\t\t\t\t<li>Chwil Bart\u0142omiej;</li>\r\n\t\t\t\t<li>Czarnecka Natalia;</li>\r\n\t\t\t\t<li>Gawro\u0144ska Iga;</li>\r\n\r\n\t\t\t\t<li>Grabarczyk Marta;</li>\r\n\t\t\t\t<li>Jastrz\u0105b Katarzyna;</li>\r\n\t\t\t\t<li>Krawczak Olga;</li>\r\n\t\t\t\t<li>Krawczyk Marianna;</li>\r\n\t\t\t\t<li>Kur Natalia;</li>\r\n\t\t\t\t<li>Kwiatek Marta;</li>\r\n\r\n\t\t\t\t<li>La\u015bkiewicz Joanna;</li>\r\n\t\t\t\t<li>Machczy\u0144ska Daria;</li>\r\n\t\t\t\t<li>Miecznikowska Izabela;</li>\r\n\t\t\t\t<li>Moczulska Karolina;</li>\r\n\t\t\t\t<li>Mo\u015bcicka Aneta;</li>\r\n\t\t\t\t<li>Narloch Sabina;</li>\r\n\r\n\t\t\t\t<li>Przybysz Pawe\u0142;</li>\r\n\t\t\t\t<li>Puchta Marek;</li>\r\n\t\t\t\t<li>Ryska Cezary;</li>\r\n\t\t\t\t<li>Sandomierski Bart\u0142omiej;</li>\r\n\t\t\t\t<li>S\u0142awi\u0144ski Tomasz;</li>\r\n\t\t\t\t<li>S\u0142owik Olga;</li>\r\n\r\n\t\t\t\t<li>Starzycka Katarzyna;</li>\r\n\t\t\t\t<li>Strzelczak Karolina;</li>\r\n\t\t\t\t<li>Szafran Danuta;</li>\r\n\t\t\t\t<li>Szmigielska Magdalena;</li>\r\n\t\t\t\t<li>Szulkowska Alicja;</li>\r\n\t\t\t\t<li>\u015alusarczyk Anna;</li>\r\n\r\n\t\t\t\t<li>Tytkowska Anna.</li>\r\n\t\t\t</ul>\r\n\t\t\t<li>\r\n\t\t\t\t<p>\r\n\t\t\t\t\tLyc\u00e9e priv\u00e9 g\u00e9n\u00e9ral no. 42, ul. Iwicka 47 B, 00-735 Warszawa; classe premi\u00e8re, orientation g\u00e9n\u00e9rale, sous la supervision de Micha\u0142 Friedrich:\r\n\t\t\t\t</p>\r\n\r\n\t\t\t\t<ul>\r\n\t\t\t\t\t<li>Baraniecka Marta;</li>\r\n\r\n\t\t\t\t\t<li>Go\u0142aszewska Ewa;</li>\r\n\t\t\t\t\t<li>Kwiatkowski Micha\u0142;</li>\r\n\t\t\t\t\t<li>Machnikowska Monika;</li>\r\n\t\t\t\t\t<li>Pietrzak Bartosz;</li>\r\n\t\t\t\t\t<li>Przespolewski Przemys\u0142aw;</li>\r\n\t\t\t\t\t<li>Rosi\u0144ska Zuzanna;</li>\r\n\r\n\t\t\t\t\t<li>Sibiga Magdalena.</li>\r\n\t\t\t\t</ul>\r\n\t\t\t</li>\r\n\t\t\t<li>\r\n\t\t\t\t<p>\r\n\t\t\t\t\tLXIV Lyc\u00e9e g\u00e9n\u00e9ral de St. I. Witkiewicz,\r\n\t\t\t\t\tul. Elbl\u0105ska 51, 01-737 Warszawa; classe premi\u00e8re, orientation g\u00e9n\u00e9rale, sous la supervision de Daniel Zych:\r\n\t\t\t\t</p>\r\n\r\n\t\t\t\t<ul>\r\n\r\n\t\t\t\t\t<li>Andrzejczak Kamil;</li>\r\n\t\t\t\t\t<li>Czubaj Konrad;</li>\r\n\t\t\t\t\t<li>Dr\u0105gowska Katarzyna;</li>\r\n\t\t\t\t\t<li>Gajewska Magdalena;</li>\r\n\t\t\t\t\t<li>G\u0142owacki Jan;</li>\r\n\t\t\t\t\t<li>Grad Pawe\u0142;</li>\r\n\r\n\t\t\t\t\t<li>Hnatowski Bartek;</li>\r\n\t\t\t\t\t<li>Karwowski Marcin;</li>\r\n\t\t\t\t\t<li>K\u0142os Aneta;</li>\r\n\t\t\t\t\t<li>Kozie\u0142 Barbara;</li>\r\n\t\t\t\t\t<li>Koz\u0142owska Anna;</li>\r\n\t\t\t\t\t<li>Krug Pamela;</li>\r\n\r\n\t\t\t\t\t<li>Krzosek Jakub;</li>\r\n\t\t\t\t\t<li>Luba\u015b Micha\u0142;</li>\r\n\t\t\t\t\t<li>Masewicz Natalia;</li>\r\n\t\t\t\t\t<li>Mastalerz Agnieszka;</li>\r\n\t\t\t\t\t<li>Modelska Marta;</li>\r\n\t\t\t\t\t<li>Nowak Aleksandra;</li>\r\n\r\n\t\t\t\t\t<li>Pabian Agnieszka;</li>\r\n\t\t\t\t\t<li>Paszkowska Aleksandra;</li>\r\n\t\t\t\t\t<li>Pielat Zofia;</li>\r\n\t\t\t\t\t<li>Poniecka Agnieszka;</li>\r\n\t\t\t\t\t<li>Pytlak Urszula;</li>\r\n\t\t\t\t\t<li>Rosa Karolina;</li>\r\n\r\n\t\t\t\t\t<li>Smyczy\u0144ska Kamila;</li>\r\n\t\t\t\t\t<li>Stoli\u0144ska Barbara;</li>\r\n\t\t\t\t\t<li>Szyma\u0144ska Katarzyna;</li>\r\n\t\t\t\t\t<li>\u015acibior Ewa;</li>\r\n\t\t\t\t\t<li>Witczak Magda;</li>\r\n\t\t\t\t\t<li>Witkowska Justyna;</li>\r\n\r\n\t\t\t\t\t<li>Wyrzykowska Jowita;</li>\r\n\t\t\t\t\t<li>Zi\u00f3\u0142kowska Adrianna.</li>\r\n\t\t\t\t</ul>\r\n\t\t\t</li>\r\n\t  </li>\r\n\t  </ol>\r\n", 
+            "left_column": "<h2>Volunteers</h2>\r\n\t<p>Writers' biographical entries as well as periods' and genres'\r\ndefinitions placed on web library Wolne Lektury were written by students from four schools during \"Wolontariat dla wiedzy\" (\"Volunteering for knowledge\") workshops. </p> <p>\r\n The students worked together under the factual guidance of teachers and specialists - literary scholars<a href=\"http://wolnepodreczniki.pl/wolontariat/\">\r\n\r\n\ton wiki platform</a>\r\n prepared by <a href=\"http://2ia.pl/\">2ia</a> team. At the same time the students learnt how to use a computer and the Internet while searching for necessary information how to verify the credibility of the source. </p>\r\n\r\n<p>\r\n\"Wolontariat dla wiedzy\" project was realised thanks to the support of <a href=\"http://www.menis.gov.pl/\">\r\nMinisterstwo Edukacji Narodowej</a>. The rewards for the student were funded by<a href=\"http://www.nk.com.pl/engine/index.php?page=glowna\">\r\n\r\nWydawnictwo Nasza Ksi\u0119garnia</a>\r\nand<a href=\"http://helion.pl/\">Wydawnictwo Helion</a>. Each entry was verified on <a href=\"http://www.plagiat.pl/webplagiat/main.action\">\r\nPlagiat.pl</a> website.\r\n</p>\r\n\r\n<p>\r\n\t\t<a href=\"/static/wolontariat.pdf\">Report on completion of \"Wolontariat dla wiedzy\" project (PL)</a>.\r\n\t</p>\r\n\r\n\t<p>\r\n\t<img src=\"/static/img/wolontariat/okladka.jpg\" style='margin: 10px' />\r\n\t<img src=\"/static/img/wolontariat/01.jpg\" style='margin: 10px' />\r\n\t<img src=\"/static/img/wolontariat/02.jpg\" style='margin: 10px' />\r\n    <img src=\"/static/img/wolontariat/03.jpg\" style='margin: 10px' />\r\n    <img src=\"/static/img/wolontariat/04.jpg\" style='margin: 10px' />\r\n\t</p>", 
+            "right_column_uk": "<h2>\u0410\u0432\u0442\u043e\u0440\u0438</h2>\r\n\r\n <ol>\r\n <li>\r\n <p>\r\n \u0413\u0456\u043c\u043d\u0430\u0437\u0456\u044f \u211640 \u0437 \u0456\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0456\u0439\u043d\u0438\u043c\u0438 \u0432\u0456\u0434\u0434\u0456\u043b\u0430\u043c\u0438 \u0432 \u041a\u043e\u043c\u043f\u043b\u0435\u043a\u0441\u0456 \u0448\u043a\u0456\u043b \u2116 69 \u0456\u043c\u0435\u043d\u0456 \u0410\u0440\u043c\u0456\u0457 \u041a\u0440\u0430\u0439\u043e\u0432\u043e\u0457 \u0411\u043e\u0439\u043e\u0432\u043e\u0457 \u0413\u0440\u0443\u043f\u0438 \u201c\u041a\u0420\u0418\u0411\u0410\u0420\u201d,\r\n \u0432\u0443\u043b. \u0414\u0440\u0435\u0432\u043d\u044f\u043d\u0430 8, 00-345 \u0412\u0430\u0440\u0448\u0430\u0432\u0430; \u0434\u0440\u0443\u0433\u0438\u0439 \u043a\u043b\u0430\u0441 \u043f\u0456\u0434 \u043e\u043f\u0456\u043a\u043e\u044e \u0410\u043d\u043d\u0438 \u0411\u0443\u0434\u0437\u044f\u0440\u0435\u043a-\u0424\u0440\u0456\u0434\u0440\u0456\u0445:\r\n </p>\r\n\r\n <ul>\r\n <li>\u0411\u0443\u0440\u0434\u043e\u043d \u0424\u0456\u043b\u0456\u043f;</li>\r\n\r\n <li>\u0414\u0435\u043c\u0431\u0441\u044c\u043a\u0456 \u0411\u0430\u0440\u0442\u0435\u043a;</li>\r\n <li>\u042f\u0446\u043a\u043e\u0432\u0456\u0447 \u041a\u0430\u043c\u0456\u043b;</li>\r\n <li>\u041a\u0443\u0440\u0435\u043a \u041f\u0430\u0432\u0435\u043b;</li>\r\n <li>\u041c\u0430\u043a\u043b\u0435\u0441 \u0411\u0430\u0440\u0442\u043e\u0448;</li>\r\n <li>\u041c\u0430\u0440\u043a\u0435\u0432\u0456\u0447 \u0404\u0440\u0435\u043c\u044f\u0448;</li>\r\n <li>\u041c\u0456\u0433\u0434\u0430\u043b \u041a\u0430\u0442\u0430\u0436\u0438\u043d\u0430;</li>\r\n\r\n <li>\u041c\u0456\u043e\u0434\u0443\u0448\u0435\u0432\u0441\u044c\u043a\u0456 \u041c\u0456\u0445\u0430\u043b;</li>\r\n <li>\u0424\u0430\u0439\u0444\u0435\u0440 \u0406\u0434\u0430;</li>\r\n <li>\u041f\u043b\u0430\u0441\u043a\u043e\u0432\u0456\u0446\u044c\u043a\u0430 \u041a\u0430\u0440\u043e\u043b\u0456\u043d\u0430;</li>\r\n <li>\u0421\u0430\u0439\u043b\u0435\u0440 \u0415\u0432\u0430.</li>\r\n </ul>\r\n </li>\r\n\r\n <li>\r\n <p>\r\n XXXIII \u0417\u0430\u0433\u0430\u043b\u044c\u043d\u043e\u043e\u0441\u0432\u0456\u0442\u043d\u0438\u0439 \u043b\u0456\u0446\u0435\u0439 \u0456\u043c\u0435\u043d\u0456 \u041c\u0438\u043a\u043e\u043b\u0430\u044f \u041a\u043e\u043f\u0435\u0440\u043d\u0438\u043a\u0430,\r\n \u0432\u0443\u043b. \u0411\u0435\u043c\u0430 76, 01-225 \u0412\u0430\u0440\u0448\u0430\u0432\u0430; \u043f\u0435\u0440\u0448\u0438\u0439 \u043a\u043b\u0430\u0441 \u0431\u0456\u043e\u043b\u043e\u0433\u0456\u0447\u043d\u043e-\u0445\u0456\u043c\u0456\u0447\u043d\u043e\u0433\u043e \u043f\u0440\u043e\u0444\u0456\u043b\u044e \u043f\u0456\u0434 \u043e\u043f\u0456\u043a\u043e\u044e \u0415\u043b\u044c\u0436\u0431\u0454\u0442\u0438 \u041a\u043e\u043d\u043a\u043e\u0432\u0441\u044c\u043a\u043e\u0457 :\r\n </p>\r\n\r\n <ul>\r\n <li>\u0425\u0432\u0456\u043b \u0411\u0430\u0440\u0442\u043b\u043e\u043c\u0454\u0439;</li>\r\n <li>\u0427\u0430\u0440\u043d\u0435\u0446\u044c\u043a\u0430 \u041d\u0430\u0442\u0430\u043b\u0456\u044f ;</li>\r\n <li>\u0490\u0430\u0432\u0440\u043e\u043d\u0441\u044c\u043a\u0430 \u0406\u0491\u0430 ;</li>\r\n\r\n <li>\u0490\u0440\u0430\u0431\u0430\u0440\u0447\u0438\u043a \u041c\u0430\u0440\u0442\u0430;</li>\r\n <li>\u042f\u0430\u0441\u0442\u0436\u043e\u043c\u0431 \u041a\u0430\u0442\u0430\u0436\u0438\u043d\u0430;</li>\r\n <li>\u041a\u0440\u0430\u0432\u0447\u0430\u043a \u041e\u043b\u044c\u0433\u0430;</li>\r\n <li>\u041a\u0440\u0430\u0432\u0447\u0438\u043a \u041c\u0430\u0440\u0456\u0430\u043d\u043d\u0430 ;</li>\r\n <li>\u041a\u0443\u0440 \u041d\u0430\u0442\u0430\u043b\u0456\u044f;</li>\r\n <li>\u041a\u0432\u044f\u0442\u0435\u043a \u041c\u0430\u0440\u0442\u0430;</li>\r\n\r\n <li>\u041b\u0430\u0441\u044c\u043a\u0435\u0432\u0438\u0447 \u0419\u043e\u0430\u043d\u043d\u0430;</li>\r\n <li>\u041c\u0430\u0445\u0447\u0438\u043d\u0441\u044c\u043a\u0430 \u0414\u0430\u0440\u0456\u044f;</li>\r\n <li>\u041c\u0454\u0447\u043d\u0456\u043a\u043e\u0432\u0441\u044c\u043a\u0430 \u0406\u0437\u0430\u0431\u0435\u043b\u044f;</li>\r\n <li>\u041c\u043e\u0447\u0443\u043b\u0441\u044c\u043a\u0430 \u041a\u0430\u0440\u043e\u043b\u0456\u043d\u0430;</li>\r\n <li>\u041c\u043e\u0441\u044c\u0446\u0456\u0446\u043a\u0430 \u0410\u043d\u0435\u0442\u0430;</li>\r\n <li>\u041d\u0430\u0440\u043b\u043e\u0445 \u0421\u0430\u0431\u0456\u043d\u0430;</li>\r\n\r\n <li>\u041f\u0448\u0438\u0431\u0438\u0448 \u041f\u0430\u0432\u0435\u043b;</li>\r\n <li>\u041f\u0443\u0445\u0442\u0430 \u041c\u0430\u0440\u0435\u043a;</li>\r\n <li>\u0420\u0438\u0441\u043a\u0430 \u0426\u0435\u0437\u0430\u0440\u0438;</li>\r\n <li>\u0421\u0430\u043d\u0434\u043e\u043c\u0454\u0440\u0441\u044c\u043a\u0456 \u0411\u0430\u0440\u043b\u043e\u043c\u0454\u0439;</li>\r\n <li>\u0421\u043b\u0430\u0432\u0456\u043d\u0441\u044c\u043a\u0456 \u0422\u043e\u043c\u0430\u0448;</li>\r\n <li>\u0421\u043b\u043e\u0432\u0456\u043a \u041e\u043b\u044c\u0433\u0430;</li>\r\n\r\n <li>\u0421\u0442\u0430\u0436\u0438\u0446\u044c\u043a\u0430 \u041a\u0430\u0442\u0430\u0436\u0438\u043d\u0430;</li>\r\n <li>\u0421\u0442\u0436\u0435\u043b\u0447\u0430\u043a \u041a\u0430\u0440\u043e\u043b\u0456\u043d\u0430;</li>\r\n <li>\u0428\u0430\u0444\u0440\u0430\u043d \u0414\u0430\u043d\u0443\u0442\u0430;</li>\r\n <li>\u0428\u043c\u0456\u0491\u0454\u043b\u044c\u0441\u044c\u043a\u0430 \u041c\u0430\u0491\u0434\u0430\u043b\u0435\u043d\u0430;</li>\r\n <li>\u0428\u0443\u043b\u043a\u043e\u0432\u0430\u0441\u044c\u043a\u0430 \u0410\u043b\u0456\u0446\u0456\u044f;</li>\r\n <li>\u0421\u044c\u043b\u0443\u0441\u0430\u0440\u0447\u0438\u043a \u0410\u043d\u043d\u0430;</li>\r\n\r\n <li>\u0422\u0438\u0442\u043a\u043e\u0432\u0441\u044c\u043a\u0430 \u0410\u043d\u043d\u0430.</li>\r\n </ul>\r\n <li>\r\n <p>\r\n \u0410\u0432\u0442\u043e\u0440\u0441\u044c\u043a\u0438\u0439 \u041d\u0435\u043f\u0443\u0431\u043b\u0456\u0447\u043d\u0438\u0439 \u0417\u0430\u0433\u0430\u043b\u044c\u043d\u043e\u043e\u0441\u0432\u0456\u0442\u043d\u0456\u0439 \u041b\u0456\u0446\u0435\u0439 \u2116   42, \u0432\u0443\u043b. \u0406\u0432\u0456\u0446\u044c\u043a\u0430 47 B, 00-735 \u0412\u0430\u0440\u0448\u0430\u0432\u0430; \u043f\u0435\u0440\u0448\u0438\u0439 \u043a\u043b\u0430\u0441 \u0437\u0430\u0433\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043f\u0440\u043e\u0444\u0456\u043b\u044e \u043f\u0456\u0434 \u043e\u043f\u0456\u043a\u043e\u044e \u041c\u0456\u0445\u0430\u043b\u0430 \u0424\u0440\u0456\u0434\u0440\u0456\u0445\u0430:\r\n </p>\r\n\r\n <ul>\r\n <li>\u0411\u0430\u0440\u0430\u043d\u0454\u0446\u044c\u043a\u0430 \u041c\u0430\u0440\u0442\u0430;</li>\r\n\r\n <li>\u0490\u043e\u043b\u0430\u0448\u0435\u0432\u0441\u044c\u043a\u0430 \u0415\u0432\u0430;</li>\r\n <li>\u041a\u0432\u044f\u0442\u043a\u043e\u0432\u0441\u044c\u043a\u0456 \u041c\u0456\u0445\u0430\u043b;</li>\r\n <li>\u041c\u0430\u0445\u043d\u0456\u043a\u043e\u0432\u0441\u044c\u043a\u0430 \u041c\u043e\u043d\u0456\u043a\u0430;</li>\r\n  <li>\u041f\u0454\u0442\u0436\u0430\u043a \u0411\u0430\u0440\u0442\u043e\u0448;</li>\r\n <li>\u041f\u0448\u0435\u0441\u043f\u043e\u043b\u0435\u0432\u0441\u044c\u043a\u0456 \u041f\u0448\u0435\u043c\u0438\u0441\u043b\u0430\u0432;</li>\r\n <li>\u0420\u043e\u0441\u0456\u043d\u0441\u044c\u043a\u0430 \u0417\u0443\u0437\u0430\u043d\u043d\u0430;</li>\r\n\r\n <li>\u0421\u0456\u0431\u0456\u0491\u0430 \u041c\u0430\u0491\u0434\u0430\u043b\u0435\u043d\u0430.</li>\r\n </ul>\r\n </li>\r\n <li>\r\n <p>\r\n LXIV \u0417\u0430\u0433\u0430\u043b\u044c\u043d\u043e\u043e\u0441\u0432\u0456\u0442\u043d\u0456\u0439 \u041b\u0456\u0446\u0435\u0439 \u0456\u043c\u0435\u043d\u0456 \u0421\u0442.\u0406. \u0412\u0456\u0442\u043a\u0454\u0432\u0456\u0447\u0430,\r\n \u0432\u0443\u043b. \u0415\u043b\u044c\u0431\u043b\u043e\u043d\u0437\u044c\u043a\u0430 51, 01-737 \u0412\u0430\u0440\u0448\u0430\u0432\u0430; \u043f\u0435\u0440\u0448\u0438\u0439 \u043a\u043b\u0430\u0441 \u0437\u0430\u0433\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043f\u0440\u043e\u0444\u0456\u043b\u044e \u043f\u0456\u0434 \u043e\u043f\u0456\u043a\u043e\u044e \u0414\u0430\u043d\u0454\u043b\u0430 \u0417\u0438\u0445\u0430:\r\n </p>\r\n\r\n <ul>\r\n\r\n <li>\u0410\u043d\u0434\u0436\u0435\u0439\u0447\u0430\u043a \u041a\u0430\u043c\u0456\u043b;</li>\r\n <li>\u0427\u0443\u0431\u0430\u0439 \u041a\u043e\u043d\u0440\u0430\u0434;</li>\r\n <li>\u0414\u0440\u043e\u043d\u0491\u043e\u0432\u0441\u044c\u043a\u0430 \u041a\u0430\u0442\u0430\u0436\u0438\u043d\u0430;</li>\r\n <li>\u0490\u0430\u0454\u0432\u0441\u044c\u043a\u0430 \u041c\u0430\u0491\u0434\u0430\u043b\u0435\u043d\u0430;</li>\r\n <li>\u0490\u043b\u043e\u0432\u0430\u0446\u044c\u043a\u0456 \u042f\u043d;</li>\r\n  <li>\u0490\u0440\u0430\u0434 \u041f\u0430\u0432\u0435\u043b;</li>\r\n\r\n <li>\u0413\u043d\u0430\u0442\u043e\u0432\u0441\u044c\u043a\u0456 \u0411\u0430\u0440\u0442\u0435\u043a;</li>\r\n <li>\u041a\u0430\u0440\u0432\u043e\u0432\u0441\u044c\u043a\u0456 \u041c\u0430\u0440\u0446\u0456\u043d;</li>\r\n <li>\u041a\u043b\u043e\u0441 \u0410\u043d\u0435\u0442\u0430;</li>\r\n <li>\u041a\u043e\u0437\u0454\u043b \u0411\u0430\u0440\u0431\u0430\u0440\u0430;</li>\r\n <li>\u041a\u043e\u0437\u043b\u043e\u0432\u0441\u044c\u043a\u0430 \u0410\u043d\u043d\u0430;</li>\r\n <li>\u041a\u0440\u0443\u0491 \u041f\u0430\u043c\u0435\u043b\u0430;</li>\r\n\r\n <li>\u041a\u0436\u043e\u0441\u0435\u043a \u042f\u043a\u0443\u0431;</li>\r\n <li>\u041b\u0443\u0431\u0430\u0441\u044c \u041c\u0456\u0445\u0430\u043b;</li>\r\n <li>\u041c\u0430\u0441\u0435\u0432\u0456\u0447 \u041d\u0430\u0442\u0430\u043b\u0456\u044f;</li>\r\n <li>\u041c\u0430\u0441\u0442\u0430\u043b\u0435\u0436 \u0410\u0491\u043d\u0454\u0448\u043a\u0430;</li>\r\n <li>\u041c\u043e\u0434\u0435\u043b\u044c\u0441\u044c\u043a\u0430 \u041c\u0430\u0440\u0442\u0430;</li>\r\n <li>\u041d\u043e\u0432\u0430\u043a \u0410\u043b\u0435\u043a\u0441\u0430\u043d\u0434\u0440\u0430;</li>\r\n\r\n <li>\u041f\u0430\u0431\u044f\u043d \u0410\u0491\u043d\u0454\u0448\u043a\u0430;</li>\r\n <li>\u041f\u0430\u0448\u043a\u043e\u0432\u0441\u044c\u043a\u0430 \u0410\u043b\u0435\u043a\u0441\u0430\u043d\u0434\u0440\u0430;</li>\r\n <li>\u041f\u0454\u043b\u0430\u0442 \u0417\u043e\u0444\u0456\u044f;</li>\r\n <li>\u041f\u043e\u043d\u0454\u0446\u044c\u043a\u0430 \u0410\u0491\u043d\u0454\u0448\u043a\u0430;</li>\r\n <li>\u041f\u0438\u0442\u043b\u0430\u043a \u0423\u0440\u0448\u0443\u043b\u044f;</li>\r\n <li>\u0420\u043e\u0441\u0430 \u041a\u0430\u0440\u043e\u043b\u0456\u043d\u0430;</li>\r\n\r\n <li>\u0421\u043c\u0447\u0438\u043d\u0441\u044c\u043a\u0430 \u041a\u0430\u043c\u0456\u043b\u044f;</li>\r\n <li>\u0421\u0442\u043e\u043b\u0456\u043d\u0441\u044c\u043a\u0430 \u0411\u0430\u0440\u0431\u0430\u0440\u0430;</li>\r\n <li>\u0428\u0438\u043c\u0430\u043d\u0441\u044c\u043a\u0430 \u041a\u0430\u0442\u0430\u0436\u0438\u043d\u0430;</li>\r\n <li>\u0421\u044c\u0446\u0456\u0431\u043e\u0440 \u0415\u0432\u0430;</li>\r\n <li>\u0412\u0456\u0442\u0447\u0430\u043a \u041c\u0430\u0491\u0434\u0430;</li>\r\n <li>\u0412\u0456\u0442\u043a\u043e\u0432\u0441\u044c\u043a\u0430 \u042e\u0441\u0442\u0438\u043d\u0430;</li>\r\n\r\n <li>\u0412\u0438\u0436\u0438\u043a\u043e\u0432\u0441\u044c\u043a\u0430 \u0419\u043e\u0432\u0456\u0442\u0430;</li>\r\n <li>\u0417\u044e\u043b\u043a\u043e\u0432\u0441\u044c\u043a\u0430 \u0410\u0434\u0440\u0456\u0430\u043d\u043d\u0430.</li>\r\n </ul>\r\n </li>\r\n  </li>\r\n  </ol>", 
+            "title_en": "Volunteering for knowledge", 
+            "left_column_pl": "<h2>Wolontariat</h2>\r\n\t<p>\r\n\t\tBiogramy pisarzy oraz definicje epok i gatunk\u00f3w literackich w\r\n\t\tbibliotece internetowej Wolne Lektury napisali uczniowie\r\n\t\tczterech szk\u00f3\u0142 podczas warsztat\u00f3w \u201eWolontariat dla wiedzy\u201d.\r\n\t</p>\r\n\r\n\t<p>\r\n\t\tUczniowie pracowali wsp\u00f3lnie pod merytorycznym nadzorem\r\n\t\tnauczycieli i specjalist\u00f3w \u2013 literaturoznawc\u00f3w na\r\n\t\t<a href=\"http://wolnepodreczniki.pl/wolontariat/\">\r\n\r\n\t\t\tplatformie internetowej wiki</a>\r\n\t\tprzygotowanej przez zesp\u00f3\u0142\r\n\t\t<a href=\"http://2ia.pl/\">2ia</a>. Praca nad notami by\u0142a jednocze\u015bnie nauk\u0105 wykorzystywania\r\n\t\tkomputer\u00f3w i internetu do wyszukiwania informacji, a tak\u017ce\r\n\t\tweryfikowania ich wiarygodno\u015bci.\r\n\t</p>\r\n\r\n\t<p>\r\n\t\tProjekt \"Wolontariat dla wiedzy\" zosta\u0142 zrealizowany dzi\u0119ki\r\n\t\twsparciu\r\n\t\t<a href=\"http://www.menis.gov.pl/\">\r\n\t\t\tMinisterstwa Edukacji Narodowej</a>. Nagrody dla uczni\u00f3w ufundowali\r\n\t\t<a href=\"http://www.nk.com.pl/engine/index.php?page=glowna\">\r\n\r\n\t\t\tWydawnictwo Nasza Ksi\u0119garnia</a>\r\n\t\ti\r\n\t\t<a href=\"http://helion.pl/\">Wydawnictwo Helion</a>. Noty zweryfikowano w serwisie\r\n\t\t<a href=\"http://www.plagiat.pl/webplagiat/main.action\">\r\n\t\t\tPlagiat.pl</a>.\r\n\t</p>\r\n\r\n\t<p>\r\n\t\t<a href=\"/static/wolontariat.pdf\">Raport z realizacji projektu \u201eWolontariat dla wiedzy\"</a>.\r\n\t</p>\r\n\r\n\t<p>\r\n\t<img src=\"/static/img/wolontariat/okladka.jpg\" style='margin: 10px' />\r\n\t<img src=\"/static/img/wolontariat/01.jpg\" style='margin: 10px' />\r\n\t<img src=\"/static/img/wolontariat/02.jpg\" style='margin: 10px' />\r\n    <img src=\"/static/img/wolontariat/03.jpg\" style='margin: 10px' />\r\n    <img src=\"/static/img/wolontariat/04.jpg\" style='margin: 10px' />\r\n\t</p>\r\n", 
+            "left_column_ru": "<h2>\u0412\u043e\u043b\u043e\u043d\u0442\u0435\u0440\u0441\u0442\u0432\u043e</h2>\r\n\r\n        <p> \u041f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u044f, \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u043f\u043e\u043f\u043e\u043b\u043d\u044f\u044e\u0449\u0438\u0435 \u043d\u0430\u0448\u0443 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443, \u043c\u044b \u043f\u044b\u0442\u0430\u0435\u043c\u0441\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0442\u044c \u0442\u0449\u0430\u0442\u0435\u043b\u044c\u043d\u043e. \u042d\u0442\u043e \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u044b\u043c\r\n        \u043b\u0438\u0448\u044c \u0431\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u044f \u043d\u0430\u0448\u0438\u043c \u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a\u0430\u043c-\u0432\u043e\u043b\u043e\u043d\u0442\u0435\u0440\u0430\u043c.</p>\r\n\r\n        \r\n        <p>\u041c\u044b \u043f\u0440\u0438\u0433\u043b\u0430\u0448\u0430\u0435\u043c \u0432\u0441\u0435\u0445 \u0436\u0435\u043b\u0430\u044e\u0449\u0438\u0445 \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u0448\u043a\u043e\u043b\u044c\u043d\u0443\u044e \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442-\u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 Wolne Lektury \u0432\u043c\u0435\u0441\u0442\u0435 \u0441 \u043d\u0430\u043c\u0438.</p>\r\n        \r\n        <p>\u041c\u044b \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c \u0432\u0441\u0435\u043c \u0432\u043e\u043b\u043e\u043d\u0442\u0435\u0440\u0430\u043c \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0443 \u0438 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0443 \u043f\u043e \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044e \u0442\u0435\u043a\u0441\u0442\u043e\u0432: \u0442\u0435\u0445\u043d\u0438\u0447\u0435\u0441\u043a\u043e\u0439 \u0440\u0435\u0434\u0430\u043a\u0446\u0438\u0438 \u0438\r\n        \u0440\u0435\u0434\u0430\u043a\u0446\u0438\u0438 \u043f\u043e \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443. \u0412\u043e\u043b\u043e\u043d\u0442\u0435\u0440\u044b \u043c\u043e\u0433\u0443\u0442 \u043f\u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u044c\u0441\u044f \u043a\u0430\u043a \u0441 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430\u043c\u0438, \u0442\u0430\u043a \u0438 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044f\u043c\u0438, \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u043c\u0438 \u0441 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442-\u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u044f\u043c\u0438.\r\n        \u041e\u043d\u0438, \u0432\u043c\u0435\u0441\u0442\u0435 \u0441 \u043d\u0430\u043c\u0438, \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u0443\u044e\u0442 \u0443\u0447\u0435\u0431\u0443 \u0438 \u043a\u043e\u043d\u0444\u0435\u0440\u0435\u043d\u0446\u0438\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u043e\u043c\u043e\u0433\u0430\u044e\u0442 \u0432 \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0435 \u0442\u0435\u043a\u0441\u0442\u043e\u0432 \u0434\u043b\u044f \u0441\u043b\u0443\u0448\u0430\u043d\u0438\u044f (\u0442.\u043d.\r\n        \u0430\u0443\u0434\u0438\u043e\u043a\u043d\u0438\u0433). \u041c\u044b \u0432\u044b\u0434\u0430\u0435\u043c \u0434\u043e\u0433\u043e\u0432\u043e\u0440\u044b \u0438 \u0441\u043f\u0440\u0430\u0432\u043a\u0438 \u043d\u0430\u0441\u0447\u0435\u0442 \u0442\u043e\u0433\u043e, \u043a\u043e\u0433\u0434\u0430 \r\n        \u0438 \u043a\u0430\u043a\u0438\u0435 \u0440\u0430\u0431\u043e\u0442\u044b \u0431\u044b\u043b\u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u044b \u0432\u043e\u043b\u043e\u043d\u0442\u0435\u0440\u043e\u043c \u0432 \u043f\u043e\u043b\u044c\u0437\u0443 \u043d\u0430\u0448\u0435\u0433\u043e \r\n        \u0444\u043e\u043d\u0434\u0430. \u0423\u0447\u0435\u0431\u0430, \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0430 \u043f\u043e \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044e \u0438 \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0430\u044e\u0449\u0438\u0435 \u0438\u0445 \u0441\u043f\u0440\u0430\u0432\u043a\u0438 \u043c\u043e\u0433\u0443\u0442 \u044f\u0432\u043b\u044f\u0442\u044c\u0441\u044f \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u043c\u0438 \u0432 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435\r\n        \u043f\u043e\u0432\u044b\u0448\u0435\u043d\u0438\u044f \u043a\u0432\u0430\u043b\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 \u0438 \u043f\u0440\u043e\u0434\u0432\u0438\u0436\u0435\u043d\u0438\u044f \u043f\u043e \u0441\u043b\u0443\u0436\u0431\u0435.</p>\r\n\r\n        \r\n        <h2>\u0427\u0442\u043e \u043d\u0430\u043c \u043d\u0430\u0434\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c?</h2>\r\n        \r\n        <p>\u0421\u0430\u043c\u043e\u0439 \u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u0440\u0430\u0431\u043e\u0442\u043e\u0439 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0430 \u0447\u0442\u0435\u043d\u0438\u0439 \u0434\u043b\u044f \u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u0438. \u0412 \u0442\u0435\u043a\u0441\u0442\u0430\u0445, \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0445 \u043d\u0430\u043c\u0438 \u0438\u0437 \u041d\u0430\u0440\u043e\u0434\u043d\u043e\u0439 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438, \u0441\u043b\u0435\u0434\u0443\u0435\u0442 \u0443\u0434\u0430\u043b\u0438\u0442\u044c \u043e\u043f\u0435\u0447\u0430\u0442\u043a\u0438 \u0438 \u0434\u0440\u0443\u0433\u0438\u0435 \u043c\u0435\u0445\u0430\u043d\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u043e\u0448\u0438\u0431\u043a\u0438. \r\n        \u0417\u0430\u0442\u0435\u043c \u043d\u0430\u043c \u043d\u0430\u0434\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0441\u043d\u043e\u0441\u043a\u0438, \u043d\u0435 \u0437\u0430\u0431\u044b\u0432\u0430\u044f \u043e \u0442\u043e\u043c, \u0447\u0442\u043e \u043d\u0430\u0448\u0435 \u043f\u0440\u0435\u0434\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043e\u0431\u0440\u0430\u0449\u0435\u043d\u043e \u043a \u0443\u0447\u0435\u043d\u0438\u043a\u0430\u043c, \u0434\u043b\u044f \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043c\u043d\u043e\u0433\u043e \u0441\u043b\u043e\u0432 \u0438 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0439 \u0437\u0432\u0443\u0447\u0438\u0442 \u0430\u043d\u0430\u0445\u0440\u043e\u043d\u0438\u0447\u043d\u043e.\r\n         \u041f\u0440\u0435\u0436\u043d\u0438\u0435 \u0438\u0437\u0434\u0430\u043d\u0438\u044f (\u0440\u0435\u0436\u0438\u043c \u0430\u0432\u0442\u043e\u0440\u0441\u043a\u043e\u0433\u043e \u043f\u0440\u0430\u0432\u0430) \u043f\u043e\u0434\u0432\u0435\u0440\u0433\u0430\u044e\u0442\u0441\u044f \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0439 \u044f\u0437\u044b\u043a\u043e\u0432\u043e\u0439 \u0430\u043a\u0442\u0443\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438, \u043d\u0430\u043f\u0440. \u043f\u043e \u043e\u0440\u0444\u043e\u0433\u0440\u0430\u0444\u0438\u0438 \u0438\u043b\u0438 \u0444\u043b\u0435\u043a\u0441\u0438\u0438. \u041f\u0440\u0438\u0447\u0435\u043c, \u043c\u044b \u0437\u0430\u0431\u043e\u0442\u0438\u043c\u0441\u044f \u043e \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0438\r\n        \u0445\u0443\u0434\u043e\u0436\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0433\u043e \u0441\u0432\u043e\u0435\u043e\u0431\u0440\u0430\u0437\u0438\u044f \u0442\u0435\u043a\u0441\u0442\u0430. \u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u043c \u044d\u0442\u0430\u043f\u043e\u043c \u0441\u0447\u0438\u0442\u0430\u0435\u0442\u0441\u044f \u043f\u043e\u0438\u0441\u043a \u043b\u0438\u0442\u0435\u0440\u0430\u0442\u0443\u0440\u043d\u044b\u0445 \u043c\u043e\u0442\u0438\u0432\u043e\u0432 \u0438 \u0442\u0435\u043c, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0434\u043e\u043b\u0436\u0435\u043d \u043f\u043e\u043c\u043e\u0447\u044c \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u043b\u0438\u0442\u0435\u0440\u0430\u0442\u0443\u0440\u0443 \"\u043d\u0430\u0441\u043a\u0432\u043e\u0437\u044c\".\r\n        \u0412\u043e \u0432\u0441\u0435\u0445 \u044d\u0442\u0438\u0445 \u0440\u0430\u0431\u043e\u0442\u0430\u0445 \u0441\u0432\u043e\u044e \u043f\u043e\u043c\u043e\u0449\u044c \u043e\u043a\u0430\u0437\u044b\u0432\u0430\u044e\u0442 \u043d\u0430\u043c \u0432\u043e\u043b\u043e\u043d\u0442\u0435\u0440\u044b - \u0443\u0447\u0438\u0442\u0435\u043b\u044f \u0438 \u0441\u0442\u0443\u0434\u0435\u043d\u0442\u044b, \u0447\u0430\u0441\u0442\u043e \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0449\u0438\u0435 \u0441\u0432\u043e\u0438 \u0441\u043e\u0432\u0435\u0442\u044b \u0438 \u0437\u0430\u043c\u0435\u0447\u0430\u043d\u0438\u044f \u0432\u043e \u0432\u0440\u0435\u043c\u044f\r\n        \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u043d\u0438\u044f \u0432\u0430\u0436\u043d\u044b\u0445 \u0440\u0435\u0448\u0435\u043d\u0438\u0439.</p>\r\n        \r\n        <h2>\u041a\u0430\u043a \u043f\u043e\u0441\u0442\u0443\u043f\u0438\u0442\u044c \u0432 \u043d\u0430\u0448 \u0444\u043e\u043d\u0434?</h2>\r\n        \r\n        <p>\u0412\u0441\u0435\u0445 \u0436\u0435\u043b\u0430\u044e\u0449\u0438\u0445 \u043f\u0440\u043e\u0441\u0438\u043c \u043f\u043e\u0441\u043b\u0430\u0442\u044c \u0438-\u043c\u0435\u0439\u043b \u043f\u043e \u0430\u0434\u0440\u0435\u0441\u0443 <a href=\"mail:fundacja@nowoczesnapolska.org.pl\">fundacja@nowoczesnapolska.org.pl</a>.</p>\r\n\r\n        <p>\u041c\u044b \u043f\u0440\u0438\u0433\u043b\u0430\u0448\u0430\u0435\u043c \u0442\u0430\u043a\u0436\u0435 \u043d\u0430 <a href=\"http://redmine.nowoczesnapolska.org.pl/projects/wl-publikacje\">\u0441\u0430\u0439\u0442 \u0440\u0435\u0434\u0430\u043a\u0446\u0438\u0438 Wolne Lektury</a>, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u0439\u0442\u0438 \u0432\u0441\u044e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u0442\u043e\u043c, \u043a\u0430\u043a \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u0442\u044c \u043a \u0440\u0435\u0434\u0430\u043a\u0446\u0438\u043e\u043d\u043d\u044b\u043c \u0440\u0430\u0431\u043e\u0442\u0430\u043c.</p>\r\n", 
+            "right_column_lt": "\t<h2>Autoriai</h2>\r\n\r\n\t<ol>\r\n\t\t<li>\r\n\t\t\t<p>\r\n\t\t\t\tGimnazija nr 40 Lenkijos Armijos Koviokjan\u010dios Grup\u0117s \u201eKRYBAR\u201d vardo Mokykl\u0173 Kompleksas nr 69,\r\n\t\t\t\tul. Drewniana 8, 00-345 Warszawa; antra klas\u0117 globojama mokytojos\r\n\t\t\t\tAnny Budziarek-Friedrich:\r\n\t\t\t</p>\r\n\r\n\t\t\t<ul>\r\n\t\t\t\t<li>Burdon Filip;</li>\r\n\r\n\t\t\t\t<li>D\u0119bski Bartek;</li>\r\n\t\t\t\t<li>Jackowicz Kamil;</li>\r\n\t\t\t\t<li>Kurek Pawe\u0142;</li>\r\n\t\t\t\t<li>Makles Bartosz;</li>\r\n\t\t\t\t<li>Markiewicz Jeremiasz;</li>\r\n\t\t\t\t<li>Migda\u0142 Katarzyna;</li>\r\n\r\n\t\t\t\t<li>Mioduszewski Micha\u0142;</li>\r\n\t\t\t\t<li>Pfeiffer Ida;</li>\r\n\t\t\t\t<li>P\u0142askowicka Karolina;</li>\r\n\t\t\t\t<li>Sailer Ewa.</li>\r\n\t\t\t</ul>\r\n\t\t</li>\r\n\r\n\t\t<li>\r\n\t\t\t<p>\r\n\t\t\t\tXXXIII Miko\u0142ojaus Koperniko Bendrojo Lavinimo Licejus\r\n\t\t\t\tul. Bema 76, 01-225 Warszawa; pirma klas\u0117 biologijos chemijos profiles,\r\n\t\t\t\tglobojama mokytojos El\u017cbiety Konkowskiej:\r\n\t\t\t</p>\r\n\r\n\t\t\t<ul>\r\n\t\t\t\t<li>Chwil Bart\u0142omiej;</li>\r\n\t\t\t\t<li>Czarnecka Natalia;</li>\r\n\t\t\t\t<li>Gawro\u0144ska Iga;</li>\r\n\r\n\t\t\t\t<li>Grabarczyk Marta;</li>\r\n\t\t\t\t<li>Jastrz\u0105b Katarzyna;</li>\r\n\t\t\t\t<li>Krawczak Olga;</li>\r\n\t\t\t\t<li>Krawczyk Marianna;</li>\r\n\t\t\t\t<li>Kur Natalia;</li>\r\n\t\t\t\t<li>Kwiatek Marta;</li>\r\n\r\n\t\t\t\t<li>La\u015bkiewicz Joanna;</li>\r\n\t\t\t\t<li>Machczy\u0144ska Daria;</li>\r\n\t\t\t\t<li>Miecznikowska Izabela;</li>\r\n\t\t\t\t<li>Moczulska Karolina;</li>\r\n\t\t\t\t<li>Mo\u015bcicka Aneta;</li>\r\n\t\t\t\t<li>Narloch Sabina;</li>\r\n\r\n\t\t\t\t<li>Przybysz Pawe\u0142;</li>\r\n\t\t\t\t<li>Puchta Marek;</li>\r\n\t\t\t\t<li>Ryska Cezary;</li>\r\n\t\t\t\t<li>Sandomierski Bart\u0142omiej;</li>\r\n\t\t\t\t<li>S\u0142awi\u0144ski Tomasz;</li>\r\n\t\t\t\t<li>S\u0142owik Olga;</li>\r\n\r\n\t\t\t\t<li>Starzycka Katarzyna;</li>\r\n\t\t\t\t<li>Strzelczak Karolina;</li>\r\n\t\t\t\t<li>Szafran Danuta;</li>\r\n\t\t\t\t<li>Szmigielska Magdalena;</li>\r\n\t\t\t\t<li>Szulkowska Alicja;</li>\r\n\t\t\t\t<li>\u015alusarczyk Anna;</li>\r\n\r\n\t\t\t\t<li>Tytkowska Anna.</li>\r\n\t\t\t</ul>\r\n\t\t\t<li>\r\n\t\t\t\t<p>\r\n\t\t\t\t \tPrivatus Bendrojo Lavinimo Licejus nr\r\n\t\t\t\t\t42, ul. Iwicka 47 B, 00-735 Warszawa; \r\n\t\t\t\t\tpirma klas\u0117 bendros profiles,\r\n\t\t\t   \tglobojama mokytojaus Micha\u0142 Friedrich\r\n\t\t\t\t\t\r\n\t\t\t\t</p>\r\n\r\n\t\t\t\t<ul>\r\n\t\t\t\t\t<li>Baraniecka Marta;</li>\r\n\r\n\t\t\t\t\t<li>Go\u0142aszewska Ewa;</li>\r\n\t\t\t\t\t<li>Kwiatkowski Micha\u0142;</li>\r\n\t\t\t\t\t<li>Machnikowska Monika;</li>\r\n\t\t\t\t\t<li>Pietrzak Bartosz;</li>\r\n\t\t\t\t\t<li>Przespolewski Przemys\u0142aw;</li>\r\n\t\t\t\t\t<li>Rosi\u0144ska Zuzanna;</li>\r\n\r\n\t\t\t\t\t<li>Sibiga Magdalena.</li>\r\n\t\t\t\t</ul>\r\n\t\t\t</li>\r\n\t\t\t<li>\r\n\t\t\t\t<p>\r\n\t\t\t\t\tLXIV St. I. Witkiewicz Bendrojo Lavinimo Licejus\r\n\t\t\t\t\tul. Elbl\u0105ska 51, 01-737 Warszawa; pirma klas\u0117 bendros profiles,\r\n\t\t\t   \tglobojama mokytojaus Daniel Zych:\r\n\t\t\t\t</p>\r\n\r\n\t\t\t\t<ul>\r\n\r\n\t\t\t\t\t<li>Andrzejczak Kamil;</li>\r\n\t\t\t\t\t<li>Czubaj Konrad;</li>\r\n\t\t\t\t\t<li>Dr\u0105gowska Katarzyna;</li>\r\n\t\t\t\t\t<li>Gajewska Magdalena;</li>\r\n\t\t\t\t\t<li>G\u0142owacki Jan;</li>\r\n\t\t\t\t\t<li>Grad Pawe\u0142;</li>\r\n\r\n\t\t\t\t\t<li>Hnatowski Bartek;</li>\r\n\t\t\t\t\t<li>Karwowski Marcin;</li>\r\n\t\t\t\t\t<li>K\u0142os Aneta;</li>\r\n\t\t\t\t\t<li>Kozie\u0142 Barbara;</li>\r\n\t\t\t\t\t<li>Koz\u0142owska Anna;</li>\r\n\t\t\t\t\t<li>Krug Pamela;</li>\r\n\r\n\t\t\t\t\t<li>Krzosek Jakub;</li>\r\n\t\t\t\t\t<li>Luba\u015b Micha\u0142;</li>\r\n\t\t\t\t\t<li>Masewicz Natalia;</li>\r\n\t\t\t\t\t<li>Mastalerz Agnieszka;</li>\r\n\t\t\t\t\t<li>Modelska Marta;</li>\r\n\t\t\t\t\t<li>Nowak Aleksandra;</li>\r\n\r\n\t\t\t\t\t<li>Pabian Agnieszka;</li>\r\n\t\t\t\t\t<li>Paszkowska Aleksandra;</li>\r\n\t\t\t\t\t<li>Pielat Zofia;</li>\r\n\t\t\t\t\t<li>Poniecka Agnieszka;</li>\r\n\t\t\t\t\t<li>Pytlak Urszula;</li>\r\n\t\t\t\t\t<li>Rosa Karolina;</li>\r\n\r\n\t\t\t\t\t<li>Smyczy\u0144ska Kamila;</li>\r\n\t\t\t\t\t<li>Stoli\u0144ska Barbara;</li>\r\n\t\t\t\t\t<li>Szyma\u0144ska Katarzyna;</li>\r\n\t\t\t\t\t<li>\u015acibior Ewa;</li>\r\n\t\t\t\t\t<li>Witczak Magda;</li>\r\n\t\t\t\t\t<li>Witkowska Justyna;</li>\r\n\r\n\t\t\t\t\t<li>Wyrzykowska Jowita;</li>\r\n\t\t\t\t\t<li>Zi\u00f3\u0142kowska Adrianna.</li>\r\n\t\t\t\t</ul>\r\n\t\t\t</li>\r\n\t  </li>\r\n\t  </ol>\r\n", 
+            "title_es": "Voluntariado para el conocimiento", 
+            "page_title_fr": "B\u00e9n\u00e9volat pour le savoir au WolneLektury.pl", 
+            "page_title_uk": "\u0412\u043e\u043b\u043e\u043d\u0442\u0435\u0440\u0441\u0442\u0432\u043e \u0432 \u043e\u0441\u0432\u0456\u0442\u0456 \u0443 WolneLektury.pl", 
+            "page_title_de": "Volontariat f\u00fcr Wissen unter WolneLektury.pl", 
+            "slug": "voluntary_services", 
+            "page_title_lt": "Lik savanoriu LaisvojiLiteratura.lt kad su\u009einoti daugiau", 
+            "right_column_de": "\t<h2>Autoren</h2>\r\n\r\n\t<ol>\r\n\t\t<li>\r\n\t\t\t<p>\r\n\t\t\t\tGymnasium Nr. 40 mit Integrationsabteilungen \r\n\t\t\t\tSchulverbund Nr. 69 Schulname: Armii Krajowej Grupy Bojowej \u201eKRYBAR\u201d, \r\n\t\t\t\tStr. Drewniana 8, 00-345 Warszawa; 2. Klasse\r\n\t\t\t\tKlassenlehrerin: Anna Budziarek-Friedrich:\r\n\t\t\t</p>\r\n\r\n\t\t\t<ul>\r\n\t\t\t\t<li>Burdon Filip;</li>\r\n\r\n\t\t\t\t<li>D\u0119bski Bartek;</li>\r\n\t\t\t\t<li>Jackowicz Kamil;</li>\r\n\t\t\t\t<li>Kurek Pawe\u0142;</li>\r\n\t\t\t\t<li>Makles Bartosz;</li>\r\n\t\t\t\t<li>Markiewicz Jeremiasz;</li>\r\n\t\t\t\t<li>Migda\u0142 Katarzyna;</li>\r\n\r\n\t\t\t\t<li>Mioduszewski Micha\u0142;</li>\r\n\t\t\t\t<li>Pfeiffer Ida;</li>\r\n\t\t\t\t<li>P\u0142askowicka Karolina;</li>\r\n\t\t\t\t<li>Sailer Ewa.</li>\r\n\t\t\t</ul>\r\n\t\t</li>\r\n\r\n\t\t<li>\r\n\t\t\t<p>\r\n\t\t\t\tXXXIII Kopernikus Oberschule,\r\n\t\t\t\tStr. Bema 76, 01-225 Warszawa; 1. Klasse; \r\n\t\t\t\tFachbereiche: Biologie-Chemie; Klassenlehrerin: El\u017cbieta Konkowska:\r\n\t\t\t</p>\r\n\r\n\t\t\t<ul>\r\n\t\t\t\t<li>Chwil Bart\u0142omiej;</li>\r\n\t\t\t\t<li>Czarnecka Natalia;</li>\r\n\t\t\t\t<li>Gawro\u0144ska Iga;</li>\r\n\r\n\t\t\t\t<li>Grabarczyk Marta;</li>\r\n\t\t\t\t<li>Jastrz\u0105b Katarzyna;</li>\r\n\t\t\t\t<li>Krawczak Olga;</li>\r\n\t\t\t\t<li>Krawczyk Marianna;</li>\r\n\t\t\t\t<li>Kur Natalia;</li>\r\n\t\t\t\t<li>Kwiatek Marta;</li>\r\n\r\n\t\t\t\t<li>La\u015bkiewicz Joanna;</li>\r\n\t\t\t\t<li>Machczy\u0144ska Daria;</li>\r\n\t\t\t\t<li>Miecznikowska Izabela;</li>\r\n\t\t\t\t<li>Moczulska Karolina;</li>\r\n\t\t\t\t<li>Mo\u015bcicka Aneta;</li>\r\n\t\t\t\t<li>Narloch Sabina;</li>\r\n\r\n\t\t\t\t<li>Przybysz Pawe\u0142;</li>\r\n\t\t\t\t<li>Puchta Marek;</li>\r\n\t\t\t\t<li>Ryska Cezary;</li>\r\n\t\t\t\t<li>Sandomierski Bart\u0142omiej;</li>\r\n\t\t\t\t<li>S\u0142awi\u0144ski Tomasz;</li>\r\n\t\t\t\t<li>S\u0142owik Olga;</li>\r\n\r\n\t\t\t\t<li>Starzycka Katarzyna;</li>\r\n\t\t\t\t<li>Strzelczak Karolina;</li>\r\n\t\t\t\t<li>Szafran Danuta;</li>\r\n\t\t\t\t<li>Szmigielska Magdalena;</li>\r\n\t\t\t\t<li>Szulkowska Alicja;</li>\r\n\t\t\t\t<li>\u015alusarczyk Anna;</li>\r\n\r\n\t\t\t\t<li>Tytkowska Anna.</li>\r\n\t\t\t</ul>\r\n\t\t\t<li>\r\n\t\t\t\t<p>\r\n\t\t\t\t\tPrivate Oberschule Nr 42,\r\n\t\t\t\t\tStr. Iwicka 47 B, 00-735 Warszawa; 1. Klasse\r\n\t\t\t\t\tFachbereich: Allgemeinbildung; Klassenlehrer: Micha\u0142 Friedrich:\r\n\t\t\t\t</p>\r\n\r\n\t\t\t\t<ul>\r\n\t\t\t\t\t<li>Baraniecka Marta;</li>\r\n\r\n\t\t\t\t\t<li>Go\u0142aszewska Ewa;</li>\r\n\t\t\t\t\t<li>Kwiatkowski Micha\u0142;</li>\r\n\t\t\t\t\t<li>Machnikowska Monika;</li>\r\n\t\t\t\t\t<li>Pietrzak Bartosz;</li>\r\n\t\t\t\t\t<li>Przespolewski Przemys\u0142aw;</li>\r\n\t\t\t\t\t<li>Rosi\u0144ska Zuzanna;</li>\r\n\r\n\t\t\t\t\t<li>Sibiga Magdalena.</li>\r\n\t\t\t\t</ul>\r\n\t\t\t</li>\r\n\t\t\t<li>\r\n\t\t\t\t<p>\r\n\t\t\t\t\tLXIV Witkiewicz Oberschule,\r\n\t\t\t\t\tStr. Elbl\u0105ska 51, 01-737 Warszawa; 1. Klasse, \r\n\t\t\t\t\tFachbereich: Allgemeinbildung; Klassenlehrer: Daniel Zych:\r\n\t\t\t\t</p>\r\n\r\n\t\t\t\t<ul>\r\n\r\n\t\t\t\t\t<li>Andrzejczak Kamil;</li>\r\n\t\t\t\t\t<li>Czubaj Konrad;</li>\r\n\t\t\t\t\t<li>Dr\u0105gowska Katarzyna;</li>\r\n\t\t\t\t\t<li>Gajewska Magdalena;</li>\r\n\t\t\t\t\t<li>G\u0142owacki Jan;</li>\r\n\t\t\t\t\t<li>Grad Pawe\u0142;</li>\r\n\r\n\t\t\t\t\t<li>Hnatowski Bartek;</li>\r\n\t\t\t\t\t<li>Karwowski Marcin;</li>\r\n\t\t\t\t\t<li>K\u0142os Aneta;</li>\r\n\t\t\t\t\t<li>Kozie\u0142 Barbara;</li>\r\n\t\t\t\t\t<li>Koz\u0142owska Anna;</li>\r\n\t\t\t\t\t<li>Krug Pamela;</li>\r\n\r\n\t\t\t\t\t<li>Krzosek Jakub;</li>\r\n\t\t\t\t\t<li>Luba\u015b Micha\u0142;</li>\r\n\t\t\t\t\t<li>Masewicz Natalia;</li>\r\n\t\t\t\t\t<li>Mastalerz Agnieszka;</li>\r\n\t\t\t\t\t<li>Modelska Marta;</li>\r\n\t\t\t\t\t<li>Nowak Aleksandra;</li>\r\n\r\n\t\t\t\t\t<li>Pabian Agnieszka;</li>\r\n\t\t\t\t\t<li>Paszkowska Aleksandra;</li>\r\n\t\t\t\t\t<li>Pielat Zofia;</li>\r\n\t\t\t\t\t<li>Poniecka Agnieszka;</li>\r\n\t\t\t\t\t<li>Pytlak Urszula;</li>\r\n\t\t\t\t\t<li>Rosa Karolina;</li>\r\n\r\n\t\t\t\t\t<li>Smyczy\u0144ska Kamila;</li>\r\n\t\t\t\t\t<li>Stoli\u0144ska Barbara;</li>\r\n\t\t\t\t\t<li>Szyma\u0144ska Katarzyna;</li>\r\n\t\t\t\t\t<li>\u015acibior Ewa;</li>\r\n\t\t\t\t\t<li>Witczak Magda;</li>\r\n\t\t\t\t\t<li>Witkowska Justyna;</li>\r\n\r\n\t\t\t\t\t<li>Wyrzykowska Jowita;</li>\r\n\t\t\t\t\t<li>Zi\u00f3\u0142kowska Adrianna.</li>\r\n\t\t\t\t</ul>\r\n\t\t\t</li>\r\n\t  </li>\r\n\t  </ol>\r\n", 
+            "page_title_pl": "Wolontariat dla wiedzy w WolneLektury.pl", 
+            "left_column_es": "<h2>Voluntariado</h2>\r\n\r\n\t<p>\r\n\r\n\t\tBiograf\u00edas de escritores y definiciones de las \u00e9pocas y g\u00e9neros literarios en la biblioteca virtual de Wolne Lektury fueron escritas por estudiantes de cuatro escuelas durante los talleres \u201cVoluntariado para el conocimiento\u201d.  </p>\r\n\r\n\r\n\r\n\t<p>\r\n\r\n\t\tLos estudiantes trabajaron juntos bajo la supervisi\u00f3n de profesores y especialistas-fil\u00f3logos en\r\n\r\n\t\t<a href=\"http://wolnepodreczniki.pl/wolontariat/\">\r\n\r\n\r\n\r\n\t\t\tla plataforma virtual wiki </a>\r\n\r\n\t\tpreparada por el equipo\r\n\r\n\t\t<a href=\"http://2ia.pl/\">2ia</a>. Gracias a este trabajo los estudiantes aprendieron a usar los ordenadores e internet para encontrar informaciones y verificar si se les puede confiar.\t</p>\r\n\r\n\r\n\r\n\t<p>\r\n\r\n\t\tEl proyecto \"Voluntariado para el conocimiento\" se pudo realizar gracias al apoyo del\t\t<a href=\"http://www.menis.gov.pl/\">\r\n\r\n\t\t\tMinisterio de la Educaci\u00f3n Nacional</a>. Los premios para los estudiantes fueron fundados por\r\n\r\n\t\t<a href=\"http://www.nk.com.pl/engine/index.php?page=glowna\">\r\n\r\n\r\n\r\n\t\t\tEditorial Nasza Ksi\u0119garnia</a>\r\n\r\n\t\ty\r\n\r\n\t\t<a href=\"http://helion.pl/\">Editorial Helion</a>.  Las notas fueron verificadas en la p\u00e1gina\r\n\r\n\t\t<a href=\"http://www.plagiat.pl/webplagiat/main.action\">\r\n\r\n\t\t\tPlagiat.pl</a>.\r\n\r\n\t</p>\r\n\r\n\r\n\r\n\t<p>\r\n\r\n\t\t<a href=\"/static/wolontariat.pdf\"> El informe de la realizaci\u00f3n del proyecto \u201cVoluntariado para el conocimiento\u201d</a>.\r\n\r\n\t</p>\r\n\r\n\r\n\r\n\t<p>\r\n\r\n\t<img src=\"/static/img/wolontariat/okladka.jpg\" style='margin: 10px' />\r\n\r\n\t<img src=\"/static/img/wolontariat/01.jpg\" style='margin: 10px' />\r\n\r\n\t<img src=\"/static/img/wolontariat/02.jpg\" style='margin: 10px' />\r\n\r\n    <img src=\"/static/img/wolontariat/03.jpg\" style='margin: 10px' />\r\n\r\n    <img src=\"/static/img/wolontariat/04.jpg\" style='margin: 10px' />\r\n\r\n\t</p>", 
+            "left_column_en": "<h2>Volunteers</h2>\r\n\t<p>Writers' biographical entries as well as periods' and genres'\r\ndefinitions placed on web library Wolne Lektury were written by students from four schools during \"Wolontariat dla wiedzy\" (\"Volunteering for knowledge\") workshops. </p> <p>\r\n The students worked together under the factual guidance of teachers and specialists - literary scholars<a href=\"http://wolnepodreczniki.pl/wolontariat/\">\r\n\r\n\ton wiki platform</a>\r\n prepared by <a href=\"http://2ia.pl/\">2ia</a> team. At the same time the students learnt how to use a computer and the Internet while searching for necessary information how to verify the credibility of the source. </p>\r\n\r\n<p>\r\n\"Wolontariat dla wiedzy\" project was realised thanks to the support of <a href=\"http://www.menis.gov.pl/\">\r\nMinisterstwo Edukacji Narodowej</a>. The rewards for the student were funded by<a href=\"http://www.nk.com.pl/engine/index.php?page=glowna\">\r\n\r\nWydawnictwo Nasza Ksi\u0119garnia</a>\r\nand<a href=\"http://helion.pl/\">Wydawnictwo Helion</a>. Each entry was verified on <a href=\"http://www.plagiat.pl/webplagiat/main.action\">\r\nPlagiat.pl</a> website.\r\n</p>\r\n\r\n<p>\r\n\t\t<a href=\"/static/wolontariat.pdf\">Report on completion of \"Wolontariat dla wiedzy\" project (PL)</a>.\r\n\t</p>\r\n\r\n\t<p>\r\n\t<img src=\"/static/img/wolontariat/okladka.jpg\" style='margin: 10px' />\r\n\t<img src=\"/static/img/wolontariat/01.jpg\" style='margin: 10px' />\r\n\t<img src=\"/static/img/wolontariat/02.jpg\" style='margin: 10px' />\r\n    <img src=\"/static/img/wolontariat/03.jpg\" style='margin: 10px' />\r\n    <img src=\"/static/img/wolontariat/04.jpg\" style='margin: 10px' />\r\n\t</p>", 
+            "title_pl": "Wolontariat dla wiedzy", 
+            "title_ru": "\u0412\u043e\u043b\u043e\u043d\u0442\u0435\u0440\u0441\u0442\u0432\u043e \u0434\u043b\u044f \u0437\u043d\u0430\u043d\u0438\u0439", 
+            "page_title_ru": "\u0412\u043e\u043b\u043e\u043d\u0442\u0435\u0440\u0441\u0442\u0432\u043e \u0434\u043b\u044f \u0437\u043d\u0430\u043d\u0438\u0439 \u043d\u0430 WolneLektury.pl"
+        }
+    }, 
+    {
+        "pk": 4, 
+        "model": "infopages.infopage", 
+        "fields": {
+            "title_de": "Widget", 
+            "page_title": "Widget", 
+            "left_column_uk": "", 
+            "right_column_pl": "<h2>Jak umie\u015bci\u0107 wid\u017cet Wolne Lektury na stronie WWW</h2>\r\n<p>T\u0119 cz\u0119\u015b\u0107 kodu nale\u017cy umie\u015bci\u0107 tam, gdzie ma pojawi\u0107 si\u0119 wid\u017cet.</p>\r\n<input type=\"text\" value=\"<div id='wl'></div>\" size=\"50\">\r\n\r\n<p>T\u0119 cz\u0119\u015b\u0107 kodu nale\u017cy umie\u015bci\u0107 tu\u017c przed zamkni\u0119ciem taga body, czyli przed &lt;/body&gt;</p>\r\n\r\n<input type=\"text\" value=\"<script type='text/javascript' src='http://www.wolnelektury.pl/static/js/widget.js'></script>\" size=\"50\">", 
+            "page_title_en": "Widget", 
+            "page_title_es": "Widget", 
+            "left_column_lt": "", 
+            "title_fr": "Widget", 
+            "right_column_ru": "", 
+            "left_column_fr": "", 
+            "title": "Widget", 
+            "title_lt": "Widget", 
+            "right_column": "<h2>Jak umie\u015bci\u0107 wid\u017cet Wolne Lektury na stronie WWW</h2>\r\n<p>T\u0119 cz\u0119\u015b\u0107 kodu nale\u017cy umie\u015bci\u0107 tam, gdzie ma pojawi\u0107 si\u0119 wid\u017cet.</p>\r\n<input type=\"text\" value=\"<div id='wl'></div>\" size=\"50\">\r\n\r\n<p>T\u0119 cz\u0119\u015b\u0107 kodu nale\u017cy umie\u015bci\u0107 tu\u017c przed zamkni\u0119ciem taga body, czyli przed &lt;/body&gt;</p>\r\n\r\n<input type=\"text\" value=\"<script type='text/javascript' src='http://www.wolnelektury.pl/static/js/widget.js'></script>\" size=\"50\">", 
+            "right_column_es": "", 
+            "right_column_en": "", 
+            "left_column_de": "", 
+            "title_uk": "Widget", 
+            "right_column_fr": "", 
+            "left_column": "<h2>Wid\u017cet Wolne Lektury na Twojej stronie WWW</h2>\r\n<p>Umie\u015b\u0107 wid\u017cet \u2013 wyszukiwark\u0119 Wolnych Lektur umo\u017cliwiaj\u0105c\u0105 dost\u0119p do darmowych lektur i audiobook\u00f3w \u2013 na swojej stronie WWW!</p>\r\n<p>Po prostu skopiuj poni\u017cszy kod HTML.</p> \r\n\r\n<textarea cols=\"37\" rows=\"12\"><!-- START Umiescic ten element, w miejscu w ktorym ma sie pojawic widget -->\r\n<div id=\"wl\"></div>\r\n<!-- KONIEC -->\r\n\r\n<!-- START Umiescic ten element zaraz przed zamknieciem taga body: </body> -->\r\n<script type=\"text/javascript\" src=\"http://www.wolnelektury.pl/static/js/widget.js\"></script>\r\n<!-- KONIEC --></textarea>\r\n\r\n\r\n<p>Tak b\u0119dzie prezentowa\u0142 si\u0119 wid\u017cet po umieszczeniu go na stronie:</p>\r\n<div id=\"wl\"></div>\r\n<script type=\"text/javascript\" src=\"http://www.wolnelektury.pl/static/js/widget.js\"></script>", 
+            "right_column_uk": "", 
+            "title_en": "Widget", 
+            "left_column_pl": "<h2>Wid\u017cet Wolne Lektury na Twojej stronie WWW</h2>\r\n<p>Umie\u015b\u0107 wid\u017cet \u2013 wyszukiwark\u0119 Wolnych Lektur umo\u017cliwiaj\u0105c\u0105 dost\u0119p do darmowych lektur i audiobook\u00f3w \u2013 na swojej stronie WWW!</p>\r\n<p>Po prostu skopiuj poni\u017cszy kod HTML.</p> \r\n\r\n<textarea cols=\"37\" rows=\"12\"><!-- START Umiescic ten element, w miejscu w ktorym ma sie pojawic widget -->\r\n<div id=\"wl\"></div>\r\n<!-- KONIEC -->\r\n\r\n<!-- START Umiescic ten element zaraz przed zamknieciem taga body: </body> -->\r\n<script type=\"text/javascript\" src=\"http://www.wolnelektury.pl/static/js/widget.js\"></script>\r\n<!-- KONIEC --></textarea>\r\n\r\n\r\n<p>Tak b\u0119dzie prezentowa\u0142 si\u0119 wid\u017cet po umieszczeniu go na stronie:</p>\r\n<div id=\"wl\"></div>\r\n<script type=\"text/javascript\" src=\"http://www.wolnelektury.pl/static/js/widget.js\"></script>", 
+            "left_column_ru": "", 
+            "right_column_lt": "", 
+            "title_es": "Widget", 
+            "page_title_fr": "Widget", 
+            "page_title_uk": "Widget", 
+            "page_title_de": "Widget", 
+            "slug": "widget", 
+            "page_title_lt": "Widget", 
+            "right_column_de": "", 
+            "page_title_pl": "Wid\u017cet", 
+            "left_column_es": "", 
+            "left_column_en": "", 
+            "title_pl": "Wid\u017cet Wolne Lektury", 
+            "title_ru": "Widget", 
+            "page_title_ru": "Widget"
+        }
+    }
+]
diff --git a/apps/infopages/migrations/0001_initial.py b/apps/infopages/migrations/0001_initial.py
new file mode 100644 (file)
index 0000000..a28ce3a
--- /dev/null
@@ -0,0 +1,110 @@
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+class Migration(SchemaMigration):
+
+    def forwards(self, orm):
+
+        # Adding model 'InfoPage'
+        db.create_table('infopages_infopage', (
+            ('title_de', self.gf('django.db.models.fields.CharField')(max_length=120, null=True, blank=True)),
+            ('page_title', self.gf('django.db.models.fields.CharField')(max_length=120, blank=True)),
+            ('left_column_uk', self.gf('django.db.models.fields.TextField')(null=True, blank=True)),
+            ('right_column_pl', self.gf('django.db.models.fields.TextField')(null=True, blank=True)),
+            ('page_title_en', self.gf('django.db.models.fields.CharField')(max_length=120, null=True, blank=True)),
+            ('page_title_es', self.gf('django.db.models.fields.CharField')(max_length=120, null=True, blank=True)),
+            ('left_column_lt', self.gf('django.db.models.fields.TextField')(null=True, blank=True)),
+            ('title_fr', self.gf('django.db.models.fields.CharField')(max_length=120, null=True, blank=True)),
+            ('right_column_ru', self.gf('django.db.models.fields.TextField')(null=True, blank=True)),
+            ('left_column_fr', self.gf('django.db.models.fields.TextField')(null=True, blank=True)),
+            ('title', self.gf('django.db.models.fields.CharField')(max_length=120, blank=True)),
+            ('title_lt', self.gf('django.db.models.fields.CharField')(max_length=120, null=True, blank=True)),
+            ('right_column', self.gf('django.db.models.fields.TextField')(blank=True)),
+            ('right_column_es', self.gf('django.db.models.fields.TextField')(null=True, blank=True)),
+            ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+            ('right_column_en', self.gf('django.db.models.fields.TextField')(null=True, blank=True)),
+            ('left_column_de', self.gf('django.db.models.fields.TextField')(null=True, blank=True)),
+            ('title_uk', self.gf('django.db.models.fields.CharField')(max_length=120, null=True, blank=True)),
+            ('right_column_fr', self.gf('django.db.models.fields.TextField')(null=True, blank=True)),
+            ('left_column', self.gf('django.db.models.fields.TextField')(blank=True)),
+            ('right_column_uk', self.gf('django.db.models.fields.TextField')(null=True, blank=True)),
+            ('title_en', self.gf('django.db.models.fields.CharField')(max_length=120, null=True, blank=True)),
+            ('left_column_pl', self.gf('django.db.models.fields.TextField')(null=True, blank=True)),
+            ('left_column_ru', self.gf('django.db.models.fields.TextField')(null=True, blank=True)),
+            ('right_column_lt', self.gf('django.db.models.fields.TextField')(null=True, blank=True)),
+            ('title_es', self.gf('django.db.models.fields.CharField')(max_length=120, null=True, blank=True)),
+            ('page_title_fr', self.gf('django.db.models.fields.CharField')(max_length=120, null=True, blank=True)),
+            ('page_title_uk', self.gf('django.db.models.fields.CharField')(max_length=120, null=True, blank=True)),
+            ('page_title_de', self.gf('django.db.models.fields.CharField')(max_length=120, null=True, blank=True)),
+            ('slug', self.gf('django.db.models.fields.SlugField')(unique=True, max_length=120, db_index=True)),
+            ('page_title_lt', self.gf('django.db.models.fields.CharField')(max_length=120, null=True, blank=True)),
+            ('right_column_de', self.gf('django.db.models.fields.TextField')(null=True, blank=True)),
+            ('page_title_pl', self.gf('django.db.models.fields.CharField')(max_length=120, null=True, blank=True)),
+            ('left_column_es', self.gf('django.db.models.fields.TextField')(null=True, blank=True)),
+            ('left_column_en', self.gf('django.db.models.fields.TextField')(null=True, blank=True)),
+            ('title_pl', self.gf('django.db.models.fields.CharField')(max_length=120, null=True, blank=True)),
+            ('title_ru', self.gf('django.db.models.fields.CharField')(max_length=120, null=True, blank=True)),
+            ('page_title_ru', self.gf('django.db.models.fields.CharField')(max_length=120, null=True, blank=True)),
+        ))
+
+        if not db.dry_run:
+            from django.core.management import call_command
+            call_command("loaddata", "wl_data")
+
+        db.send_create_signal('infopages', ['InfoPage'])
+
+
+    def backwards(self, orm):
+
+        # Deleting model 'InfoPage'
+        db.delete_table('infopages_infopage')
+
+
+    models = {
+        'infopages.infopage': {
+            'Meta': {'object_name': 'InfoPage'},
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'left_column': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'left_column_de': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            'left_column_en': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            'left_column_es': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            'left_column_fr': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            'left_column_lt': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            'left_column_pl': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            'left_column_ru': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            'left_column_uk': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            'page_title': ('django.db.models.fields.CharField', [], {'max_length': '120', 'blank': 'True'}),
+            'page_title_de': ('django.db.models.fields.CharField', [], {'max_length': '120', 'null': True, 'blank': True}),
+            'page_title_en': ('django.db.models.fields.CharField', [], {'max_length': '120', 'null': True, 'blank': True}),
+            'page_title_es': ('django.db.models.fields.CharField', [], {'max_length': '120', 'null': True, 'blank': True}),
+            'page_title_fr': ('django.db.models.fields.CharField', [], {'max_length': '120', 'null': True, 'blank': True}),
+            'page_title_lt': ('django.db.models.fields.CharField', [], {'max_length': '120', 'null': True, 'blank': True}),
+            'page_title_pl': ('django.db.models.fields.CharField', [], {'max_length': '120', 'null': True, 'blank': True}),
+            'page_title_ru': ('django.db.models.fields.CharField', [], {'max_length': '120', 'null': True, 'blank': True}),
+            'page_title_uk': ('django.db.models.fields.CharField', [], {'max_length': '120', 'null': True, 'blank': True}),
+            'right_column': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'right_column_de': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            'right_column_en': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            'right_column_es': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            'right_column_fr': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            'right_column_lt': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            'right_column_pl': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            'right_column_ru': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            'right_column_uk': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+            'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '120', 'db_index': 'True'}),
+            'title': ('django.db.models.fields.CharField', [], {'max_length': '120', 'blank': 'True'}),
+            'title_de': ('django.db.models.fields.CharField', [], {'max_length': '120', 'null': True, 'blank': True}),
+            'title_en': ('django.db.models.fields.CharField', [], {'max_length': '120', 'null': True, 'blank': True}),
+            'title_es': ('django.db.models.fields.CharField', [], {'max_length': '120', 'null': True, 'blank': True}),
+            'title_fr': ('django.db.models.fields.CharField', [], {'max_length': '120', 'null': True, 'blank': True}),
+            'title_lt': ('django.db.models.fields.CharField', [], {'max_length': '120', 'null': True, 'blank': True}),
+            'title_pl': ('django.db.models.fields.CharField', [], {'max_length': '120', 'null': True, 'blank': True}),
+            'title_ru': ('django.db.models.fields.CharField', [], {'max_length': '120', 'null': True, 'blank': True}),
+            'title_uk': ('django.db.models.fields.CharField', [], {'max_length': '120', 'null': True, 'blank': True})
+        }
+    }
+
+    complete_apps = ['infopages']
diff --git a/apps/infopages/migrations/__init__.py b/apps/infopages/migrations/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/apps/infopages/models.py b/apps/infopages/models.py
new file mode 100644 (file)
index 0000000..9fe7b32
--- /dev/null
@@ -0,0 +1,26 @@
+# -*- coding: utf-8 -*-
+# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
+from django.db import models
+from django.utils.translation import ugettext_lazy as _
+
+class InfoPage(models.Model):
+    """
+    An InfoPage is used to display a two-column flatpage
+    """
+
+    page_title = models.CharField(_('page title'), max_length=120, blank=True)
+    slug = models.SlugField(_('slug'), max_length=120, unique=True, db_index=True)
+    title = models.CharField(_('title'), max_length=120, blank=True)
+    left_column = models.TextField(_('left column'), blank=True)
+    right_column = models.TextField(_('right column'), blank=True)
+
+    class Meta:
+        ordering = ('slug',)
+        verbose_name = _('info page')
+        verbose_name_plural = _('info pages')
+
+    def __unicode__(self):
+        return self.title
+
diff --git a/apps/infopages/views.py b/apps/infopages/views.py
new file mode 100644 (file)
index 0000000..07a416b
--- /dev/null
@@ -0,0 +1,16 @@
+# -*- coding: utf-8 -*-
+# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
+from django.shortcuts import render_to_response
+from django.template import RequestContext
+
+from catalogue.forms import SearchForm
+from infopages.models import InfoPage
+
+def infopage(request, slug):
+    form = SearchForm()
+    object = InfoPage.objects.get(slug=slug)
+
+    return render_to_response('info/base.html', locals(),
+                context_instance=RequestContext(request))
\ No newline at end of file
index 813621f..1447453 100644 (file)
@@ -1,3 +1,7 @@
+# -*- coding: utf-8 -*-
+# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
 from django.contrib import admin
 from django.utils.translation import ugettext_lazy as _
 
diff --git a/apps/lessons/locale/de/LC_MESSAGES/django.mo b/apps/lessons/locale/de/LC_MESSAGES/django.mo
new file mode 100644 (file)
index 0000000..512a6c3
Binary files /dev/null and b/apps/lessons/locale/de/LC_MESSAGES/django.mo differ
diff --git a/apps/lessons/locale/de/LC_MESSAGES/django.po b/apps/lessons/locale/de/LC_MESSAGES/django.po
new file mode 100644 (file)
index 0000000..99d4bd7
--- /dev/null
@@ -0,0 +1,49 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-05-18 11:00+0200\n"
+"PO-Revision-Date: 2010-06-03 01:40+0100\n"
+"Last-Translator: Iwona Fiałkowska <ifialkowska@gmail.com>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: models.py:12
+msgid "title"
+msgstr "Titel"
+
+#: models.py:13
+msgid "slug"
+msgstr "slug"
+
+#: models.py:14
+msgid "file"
+msgstr "Datei"
+
+#: models.py:15
+msgid "author"
+msgstr "Autor"
+
+#: models.py:16
+msgid "slideshare ID"
+msgstr "Dia ID"
+
+#: models.py:17
+msgid "description"
+msgstr "Beschreibung"
+
+#: models.py:29
+msgid "document"
+msgstr "Dokument"
+
+#: models.py:29
+msgid "documents"
+msgstr "Dokumente"
+
diff --git a/apps/lessons/locale/en/LC_MESSAGES/django.mo b/apps/lessons/locale/en/LC_MESSAGES/django.mo
new file mode 100644 (file)
index 0000000..daef484
Binary files /dev/null and b/apps/lessons/locale/en/LC_MESSAGES/django.mo differ
diff --git a/apps/lessons/locale/en/LC_MESSAGES/django.po b/apps/lessons/locale/en/LC_MESSAGES/django.po
new file mode 100644 (file)
index 0000000..e001f69
--- /dev/null
@@ -0,0 +1,49 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-05-18 11:00+0200\n"
+"PO-Revision-Date: 2010-06-09 16:44+0100\n"
+"Last-Translator: K Izdebska <villdeo.tess@gmail.com>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: models.py:12
+msgid "title"
+msgstr "title"
+
+#: models.py:13
+msgid "slug"
+msgstr "slug"
+
+#: models.py:14
+msgid "file"
+msgstr "file"
+
+#: models.py:15
+msgid "author"
+msgstr "author"
+
+#: models.py:16
+msgid "slideshare ID"
+msgstr "slideshare ID"
+
+#: models.py:17
+msgid "description"
+msgstr "description"
+
+#: models.py:29
+msgid "document"
+msgstr "document"
+
+#: models.py:29
+msgid "documents"
+msgstr "documents"
+
diff --git a/apps/lessons/locale/es/LC_MESSAGES/django.mo b/apps/lessons/locale/es/LC_MESSAGES/django.mo
new file mode 100644 (file)
index 0000000..b674d77
Binary files /dev/null and b/apps/lessons/locale/es/LC_MESSAGES/django.mo differ
diff --git a/apps/lessons/locale/es/LC_MESSAGES/django.po b/apps/lessons/locale/es/LC_MESSAGES/django.po
new file mode 100644 (file)
index 0000000..2c9d19b
--- /dev/null
@@ -0,0 +1,49 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-05-18 11:00+0200\n"
+"PO-Revision-Date: 2010-08-11 10:05+0100\n"
+"Last-Translator: Katarzyna Flis <kas.flis@gmail.com>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: models.py:12
+msgid "title"
+msgstr "título"
+
+#: models.py:13
+msgid "slug"
+msgstr "slug"
+
+#: models.py:14
+msgid "file"
+msgstr "archivo"
+
+#: models.py:15
+msgid "author"
+msgstr "autor"
+
+#: models.py:16
+msgid "slideshare ID"
+msgstr "slideshare ID"
+
+#: models.py:17
+msgid "description"
+msgstr "descripción"
+
+#: models.py:29
+msgid "document"
+msgstr "documento"
+
+#: models.py:29
+msgid "documents"
+msgstr "documentos"
+
diff --git a/apps/lessons/locale/fr/LC_MESSAGES/django.mo b/apps/lessons/locale/fr/LC_MESSAGES/django.mo
new file mode 100644 (file)
index 0000000..f4d52c1
Binary files /dev/null and b/apps/lessons/locale/fr/LC_MESSAGES/django.mo differ
diff --git a/apps/lessons/locale/fr/LC_MESSAGES/django.po b/apps/lessons/locale/fr/LC_MESSAGES/django.po
new file mode 100644 (file)
index 0000000..7a445c6
--- /dev/null
@@ -0,0 +1,49 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-05-18 11:00+0200\n"
+"PO-Revision-Date: 2010-07-12 20:34+0100\n"
+"Last-Translator: Natalia Kertyczak <natalczyk@o2.pl>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: models.py:12
+msgid "title"
+msgstr "titre"
+
+#: models.py:13
+msgid "slug"
+msgstr "slug"
+
+#: models.py:14
+msgid "file"
+msgstr "fichier"
+
+#: models.py:15
+msgid "author"
+msgstr "auteur"
+
+#: models.py:16
+msgid "slideshare ID"
+msgstr "slideshare ID"
+
+#: models.py:17
+msgid "description"
+msgstr "description"
+
+#: models.py:29
+msgid "document"
+msgstr "document"
+
+#: models.py:29
+msgid "documents"
+msgstr "documents"
+
diff --git a/apps/lessons/locale/lt/LC_MESSAGES/django.mo b/apps/lessons/locale/lt/LC_MESSAGES/django.mo
new file mode 100644 (file)
index 0000000..bbe12bd
Binary files /dev/null and b/apps/lessons/locale/lt/LC_MESSAGES/django.mo differ
diff --git a/apps/lessons/locale/lt/LC_MESSAGES/django.po b/apps/lessons/locale/lt/LC_MESSAGES/django.po
new file mode 100644 (file)
index 0000000..eb94aba
--- /dev/null
@@ -0,0 +1,50 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-05-18 11:00+0200\n"
+"PO-Revision-Date: 2010-07-09 22:59+0100\n"
+"Last-Translator: Alicja Sinkiewicz <alicja.sinkiewicz@gmail.com>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Translated-Using: django-rosetta 0.5.3\n"
+
+#: models.py:12
+msgid "title"
+msgstr "pavadinimas"
+
+#: models.py:13
+msgid "slug"
+msgstr "slugas"
+
+#: models.py:14
+msgid "file"
+msgstr "failas"
+
+#: models.py:15
+msgid "author"
+msgstr "autorius"
+
+#: models.py:16
+msgid "slideshare ID"
+msgstr "slideshare ID"
+
+#: models.py:17
+msgid "description"
+msgstr "aprašymas"
+
+#: models.py:29
+msgid "document"
+msgstr "dokumentas"
+
+#: models.py:29
+msgid "documents"
+msgstr "dokumentai"
+
diff --git a/apps/lessons/locale/pl/LC_MESSAGES/django.mo b/apps/lessons/locale/pl/LC_MESSAGES/django.mo
new file mode 100644 (file)
index 0000000..92e6388
Binary files /dev/null and b/apps/lessons/locale/pl/LC_MESSAGES/django.mo differ
diff --git a/apps/lessons/locale/pl/LC_MESSAGES/django.po b/apps/lessons/locale/pl/LC_MESSAGES/django.po
new file mode 100644 (file)
index 0000000..4967ba6
--- /dev/null
@@ -0,0 +1,49 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+# 
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-05-18 11:00+0200\n"
+"PO-Revision-Date: 2010-05-19 16:19\n"
+"Last-Translator: <radoslaw.czajka@nowoczesnapolska.org.pl>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Translated-Using: django-rosetta 0.5.3\n"
+
+#: models.py:12
+msgid "title"
+msgstr "tytuł"
+
+#: models.py:13
+msgid "slug"
+msgstr ""
+
+#: models.py:14
+msgid "file"
+msgstr "plik"
+
+#: models.py:15
+msgid "author"
+msgstr "autor"
+
+#: models.py:16
+msgid "slideshare ID"
+msgstr ""
+
+#: models.py:17
+msgid "description"
+msgstr "opis"
+
+#: models.py:29
+msgid "document"
+msgstr "dokument"
+
+#: models.py:29
+msgid "documents"
+msgstr "dokumenty"
diff --git a/apps/lessons/locale/ru/LC_MESSAGES/django.mo b/apps/lessons/locale/ru/LC_MESSAGES/django.mo
new file mode 100644 (file)
index 0000000..4d9da85
Binary files /dev/null and b/apps/lessons/locale/ru/LC_MESSAGES/django.mo differ
diff --git a/apps/lessons/locale/ru/LC_MESSAGES/django.po b/apps/lessons/locale/ru/LC_MESSAGES/django.po
new file mode 100644 (file)
index 0000000..4f239c6
--- /dev/null
@@ -0,0 +1,49 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-05-18 11:00+0200\n"
+"PO-Revision-Date: 2010-06-02 17:07+0100\n"
+"Last-Translator: I <moth_04@yahoo.pl>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: models.py:12
+msgid "title"
+msgstr "заглавие"
+
+#: models.py:13
+msgid "slug"
+msgstr "slug"
+
+#: models.py:14
+msgid "file"
+msgstr "файл"
+
+#: models.py:15
+msgid "author"
+msgstr "автор"
+
+#: models.py:16
+msgid "slideshare ID"
+msgstr "slideshare ID"
+
+#: models.py:17
+msgid "description"
+msgstr "описание"
+
+#: models.py:29
+msgid "document"
+msgstr "документ"
+
+#: models.py:29
+msgid "documents"
+msgstr "документы"
+
diff --git a/apps/lessons/locale/uk/LC_MESSAGES/django.mo b/apps/lessons/locale/uk/LC_MESSAGES/django.mo
new file mode 100644 (file)
index 0000000..0530fba
Binary files /dev/null and b/apps/lessons/locale/uk/LC_MESSAGES/django.mo differ
diff --git a/apps/lessons/locale/uk/LC_MESSAGES/django.po b/apps/lessons/locale/uk/LC_MESSAGES/django.po
new file mode 100644 (file)
index 0000000..0df9905
--- /dev/null
@@ -0,0 +1,50 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-05-18 11:00+0200\n"
+"PO-Revision-Date: 2010-08-26 13:13+0100\n"
+"Last-Translator: Natalia Kertyczak <natalczyk@o2.pl>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: models.py:12
+#, fuzzy
+msgid "title"
+msgstr "заголовок"
+
+#: models.py:13
+msgid "slug"
+msgstr "слуґ"
+
+#: models.py:14
+msgid "file"
+msgstr "файл"
+
+#: models.py:15
+msgid "author"
+msgstr "автор"
+
+#: models.py:16
+msgid "slideshare ID"
+msgstr "slideshare ID"
+
+#: models.py:17
+msgid "description"
+msgstr "опис"
+
+#: models.py:29
+msgid "document"
+msgstr "документ"
+
+#: models.py:29
+msgid "documents"
+msgstr "документи"
+
index b0cd593..ffb2b6c 100644 (file)
@@ -1,11 +1,14 @@
 # -*- coding: utf-8 -*-
+# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
 from django.db import models
 from django.utils.translation import ugettext_lazy as _
 
 from os import path
 
 class Document(models.Model):
-    """Dokument - materiał pomocniczy dla nauczycieli."""
+    """Document - hand-out for teachers"""
     title = models.CharField(_('title'), max_length=120)
     slug = models.SlugField(_('slug'))
     file = models.FileField(_('file'), upload_to='lessons/document')
@@ -13,14 +16,14 @@ class Document(models.Model):
     slideshare_id = models.CharField(_('slideshare ID'), blank=True, max_length=120)
     description = models.TextField(_('description'), blank=True)
     created_at = models.DateTimeField(auto_now_add=True)
-    
+
     def slideshare_player(self):
         base, ext = path.splitext(self.file.name)
         if ext in ('.ppt', '.pps', '.pot', '.pptx', '.potx', '.ppsx', '.odp', '.key', '.zip', '.pdf',):
             return 'ssplayer2.swf'
         else:
             return 'ssplayerd.swf'
-    
+
     class Meta:
         ordering = ['slug']
         verbose_name, verbose_name_plural = _("document"), _("documents")
index d43ac3a..1d25637 100644 (file)
@@ -1,18 +1,19 @@
 # -*- coding: utf-8 -*-
+# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
 from django.conf.urls.defaults import *
 from catalogue import forms
-from lessons import models
 
 
 urlpatterns = patterns('',
-    url(r'^$', 'django.views.generic.list_detail.object_list', {
-        'queryset': models.Document.objects.all(),
-        'template_name': 'lessons/document_list.html',
+    url(r'^$', 'django.views.generic.simple.direct_to_template', {
+        'template': 'lessons/document_list.html',
         'extra_context': {
             'form': forms.SearchForm(),
         },
     }, name='lessons_document_list'),
-    
+
     url(r'^(?P<slug>[a-zA-Z0-9_-]+)/$', 'lessons.views.document_detail', name='lessons_document_detail'),
 )
 
index e226919..242526d 100644 (file)
@@ -1,3 +1,7 @@
+# -*- coding: utf-8 -*-
+# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
 from django.views.generic.list_detail import object_detail
 from catalogue import forms
 from lessons import models
@@ -7,7 +11,7 @@ def document_detail(request, slug):
     template_name = 'lessons/document_detail.html'
     if request.is_ajax():
         template_name = 'lessons/ajax_document_detail.html'
-    
+
     return object_detail(request,
         slug=slug,
         slug_field='slug',
diff --git a/apps/modeltranslation/__init__.py b/apps/modeltranslation/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/apps/modeltranslation/admin.py b/apps/modeltranslation/admin.py
new file mode 100644 (file)
index 0000000..b51e3a3
--- /dev/null
@@ -0,0 +1,140 @@
+# -*- coding: utf-8 -*-
+from copy import deepcopy
+
+from django import forms, template
+from django.conf import settings
+from django.contrib import admin
+from django.contrib.contenttypes import generic
+
+from modeltranslation.translator import translator
+from modeltranslation.utils import get_translation_fields
+# Ensure that models are registered for translation before TranslationAdmin
+# runs. The import is supposed to resolve a race condition between model import
+# and translation registration in production (see issue 19).
+import modeltranslation.models
+
+
+class TranslationAdminBase(object):
+    """
+    Mixin class which adds patch_translation_field functionality.
+    """
+    def patch_translation_field(self, db_field, field, **kwargs):
+        trans_opts = translator.get_options_for_model(self.model)
+
+        # Hide the original field by making it non-editable.
+        if db_field.name in trans_opts.fields:
+            db_field.editable = False
+
+        # For every localized field copy the widget from the original field
+        if db_field.name in trans_opts.localized_fieldnames_rev:
+            orig_fieldname = trans_opts.localized_fieldnames_rev[db_field.name]
+            orig_formfield = self.formfield_for_dbfield( \
+                                self.model._meta.get_field(orig_fieldname),
+                                                           **kwargs)
+
+            # In case the original form field was required, make the default
+            # translation field required instead.
+            if db_field.language == settings.LANGUAGES[0][0] and \
+               orig_formfield.required:
+                orig_formfield.required = False
+                orig_formfield.blank = True
+                field.required = True
+                field.blank = False
+
+            field.widget = deepcopy(orig_formfield.widget)
+
+
+class TranslationAdmin(admin.ModelAdmin, TranslationAdminBase):
+    def __init__(self, *args, **kwargs):
+        super(TranslationAdmin, self).__init__(*args, **kwargs)
+
+        trans_opts = translator.get_options_for_model(self.model)
+
+        # Replace original field with translation field for each language
+        if self.fields:
+            fields_new = list(self.fields)
+            for field in self.fields:
+                if field in trans_opts.fields:
+                    index = fields_new.index(field)
+                    translation_fields = get_translation_fields(field)
+                    fields_new[index:index + 1] = translation_fields
+            self.fields = fields_new
+
+        if self.fieldsets:
+            fieldsets_new = list(self.fieldsets)
+            for (name, dct) in self.fieldsets:
+                if 'fields' in dct:
+                    fields_new = list(dct['fields'])
+                    for field in dct['fields']:
+                        if field in trans_opts.fields:
+                            index = fields_new.index(field)
+                            translation_fields = get_translation_fields(field)
+                            fields_new[index:index + 1] = translation_fields
+                    dct['fields'] = fields_new
+            self.fieldsets = fieldsets_new
+
+        if self.list_editable:
+            editable_new = list(self.list_editable)
+            display_new = list(self.list_display)
+            for field in self.list_editable:
+                if field in trans_opts.fields:
+                    index = editable_new.index(field)
+                    display_index = display_new.index(field)
+                    translation_fields = get_translation_fields(field)
+                    editable_new[index:index + 1] = translation_fields
+                    display_new[display_index:display_index + 1] = \
+                        translation_fields
+            self.list_editable = editable_new
+            self.list_display = display_new
+
+        if self.prepopulated_fields:
+            prepopulated_fields_new = dict(self.prepopulated_fields)
+            for (k, v) in self.prepopulated_fields.items():
+                translation_fields = get_translation_fields(v[0])
+                prepopulated_fields_new[k] = tuple([translation_fields[0]])
+            self.prepopulated_fields = prepopulated_fields_new
+
+    def formfield_for_dbfield(self, db_field, **kwargs):
+        # Call the baseclass function to get the formfield
+        field = super(TranslationAdmin, self).formfield_for_dbfield(db_field,
+                                                                    **kwargs)
+        self.patch_translation_field(db_field, field, **kwargs)
+        return field
+
+
+class TranslationTabularInline(admin.TabularInline, TranslationAdminBase):
+    def formfield_for_dbfield(self, db_field, **kwargs):
+        # Call the baseclass function to get the formfield
+        field = super(TranslationTabularInline,
+                      self).formfield_for_dbfield(db_field, **kwargs)
+        self.patch_translation_field(db_field, field, **kwargs)
+        return field
+
+
+class TranslationStackedInline(admin.StackedInline, TranslationAdminBase):
+    def formfield_for_dbfield(self, db_field, **kwargs):
+        # Call the baseclass function to get the formfield
+        field = super(TranslationStackedInline,
+                      self).formfield_for_dbfield(db_field, **kwargs)
+        self.patch_translation_field(db_field, field, **kwargs)
+        return field
+
+
+class TranslationGenericTabularInline(generic.GenericTabularInline,
+                                      TranslationAdminBase):
+    def formfield_for_dbfield(self, db_field, **kwargs):
+        # Call the baseclass function to get the formfield
+        field = super(TranslationGenericTabularInline,
+                      self).formfield_for_dbfield(db_field, **kwargs)
+        self.patch_translation_field(db_field, field, **kwargs)
+        return field
+
+
+class TranslationGenericStackedInline(generic.GenericStackedInline,
+                                      TranslationAdminBase):
+    def formfield_for_dbfield(self, db_field, **kwargs):
+        # Call the baseclass function to get the formfield
+        field = super(TranslationGenericStackedInline,
+                      self).formfield_for_dbfield(db_field, **kwargs)
+        self.patch_translation_field(db_field, field, **kwargs)
+        return field
diff --git a/apps/modeltranslation/fields.py b/apps/modeltranslation/fields.py
new file mode 100644 (file)
index 0000000..be942f6
--- /dev/null
@@ -0,0 +1,114 @@
+# -*- coding: utf-8 -*-
+from django.conf import settings
+from django.db.models.fields import Field, CharField
+
+from modeltranslation.utils import get_language, build_localized_fieldname
+
+
+class TranslationField(Field):
+    """
+    The translation field functions as a proxy to the original field which is
+    wrapped.
+
+    For every field defined in the model's ``TranslationOptions`` localized
+    versions of that field are added to the model depending on the languages
+    given in ``settings.LANGUAGES``.
+
+    If for example there is a model ``News`` with a field ``title`` which is
+    registered for translation and the ``settings.LANGUAGES`` contains the
+    ``de`` and ``en`` languages, the fields ``title_de`` and ``title_en`` will
+    be added to the model class. These fields are realized using this
+    descriptor.
+
+    The translation field needs to know which language it contains therefore
+    that needs to be specified when the field is created.
+    """
+    def __init__(self, translated_field, language, *args, **kwargs):
+        # Store the originally wrapped field for later
+        self.translated_field = translated_field
+        self.language = language
+
+        # Update the dict of this field with the content of the original one
+        # This might be a bit radical?! Seems to work though...
+        self.__dict__.update(translated_field.__dict__)
+
+        # Translation are always optional (for now - maybe add some parameters
+        # to the translation options for configuring this)
+        self.null = True
+        self.blank = True
+
+        # Adjust the name of this field to reflect the language
+        self.attname = build_localized_fieldname(translated_field.name,
+                                                 language)
+        self.name = self.attname
+
+        # Copy the verbose name and append a language suffix (will e.g. in the
+        # admin). This might be a proxy function so we have to check that here.
+        if hasattr(translated_field.verbose_name, '_proxy____unicode_cast'):
+            verbose_name = \
+                translated_field.verbose_name._proxy____unicode_cast()
+        else:
+            verbose_name = translated_field.verbose_name
+        self.verbose_name = '%s [%s]' % (verbose_name, language)
+
+    def pre_save(self, model_instance, add):
+        val = super(TranslationField, self).pre_save(model_instance, add)
+        if get_language() == self.language and not add:
+            # Rule is: 3. Assigning a value to a translation field of the
+            # default language also updates the original field
+            model_instance.__dict__[self.translated_field.name] = val
+        return val
+
+    def get_internal_type(self):
+        return self.translated_field.get_internal_type()
+
+    #def contribute_to_class(self, cls, name):
+        #super(TranslationField, self).contribute_to_class(cls, name)
+        ##setattr(cls, 'get_%s_display' % self.name,
+                ##curry(cls._get_FIELD_display, field=self))
+
+    def south_field_triple(self):
+        """Returns a suitable description of this field for South."""
+        # We'll just introspect the _actual_ field.
+        from south.modelsinspector import introspector
+        field_class = '%s.%s' % (self.translated_field.__class__.__module__,
+                                 self.translated_field.__class__.__name__)
+        args, kwargs = introspector(self.translated_field)
+
+        # This is patched in init and so should be here! -- lqc
+        kwargs['blank'], kwargs['null'] = True, True
+
+        # That's our definition!
+        return (field_class, args, kwargs)
+
+    def formfield(self, *args, **kwargs):
+        """Preserves the widget of the translated field."""
+        trans_formfield = self.translated_field.formfield(*args, **kwargs)
+        defaults = {'widget': type(trans_formfield.widget)}
+        defaults.update(kwargs)
+        return super(TranslationField, self).formfield(*args, **defaults)
+
+
+#class CurrentLanguageField(CharField):
+    #def __init__(self, **kwargs):
+        #super(CurrentLanguageField, self).__init__(null=True, max_length=5,
+              #**kwargs)
+
+    #def contribute_to_class(self, cls, name):
+        #super(CurrentLanguageField, self).contribute_to_class(cls, name)
+        #registry = CurrentLanguageFieldRegistry()
+        #registry.add_field(cls, self)
+
+
+#class CurrentLanguageFieldRegistry(object):
+    #_registry = {}
+
+    #def add_field(self, model, field):
+        #reg = self.__class__._registry.setdefault(model, [])
+        #reg.append(field)
+
+    #def get_fields(self, model):
+        #return self.__class__._registry.get(model, [])
+
+    #def __contains__(self, model):
+        #return model in self.__class__._registry
diff --git a/apps/modeltranslation/management/__init__.py b/apps/modeltranslation/management/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/apps/modeltranslation/management/commands/__init__.py b/apps/modeltranslation/management/commands/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/apps/modeltranslation/management/commands/update_translation_fields.py b/apps/modeltranslation/management/commands/update_translation_fields.py
new file mode 100644 (file)
index 0000000..adb5e6d
--- /dev/null
@@ -0,0 +1,30 @@
+# -*- coding: utf-8 -*-
+from django.conf import settings
+from django.core.management.base import (BaseCommand, CommandError,
+                                         NoArgsCommand)
+
+from modeltranslation.translator import translator
+from modeltranslation.utils import build_localized_fieldname
+
+
+class Command(NoArgsCommand):
+    help = 'Updates the default translation fields of all or the specified' \
+           'translated application using the value of the original field.'
+
+    def handle(self, **options):
+        default_lang = settings.LANGUAGES[0][0]
+        print "Using default language:", default_lang
+
+        for model, trans_opts in translator._registry.items():
+            print "Updating data of model '%s'" % model
+            for obj in model.objects.all():
+                for fieldname in trans_opts.fields:
+                    def_lang_fieldname = \
+                        build_localized_fieldname(fieldname, default_lang)
+                    #print "setting %s from %s to %s." % \
+                          #(def_lang_fieldname, fieldname,
+                           #obj.__dict__[fieldname])
+                    if not getattr(obj, def_lang_fieldname):
+                        setattr(obj, def_lang_fieldname,
+                                obj.__dict__[fieldname])
+                obj.save()
diff --git a/apps/modeltranslation/models.py b/apps/modeltranslation/models.py
new file mode 100644 (file)
index 0000000..739c897
--- /dev/null
@@ -0,0 +1,44 @@
+# -*- coding: utf-8 -*-
+import sys
+
+from django.conf import settings
+from django.core.exceptions import ImproperlyConfigured
+from django.db import models
+
+from modeltranslation.translator import translator
+
+# Every model registered with the modeltranslation.translator.translator
+# is patched to contain additional localized versions for every
+# field specified in the model's translation options.
+
+# Import the project's global "translation.py" which registers model
+# classes and their translation options with the translator object.
+if getattr(settings, 'TRANSLATION_REGISTRY', False):
+    try:
+        __import__(settings.TRANSLATION_REGISTRY, {}, {}, [''])
+    except ImportError:
+        sys.stderr.write("modeltranslation: Can't import module '%s'.\n"
+                         "(If the module exists, it's causing an "
+                         "ImportError somehow.)\n" %\
+                         settings.TRANSLATION_REGISTRY)
+        # For some reason ImportErrors raised in translation.py or in modules
+        # that are included from there become swallowed. Work around this
+        # problem by printing the traceback explicitly.
+        import traceback
+        traceback.print_exc()
+
+    # After importing all translation modules, all translation classes are
+    # registered with the translator.
+    if settings.DEBUG:
+        try:
+            if sys.argv[1] in ('runserver', 'runserver_plus'):
+                translated_model_names = ', '.join(
+                    t.__name__ for t in translator._registry.keys())
+                print('modeltranslation: Registered %d models for '
+                      'translation (%s).' % (len(translator._registry),
+                                             translated_model_names))
+        except IndexError:
+            pass
+else:
+    raise ImproperlyConfigured("You haven't set the TRANSLATION_REGISTRY "
+                               "setting yet.")
diff --git a/apps/modeltranslation/tests.py b/apps/modeltranslation/tests.py
new file mode 100644 (file)
index 0000000..3e0f39b
--- /dev/null
@@ -0,0 +1,258 @@
+# -*- coding: utf-8 -*-
+from django.conf import settings
+from django.contrib.auth.models import User
+from django.contrib.contenttypes.models import ContentType
+from django.db import models
+from django.test import TestCase
+from django.utils.thread_support import currentThread
+from django.utils.translation import get_language
+from django.utils.translation import trans_real
+
+# TODO: tests for TranslationAdmin
+
+from modeltranslation import translator
+
+settings.LANGUAGES = (('de', 'Deutsch'),
+                      ('en', 'English'))
+
+
+class TestModel(models.Model):
+    title = models.CharField(max_length=255)
+    text = models.TextField(null=True)
+
+
+class TestTranslationOptions(translator.TranslationOptions):
+    fields = ('title', 'text',)
+
+
+translator.translator._registry = {}
+translator.translator.register(TestModel, TestTranslationOptions)
+
+
+class ModelTranslationTest(TestCase):
+    """Basic tests for the modeltranslation application."""
+    urls = 'modeltranslation.testurls'
+
+    def setUp(self):
+        trans_real.activate("de")
+
+    def tearDown(self):
+        trans_real.deactivate()
+
+    def test_registration(self):
+        self.client.post('/set_language/', data={'language': 'de'})
+        #self.client.session['django_language'] = 'de-de'
+        #self.client.cookies[settings.LANGUAGE_COOKIE_NAME] = 'de-de'
+
+        langs = tuple(l[0] for l in settings.LANGUAGES)
+        self.failUnlessEqual(2, len(langs))
+        self.failUnless('de' in langs)
+        self.failUnless('en' in langs)
+        self.failUnless(translator.translator)
+
+        # Check that only one model is registered for translation
+        self.failUnlessEqual(len(translator.translator._registry), 1)
+
+        # Try to unregister a model that is not registered
+        self.assertRaises(translator.NotRegistered,
+                          translator.translator.unregister, User)
+
+        # Try to get options for a model that is not registered
+        self.assertRaises(translator.NotRegistered,
+                          translator.translator.get_options_for_model, User)
+
+    def test_translated_models(self):
+        # First create an instance of the test model to play with
+        inst = TestModel.objects.create(title="Testtitle", text="Testtext")
+        field_names = dir(inst)
+        self.failUnless('id' in field_names)
+        self.failUnless('title' in field_names)
+        self.failUnless('text' in field_names)
+        self.failUnless('title_de' in field_names)
+        self.failUnless('title_en' in field_names)
+        self.failUnless('text_de' in field_names)
+        self.failUnless('text_en' in field_names)
+
+        inst.delete()
+
+    def test_set_translation(self):
+        self.failUnlessEqual(get_language(), "de")
+        # First create an instance of the test model to play with
+        title1_de = "title de"
+        title1_en = "title en"
+        title2_de = "title2 de"
+        inst1 = TestModel(title_en=title1_en, text="Testtext")
+        inst1.title = title1_de
+        inst2 = TestModel(title=title2_de, text="Testtext")
+        inst1.save()
+        inst2.save()
+
+        self.failUnlessEqual(inst1.title, title1_de)
+        self.failUnlessEqual(inst1.title_en, title1_en)
+
+        self.failUnlessEqual(inst2.title, title2_de)
+        self.failUnlessEqual(inst2.title_en, None)
+
+        del inst1
+        del inst2
+
+        # Check that the translation fields are correctly saved and provide the
+        # correct value when retrieving them again.
+        n = TestModel.objects.get(title=title1_de)
+        self.failUnlessEqual(n.title, title1_de)
+        self.failUnlessEqual(n.title_en, title1_en)
+
+    def test_titleonly(self):
+        title1_de = "title de"
+        n = TestModel.objects.create(title=title1_de)
+        self.failUnlessEqual(n.title, title1_de)
+        # Because the original field "title" was specified in the constructor
+        # it is directly passed into the instance's __dict__ and the descriptor
+        # which updates the associated default translation field is not called
+        # and the default translation will be None.
+        self.failUnlessEqual(n.title_de, None)
+        self.failUnlessEqual(n.title_en, None)
+
+        # Now assign the title, that triggers the descriptor and the default
+        # translation field is updated
+        n.title = title1_de
+        self.failUnlessEqual(n.title, title1_de)
+        self.failUnlessEqual(n.title_de, title1_de)
+        self.failUnlessEqual(n.title_en, None)
+
+    def test_rule1(self):
+        """
+        Rule 1: Reading the value from the original field returns the value in
+        translated to the current language.
+        """
+        title1_de = "title de"
+        title1_en = "title en"
+        text_de = "Dies ist ein deutscher Satz"
+        text_en = "This is an english sentence"
+
+        # Test 1.
+        n = TestModel.objects.create(title_de=title1_de, title_en=title1_en,
+                                     text_de=text_de, text_en=text_en)
+        n.save()
+
+        # language is set to "de" at this point
+        self.failUnlessEqual(get_language(), "de")
+        self.failUnlessEqual(n.title, title1_de)
+        self.failUnlessEqual(n.title_de, title1_de)
+        self.failUnlessEqual(n.title_en, title1_en)
+        self.failUnlessEqual(n.text, text_de)
+        self.failUnlessEqual(n.text_de, text_de)
+        self.failUnlessEqual(n.text_en, text_en)
+        # Now switch to "en"
+        trans_real.activate("en")
+        self.failUnlessEqual(get_language(), "en")
+        # Title should now be return the english one (just by switching the
+        # language)
+        self.failUnlessEqual(n.title, title1_en)
+        self.failUnlessEqual(n.text, text_en)
+
+        n = TestModel.objects.create(title_de=title1_de, title_en=title1_en,
+                                     text_de=text_de, text_en=text_en)
+        n.save()
+        # language is set to "en" at this point
+        self.failUnlessEqual(n.title, title1_en)
+        self.failUnlessEqual(n.title_de, title1_de)
+        self.failUnlessEqual(n.title_en, title1_en)
+        self.failUnlessEqual(n.text, text_en)
+        self.failUnlessEqual(n.text_de, text_de)
+        self.failUnlessEqual(n.text_en, text_en)
+        trans_real.activate("de")
+        self.failUnlessEqual(get_language(), "de")
+        self.failUnlessEqual(n.title, title1_de)
+        self.failUnlessEqual(n.text, text_de)
+        trans_real.deactivate()
+
+    def test_rule2(self):
+        """
+        Rule 2: Assigning a value to the original field also updates the value
+        in the associated translation field of the default language
+        """
+        self.failUnlessEqual(get_language(), "de")
+        title1_de = "title de"
+        title1_en = "title en"
+        n = TestModel.objects.create(title_de=title1_de, title_en=title1_en)
+        self.failUnlessEqual(n.title, title1_de)
+        self.failUnlessEqual(n.title_de, title1_de)
+        self.failUnlessEqual(n.title_en, title1_en)
+
+        title2 = "Neuer Titel"
+        n.title = title2
+        n.save()
+        self.failUnlessEqual(n.title, title2)
+        self.failUnlessEqual(n.title, n.title_de)
+
+        trans_real.activate("en")
+        self.failUnlessEqual(get_language(), "en")
+        title3 = "new title"
+
+        n.title = title3
+        n.title_de = title1_de
+        n.save()
+        self.failUnlessEqual(n.title, title3)
+        self.failUnlessEqual(n.title, n.title_en)
+        self.failUnlessEqual(title1_de, n.title_de)
+
+        trans_real.deactivate()
+
+    def test_rule3(self):
+        """
+        Rule 3: Assigning a value to a translation field of the default
+        language also updates the original field - note that the value of the
+        original field will not be updated until the model instance is saved.
+        """
+        title1_de = "title de"
+        title1_en = "title en"
+        n = TestModel.objects.create(title_de=title1_de, title_en=title1_en)
+        self.failUnlessEqual(get_language(), "de")
+        self.failUnlessEqual(n.title, title1_de)
+        self.failUnlessEqual(n.title_de, title1_de)
+        self.failUnlessEqual(n.title_en, title1_en)
+
+        n.title_de = "Neuer Titel"
+        n.save()
+        self.failUnlessEqual(n.title, n.title_de)
+
+        # Now switch to "en"
+        trans_real.activate("en")
+        self.failUnlessEqual(get_language(), "en")
+        n.title_en = "New title"
+        # the n.title field is not updated before the instance is saved
+        n.save()
+        self.failUnlessEqual(n.title, n.title_en)
+        trans_real.deactivate()
+
+    def test_rule4(self):
+        """
+        Rule 4: If both fields - the original and the translation field of the
+        default language - are updated at the same time, the translation field
+        wins.
+        """
+        self.failUnlessEqual(get_language(), "de")
+        title1_de = "title de"
+        title1_en = "title en"
+        n = TestModel.objects.create(title_de=title1_de, title_en=title1_en)
+        self.failUnlessEqual(n.title, title1_de)
+        self.failUnlessEqual(n.title_de, title1_de)
+        self.failUnlessEqual(n.title_en, title1_en)
+
+        title2_de = "neu de"
+        title2_en = "new en"
+        title_foo = "foo"
+        n.title = title_foo
+        n.title_de = title2_de
+        n.title_en = title2_en
+        n.save()
+        self.failUnlessEqual(n.title, title2_de)
+        self.failUnlessEqual(n.title_de, title2_de)
+        self.failUnlessEqual(n.title_en, title2_en)
+
+        n.title = title_foo
+        n.save()
+        self.failUnlessEqual(n.title, title_foo)
+        self.failUnlessEqual(n.title_de, title_foo)
+        self.failUnlessEqual(n.title_en, title2_en)
diff --git a/apps/modeltranslation/testurls.py b/apps/modeltranslation/testurls.py
new file mode 100644 (file)
index 0000000..8cb4d86
--- /dev/null
@@ -0,0 +1,7 @@
+# -*- coding: utf-8 -*-
+from django.conf.urls.defaults import *
+
+urlpatterns = patterns('',
+    url(r'^set_language/$', 'django.views.i18n.set_language', {},
+        name='set_language'),
+)
diff --git a/apps/modeltranslation/translator.py b/apps/modeltranslation/translator.py
new file mode 100644 (file)
index 0000000..0a55362
--- /dev/null
@@ -0,0 +1,191 @@
+# -*- coding: utf-8 -*-
+from django.conf import settings
+#from django.contrib.contenttypes.models import ContentType
+from django.db import models
+from django.db.models import signals
+from django.db.models.base import ModelBase
+from django.utils.functional import curry
+
+from modeltranslation.fields import TranslationField
+from modeltranslation.utils import (TranslationFieldDescriptor,
+                                    build_localized_fieldname)
+
+
+class AlreadyRegistered(Exception):
+    pass
+
+
+class NotRegistered(Exception):
+    pass
+
+
+class TranslationOptions(object):
+    """
+    The TranslationOptions object is used to specify the fields to translate.
+
+    The options are registered in combination with a model class at the
+    ``modeltranslation.translator.translator`` instance.
+
+    It caches the content type of the translated model for faster lookup later
+    on.
+    """
+    def __init__(self, *args, **kwargs):
+        # self.translation_model = None
+        #self.model_ct = None
+        self.localized_fieldnames = list()
+
+
+def add_localized_fields(model):
+    """
+    Monkey patchs the original model class to provide additional fields for
+    every language. Only do that for fields which are defined in the
+    translation options of the model.
+
+    Returns a dict mapping the original fieldname to a list containing the
+    names of the localized fields created for the original field.
+    """
+    localized_fields = dict()
+    translation_opts = translator.get_options_for_model(model)
+    for field_name in translation_opts.fields:
+        localized_fields[field_name] = list()
+        for l in settings.LANGUAGES:
+            # Construct the name for the localized field
+            localized_field_name = build_localized_fieldname(field_name, l[0])
+            # Check if the model already has a field by that name
+            if hasattr(model, localized_field_name):
+                raise ValueError("Error adding translation field. The model "\
+                                 "'%s' already contains a field named '%s'. "\
+                                 % (instance.__class__.__name__,
+                                    localized_field_name))
+
+            # This approach implements the translation fields as full valid
+            # django model fields and therefore adds them via add_to_class
+            localized_field = model.add_to_class( \
+                localized_field_name,
+                TranslationField(model._meta.get_field(field_name), l[0]))
+            localized_fields[field_name].append(localized_field_name)
+    return localized_fields
+
+
+#def translated_model_initialized(field_names, instance, **kwargs):
+    #print "translated_model_initialized instance:", \
+          #instance, ", field:", field_names
+    #for field_name in field_names:
+        #initial_val = getattr(instance, field_name)
+        #print "  field: %s, initialval: %s" % (field_name, initial_val)
+        #setattr(instance.__class__, field_name,
+                #TranslationFieldDescriptor(field_name, initial_val))
+
+
+#def translated_model_initializing(sender, args, kwargs, **signal_kwargs):
+    #print "translated_model_initializing", sender, args, kwargs
+    #trans_opts = translator.get_options_for_model(sender)
+    #for field_name in trans_opts.fields:
+        #setattr(sender, field_name, TranslationFieldDescriptor(field_name))
+
+
+class Translator(object):
+    """
+    A Translator object encapsulates an instance of a translator. Models are
+    registered with the Translator using the register() method.
+    """
+    def __init__(self):
+        # model_class class -> translation_opts instance
+        self._registry = {}
+
+    def register(self, model_or_iterable, translation_opts, **options):
+        """
+        Registers the given model(s) with the given translation options.
+
+        The model(s) should be Model classes, not instances.
+
+        If a model is already registered for translation, this will raise
+        AlreadyRegistered.
+        """
+        # Don't import the humongous validation code unless required
+        if translation_opts and settings.DEBUG:
+            from django.contrib.admin.validation import validate
+        else:
+            validate = lambda model, adminclass: None
+
+        #if not translation_opts:
+            #translation_opts = TranslationOptions
+        if isinstance(model_or_iterable, ModelBase):
+            model_or_iterable = [model_or_iterable]
+
+        for model in model_or_iterable:
+            if model in self._registry:
+                raise AlreadyRegistered('The model %s is already registered '
+                                        'for translation' % model.__name__)
+
+            # If we got **options then dynamically construct a subclass of
+            # translation_opts with those **options.
+            if options:
+                # For reasons I don't quite understand, without a __module__
+                # the created class appears to "live" in the wrong place,
+                # which causes issues later on.
+                options['__module__'] = __name__
+                translation_opts = type("%sAdmin" % model.__name__,
+                                        (translation_opts,), options)
+
+            # Validate (which might be a no-op)
+            #validate(translation_opts, model)
+
+            # Store the translation class associated to the model
+            self._registry[model] = translation_opts
+
+            # Get the content type of the original model and store it on the
+            # translation options for faster lookup later on.
+            #translation_opts.model_ct = \
+                #ContentType.objects.get_for_model(model)
+
+            # Add the localized fields to the model and store the names of
+            # these fields in the model's translation options for faster lookup
+            # later on.
+            translation_opts.localized_fieldnames = add_localized_fields(model)
+
+            # Create a reverse dict mapping the localized_fieldnames to the
+            # original fieldname
+            rev_dict = dict()
+            for orig_name, loc_names in \
+                translation_opts.localized_fieldnames.items():
+                for ln in loc_names:
+                    rev_dict[ln] = orig_name
+
+            translation_opts.localized_fieldnames_rev = rev_dict
+
+        # print "Applying descriptor field for model %s" % model
+        for field_name in translation_opts.fields:
+            setattr(model, field_name, TranslationFieldDescriptor(field_name))
+
+        #signals.pre_init.connect(translated_model_initializing, sender=model,
+                                 #weak=False)
+
+    def unregister(self, model_or_iterable):
+        """
+        Unregisters the given model(s).
+
+        If a model isn't already registered, this will raise NotRegistered.
+        """
+        if isinstance(model_or_iterable, ModelBase):
+            model_or_iterable = [model_or_iterable]
+        for model in model_or_iterable:
+            if model not in self._registry:
+                raise NotRegistered('The model "%s" is not registered for '
+                                    'translation' % model.__name__)
+            del self._registry[model]
+
+    def get_options_for_model(self, model):
+        """
+        Returns the translation options for the given ``model``. If the
+        ``model`` is not registered a ``NotRegistered`` exception is raised.
+        """
+        try:
+            return self._registry[model]
+        except KeyError:
+            raise NotRegistered('The model "%s" is not registered for '
+                                'translation' % model.__name__)
+
+
+# This global object represents the singleton translator object
+translator = Translator()
diff --git a/apps/modeltranslation/utils.py b/apps/modeltranslation/utils.py
new file mode 100644 (file)
index 0000000..aeb57d1
--- /dev/null
@@ -0,0 +1,123 @@
+# -*- coding: utf-8 -*-
+from django.db import models
+from django.conf import settings
+from django.core.exceptions import ValidationError
+from django.contrib.contenttypes.models import ContentType
+from django.utils.translation import get_language as _get_language
+
+
+def get_language():
+    """
+    Return an active language code that is guaranteed to be in
+    settings.LANGUAGES (Django does not seem to guarantee this for us.)
+
+    """
+    lang = _get_language()
+    available_languages = [l[0] for l in settings.LANGUAGES]
+    if lang not in available_languages and '-' in lang:
+        lang = lang.split('-')[0]
+    if lang in available_languages:
+        return lang
+    return available_languages[0]
+
+
+def get_translation_fields(field):
+    """Returns a list of localized fieldnames for a given field."""
+    return [build_localized_fieldname(field, l[0]) for l in settings.LANGUAGES]
+
+
+def build_localized_fieldname(field_name, lang):
+    return '%s_%s' % (field_name, lang.replace('-', '_'))
+
+
+class TranslationFieldDescriptor(object):
+    """A descriptor used for the original translated field."""
+    def __init__(self, name, initial_val=""):
+        """
+        The ``name`` is the name of the field (which is not available in the
+        descriptor by default - this is Python behaviour).
+        """
+        self.name = name
+        self.val = initial_val
+
+    def __set__(self, instance, value):
+        lang = get_language()
+        loc_field_name = build_localized_fieldname(self.name, lang)
+        # also update the translation field of the current language
+        setattr(instance, loc_field_name, value)
+        # update the original field via the __dict__ to prevent calling the
+        # descriptor
+        instance.__dict__[self.name] = value
+
+    def __get__(self, instance, owner):
+        if not instance:
+            raise ValueError(u"Translation field '%s' can only be "
+                              "accessed via an instance not via "
+                              "a class." % self.name)
+        lang = get_language()
+        loc_field_name = build_localized_fieldname(self.name, lang)
+        if hasattr(instance, loc_field_name):
+            return getattr(instance, loc_field_name) or \
+                   instance.__dict__[self.name]
+        return instance.__dict__[self.name]
+
+
+#def create_model(name, fields=None, app_label='', module='', options=None,
+                 #admin_opts=None):
+    #"""
+    #Create specified model.
+    #This is taken from http://code.djangoproject.com/wiki/DynamicModels
+    #"""
+    #class Meta:
+        ## Using type('Meta', ...) gives a dictproxy error during model
+        ## creation
+        #pass
+
+    #if app_label:
+        ## app_label must be set using the Meta inner class
+        #setattr(Meta, 'app_label', app_label)
+
+    ## Update Meta with any options that were provided
+    #if options is not None:
+        #for key, value in options.iteritems():
+            #setattr(Meta, key, value)
+
+    ## Set up a dictionary to simulate declarations within a class
+    #attrs = {'__module__': module, 'Meta': Meta}
+
+    ## Add in any fields that were provided
+    #if fields:
+        #attrs.update(fields)
+
+    ## Create the class, which automatically triggers ModelBase processing
+    #model = type(name, (models.Model,), attrs)
+
+    ## Create an Admin class if admin options were provided
+    #if admin_opts is not None:
+        #class Admin(admin.ModelAdmin):
+            #pass
+        #for key, value in admin_opts:
+            #setattr(Admin, key, value)
+        #admin.site.register(model, Admin)
+
+    #return model
+
+
+def copy_field(field):
+    """
+    Instantiate a new field, with all of the values from the old one, except
+    the to and to_field in the case of related fields.
+
+    This taken from http://www.djangosnippets.org/snippets/442/
+    """
+    base_kw = dict([(n, getattr(field, n, '_null')) for n in \
+              models.fields.Field.__init__.im_func.func_code.co_varnames])
+    if isinstance(field, models.fields.related.RelatedField):
+        rel = base_kw.get('rel')
+        rel_kw = dict([(n, getattr(rel, n, '_null')) for n in \
+                 rel.__init__.im_func.func_code.co_varnames])
+        if isinstance(field, models.fields.related.ForeignKey):
+            base_kw['to_field'] = rel_kw.pop('field_name')
+        base_kw.update(rel_kw)
+    base_kw.pop('self')
+    return field.__class__(**base_kw)
index 956d2cf..a8f5110 100644 (file)
@@ -17,7 +17,7 @@ class FilteredSelectMultiple(forms.SelectMultiple):
         js = ['js/SelectBox.js' , 'js/SelectFilter2.js']
         return forms.Media(js=['%s%s' % (settings.ADMIN_MEDIA_PREFIX, url) for url in js])
     media = property(_media)
-    
+
     def __init__(self, verbose_name, is_stacked, attrs=None, choices=()):
         self.verbose_name = verbose_name
         self.is_stacked = is_stacked
@@ -44,7 +44,7 @@ class TaggableModelForm(forms.ModelForm):
             kwargs['initial']['tags'] = [tag.id for tag in self.tag_model.objects.get_for_object(kwargs['instance'])]
         super(TaggableModelForm, self).__init__(*args, **kwargs)
         self.fields['tags'].choices = [(tag.id, tag.name) for tag in self.tag_model.objects.all()]
-    
+
     def save(self, commit):
         obj = super(TaggableModelForm, self).save()
         tag_ids = self.cleaned_data['tags']
@@ -59,7 +59,7 @@ class TaggableModelForm(forms.ModelForm):
 
 class TaggableModelAdmin(admin.ModelAdmin):
     form = TaggableModelForm
-    
+
     def get_form(self, request, obj=None):
         form = super(TaggableModelAdmin, self).get_form(request, obj)
         form.tag_model = self.tag_model
diff --git a/apps/newtagging/locale/de/LC_MESSAGES/django.mo b/apps/newtagging/locale/de/LC_MESSAGES/django.mo
new file mode 100644 (file)
index 0000000..989b38e
Binary files /dev/null and b/apps/newtagging/locale/de/LC_MESSAGES/django.mo differ
diff --git a/apps/newtagging/locale/de/LC_MESSAGES/django.po b/apps/newtagging/locale/de/LC_MESSAGES/django.po
new file mode 100644 (file)
index 0000000..0ea17f3
--- /dev/null
@@ -0,0 +1,50 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-05-18 11:01+0200\n"
+"PO-Revision-Date: 2010-06-03 01:45+0100\n"
+"Last-Translator: Iwona Fiałkowska <ifialkowska@gmail.com>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: admin.py:38
+msgid "tags"
+msgstr "tags"
+
+#: models.py:491
+msgid "tag"
+msgstr "tag"
+
+#: models.py:492
+msgid "content type"
+msgstr "Inhaltstyp"
+
+#: models.py:493
+msgid "object id"
+msgstr "ID Objekt"
+
+#: views.py:30
+msgid "tagged_object_list must be called with a queryset or a model."
+msgstr ""
+
+#: views.py:32
+msgid "tagged_object_list must be called with a tag model."
+msgstr ""
+
+#: views.py:34
+msgid "tagged_object_list must be called with a tag."
+msgstr ""
+
+#: views.py:38
+#, python-format
+msgid "No tags found matching \"%s\"."
+msgstr ""
+
diff --git a/apps/newtagging/locale/en/LC_MESSAGES/django.mo b/apps/newtagging/locale/en/LC_MESSAGES/django.mo
new file mode 100644 (file)
index 0000000..78acb03
Binary files /dev/null and b/apps/newtagging/locale/en/LC_MESSAGES/django.mo differ
diff --git a/apps/newtagging/locale/en/LC_MESSAGES/django.po b/apps/newtagging/locale/en/LC_MESSAGES/django.po
new file mode 100644 (file)
index 0000000..14bcf1c
--- /dev/null
@@ -0,0 +1,50 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-05-18 11:01+0200\n"
+"PO-Revision-Date: 2010-06-09 16:52+0100\n"
+"Last-Translator: K Izdebska <villdeo.tess@gmail.com>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: admin.py:38
+msgid "tags"
+msgstr "tags"
+
+#: models.py:491
+msgid "tag"
+msgstr "tag"
+
+#: models.py:492
+msgid "content type"
+msgstr "content type"
+
+#: models.py:493
+msgid "object id"
+msgstr "object id"
+
+#: views.py:30
+msgid "tagged_object_list must be called with a queryset or a model."
+msgstr "tagged_object_list must be defined with a queryset or a model"
+
+#: views.py:32
+msgid "tagged_object_list must be called with a tag model."
+msgstr "tagged_object_list must be defined with a tag model"
+
+#: views.py:34
+msgid "tagged_object_list must be called with a tag."
+msgstr "tagged_object_list must be defined with a tag"
+
+#: views.py:38
+#, python-format
+msgid "No tags found matching \"%s\"."
+msgstr "Found no tags matching \"%s\"."
+
diff --git a/apps/newtagging/locale/es/LC_MESSAGES/django.mo b/apps/newtagging/locale/es/LC_MESSAGES/django.mo
new file mode 100644 (file)
index 0000000..1cd5353
Binary files /dev/null and b/apps/newtagging/locale/es/LC_MESSAGES/django.mo differ
diff --git a/apps/newtagging/locale/es/LC_MESSAGES/django.po b/apps/newtagging/locale/es/LC_MESSAGES/django.po
new file mode 100644 (file)
index 0000000..4a242d3
--- /dev/null
@@ -0,0 +1,50 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-05-18 11:01+0200\n"
+"PO-Revision-Date: 2010-08-11 10:10+0100\n"
+"Last-Translator: Katarzyna Flis <kas.flis@gmail.com>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: admin.py:38
+msgid "tags"
+msgstr "tags"
+
+#: models.py:491
+msgid "tag"
+msgstr "tag"
+
+#: models.py:492
+msgid "content type"
+msgstr "tipo de contenido"
+
+#: models.py:493
+msgid "object id"
+msgstr "id de objeto"
+
+#: views.py:30
+msgid "tagged_object_list must be called with a queryset or a model."
+msgstr "lista_de_objetos_agregados debe ser llamada con un queryset o un modelo."
+
+#: views.py:32
+msgid "tagged_object_list must be called with a tag model."
+msgstr "lista_de_objetos_agregados debe ser nombrada con un modelo de tag."
+
+#: views.py:34
+msgid "tagged_object_list must be called with a tag."
+msgstr "lista_de_objetos_agregados debe ser nombrada con un tag."
+
+#: views.py:38
+#, python-format
+msgid "No tags found matching \"%s\"."
+msgstr "No se han encontrado tags correspondientes \"%s\"."
+
diff --git a/apps/newtagging/locale/fr/LC_MESSAGES/django.mo b/apps/newtagging/locale/fr/LC_MESSAGES/django.mo
new file mode 100644 (file)
index 0000000..0cc0b86
Binary files /dev/null and b/apps/newtagging/locale/fr/LC_MESSAGES/django.mo differ
diff --git a/apps/newtagging/locale/fr/LC_MESSAGES/django.po b/apps/newtagging/locale/fr/LC_MESSAGES/django.po
new file mode 100644 (file)
index 0000000..4da9334
--- /dev/null
@@ -0,0 +1,50 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-05-18 11:01+0200\n"
+"PO-Revision-Date: 2010-07-12 20:36+0100\n"
+"Last-Translator: Natalia Kertyczak <natalczyk@o2.pl>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: admin.py:38
+msgid "tags"
+msgstr "tags"
+
+#: models.py:491
+msgid "tag"
+msgstr "tag"
+
+#: models.py:492
+msgid "content type"
+msgstr "type du contenu"
+
+#: models.py:493
+msgid "object id"
+msgstr "ID d'objet"
+
+#: views.py:30
+msgid "tagged_object_list must be called with a queryset or a model."
+msgstr ""
+
+#: views.py:32
+msgid "tagged_object_list must be called with a tag model."
+msgstr ""
+
+#: views.py:34
+msgid "tagged_object_list must be called with a tag."
+msgstr ""
+
+#: views.py:38
+#, python-format
+msgid "No tags found matching \"%s\"."
+msgstr ""
+
diff --git a/apps/newtagging/locale/lt/LC_MESSAGES/django.mo b/apps/newtagging/locale/lt/LC_MESSAGES/django.mo
new file mode 100644 (file)
index 0000000..27346fc
Binary files /dev/null and b/apps/newtagging/locale/lt/LC_MESSAGES/django.mo differ
diff --git a/apps/newtagging/locale/lt/LC_MESSAGES/django.po b/apps/newtagging/locale/lt/LC_MESSAGES/django.po
new file mode 100644 (file)
index 0000000..1181140
--- /dev/null
@@ -0,0 +1,51 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-05-18 11:01+0200\n"
+"PO-Revision-Date: 2010-07-12 19:41+0100\n"
+"Last-Translator: Alicja Sinkiewicz <alicja.sinkiewicz@gmail.com>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Translated-Using: django-rosetta 0.5.3\n"
+
+#: admin.py:38
+msgid "tags"
+msgstr "tagai"
+
+#: models.py:491
+msgid "tag"
+msgstr "tagas"
+
+#: models.py:492
+msgid "content type"
+msgstr "turinio rūšis "
+
+#: models.py:493
+msgid "object id"
+msgstr "id obiektas"
+
+#: views.py:30
+msgid "tagged_object_list must be called with a queryset or a model."
+msgstr "sutagintas_objektų _ sąrašas turi būti iššaukas su queryset arba su modeliu."
+
+#: views.py:32
+msgid "tagged_object_list must be called with a tag model."
+msgstr "sutagintas_objektų _ sąrašas turi būti iššaukas su tago modeliu."
+
+#: views.py:34
+msgid "tagged_object_list must be called with a tag."
+msgstr "sutagintas_objektų _ sąrašas turi būti iššaukas su tagu."
+
+#: views.py:38
+#, python-format
+msgid "No tags found matching \"%s\"."
+msgstr "Ne surado tagu tinkančių prie \"%s\"."
+
diff --git a/apps/newtagging/locale/pl/LC_MESSAGES/django.mo b/apps/newtagging/locale/pl/LC_MESSAGES/django.mo
new file mode 100644 (file)
index 0000000..c904a23
Binary files /dev/null and b/apps/newtagging/locale/pl/LC_MESSAGES/django.mo differ
diff --git a/apps/newtagging/locale/pl/LC_MESSAGES/django.po b/apps/newtagging/locale/pl/LC_MESSAGES/django.po
new file mode 100644 (file)
index 0000000..3245807
--- /dev/null
@@ -0,0 +1,50 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+# 
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-05-18 11:01+0200\n"
+"PO-Revision-Date: 2010-05-19 16:20\n"
+"Last-Translator: <radoslaw.czajka@nowoczesnapolska.org.pl>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Translated-Using: django-rosetta 0.5.3\n"
+
+#: admin.py:38
+msgid "tags"
+msgstr "tagi"
+
+#: models.py:491
+msgid "tag"
+msgstr "tag"
+
+#: models.py:492
+msgid "content type"
+msgstr "typ zawartości"
+
+#: models.py:493
+msgid "object id"
+msgstr "id obiektu"
+
+#: views.py:30
+msgid "tagged_object_list must be called with a queryset or a model."
+msgstr ""
+
+#: views.py:32
+msgid "tagged_object_list must be called with a tag model."
+msgstr ""
+
+#: views.py:34
+msgid "tagged_object_list must be called with a tag."
+msgstr ""
+
+#: views.py:38
+#, python-format
+msgid "No tags found matching \"%s\"."
+msgstr ""
diff --git a/apps/newtagging/locale/ru/LC_MESSAGES/django.mo b/apps/newtagging/locale/ru/LC_MESSAGES/django.mo
new file mode 100644 (file)
index 0000000..95c389c
Binary files /dev/null and b/apps/newtagging/locale/ru/LC_MESSAGES/django.mo differ
diff --git a/apps/newtagging/locale/ru/LC_MESSAGES/django.po b/apps/newtagging/locale/ru/LC_MESSAGES/django.po
new file mode 100644 (file)
index 0000000..02133d2
--- /dev/null
@@ -0,0 +1,50 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-05-18 11:01+0200\n"
+"PO-Revision-Date: 2010-06-02 17:08+0100\n"
+"Last-Translator: I <moth_04@yahoo.pl>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: admin.py:38
+msgid "tags"
+msgstr "таги"
+
+#: models.py:491
+msgid "tag"
+msgstr "таг"
+
+#: models.py:492
+msgid "content type"
+msgstr "тип содержания"
+
+#: models.py:493
+msgid "object id"
+msgstr "ID объекта"
+
+#: views.py:30
+msgid "tagged_object_list must be called with a queryset or a model."
+msgstr "список таг-объектов должен сочетаться с набором вопросов или с моделью."
+
+#: views.py:32
+msgid "tagged_object_list must be called with a tag model."
+msgstr "список таг-объектов дожен сочетаться с таг-моделью."
+
+#: views.py:34
+msgid "tagged_object_list must be called with a tag."
+msgstr "список таг-объектов должен сочетаться с тагом."
+
+#: views.py:38
+#, python-format
+msgid "No tags found matching \"%s\"."
+msgstr "Никакой таг не соответствует \"%s\"."
+
diff --git a/apps/newtagging/locale/uk/LC_MESSAGES/django.mo b/apps/newtagging/locale/uk/LC_MESSAGES/django.mo
new file mode 100644 (file)
index 0000000..fdf2a70
Binary files /dev/null and b/apps/newtagging/locale/uk/LC_MESSAGES/django.mo differ
diff --git a/apps/newtagging/locale/uk/LC_MESSAGES/django.po b/apps/newtagging/locale/uk/LC_MESSAGES/django.po
new file mode 100644 (file)
index 0000000..2a7631a
--- /dev/null
@@ -0,0 +1,50 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-05-18 11:01+0200\n"
+"PO-Revision-Date: 2010-08-26 13:14+0100\n"
+"Last-Translator: Natalia Kertyczak <natalczyk@o2.pl>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: admin.py:38
+msgid "tags"
+msgstr "теґи"
+
+#: models.py:491
+msgid "tag"
+msgstr "теґ"
+
+#: models.py:492
+msgid "content type"
+msgstr "тип змісту"
+
+#: models.py:493
+msgid "object id"
+msgstr "ІД об'єкту"
+
+#: views.py:30
+msgid "tagged_object_list must be called with a queryset or a model."
+msgstr "tagged_object_list must be called with a queryset or a model."
+
+#: views.py:32
+msgid "tagged_object_list must be called with a tag model."
+msgstr "tagged_object_list must be called with a tag model."
+
+#: views.py:34
+msgid "tagged_object_list must be called with a tag."
+msgstr "tagged_object_list must be called with a tag."
+
+#: views.py:38
+#, python-format
+msgid "No tags found matching \"%s\"."
+msgstr "Не знайдено теґів відповідаючих  \"%s\"."
+
index 1dbcb29..3107070 100644 (file)
@@ -1,3 +1,4 @@
+# -*- coding: utf-8 -*-
 """
 Custom managers for Django models registered with the tagging
 application.
@@ -13,15 +14,15 @@ class ModelTagManager(models.Manager):
     def __init__(self, tag_model):
         super(ModelTagManager, self).__init__()
         self.tag_model = tag_model
-    
+
     def get_query_set(self):
         content_type = ContentType.objects.get_for_model(self.model)
         return self.tag_model.objects.filter(
             items__content_type__pk=content_type.pk).distinct()
-    
+
     def related(self, tags, *args, **kwargs):
         return self.tag_model.objects.related_for_model(tags, self.model, *args, **kwargs)
-    
+
     def usage(self, *args, **kwargs):
         return self.tag_model.objects.usage_for_model(self.model, *args, **kwargs)
 
@@ -61,7 +62,7 @@ class TagDescriptor(object):
     """
     def __init__(self, tag_model):
         self.tag_model = tag_model
-    
+
     def __get__(self, instance, owner):
         if not instance:
             tag_manager = ModelTagManager(self.tag_model)
index e121994..ea2a41f 100644 (file)
@@ -1,8 +1,12 @@
+# -*- coding: utf-8 -*-
 """
 Models and managers for generic tagging.
 """
+
 # Python 2.3 compatibility
-if not hasattr(__builtins__, 'set'):
+try:
+    set
+except NameError:
     from sets import Set as set
 
 from django.contrib.contenttypes import generic
@@ -11,6 +15,7 @@ from django.db import connection, models
 from django.utils.translation import ugettext_lazy as _
 from django.db.models.base import ModelBase
 from django.core.exceptions import ObjectDoesNotExist
+from django.dispatch import Signal
 
 qn = connection.ops.quote_name
 
@@ -20,6 +25,8 @@ except ImportError:
     parse_lookup = None
 
 
+tags_updated = Signal(providing_args=["affected_tags"])
+
 def get_queryset_and_model(queryset_or_model):
     """
     Given a ``QuerySet`` or a ``Model``, returns a two-tuple of
@@ -41,7 +48,17 @@ class TagManager(models.Manager):
     def __init__(self, intermediary_table_model):
         super(TagManager, self).__init__()
         self.intermediary_table_model = intermediary_table_model
-    
+        models.signals.pre_delete.connect(self.target_deleted)
+
+    def target_deleted(self, instance, **kwargs):
+        """ clear tag relations before deleting an object """
+        try:
+            int(instance.pk)
+        except ValueError:
+            return
+
+        self.update_tags(instance, [])
+
     def update_tags(self, obj, tags):
         """
         Update tags associated with an object.
@@ -50,7 +67,7 @@ class TagManager(models.Manager):
         current_tags = list(self.filter(items__content_type__pk=content_type.pk,
                                         items__object_id=obj.pk))
         updated_tags = self.model.get_tag_list(tags)
-    
+
         # Remove tags which no longer apply
         tags_for_removal = [tag for tag in current_tags \
                             if tag not in updated_tags]
@@ -59,10 +76,14 @@ class TagManager(models.Manager):
                                                object_id=obj.pk,
                                                tag__in=tags_for_removal).delete()
         # Add new tags
-        for tag in updated_tags:
+        tags_to_add = [tag for tag in updated_tags
+                       if tag not in current_tags]
+        for tag in tags_to_add:
             if tag not in current_tags:
                 self.intermediary_table_model._default_manager.create(tag=tag, content_object=obj)
-    
+
+        tags_updated.send(sender=obj, affected_tags=tags_to_add + tags_for_removal)
+
     def remove_tag(self, obj, tag):
         """
         Remove tag from an object.
@@ -79,7 +100,7 @@ class TagManager(models.Manager):
         ctype = ContentType.objects.get_for_model(obj)
         return self.filter(items__content_type__pk=ctype.pk,
                            items__object_id=obj.pk)
-    
+
     def _get_usage(self, model, counts=False, min_count=None, extra_joins=None, extra_criteria=None, params=None, extra=None):
         """
         Perform the custom SQL query for ``usage_for_model`` and
@@ -90,12 +111,12 @@ class TagManager(models.Manager):
         model_table = qn(model._meta.db_table)
         model_pk = '%s.%s' % (model_table, qn(model._meta.pk.column))
         tag_columns = self._get_tag_columns()
-        
+
         if extra is None: extra = {}
         extra_where = ''
         if 'where' in extra:
             extra_where = 'AND ' + ' AND '.join(extra['where'])
-        
+
         query = """
         SELECT DISTINCT %(tag_columns)s%(count_sql)s
         FROM
@@ -108,7 +129,7 @@ class TagManager(models.Manager):
         WHERE %(tagged_item)s.content_type_id = %(content_type_id)s
             %%s
             %(extra_where)s
-        GROUP BY %(tag)s.id, %(tag)s.name
+        GROUP BY %(tag_columns)s, %(tag)s.id, %(tag)s.name
         %%s
         ORDER BY %(tag)s.%(ordering)s ASC""" % {
             'tag': qn(self.model._meta.db_table),
@@ -220,12 +241,12 @@ class TagManager(models.Manager):
         tag_count = len(tags)
         tagged_item_table = qn(self.intermediary_table_model._meta.db_table)
         tag_columns = self._get_tag_columns()
-        
+
         if extra is None: extra = {}
         extra_where = ''
         if 'where' in extra:
             extra_where = 'AND ' + ' AND '.join(extra['where'])
-        
+
         # Temporary table in this query is a hack to prevent MySQL from executing
         # inner query as dependant query (which could result in severe performance loss)
         query = """
@@ -297,7 +318,7 @@ class TaggedItemManager(models.Manager):
     def __init__(self, tag_model):
         super(TaggedItemManager, self).__init__()
         self.tag_model = tag_model
-    
+
     def get_by_model(self, queryset_or_model, tags):
         """
         Create a ``QuerySet`` containing instances of the specified
@@ -469,7 +490,7 @@ class TaggedItemManager(models.Manager):
 def create_intermediary_table_model(model):
     """Create an intermediary table model for the specific tag model"""
     name = model.__name__ + 'Relation'
-     
+
     class Meta:
         db_table = '%s_relation' % model._meta.db_table
         unique_together = (('tag', 'content_type', 'object_id'),)
@@ -479,8 +500,8 @@ def create_intermediary_table_model(model):
             return u'%s [%s]' % (self.content_type.get_object_for_this_type(pk=self.object_id), self.tag)
         except ObjectDoesNotExist:
             return u'<deleted> [%s]' % self.tag
-            
-    # Set up a dictionary to simulate declarations within a class    
+
+    # Set up a dictionary to simulate declarations within a class
     attrs = {
         '__module__': model.__module__,
         'Meta': Meta,
@@ -509,15 +530,15 @@ class TagMeta(ModelBase):
 class TagBase(models.Model):
     """Abstract class to be inherited by model classes."""
     __metaclass__ = TagMeta
-    
+
     class Meta:
         abstract = True
-    
+
     @staticmethod
     def get_tag_list(tag_list):
         """
         Utility function for accepting tag input in a flexible manner.
-        
+
         You should probably override this method in your subclass.
         """
         if isinstance(tag_list, TagBase):
index 150a084..b88e9c4 100644 (file)
@@ -1,3 +1,4 @@
+# -*- coding: utf-8 -*-
 """
 Tagging related views.
 """
diff --git a/apps/pagination/__init__.py b/apps/pagination/__init__.py
deleted file mode 100644 (file)
index 8b13789..0000000
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/apps/pagination/middleware.py b/apps/pagination/middleware.py
deleted file mode 100644 (file)
index 0bab767..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-class PaginationMiddleware(object):
-    """
-    Inserts a variable representing the current page onto the request object if
-    it exists in either **GET** or **POST** portions of the request.
-    """
-    def process_request(self, request):
-        try:
-            request.page = int(request.REQUEST['page'])
-        except (KeyError, ValueError):
-            request.page = 1
\ No newline at end of file
diff --git a/apps/pagination/models.py b/apps/pagination/models.py
deleted file mode 100644 (file)
index 8b13789..0000000
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/apps/pagination/templates/pagination/pagination.html b/apps/pagination/templates/pagination/pagination.html
deleted file mode 100644 (file)
index 3799314..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-{% if is_paginated %}
-<div class="pagination">
-    {% if page_obj.has_previous %}
-        <a href="?page={{ page_obj.previous_page_number }}{{ getvars }}" class="prev">&lsaquo;&lsaquo; previous</a>
-    {% else %}
-        <span class="disabled prev">&lsaquo;&lsaquo; previous</span>
-    {% endif %}
-    {% for page in pages %}
-        {% if page %}
-            {% ifequal page page_obj.number %}
-                <span class="current page">{{ page }}</span>
-            {% else %}
-                <a href="?page={{ page }}{{ getvars }}" class="page">{{ page }}</a>
-            {% endifequal %}
-        {% else %}
-            ...
-        {% endif %}
-    {% endfor %}
-    {% if page_obj.has_next %}
-        <a href="?page={{ page_obj.next_page_number }}{{ getvars }}" class="next">next &rsaquo;&rsaquo;</a>
-    {% else %}
-        <span class="disabled next">next &rsaquo;&rsaquo;</span>
-    {% endif %}
-</div>
-{% endif %}
diff --git a/apps/pagination/templatetags/__init__.py b/apps/pagination/templatetags/__init__.py
deleted file mode 100644 (file)
index 8b13789..0000000
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/apps/pagination/templatetags/pagination_tags.py b/apps/pagination/templatetags/pagination_tags.py
deleted file mode 100644 (file)
index 4908421..0000000
+++ /dev/null
@@ -1,202 +0,0 @@
-try:
-    set
-except NameError:
-    from sets import Set as set
-from django import template
-from django.db.models.query import QuerySet
-from django.core.paginator import Paginator, QuerySetPaginator, InvalidPage
-
-register = template.Library()
-
-DEFAULT_PAGINATION = 20
-DEFAULT_WINDOW = 4
-DEFAULT_ORPHANS = 0
-
-def do_autopaginate(parser, token):
-    """
-    Splits the arguments to the autopaginate tag and formats them correctly.
-    """
-    split = token.split_contents()
-    if len(split) == 2:
-        return AutoPaginateNode(split[1])
-    elif len(split) == 3:
-        try:
-            paginate_by = int(split[2])
-        except ValueError:
-            raise template.TemplateSyntaxError(u'Got %s, but expected integer.' % split[2])
-        return AutoPaginateNode(split[1], paginate_by=paginate_by)
-    elif len(split) == 4:
-        try:
-            paginate_by = int(split[2])
-        except ValueError:
-            raise template.TemplateSyntaxError(u'Got %s, but expected integer.' % split[2])
-        try:
-            orphans = int(split[3])
-        except ValueError:
-            raise template.TemplateSyntaxError(u'Got %s, but expected integer.' % split[3])           
-        return AutoPaginateNode(split[1], paginate_by=paginate_by, orphans=orphans)
-    else:
-        raise template.TemplateSyntaxError('%r tag takes one required argument and one optional argument' % split[0])
-
-class AutoPaginateNode(template.Node):
-    """
-    Emits the required objects to allow for Digg-style pagination.
-    
-    First, it looks in the current context for the variable specified.  This
-    should be either a QuerySet or a list.
-    
-    1. If it is a QuerySet, this ``AutoPaginateNode`` will emit a 
-       ``QuerySetPaginator`` and the current page object into the context names
-       ``paginator`` and ``page_obj``, respectively.
-    
-    2. If it is a list, this ``AutoPaginateNode`` will emit a simple
-       ``Paginator`` and the current page object into the context names 
-       ``paginator`` and ``page_obj``, respectively.
-    
-    It will then replace the variable specified with only the objects for the
-    current page.
-    
-    .. note::
-        
-        It is recommended to use *{% paginate %}* after using the autopaginate
-        tag.  If you choose not to use *{% paginate %}*, make sure to display the
-        list of availabale pages, or else the application may seem to be buggy.
-    """
-    def __init__(self, queryset_var, paginate_by=DEFAULT_PAGINATION, orphans=DEFAULT_ORPHANS):
-        self.queryset_var = template.Variable(queryset_var)
-        self.paginate_by = paginate_by
-        self.orphans = orphans
-
-    def render(self, context):
-        key = self.queryset_var.var
-        value = self.queryset_var.resolve(context)
-        if issubclass(value.__class__, QuerySet):
-            model = value.model
-            paginator_class = QuerySetPaginator
-        else:
-            value = list(value)
-            try:
-                model = value[0].__class__
-            except IndexError:
-                return u''
-            paginator_class = Paginator
-        paginator = paginator_class(value, self.paginate_by, self.orphans)
-        try:
-            page_obj = paginator.page(context['request'].page)
-        except InvalidPage:
-            # context[key] = []
-            # context['invalid_page'] = True
-            # return u''
-            from django.http import Http404
-            raise Http404
-        context[key] = page_obj.object_list
-        context['paginator'] = paginator
-        context['page_obj'] = page_obj
-        return u''
-
-def paginate(context, window=DEFAULT_WINDOW):
-    """
-    Renders the ``pagination/pagination.html`` template, resulting in a
-    Digg-like display of the available pages, given the current page.  If there
-    are too many pages to be displayed before and after the current page, then
-    elipses will be used to indicate the undisplayed gap between page numbers.
-    
-    Requires one argument, ``context``, which should be a dictionary-like data
-    structure and must contain the following keys:
-    
-    ``paginator``
-        A ``Paginator`` or ``QuerySetPaginator`` object.
-    
-    ``page_obj``
-        This should be the result of calling the page method on the 
-        aforementioned ``Paginator`` or ``QuerySetPaginator`` object, given
-        the current page.
-    
-    This same ``context`` dictionary-like data structure may also include:
-    
-    ``getvars``
-        A dictionary of all of the **GET** parameters in the current request.
-        This is useful to maintain certain types of state, even when requesting
-        a different page.
-        """
-    try:
-        paginator = context['paginator']
-        page_obj = context['page_obj']
-        page_range = paginator.page_range
-        # First and last are simply the first *n* pages and the last *n* pages,
-        # where *n* is the current window size.
-        first = set(page_range[:window])
-        last = set(page_range[-window:])
-        # Now we look around our current page, making sure that we don't wrap
-        # around.
-        current_start = page_obj.number-1-window
-        if current_start < 0:
-            current_start = 0
-        current_end = page_obj.number-1+window
-        if current_end < 0:
-            current_end = 0
-        current = set(page_range[current_start:current_end])
-        pages = []
-        # If there's no overlap between the first set of pages and the current
-        # set of pages, then there's a possible need for elusion.
-        if len(first.intersection(current)) == 0:
-            first_list = sorted(list(first))
-            second_list = sorted(list(current))
-            pages.extend(first_list)
-            diff = second_list[0] - first_list[-1]
-            # If there is a gap of two, between the last page of the first
-            # set and the first page of the current set, then we're missing a
-            # page.
-            if diff == 2:
-                pages.append(second_list[0] - 1)
-            # If the difference is just one, then there's nothing to be done,
-            # as the pages need no elusion and are correct.
-            elif diff == 1:
-                pass
-            # Otherwise, there's a bigger gap which needs to be signaled for
-            # elusion, by pushing a None value to the page list.
-            else:
-                pages.append(None)
-            pages.extend(second_list)
-        else:
-            pages.extend(sorted(list(first.union(current))))
-        # If there's no overlap between the current set of pages and the last
-        # set of pages, then there's a possible need for elusion.
-        if len(current.intersection(last)) == 0:
-            second_list = sorted(list(last))
-            diff = second_list[0] - pages[-1]
-            # If there is a gap of two, between the last page of the current
-            # set and the first page of the last set, then we're missing a 
-            # page.
-            if diff == 2:
-                pages.append(second_list[0] - 1)
-            # If the difference is just one, then there's nothing to be done,
-            # as the pages need no elusion and are correct.
-            elif diff == 1:
-                pass
-            # Otherwise, there's a bigger gap which needs to be signaled for
-            # elusion, by pushing a None value to the page list.
-            else:
-                pages.append(None)
-            pages.extend(second_list)
-        else:
-            pages.extend(sorted(list(last.difference(current))))
-        to_return = {
-            'pages': pages,
-            'page_obj': page_obj,
-            'paginator': paginator,
-            'is_paginated': paginator.count > paginator.per_page,
-        }
-        if 'request' in context:
-            getvars = context['request'].GET.copy()
-            if 'page' in getvars:
-                del getvars['page']
-            if len(getvars.keys()) > 0:
-                to_return['getvars'] = "&%s" % getvars.urlencode()
-            else:
-                to_return['getvars'] = ''
-        return to_return
-    except KeyError:
-        return {}
-register.inclusion_tag('pagination/pagination.html', takes_context=True)(paginate)
-register.tag('autopaginate', do_autopaginate)
\ No newline at end of file
diff --git a/apps/pagination/tests.py b/apps/pagination/tests.py
deleted file mode 100644 (file)
index 837e55c..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-"""
->>> from django.core.paginator import Paginator
->>> from pagination.templatetags.pagination_tags import paginate
->>> from django.template import Template, Context
-
->>> p = Paginator(range(15), 2)
->>> paginate({'paginator': p, 'page_obj': p.page(1)})['pages']
-[1, 2, 3, 4, 5, 6, 7, 8]
-
->>> p = Paginator(range(17), 2)
->>> paginate({'paginator': p, 'page_obj': p.page(1)})['pages']
-[1, 2, 3, 4, 5, 6, 7, 8, 9]
-
->>> p = Paginator(range(19), 2)
->>> paginate({'paginator': p, 'page_obj': p.page(1)})['pages']
-[1, 2, 3, 4, None, 7, 8, 9, 10]
-
->>> p = Paginator(range(21), 2)
->>> paginate({'paginator': p, 'page_obj': p.page(1)})['pages']
-[1, 2, 3, 4, None, 8, 9, 10, 11]
-
-# Testing orphans
->>> p = Paginator(range(5), 2, 1)
->>> paginate({'paginator': p, 'page_obj': p.page(1)})['pages']
-[1, 2]
-
->>> p = Paginator(range(21), 2, 1)
->>> paginate({'paginator': p, 'page_obj': p.page(1)})['pages']
-[1, 2, 3, 4, None, 7, 8, 9, 10]
-
->>> t = Template("{% load pagination_tags %}{% autopaginate var 2 %}{% paginate %}")
-
-# WARNING: Please, please nobody read this portion of the code!
->>> class GetProxy(object):
-...     def __iter__(self): yield self.__dict__.__iter__
-...     def copy(self): return self
-...     def urlencode(self): return u''
-...     def keys(self): return []
->>> class RequestProxy(object):
-...     page = 1
-...     GET = GetProxy()
->>>
-# ENDWARNING
-
->>> t.render(Context({'var': range(21), 'request': RequestProxy()}))
-u'\\n<div class="pagination">...
->>>
->>> t = Template("{% load pagination_tags %}{% autopaginate var %}{% paginate %}")
->>> t.render(Context({'var': range(21), 'request': RequestProxy()}))
-u'\\n<div class="pagination">...
->>>
-"""
\ No newline at end of file
index 7d09707..19b8e82 100644 (file)
@@ -26,7 +26,7 @@ class NoAuthentication(object):
 class HttpBasicAuthentication(object):
     """
     Basic HTTP authenticater. Synopsis:
-    
+
     Authentication handlers must implement two methods:
      - `is_authenticated`: Will be called when checking for
         authentication. Receives a `request` object, please
@@ -46,7 +46,7 @@ class HttpBasicAuthentication(object):
 
         if not auth_string:
             return False
-            
+
         try:
             (authmeth, auth) = auth_string.split(" ", 1)
 
@@ -57,12 +57,12 @@ class HttpBasicAuthentication(object):
             (username, password) = auth.split(':', 1)
         except (ValueError, binascii.Error):
             return False
-        
+
         request.user = self.auth_func(username=username, password=password) \
             or AnonymousUser()
-                
+
         return not request.user in (False, None, AnonymousUser())
-        
+
     def challenge(self):
         resp = HttpResponse("Authorization Required")
         resp['WWW-Authenticate'] = 'Basic realm="%s"' % self.realm
@@ -78,7 +78,7 @@ class HttpBasicSimple(HttpBasicAuthentication):
         self.password = password
 
         super(HttpBasicSimple, self).__init__(auth_func=self.hash, realm=realm)
-    
+
     def hash(self, username, password):
         if username == self.user.username and password == self.password:
             return self.user
@@ -122,17 +122,17 @@ def initialize_server_request(request):
     request.META['Authorization'] = request.META.get('HTTP_AUTHORIZATION', '')
 
     oauth_request = oauth.OAuthRequest.from_request(
-        request.method, request.build_absolute_uri(), 
+        request.method, request.build_absolute_uri(),
         headers=request.META, parameters=params,
         query_string=request.environ.get('QUERY_STRING', ''))
-        
+
     if oauth_request:
         oauth_server = oauth.OAuthServer(oauth_datastore(oauth_request))
         oauth_server.add_signature_method(oauth.OAuthSignatureMethod_PLAINTEXT())
         oauth_server.add_signature_method(oauth.OAuthSignatureMethod_HMAC_SHA1())
     else:
         oauth_server = None
-        
+
     return oauth_server, oauth_request
 
 def send_oauth_error(err=None):
@@ -152,7 +152,7 @@ def send_oauth_error(err=None):
 
 def oauth_request_token(request):
     oauth_server, oauth_request = initialize_server_request(request)
-    
+
     if oauth_server is None:
         return INVALID_PARAMS_RESPONSE
     try:
@@ -176,20 +176,20 @@ def oauth_auth_view(request, token, callback, params):
 @login_required
 def oauth_user_auth(request):
     oauth_server, oauth_request = initialize_server_request(request)
-    
+
     if oauth_request is None:
         return INVALID_PARAMS_RESPONSE
-        
+
     try:
         token = oauth_server.fetch_request_token(oauth_request)
     except oauth.OAuthError, err:
         return send_oauth_error(err)
-        
+
     try:
         callback = oauth_server.get_callback(oauth_request)
     except:
         callback = None
-    
+
     if request.method == "GET":
         params = oauth_request.get_normalized_parameters()
 
@@ -207,26 +207,26 @@ def oauth_user_auth(request):
             else:
                 args = '?error=%s' % 'Access not granted by user.'
                 print "FORM ERROR", form.errors
-            
+
             if not callback:
                 callback = getattr(settings, 'OAUTH_CALLBACK_VIEW')
                 return get_callable(callback)(request, token)
-                
+
             response = HttpResponseRedirect(callback+args)
-                
+
         except oauth.OAuthError, err:
             response = send_oauth_error(err)
     else:
         response = HttpResponse('Action not allowed.')
-            
+
     return response
 
 def oauth_access_token(request):
     oauth_server, oauth_request = initialize_server_request(request)
-    
+
     if oauth_request is None:
         return INVALID_PARAMS_RESPONSE
-        
+
     try:
         token = oauth_server.fetch_access_token(oauth_request)
         return HttpResponse(token.to_string())
@@ -234,7 +234,7 @@ def oauth_access_token(request):
         return send_oauth_error(err)
 
 INVALID_PARAMS_RESPONSE = send_oauth_error(oauth.OAuthError('Invalid request parameters.'))
-                
+
 class OAuthAuthentication(object):
     """
     OAuth authentication. Based on work by Leah Culver.
@@ -242,12 +242,12 @@ class OAuthAuthentication(object):
     def __init__(self, realm='API'):
         self.realm = realm
         self.builder = oauth.build_authenticate_header
-    
+
     def is_authenticated(self, request):
         """
         Checks whether a means of specifying authentication
         is provided, and if so, if it is a valid token.
-        
+
         Read the documentation on `HttpBasicAuthentication`
         for more information about what goes on here.
         """
@@ -263,14 +263,14 @@ class OAuthAuthentication(object):
                 request.consumer = consumer
                 request.throttle_extra = token.consumer.id
                 return True
-            
+
         return False
-        
+
     def challenge(self):
         """
         Returns a 401 response with a small bit on
         what OAuth is, and where to learn more about it.
-        
+
         When this was written, browsers did not understand
         OAuth authentication on the browser side, and hence
         the helpful template we render. Maybe some day in the
@@ -290,7 +290,7 @@ class OAuthAuthentication(object):
         response.content = tmpl
 
         return response
-        
+
     @staticmethod
     def is_valid_request(request):
         """
@@ -302,14 +302,14 @@ class OAuthAuthentication(object):
         must_have = [ 'oauth_'+s for s in [
             'consumer_key', 'token', 'signature',
             'signature_method', 'timestamp', 'nonce' ] ]
-        
+
         is_in = lambda l: all([ (p in l) for p in must_have ])
 
         auth_params = request.META.get("HTTP_AUTHORIZATION", "")
         req_params = request.REQUEST
-             
+
         return is_in(auth_params) or is_in(req_params)
-        
+
     @staticmethod
     def validate_token(request, check_timestamp=True, check_nonce=True):
         oauth_server, oauth_request = initialize_server_request(request)
index f8dc3b8..e173d01 100755 (executable)
@@ -28,7 +28,7 @@ def getinfo(func):
     - doc (the docstring : str)
     - module (the module name : str)
     - dict (the function __dict__ : str)
-    
+
     >>> def f(self, x=1, y=2, *args, **kw): pass
 
     >>> info = getinfo(f)
@@ -37,7 +37,7 @@ def getinfo(func):
     'f'
     >>> info["argnames"]
     ['self', 'x', 'y', 'args', 'kw']
-    
+
     >>> info["defaults"]
     (1, 2)
 
@@ -75,7 +75,7 @@ def update_wrapper(wrapper, model, infodict=None):
 def new_wrapper(wrapper, model):
     """
     An improvement over functools.update_wrapper. The wrapper is a generic
-    callable object. It works by generating a copy of the wrapper with the 
+    callable object. It works by generating a copy of the wrapper with the
     right signature and by updating the copy, not the original.
     Moreovoer, 'model' can be a dictionary with keys 'name', 'doc', 'module',
     'dict', 'defaults'.
@@ -126,7 +126,7 @@ def decorator(caller):
      def caller(func, *args, **kw):
          # do something
          return func(*args, **kw)
-    
+
     Here is an example of usage:
 
     >>> @decorator
@@ -136,7 +136,7 @@ def decorator(caller):
 
     >>> chatty.__name__
     'chatty'
-    
+
     >>> @chatty
     ... def f(): pass
     ...
@@ -164,13 +164,13 @@ if __name__ == "__main__":
     import doctest; doctest.testmod()
 
 ##########################     LEGALESE    ###############################
-      
-##   Redistributions of source code must retain the above copyright 
+
+##   Redistributions of source code must retain the above copyright
 ##   notice, this list of conditions and the following disclaimer.
 ##   Redistributions in bytecode 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. 
+##   distribution.
 
 ##   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 ##   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
index 63f89ec..fc14add 100644 (file)
@@ -15,14 +15,14 @@ def generate_doc(handler_cls):
     """
     if not type(handler_cls) is handler.HandlerMetaClass:
         raise ValueError("Give me handler, not %s" % type(handler_cls))
-        
+
     return HandlerDocumentation(handler_cls)
-    
+
 class HandlerMethod(object):
     def __init__(self, method, stale=False):
         self.method = method
         self.stale = stale
-        
+
     def iter_args(self):
         args, _, _, defaults = inspect.getargspec(self.method)
 
@@ -36,34 +36,34 @@ class HandlerMethod(object):
                 yield (arg, str(defaults[-didx]))
             else:
                 yield (arg, None)
-        
+
     @property
     def signature(self, parse_optional=True):
         spec = ""
 
         for argn, argdef in self.iter_args():
             spec += argn
-            
+
             if argdef:
                 spec += '=%s' % argdef
-            
+
             spec += ', '
-            
+
         spec = spec.rstrip(", ")
-        
+
         if parse_optional:
             return spec.replace("=None", "=<optional>")
-            
+
         return spec
-        
+
     @property
     def doc(self):
         return inspect.getdoc(self.method)
-    
+
     @property
     def name(self):
         return self.method.__name__
-    
+
     @property
     def http_name(self):
         if self.name == 'read':
@@ -74,21 +74,21 @@ class HandlerMethod(object):
             return 'DELETE'
         elif self.name == 'update':
             return 'PUT'
-    
+
     def __repr__(self):
         return "<Method: %s>" % self.name
-    
+
 class HandlerDocumentation(object):
     def __init__(self, handler):
         self.handler = handler
-        
+
     def get_methods(self, include_default=False):
         for method in "read create update delete".split():
             met = getattr(self.handler, method, None)
 
             if not met:
                 continue
-                
+
             stale = inspect.getmodule(met) is handler
 
             if not self.handler.is_anonymous:
@@ -97,64 +97,64 @@ class HandlerDocumentation(object):
             else:
                 if not stale or met.__name__ == "read" \
                     and 'GET' in self.allowed_methods:
-                    
+
                     yield HandlerMethod(met, stale)
-        
+
     def get_all_methods(self):
         return self.get_methods(include_default=True)
-        
+
     @property
     def is_anonymous(self):
         return handler.is_anonymous
 
     def get_model(self):
         return getattr(self, 'model', None)
-            
+
     @property
     def has_anonymous(self):
         return self.handler.anonymous
-            
+
     @property
     def anonymous(self):
         if self.has_anonymous:
             return HandlerDocumentation(self.handler.anonymous)
-            
+
     @property
     def doc(self):
         return self.handler.__doc__
-    
+
     @property
     def name(self):
         return self.handler.__name__
-    
+
     @property
     def allowed_methods(self):
         return self.handler.allowed_methods
-    
+
     def get_resource_uri_template(self):
         """
         URI template processor.
-        
+
         See http://bitworking.org/projects/URI-Templates/
         """
         def _convert(template, params=[]):
             """URI template converter"""
             paths = template % dict([p, "{%s}" % p] for p in params)
             return u'%s%s' % (get_script_prefix(), paths)
-        
+
         try:
             resource_uri = self.handler.resource_uri()
-            
+
             components = [None, [], {}]
 
             for i, value in enumerate(resource_uri):
                 components[i] = value
-        
+
             lookup_view, args, kwargs = components
             lookup_view = get_callable(lookup_view, True)
 
             possibilities = get_resolver(None).reverse_dict.getlist(lookup_view)
-            
+
             for possibility, pattern in possibilities:
                 for result, params in possibility:
                     if args:
@@ -167,9 +167,9 @@ class HandlerDocumentation(object):
                         return _convert(result, params)
         except:
             return None
-        
+
     resource_uri_template = property(get_resource_uri_template)
-    
+
     def __repr__(self):
         return u'<Documentation for "%s">' % self.name
 
@@ -180,16 +180,16 @@ def documentation_view(request):
     """
     docs = [ ]
 
-    for handler in handler_tracker: 
+    for handler in handler_tracker:
         docs.append(generate_doc(handler))
 
-    def _compare(doc1, doc2): 
+    def _compare(doc1, doc2):
        #handlers and their anonymous counterparts are put next to each other.
        name1 = doc1.name.replace("Anonymous", "")
        name2 = doc2.name.replace("Anonymous", "")
-       return cmp(name1, name2)    
+       return cmp(name1, name2)
+
     docs.sort(_compare)
-       
-    return render_to_response('documentation.html', 
+
+    return render_to_response('documentation.html',
         { 'docs': docs }, RequestContext(request))
index 1ff0a52..c2116d2 100644 (file)
@@ -58,7 +58,7 @@ class Emitter(object):
     as the methods on the handler. Issue58 says that's no good.
     """
     EMITTERS = { }
-    RESERVED_FIELDS = set([ 'read', 'update', 'create', 
+    RESERVED_FIELDS = set([ 'read', 'update', 'create',
                             'delete', 'model', 'anonymous',
                             'allowed_methods', 'fields', 'exclude' ])
 
@@ -68,16 +68,16 @@ class Emitter(object):
         self.handler = handler
         self.fields = fields
         self.anonymous = anonymous
-        
+
         if isinstance(self.data, Exception):
             raise
-    
+
     def method_fields(self, handler, fields):
         if not handler:
             return { }
 
         ret = dict()
-            
+
         for field in fields - Emitter.RESERVED_FIELDS:
             t = getattr(handler, str(field), None)
 
@@ -85,13 +85,13 @@ class Emitter(object):
                 ret[field] = t
 
         return ret
-    
+
     def construct(self):
         """
         Recursively serialize a lot of types, and
         in cases where it doesn't recognize the type,
         it will fall back to Django's `smart_unicode`.
-        
+
         Returns `dict`.
         """
         def _any(thing, fields=()):
@@ -99,7 +99,7 @@ class Emitter(object):
             Dispatch, all types are routed through here.
             """
             ret = None
-            
+
             if isinstance(thing, QuerySet):
                 ret = _qs(thing, fields=fields)
             elif isinstance(thing, (tuple, list)):
@@ -131,19 +131,19 @@ class Emitter(object):
             Foreign keys.
             """
             return _any(getattr(data, field.name))
-        
+
         def _related(data, fields=()):
             """
             Foreign keys.
             """
             return [ _model(m, fields) for m in data.iterator() ]
-        
+
         def _m2m(data, field, fields=()):
             """
             Many to many (re-route to `_model`.)
             """
             return [ _model(m, fields) for m in getattr(data, field.name).iterator() ]
-        
+
         def _model(data, fields=()):
             """
             Models. Will respect the `fields` and/or
@@ -152,7 +152,7 @@ class Emitter(object):
             ret = { }
             handler = self.in_typemapper(type(data), self.anonymous)
             get_absolute_uri = False
-            
+
             if handler or fields:
                 v = lambda f: getattr(data, f.attname)
 
@@ -167,26 +167,26 @@ class Emitter(object):
 
                     if 'absolute_uri' in get_fields:
                         get_absolute_uri = True
-                
+
                     if not get_fields:
                         get_fields = set([ f.attname.replace("_id", "", 1)
                             for f in data._meta.fields ])
-                
+
                     # sets can be negated.
                     for exclude in exclude_fields:
                         if isinstance(exclude, basestring):
                             get_fields.discard(exclude)
-                            
+
                         elif isinstance(exclude, re._pattern_type):
                             for field in get_fields.copy():
                                 if exclude.match(field):
                                     get_fields.discard(field)
-                                    
+
                 else:
                     get_fields = set(fields)
 
                 met_fields = self.method_fields(handler, get_fields)
-                           
+
                 for f in data._meta.local_fields:
                     if f.serialize and not any([ p in met_fields for p in [ f.attname, f.name ]]):
                         if not f.rel:
@@ -197,13 +197,13 @@ class Emitter(object):
                             if f.attname[:-3] in get_fields:
                                 ret[f.name] = _fk(data, f)
                                 get_fields.remove(f.name)
-                
+
                 for mf in data._meta.many_to_many:
                     if mf.serialize and mf.attname not in met_fields:
                         if mf.attname in get_fields:
                             ret[mf.name] = _m2m(data, mf)
                             get_fields.remove(mf.name)
-                
+
                 # try to get the remainder of fields
                 for maybe_field in get_fields:
                     if isinstance(maybe_field, (list, tuple)):
@@ -225,7 +225,7 @@ class Emitter(object):
                         # using different names.
                         ret[maybe_field] = _any(met_fields[maybe_field](data))
 
-                    else:                    
+                    else:
                         maybe = getattr(data, maybe_field, None)
                         if maybe:
                             if callable(maybe):
@@ -242,13 +242,13 @@ class Emitter(object):
             else:
                 for f in data._meta.fields:
                     ret[f.attname] = _any(getattr(data, f.attname))
-                
+
                 fields = dir(data.__class__) + ret.keys()
                 add_ons = [k for k in dir(data) if k not in fields]
-                
+
                 for k in add_ons:
                     ret[k] = _any(getattr(data, k))
-            
+
             # resouce uri
             if self.in_typemapper(type(data), self.anonymous):
                 handler = self.in_typemapper(type(data), self.anonymous)
@@ -259,51 +259,51 @@ class Emitter(object):
                         ret['resource_uri'] = reverser( lambda: (url_id, fields) )()
                     except NoReverseMatch, e:
                         pass
-            
+
             if hasattr(data, 'get_api_url') and 'resource_uri' not in ret:
                 try: ret['resource_uri'] = data.get_api_url()
                 except: pass
-            
+
             # absolute uri
             if hasattr(data, 'get_absolute_url') and get_absolute_uri:
                 try: ret['absolute_uri'] = data.get_absolute_url()
                 except: pass
-            
+
             return ret
-        
+
         def _qs(data, fields=()):
             """
             Querysets.
             """
             return [ _any(v, fields) for v in data ]
-                
+
         def _list(data):
             """
             Lists.
             """
             return [ _any(v) for v in data ]
-            
+
         def _dict(data):
             """
             Dictionaries.
             """
             return dict([ (k, _any(v)) for k, v in data.iteritems() ])
-            
+
         # Kickstart the seralizin'.
         return _any(self.data, self.fields)
-    
+
     def in_typemapper(self, model, anonymous):
         for klass, (km, is_anon) in self.typemapper.iteritems():
             if model is km and is_anon is anonymous:
                 return klass
-        
+
     def render(self):
         """
         This super emitter does not implement `render`,
         this is a job for the specific emitter below.
         """
         raise NotImplementedError("Please implement render.")
-        
+
     def stream_render(self, request, stream=True):
         """
         Tells our patched middleware not to look
@@ -312,7 +312,7 @@ class Emitter(object):
         more memory friendly for large datasets.
         """
         yield self.render(request)
-        
+
     @classmethod
     def get(cls, format):
         """
@@ -322,19 +322,19 @@ class Emitter(object):
             return cls.EMITTERS.get(format)
 
         raise ValueError("No emitters found for type %s" % format)
-    
+
     @classmethod
     def register(cls, name, klass, content_type='text/plain'):
         """
         Register an emitter.
-        
+
         Parameters::
          - `name`: The name of the emitter ('json', 'xml', 'yaml', ...)
          - `klass`: The emitter class.
          - `content_type`: The content type to serve response as.
         """
         cls.EMITTERS[name] = (klass, content_type)
-        
+
     @classmethod
     def unregister(cls, name):
         """
@@ -342,7 +342,7 @@ class Emitter(object):
         want to provide output in one of the built-in emitters.
         """
         return cls.EMITTERS.pop(name, None)
-    
+
 class XMLEmitter(Emitter):
     def _to_xml(self, xml, data):
         if isinstance(data, (list, tuple)):
@@ -360,16 +360,16 @@ class XMLEmitter(Emitter):
 
     def render(self, request):
         stream = StringIO.StringIO()
-        
+
         xml = SimplerXMLGenerator(stream, "utf-8")
         xml.startDocument()
         xml.startElement("response", {})
-        
+
         self._to_xml(xml, self.construct())
-        
+
         xml.endElement("response")
         xml.endDocument()
-        
+
         return stream.getvalue()
 
 Emitter.register('xml', XMLEmitter, 'text/xml; charset=utf-8')
@@ -388,10 +388,10 @@ class JSONEmitter(Emitter):
             return '%s(%s)' % (cb, seria)
 
         return seria
-    
+
 Emitter.register('json', JSONEmitter, 'application/json; charset=utf-8')
 Mimer.register(simplejson.loads, ('application/json',))
-    
+
 class YAMLEmitter(Emitter):
     """
     YAML emitter, uses `safe_dump` to omit the
@@ -410,7 +410,7 @@ class PickleEmitter(Emitter):
     """
     def render(self, request):
         return pickle.dumps(self.construct())
-        
+
 Emitter.register('pickle', PickleEmitter, 'application/python-pickle')
 
 """
@@ -437,5 +437,5 @@ class DjangoEmitter(Emitter):
             response = serializers.serialize(format, self.data, indent=True)
 
         return response
-        
+
 Emitter.register('django', DjangoEmitter, 'text/xml; charset=utf-8')
index 351df7c..36bd6ff 100644 (file)
@@ -5,7 +5,7 @@ from django.conf import settings
 
 class Form(forms.Form):
     pass
-    
+
 class ModelForm(forms.ModelForm):
     """
     Subclass of `forms.ModelForm` which makes sure
index 2d28bb3..a128d7a 100644 (file)
@@ -19,17 +19,17 @@ class HandlerMetaClass(type):
             for k, (m, a) in typemapper.iteritems():
                 if model == m and anon == a:
                     return k
-        
+
         if hasattr(new_cls, 'model'):
             if already_registered(new_cls.model, new_cls.is_anonymous):
                 if not getattr(settings, 'PISTON_IGNORE_DUPE_MODELS', False):
                     warnings.warn("Handler already registered for model %s, "
                         "you may experience inconsistent results." % new_cls.model.__name__)
-                
+
             typemapper[new_cls] = (new_cls.model, new_cls.is_anonymous)
         else:
             typemapper[new_cls] = (None, new_cls.is_anonymous)
-        
+
         if name not in ('BaseHandler', 'AnonymousBaseHandler'):
             handler_tracker.append(new_cls)
 
@@ -40,43 +40,43 @@ class BaseHandler(object):
     Basehandler that gives you CRUD for free.
     You are supposed to subclass this for specific
     functionality.
-    
+
     All CRUD methods (`read`/`update`/`create`/`delete`)
     receive a request as the first argument from the
     resource. Use this for checking `request.user`, etc.
     """
     __metaclass__ = HandlerMetaClass
-    
+
     allowed_methods = ('GET', 'POST', 'PUT', 'DELETE')
     anonymous = is_anonymous = False
     exclude = ( 'id', )
     fields =  ( )
-    
+
     def flatten_dict(self, dct):
         return dict([ (str(k), dct.get(k)) for k in dct.keys() ])
-    
+
     def has_model(self):
         return hasattr(self, 'model') or hasattr(self, 'queryset')
 
     def queryset(self, request):
         return self.model.objects.all()
-    
+
     def value_from_tuple(tu, name):
         for int_, n in tu:
             if n == name:
                 return int_
         return None
-    
+
     def exists(self, **kwargs):
         if not self.has_model():
             raise NotImplementedError
-        
+
         try:
             self.model.objects.get(**kwargs)
             return True
         except self.model.DoesNotExist:
             return False
-    
+
     def read(self, request, *args, **kwargs):
         if not self.has_model():
             return rc.NOT_IMPLEMENTED
@@ -92,13 +92,13 @@ class BaseHandler(object):
                 return rc.BAD_REQUEST
         else:
             return self.queryset(request).filter(*args, **kwargs)
-    
+
     def create(self, request, *args, **kwargs):
         if not self.has_model():
             return rc.NOT_IMPLEMENTED
-        
+
         attrs = self.flatten_dict(request.POST)
-        
+
         try:
             inst = self.queryset(request).get(**attrs)
             return rc.DUPLICATE_ENTRY
@@ -108,7 +108,7 @@ class BaseHandler(object):
             return inst
         except self.model.MultipleObjectsReturned:
             return rc.DUPLICATE_ENTRY
-    
+
     def update(self, request, *args, **kwargs):
         if not self.has_model():
             return rc.NOT_IMPLEMENTED
@@ -132,7 +132,7 @@ class BaseHandler(object):
 
         inst.save()
         return rc.ALL_OK
-    
+
     def delete(self, request, *args, **kwargs):
         if not self.has_model():
             raise NotImplementedError
@@ -147,7 +147,7 @@ class BaseHandler(object):
             return rc.DUPLICATE_ENTRY
         except self.model.DoesNotExist:
             return rc.NOT_HERE
-        
+
 class AnonymousBaseHandler(BaseHandler):
     """
     Anonymous handler.
index 5694d0e..a1c9d49 100644 (file)
@@ -48,15 +48,15 @@ class ResourceManager(models.Manager):
         if not self._default_resource:
             self._default_resource = self.get(name=name)
 
-        return self._default_resource        
+        return self._default_resource
 
 class TokenManager(KeyManager):
     def create_token(self, consumer, token_type, timestamp, user=None):
         """
         Shortcut to create a token with random key/secret.
         """
-        token, created = self.get_or_create(consumer=consumer, 
-                                            token_type=token_type, 
+        token, created = self.get_or_create(consumer=consumer,
+                                            token_type=token_type,
                                             timestamp=timestamp,
                                             user=user)
 
@@ -65,4 +65,4 @@ class TokenManager(KeyManager):
             token.save()
 
         return token
-        
+
index 9c93af8..d205930 100644 (file)
@@ -29,7 +29,7 @@ class Nonce(models.Model):
     token_key = models.CharField(max_length=KEY_SIZE)
     consumer_key = models.CharField(max_length=KEY_SIZE)
     key = models.CharField(max_length=255)
-    
+
     def __unicode__(self):
         return u"Nonce %s for %s" % (self.key, self.consumer_key)
 
@@ -46,17 +46,17 @@ class Consumer(models.Model):
     user = models.ForeignKey(User, null=True, blank=True, related_name='consumers')
 
     objects = ConsumerManager()
-        
+
     def __unicode__(self):
         return u"Consumer %s with key %s" % (self.name, self.key)
 
     def generate_random_codes(self):
         """
         Used to generate random key/secret pairings. Use this after you've
-        added the other data in place of save(). 
+        added the other data in place of save().
 
         c = Consumer()
-        c.name = "My consumer" 
+        c.name = "My consumer"
         c.description = "An app that makes ponies from the API."
         c.user = some_user_object
         c.generate_random_codes()
@@ -77,28 +77,28 @@ class Token(models.Model):
     REQUEST = 1
     ACCESS = 2
     TOKEN_TYPES = ((REQUEST, u'Request'), (ACCESS, u'Access'))
-    
+
     key = models.CharField(max_length=KEY_SIZE)
     secret = models.CharField(max_length=SECRET_SIZE)
     verifier = models.CharField(max_length=VERIFIER_SIZE)
     token_type = models.IntegerField(choices=TOKEN_TYPES)
     timestamp = models.IntegerField(default=long(time.time()))
     is_approved = models.BooleanField(default=False)
-    
+
     user = models.ForeignKey(User, null=True, blank=True, related_name='tokens')
     consumer = models.ForeignKey(Consumer)
-    
+
     callback = models.CharField(max_length=255, null=True, blank=True)
     callback_confirmed = models.BooleanField(default=False)
-    
+
     objects = TokenManager()
-    
+
     def __unicode__(self):
         return u"%s Token %s for %s" % (self.get_token_type_display(), self.key, self.consumer)
 
     def to_string(self, only_key=False):
         token_dict = {
-            'oauth_token': self.key, 
+            'oauth_token': self.key,
             'oauth_token_secret': self.secret,
             'oauth_callback_confirmed': 'true',
         }
@@ -121,7 +121,7 @@ class Token(models.Model):
         self.key = key
         self.secret = secret
         self.save()
-        
+
     # -- OAuth 1.0a stuff
 
     def get_callback_url(self):
@@ -136,13 +136,13 @@ class Token(models.Model):
             return urlparse.urlunparse((scheme, netloc, path, params,
                 query, fragment))
         return self.callback
-    
+
     def set_callback(self, callback):
         if callback != "oob": # out of band, says "we can't do this!"
             self.callback = callback
             self.callback_confirmed = True
             self.save()
-        
+
 admin.site.register(Token)
 
 # Attach our signals
index 3a42e20..8c430ea 100644 (file)
@@ -87,7 +87,7 @@ class OAuthConsumer(object):
 class OAuthToken(object):
     """OAuthToken is a data type that represents an End User via either an access
     or request token.
-    
+
     key -- the token
     secret -- the token secret
 
@@ -133,7 +133,7 @@ class OAuthToken(object):
         if self.callback_confirmed is not None:
             data['oauth_callback_confirmed'] = self.callback_confirmed
         return urllib.urlencode(data)
+
     def from_string(s):
         """ Returns a token from something like:
         oauth_token_secret=xxx&oauth_token=xxx
@@ -157,11 +157,11 @@ class OAuthRequest(object):
     """OAuthRequest represents the request and can be serialized.
 
     OAuth parameters:
-        - oauth_consumer_key 
+        - oauth_consumer_key
         - oauth_token
         - oauth_signature_method
-        - oauth_signature 
-        - oauth_timestamp 
+        - oauth_signature
+        - oauth_timestamp
         - oauth_nonce
         - oauth_version
         - oauth_verifier
@@ -436,7 +436,7 @@ class OAuthServer(object):
     def get_callback(self, oauth_request):
         """Get the callback URL."""
         return oauth_request.get_parameter('oauth_callback')
+
     def build_authenticate_header(self, realm=''):
         """Optional support for the authenticate header."""
         return {'WWW-Authenticate': 'OAuth realm="%s"' % realm}
@@ -482,7 +482,7 @@ class OAuthServer(object):
         if not token:
             raise OAuthError('Invalid %s token: %s' % (token_type, token_field))
         return token
-    
+
     def _get_verifier(self, oauth_request):
         return oauth_request.get_parameter('oauth_verifier')
 
@@ -601,7 +601,7 @@ class OAuthSignatureMethod_HMAC_SHA1(OAuthSignatureMethod):
 
     def get_name(self):
         return 'HMAC-SHA1'
-        
+
     def build_signature_base_string(self, oauth_request, consumer, token):
         sig = (
             escape(oauth_request.get_normalized_http_method()),
index 40f065d..ee78b0e 100644 (file)
@@ -26,22 +26,22 @@ class Resource(object):
     is an authentication handler. If not specified,
     `NoAuthentication` will be used by default.
     """
-    callmap = { 'GET': 'read', 'POST': 'create', 
+    callmap = { 'GET': 'read', 'POST': 'create',
                 'PUT': 'update', 'DELETE': 'delete' }
-    
+
     def __init__(self, handler, authentication=None):
         if not callable(handler):
             raise AttributeError, "Handler not callable."
-        
+
         self.handler = handler()
-        
+
         if not authentication:
             self.authentication = (NoAuthentication(),)
         elif isinstance(authentication, (list, tuple)):
             self.authentication = authentication
         else:
             self.authentication = (authentication,)
-            
+
         # Erroring
         self.email_errors = getattr(settings, 'PISTON_EMAIL_ERRORS', True)
         self.display_errors = getattr(settings, 'PISTON_DISPLAY_ERRORS', True)
@@ -58,12 +58,12 @@ class Resource(object):
         that as well.
         """
         em = kwargs.pop('emitter_format', None)
-        
+
         if not em:
             em = request.GET.get('format', 'json')
 
         return em
-    
+
     @property
     def anonymous(self):
         """
@@ -74,16 +74,16 @@ class Resource(object):
         """
         if hasattr(self.handler, 'anonymous'):
             anon = self.handler.anonymous
-            
+
             if callable(anon):
                 return anon
 
             for klass in typemapper.keys():
                 if anon == klass.__name__:
                     return klass
-            
+
         return None
-    
+
     def authenticate(self, request, rm):
         actor, anonymous = False, True
 
@@ -97,9 +97,9 @@ class Resource(object):
                     actor, anonymous = authenticator.challenge, CHALLENGE
             else:
                 return self.handler, self.handler.is_anonymous
-        
+
         return actor, anonymous
-    
+
     @vary_on_headers('Authorization')
     def __call__(self, request, *args, **kwargs):
         """
@@ -119,19 +119,19 @@ class Resource(object):
             return actor()
         else:
             handler = actor
-        
+
         # Translate nested datastructs into `request.data` here.
         if rm in ('POST', 'PUT'):
             try:
                 translate_mime(request)
             except MimerDataException:
                 return rc.BAD_REQUEST
-        
+
         if not rm in handler.allowed_methods:
             return HttpResponseNotAllowed(handler.allowed_methods)
-        
+
         meth = getattr(handler, self.callmap.get(rm), None)
-        
+
         if not meth:
             raise Http404
 
@@ -139,18 +139,18 @@ class Resource(object):
         em_format = self.determine_emitter(request, *args, **kwargs)
 
         kwargs.pop('emitter_format', None)
-        
+
         # Clean up the request object a bit, since we might
         # very well have `oauth_`-headers in there, and we
         # don't want to pass these along to the handler.
         request = self.cleanup_request(request)
-        
+
         try:
             result = meth(request, *args, **kwargs)
         except FormValidationError, e:
             resp = rc.BAD_REQUEST
             resp.write(' '+str(e.form.errors))
-            
+
             return resp
         except TypeError, e:
             result = rc.BAD_REQUEST
@@ -158,15 +158,15 @@ class Resource(object):
             sig = hm.signature
 
             msg = 'Method signature does not match.\n\n'
-            
+
             if sig:
                 msg += 'Signature should be: %s' % sig
             else:
                 msg += 'Resource does not expect any parameters.'
 
-            if self.display_errors:                
+            if self.display_errors:
                 msg += '\n\nException was: %s' % str(e)
-                
+
             result.content = format_error(msg)
         except Http404:
             return rc.NOT_FOUND
@@ -177,13 +177,13 @@ class Resource(object):
             On errors (like code errors), we'd like to be able to
             give crash reports to both admins and also the calling
             user. There's two setting parameters for this:
-            
+
             Parameters::
              - `PISTON_EMAIL_ERRORS`: Will send a Django formatted
                error email to people in `settings.ADMINS`.
              - `PISTON_DISPLAY_ERRORS`: Will return a simple traceback
                to the caller, so he can tell you what error they got.
-               
+
             If `PISTON_DISPLAY_ERRORS` is not enabled, the caller will
             receive a basic "500 Internal Server Error" message.
             """
@@ -237,17 +237,17 @@ class Resource(object):
 
             if True in [ k.startswith("oauth_") for k in block.keys() ]:
                 sanitized = block.copy()
-                
+
                 for k in sanitized.keys():
                     if k.startswith("oauth_"):
                         sanitized.pop(k)
-                        
+
                 setattr(request, method_type, sanitized)
 
         return request
-        
-    # -- 
-    
+
+    # --
+
     def email_exception(self, reporter):
         subject = "Piston crash report"
         html = reporter.get_traceback_html()
@@ -255,6 +255,6 @@ class Resource(object):
         message = EmailMessage(settings.EMAIL_SUBJECT_PREFIX+subject,
                                 html, settings.SERVER_EMAIL,
                                 [ admin[1] for admin in settings.ADMINS ])
-        
+
         message.content_subtype = 'html'
         message.send(fail_silently=True)
index 133be13..a302d1b 100644 (file)
@@ -1,5 +1,5 @@
 # Django imports
-import django.dispatch 
+import django.dispatch
 
 # Piston imports
 from utils import send_consumer_mail
index 787791a..13377d6 100644 (file)
@@ -23,7 +23,7 @@ class DataStore(oauth.OAuthDataStore):
         elif token_type == 'access':
             token_type = Token.ACCESS
         try:
-            self.request_token = Token.objects.get(key=token, 
+            self.request_token = Token.objects.get(key=token,
                                                    token_type=token_type)
             return self.request_token
         except Token.DoesNotExist:
@@ -32,7 +32,7 @@ class DataStore(oauth.OAuthDataStore):
     def lookup_nonce(self, oauth_consumer, oauth_token, nonce):
         if oauth_token is None:
             return None
-        nonce, created = Nonce.objects.get_or_create(consumer_key=oauth_consumer.key, 
+        nonce, created = Nonce.objects.get_or_create(consumer_key=oauth_consumer.key,
                                                      token_key=oauth_token.key,
                                                      key=nonce)
         if created:
@@ -45,10 +45,10 @@ class DataStore(oauth.OAuthDataStore):
             self.request_token = Token.objects.create_token(consumer=self.consumer,
                                                             token_type=Token.REQUEST,
                                                             timestamp=self.timestamp)
-            
+
             if oauth_callback:
                 self.request_token.set_callback(oauth_callback)
-            
+
             return self.request_token
         return None
 
index d7b1830..8fdfb8f 100644 (file)
        </head>
        <body>
                <h1>API Documentation</h1>
-               
+
                {% for doc in docs %}
-               
+
                        <h3>{{ doc.name|cut:"Handler" }}:</h3>
 
                        <p>
                                {{ doc.get_doc|default:""|restructuredtext }}
                        </p>
-                       
+
                        <p>
                                URL: <b>{{ doc.get_resource_uri_template }}</b>
                        </p>
-                       
+
                        <p>
                                Accepted methods: {% for meth in doc.allowed_methods %}<b>{{ meth }}</b>{% if not forloop.last %}, {% endif %}{% endfor %}
                        </p>
-                                       
+
                        <dl>
                                {% for method in doc.get_all_methods %}
-                               
+
                                        <dt>
                                                method <i>{{ method.name }}</i>({{ method.signature }}){% if method.stale %} <i>- inherited</i>{% else %}:{% endif %}
-                                               
-                                       </dt>                           
-                                                                               
+
+                                       </dt>
+
                                        {% if method.get_doc %}
                                                <dd>
                                                        {{ method.get_doc|default:""|restructuredtext }}
                                                <dd>
                                        {% endif %}
-                               
+
                                {% endfor %}
                        </dl>
-               
+
                {% endfor %}
        </body>
 </html>
index dae840e..59c09e3 100644 (file)
@@ -6,7 +6,7 @@
        </head>
        <body>
                <h1>Authorize Token</h1>
-               
+
         <form action="{% url piston.authentication.oauth_user_auth %}" method="POST">
             {{ form.as_table }}
         </form>
index 57eda72..f19fb21 100644 (file)
@@ -32,8 +32,8 @@ class OAuthClient(client.Client):
         url = "http://testserver" + request['PATH_INFO']
 
         req = oauth.OAuthRequest.from_consumer_and_token(
-            self.consumer, token=self.token, 
-            http_method=request['REQUEST_METHOD'], http_url=url, 
+            self.consumer, token=self.token,
+            http_method=request['REQUEST_METHOD'], http_url=url,
             parameters=params
         )
 
@@ -49,7 +49,7 @@ class OAuthClient(client.Client):
 
         if isinstance(data, dict):
             data = urlencode(data)
-        
+
         return super(OAuthClient, self).post(path, data, content_type, follow, **extra)
 
 class TestCase(test.TestCase):
index 92d14ee..99f7028 100644 (file)
@@ -19,7 +19,7 @@ class ConsumerTest(TestCase):
 
     def test_create_pending(self):
         """ Ensure creating a pending Consumer sends proper emails """
-        # If it's pending we should have two messages in the outbox; one 
+        # If it's pending we should have two messages in the outbox; one
         # to the consumer and one to the site admins.
         if len(settings.ADMINS):
             self.assertEquals(len(mail.outbox), 2)
@@ -36,8 +36,8 @@ class ConsumerTest(TestCase):
         mail.outbox = []
 
         # Delete the consumer, which should fire off the cancel email.
-        self.consumer.delete() 
-        
+        self.consumer.delete()
+
         self.assertEquals(len(mail.outbox), 1)
         expected = "Your API Consumer for example.com has been canceled."
         self.assertEquals(mail.outbox[0].subject, expected)
index 8d0cce8..9128cbc 100644 (file)
@@ -39,7 +39,7 @@ class rc_factory(object):
 
     def __getattr__(self, attr):
         """
-        Returns a fresh `HttpResponse` when getting 
+        Returns a fresh `HttpResponse` when getting
         an "attribute". This is backwards compatible
         with 0.2, which is important.
         """
@@ -49,9 +49,9 @@ class rc_factory(object):
             raise AttributeError(attr)
 
         return HttpResponse(r, content_type='text/plain', status=c)
-    
+
 rc = rc_factory()
-    
+
 class FormValidationError(Exception):
     def __init__(self, form):
         self.form = form
@@ -64,7 +64,7 @@ def validate(v_form, operation='POST'):
     @decorator
     def wrap(f, self, request, *a, **kwa):
         form = v_form(getattr(request, operation))
-    
+
         if form.is_valid():
             return f(self, request, *a, **kwa)
         else:
@@ -75,11 +75,11 @@ def throttle(max_requests, timeout=60*60, extra=''):
     """
     Simple throttling decorator, caches
     the amount of requests made in cache.
-    
+
     If used on a view where users are required to
     log in, the username is used, otherwise the
     IP address of the originating request is used.
-    
+
     Parameters::
      - `max_requests`: The maximum number of requests
      - `timeout`: The timeout for the cache entry (default: 1 hour)
@@ -90,7 +90,7 @@ def throttle(max_requests, timeout=60*60, extra=''):
             ident = request.user.username
         else:
             ident = request.META.get('REMOTE_ADDR', None)
-    
+
         if hasattr(request, 'throttle_extra'):
             """
             Since we want to be able to throttle on a per-
@@ -99,7 +99,7 @@ def throttle(max_requests, timeout=60*60, extra=''):
             object. If so, append the identifier name with it.
             """
             ident += ':%s' % str(request.throttle_extra)
-        
+
         if ident:
             """
             Preferrably we'd use incr/decr here, since they're
@@ -108,7 +108,7 @@ def throttle(max_requests, timeout=60*60, extra=''):
             stable, you can change it here.
             """
             ident += ':%s' % extra
-    
+
             now = time.time()
             count, expiration = cache.get(ident, (1, None))
 
@@ -123,7 +123,7 @@ def throttle(max_requests, timeout=60*60, extra=''):
                 return t
 
             cache.set(ident, (count+1, expiration), (expiration - now))
-    
+
         return f(self, request, *args, **kwargs)
     return wrap
 
@@ -133,7 +133,7 @@ def coerce_put_post(request):
     In case we send data over PUT, Django won't
     actually look at the data and load it. We need
     to twist its arm here.
-    
+
     The try/except abominiation here is due to a bug
     in mod_python. This should fix it.
     """
@@ -146,7 +146,7 @@ def coerce_put_post(request):
             request.META['REQUEST_METHOD'] = 'POST'
             request._load_post_and_files()
             request.META['REQUEST_METHOD'] = 'PUT'
-            
+
         request.PUT = request.POST
 
 
@@ -158,10 +158,10 @@ class MimerDataException(Exception):
 
 class Mimer(object):
     TYPES = dict()
-    
+
     def __init__(self, request):
         self.request = request
-        
+
     def is_multipart(self):
         content_type = self.content_type()
 
@@ -179,7 +179,7 @@ class Mimer(object):
             for mime in mimes:
                 if ctype.startswith(mime):
                     return loadee
-                    
+
     def content_type(self):
         """
         Returns the content type of the request in all cases where it is
@@ -188,10 +188,10 @@ class Mimer(object):
         type_formencoded = "application/x-www-form-urlencoded"
 
         ctype = self.request.META.get('CONTENT_TYPE', type_formencoded)
-        
+
         if type_formencoded in ctype:
             return None
-        
+
         return ctype
 
     def translate(self):
@@ -202,21 +202,21 @@ class Mimer(object):
         key-value (and maybe just a list), the data will be placed on
         `request.data` instead, and the handler will have to read from
         there.
-        
+
         It will also set `request.content_type` so the handler has an easy
         way to tell what's going on. `request.content_type` will always be
         None for form-encoded and/or multipart form data (what your browser sends.)
-        """    
+        """
         ctype = self.content_type()
         self.request.content_type = ctype
-        
+
         if not self.is_multipart() and ctype:
             loadee = self.loader_for_type(ctype)
-            
+
             if loadee:
                 try:
                     self.request.data = loadee(self.request.raw_post_data)
-                        
+
                     # Reset both POST and PUT from request, as its
                     # misleading having their presence around.
                     self.request.POST = self.request.PUT = dict()
@@ -227,18 +227,18 @@ class Mimer(object):
                 self.request.data = None
 
         return self.request
-                
+
     @classmethod
     def register(cls, loadee, types):
         cls.TYPES[loadee] = types
-        
+
     @classmethod
     def unregister(cls, loadee):
         return cls.TYPES.pop(loadee)
 
 def translate_mime(request):
     request = Mimer(request).translate()
-    
+
 def require_mime(*mimes):
     """
     Decorator requiring a certain mimetype. There's a nifty
@@ -265,7 +265,7 @@ def require_mime(*mimes):
     return wrap
 
 require_extended = require_mime('json', 'yaml', 'xml', 'pickle')
-    
+
 def send_consumer_mail(consumer):
     """
     Send a consumer an email depending on what their status is.
@@ -280,20 +280,20 @@ def send_consumer_mail(consumer):
             subject += "has been canceled."
         elif consumer.status == "rejected":
             subject += "has been rejected."
-        else: 
+        else:
             subject += "is awaiting approval."
 
-    template = "piston/mails/consumer_%s.txt" % consumer.status    
-    
+    template = "piston/mails/consumer_%s.txt" % consumer.status
+
     try:
-        body = loader.render_to_string(template, 
+        body = loader.render_to_string(template,
             { 'consumer' : consumer, 'user' : consumer.user })
     except TemplateDoesNotExist:
-        """ 
+        """
         They haven't set up the templates, which means they might not want
         these emails sent.
         """
-        return 
+        return
 
     try:
         sender = settings.PISTON_FROM_EMAIL
diff --git a/apps/sorl/__init__.py b/apps/sorl/__init__.py
deleted file mode 100755 (executable)
index e69de29..0000000
diff --git a/apps/sorl/thumbnail/__init__.py b/apps/sorl/thumbnail/__init__.py
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/apps/sorl/thumbnail/base.py b/apps/sorl/thumbnail/base.py
deleted file mode 100755 (executable)
index 24f4d97..0000000
+++ /dev/null
@@ -1,285 +0,0 @@
-import os
-from os.path import isfile, isdir, getmtime, dirname, splitext, getsize
-from tempfile import mkstemp
-from shutil import copyfile
-
-from PIL import Image
-
-from sorl.thumbnail import defaults
-from sorl.thumbnail.processors import get_valid_options, dynamic_import
-
-
-class ThumbnailException(Exception):
-    # Stop Django templates from choking if something goes wrong.
-    silent_variable_failure = True
-
-
-class Thumbnail(object):
-    imagemagick_file_types = defaults.IMAGEMAGICK_FILE_TYPES
-
-    def __init__(self, source, requested_size, opts=None, quality=85,
-                 dest=None, convert_path=defaults.CONVERT,
-                 wvps_path=defaults.WVPS, processors=None):
-        # Paths to external commands
-        self.convert_path = convert_path
-        self.wvps_path = wvps_path
-        # Absolute paths to files
-        self.source = source
-        self.dest = dest
-
-        # Thumbnail settings
-        try:
-            x, y = [int(v) for v in requested_size]
-        except (TypeError, ValueError):
-            raise TypeError('Thumbnail received invalid value for size '
-                            'argument: %s' % repr(requested_size))
-        else:
-            self.requested_size = (x, y)
-        try:
-            self.quality = int(quality)
-            if not 0 < quality <= 100:
-                raise ValueError
-        except (TypeError, ValueError):
-            raise TypeError('Thumbnail received invalid value for quality '
-                            'argument: %r' % quality)
-
-        # Processors
-        if processors is None:
-            processors = dynamic_import(defaults.PROCESSORS)
-        self.processors = processors
-
-        # Handle old list format for opts.
-        opts = opts or {}
-        if isinstance(opts, (list, tuple)):
-            opts = dict([(opt, None) for opt in opts])
-
-        # Set Thumbnail opt(ion)s
-        VALID_OPTIONS = get_valid_options(processors)
-        for opt in opts:
-            if not opt in VALID_OPTIONS:
-                raise TypeError('Thumbnail received an invalid option: %s'
-                                % opt)
-        self.opts = opts
-
-        if self.dest is not None:
-            self.generate()
-
-    def generate(self):
-        """
-        Generates the thumbnail if it doesn't exist or if the file date of the
-        source file is newer than that of the thumbnail.
-        """
-        # Ensure dest(ination) attribute is set
-        if not self.dest:
-            raise ThumbnailException("No destination filename set.")
-
-        if not isinstance(self.dest, basestring):
-            # We'll assume dest is a file-like instance if it exists but isn't
-            # a string.
-            self._do_generate()
-        elif not isfile(self.dest) or (self.source_exists and
-            getmtime(self.source) > getmtime(self.dest)):
-
-            # Ensure the directory exists
-            directory = dirname(self.dest)
-            if directory and not isdir(directory):
-                os.makedirs(directory)
-
-            self._do_generate()
-
-    def _check_source_exists(self):
-        """
-        Ensure the source file exists. If source is not a string then it is
-        assumed to be a file-like instance which "exists".
-        """
-        if not hasattr(self, '_source_exists'):
-            self._source_exists = (self.source and
-                                   (not isinstance(self.source, basestring) or
-                                    isfile(self.source)))
-        return self._source_exists
-    source_exists = property(_check_source_exists)
-
-    def _get_source_filetype(self):
-        """
-        Set the source filetype. First it tries to use magic and
-        if import error it will just use the extension
-        """
-        if not hasattr(self, '_source_filetype'):
-            if not isinstance(self.source, basestring):
-                # Assuming a file-like object - we won't know it's type.
-                return None
-            try:
-                import magic
-            except ImportError:
-                self._source_filetype = splitext(self.source)[1].lower().\
-                   replace('.', '').replace('jpeg', 'jpg')
-            else:
-                m = magic.open(magic.MAGIC_NONE)
-                m.load()
-                ftype = m.file(self.source)
-                if ftype.find('Microsoft Office Document') != -1:
-                    self._source_filetype = 'doc'
-                elif ftype.find('PDF document') != -1:
-                    self._source_filetype = 'pdf'
-                elif ftype.find('JPEG') != -1:
-                    self._source_filetype = 'jpg'
-                else:
-                    self._source_filetype = ftype
-        return self._source_filetype
-    source_filetype = property(_get_source_filetype)
-
-    # data property is the image data of the (generated) thumbnail
-    def _get_data(self):
-        if not hasattr(self, '_data'):
-            try:
-                self._data = Image.open(self.dest)
-            except IOError, detail:
-                raise ThumbnailException(detail)
-        return self._data
-
-    def _set_data(self, im):
-        self._data = im
-    data = property(_get_data, _set_data)
-
-    # source_data property is the image data from the source file
-    def _get_source_data(self):
-        if not hasattr(self, '_source_data'):
-            if not self.source_exists:
-                raise ThumbnailException("Source file: '%s' does not exist." %
-                                         self.source)
-            if self.source_filetype == 'doc':
-                self._convert_wvps(self.source)
-            elif self.source_filetype in self.imagemagick_file_types:
-                self._convert_imagemagick(self.source)
-            else:
-                self.source_data = self.source
-        return self._source_data
-
-    def _set_source_data(self, image):
-        if isinstance(image, Image.Image):
-            self._source_data = image
-        else:
-            try:
-                self._source_data = Image.open(image)
-            except IOError, detail:
-                raise ThumbnailException("%s: %s" % (detail, image))
-            except MemoryError:
-                raise ThumbnailException("Memory Error: %s" % image)
-    source_data = property(_get_source_data, _set_source_data)
-
-    def _convert_wvps(self, filename):
-        try:
-            import subprocess
-        except ImportError:
-            raise ThumbnailException('wvps requires the Python 2.4 subprocess '
-                                     'package.')
-        tmp = mkstemp('.ps')[1]
-        try:
-            p = subprocess.Popen((self.wvps_path, filename, tmp),
-                                 stdout=subprocess.PIPE)
-            p.wait()
-        except OSError, detail:
-            os.remove(tmp)
-            raise ThumbnailException('wvPS error: %s' % detail)
-        self._convert_imagemagick(tmp)
-        os.remove(tmp)
-
-    def _convert_imagemagick(self, filename):
-        try:
-            import subprocess
-        except ImportError:
-            raise ThumbnailException('imagemagick requires the Python 2.4 '
-                                     'subprocess package.')
-        tmp = mkstemp('.png')[1]
-        if 'crop' in self.opts or 'autocrop' in self.opts:
-            x, y = [d * 3 for d in self.requested_size]
-        else:
-            x, y = self.requested_size
-        try:
-            p = subprocess.Popen((self.convert_path, '-size', '%sx%s' % (x, y),
-                '-antialias', '-colorspace', 'rgb', '-format', 'PNG24',
-                '%s[0]' % filename, tmp), stdout=subprocess.PIPE)
-            p.wait()
-        except OSError, detail:
-            os.remove(tmp)
-            raise ThumbnailException('ImageMagick error: %s' % detail)
-        self.source_data = tmp
-        os.remove(tmp)
-
-    def _do_generate(self):
-        """
-        Generates the thumbnail image.
-
-        This a semi-private method so it isn't directly available to template
-        authors if this object is passed to the template context.
-        """
-        im = self.source_data
-
-        for processor in self.processors:
-            im = processor(im, self.requested_size, self.opts)
-
-        self.data = im
-
-        filelike = not isinstance(self.dest, basestring)
-        if not filelike:
-            dest_extension = os.path.splitext(self.dest)[1][1:]
-            format = None
-        else:
-            dest_extension = None
-            format = 'JPEG'
-        if (self.source_filetype and self.source_filetype == dest_extension and
-                self.source_data == self.data):
-            copyfile(self.source, self.dest)
-        else:
-            try:
-                im.save(self.dest, format=format, quality=self.quality,
-                        optimize=1)
-            except IOError:
-                # Try again, without optimization (PIL can't optimize an image
-                # larger than ImageFile.MAXBLOCK, which is 64k by default)
-                try:
-                    im.save(self.dest, format=format, quality=self.quality)
-                except IOError, detail:
-                    raise ThumbnailException(detail)
-
-        if filelike:
-            self.dest.seek(0)
-
-    # Some helpful methods
-
-    def _dimension(self, axis):
-        if self.dest is None:
-            return None
-        return self.data.size[axis]
-
-    def width(self):
-        return self._dimension(0)
-
-    def height(self):
-        return self._dimension(1)
-
-    def _get_filesize(self):
-        if self.dest is None:
-            return None
-        if not hasattr(self, '_filesize'):
-            self._filesize = getsize(self.dest)
-        return self._filesize
-    filesize = property(_get_filesize)
-
-    def _source_dimension(self, axis):
-        if self.source_filetype in ['pdf', 'doc']:
-            return None
-        else:
-            return self.source_data.size[axis]
-
-    def source_width(self):
-        return self._source_dimension(0)
-
-    def source_height(self):
-        return self._source_dimension(1)
-
-    def _get_source_filesize(self):
-        if not hasattr(self, '_source_filesize'):
-            self._source_filesize = getsize(self.source)
-        return self._source_filesize
-    source_filesize = property(_get_source_filesize)
diff --git a/apps/sorl/thumbnail/defaults.py b/apps/sorl/thumbnail/defaults.py
deleted file mode 100644 (file)
index b4ae142..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-DEBUG = False
-BASEDIR = ''
-SUBDIR = ''
-PREFIX = ''
-QUALITY = 85
-CONVERT = '/usr/bin/convert'
-WVPS = '/usr/bin/wvPS'
-EXTENSION = 'jpg'
-PROCESSORS = (
-    'sorl.thumbnail.processors.colorspace',
-    'sorl.thumbnail.processors.autocrop',
-    'sorl.thumbnail.processors.scale_and_crop',
-    'sorl.thumbnail.processors.filters',
-)
-IMAGEMAGICK_FILE_TYPES = ('eps', 'pdf', 'psd')
diff --git a/apps/sorl/thumbnail/fields.py b/apps/sorl/thumbnail/fields.py
deleted file mode 100644 (file)
index 1b52743..0000000
+++ /dev/null
@@ -1,228 +0,0 @@
-from UserDict import DictMixin
-try:
-    from cStringIO import StringIO
-except ImportError:
-    from StringIO import StringIO
-
-from django.db.models.fields.files import ImageField, ImageFieldFile
-from django.core.files.base import ContentFile
-from django.utils.safestring import mark_safe
-from django.utils.html import escape
-
-from sorl.thumbnail.base import Thumbnail
-from sorl.thumbnail.main import DjangoThumbnail, build_thumbnail_name
-from sorl.thumbnail.utils import delete_thumbnails
-
-
-REQUIRED_ARGS = ('size',)
-ALL_ARGS = {
-    'size': 'requested_size',
-    'options': 'opts',
-    'quality': 'quality',
-    'basedir': 'basedir',
-    'subdir': 'subdir',
-    'prefix': 'prefix',
-    'extension': 'extension',
-}
-BASE_ARGS = {
-    'size': 'requested_size',
-    'options': 'opts',
-    'quality': 'quality',
-}
-TAG_HTML = '<img src="%(src)s" width="%(width)s" height="%(height)s" alt="" />'
-
-
-class ThumbsDict(object, DictMixin):
-    def __init__(self, descriptor):
-        super(ThumbsDict, self).__init__()
-        self.descriptor = descriptor
-
-    def keys(self):
-        return self.descriptor.field.extra_thumbnails.keys()
-
-
-class LazyThumbs(ThumbsDict):
-    def __init__(self, *args, **kwargs):
-        super(LazyThumbs, self).__init__(*args, **kwargs)
-        self.cached = {}
-
-    def __getitem__(self, key):
-        thumb = self.cached.get(key)
-        if not thumb:
-            args = self.descriptor.field.extra_thumbnails[key]
-            thumb = self.descriptor._build_thumbnail(args)
-            self.cached[key] = thumb
-        return thumb
-
-    def keys(self):
-        return self.descriptor.field.extra_thumbnails.keys()
-
-
-class ThumbTags(ThumbsDict):
-    def __getitem__(self, key):
-        thumb = self.descriptor.extra_thumbnails[key]
-        return self.descriptor._build_thumbnail_tag(thumb)
-
-
-class BaseThumbnailFieldFile(ImageFieldFile):
-    def _build_thumbnail(self, args):
-        # Build the DjangoThumbnail kwargs.
-        kwargs = {}
-        for k, v in args.items():
-            kwargs[ALL_ARGS[k]] = v
-        # Build the destination filename and return the thumbnail.
-        name_kwargs = {}
-        for key in ['size', 'options', 'quality', 'basedir', 'subdir',
-                    'prefix', 'extension']:
-            name_kwargs[key] = args.get(key)
-        source = getattr(self.instance, self.field.name)
-        dest = build_thumbnail_name(source.name, **name_kwargs)
-        return DjangoThumbnail(source, relative_dest=dest, **kwargs)
-
-    def _build_thumbnail_tag(self, thumb):
-        opts = dict(src=escape(thumb), width=thumb.width(),
-                    height=thumb.height())
-        return mark_safe(self.field.thumbnail_tag % opts)
-
-    def _get_extra_thumbnails(self):
-        if self.field.extra_thumbnails is None:
-            return None
-        if not hasattr(self, '_extra_thumbnails'):
-            self._extra_thumbnails = LazyThumbs(self)
-        return self._extra_thumbnails
-    extra_thumbnails = property(_get_extra_thumbnails)
-
-    def _get_extra_thumbnails_tag(self):
-        if self.field.extra_thumbnails is None:
-            return None
-        return ThumbTags(self)
-    extra_thumbnails_tag = property(_get_extra_thumbnails_tag)
-
-    def save(self, *args, **kwargs):
-        # Optionally generate the thumbnails after the image is saved.
-        super(BaseThumbnailFieldFile, self).save(*args, **kwargs)
-        if self.field.generate_on_save:
-            self.generate_thumbnails()
-
-    def delete(self, *args, **kwargs):
-        # Delete any thumbnails too (and not just ones defined here in case
-        # the {% thumbnail %} tag was used or the thumbnail sizes changed).
-        relative_source_path = getattr(self.instance, self.field.name).name
-        delete_thumbnails(relative_source_path)
-        super(BaseThumbnailFieldFile, self).delete(*args, **kwargs)
-
-    def generate_thumbnails(self):
-        # Getting the thumbs generates them.
-        if self.extra_thumbnails:
-            self.extra_thumbnails.values()
-
-
-class ImageWithThumbnailsFieldFile(BaseThumbnailFieldFile):
-    def _get_thumbnail(self):
-        return self._build_thumbnail(self.field.thumbnail)
-    thumbnail = property(_get_thumbnail)
-
-    def _get_thumbnail_tag(self):
-        return self._build_thumbnail_tag(self.thumbnail)
-    thumbnail_tag = property(_get_thumbnail_tag)
-
-    def generate_thumbnails(self, *args, **kwargs):
-        self.thumbnail.generate()
-        Super = super(ImageWithThumbnailsFieldFile, self)
-        return Super.generate_thumbnails(*args, **kwargs)
-
-
-class ThumbnailFieldFile(BaseThumbnailFieldFile):
-    def save(self, name, content, *args, **kwargs):
-        new_content = StringIO()
-        # Build the Thumbnail kwargs.
-        thumbnail_kwargs = {}
-        for k, argk in BASE_ARGS.items():
-            if not k in self.field.thumbnail:
-                continue
-            thumbnail_kwargs[argk] = self.field.thumbnail[k]
-        Thumbnail(source=content, dest=new_content, **thumbnail_kwargs)
-        new_content = ContentFile(new_content.read())
-        super(ThumbnailFieldFile, self).save(name, new_content, *args,
-                                             **kwargs)
-
-    def _get_thumbnail_tag(self):
-        opts = dict(src=escape(self.url), width=self.width,
-                    height=self.height)
-        return mark_safe(self.field.thumbnail_tag % opts)
-    thumbnail_tag = property(_get_thumbnail_tag)
-
-
-class BaseThumbnailField(ImageField):
-    def __init__(self, *args, **kwargs):
-        # The new arguments for this field aren't explicitly defined so that
-        # users can still use normal ImageField positional arguments.
-        self.extra_thumbnails = kwargs.pop('extra_thumbnails', None)
-        self.thumbnail_tag = kwargs.pop('thumbnail_tag', TAG_HTML)
-        self.generate_on_save = kwargs.pop('generate_on_save', False)
-
-        super(BaseThumbnailField, self).__init__(*args, **kwargs)
-        _verify_thumbnail_attrs(self.thumbnail)
-        if self.extra_thumbnails:
-            for extra, attrs in self.extra_thumbnails.items():
-                name = "%r of 'extra_thumbnails'"
-                _verify_thumbnail_attrs(attrs, name)
-
-    def south_field_triple(self):
-        """
-        Return a suitable description of this field for South.
-        """
-        # We'll just introspect ourselves, since we inherit.
-        from south.modelsinspector import introspector
-        field_class = "django.db.models.fields.files.ImageField"
-        args, kwargs = introspector(self)
-        # That's our definition!
-        return (field_class, args, kwargs)
-
-
-class ImageWithThumbnailsField(BaseThumbnailField):
-    """
-    photo = ImageWithThumbnailsField(
-        upload_to='uploads',
-        thumbnail={'size': (80, 80), 'options': ('crop', 'upscale'),
-                   'extension': 'png'},
-        extra_thumbnails={
-            'admin': {'size': (70, 50), 'options': ('sharpen',)},
-        }
-    )
-    """
-    attr_class = ImageWithThumbnailsFieldFile
-
-    def __init__(self, *args, **kwargs):
-        self.thumbnail = kwargs.pop('thumbnail', None)
-        super(ImageWithThumbnailsField, self).__init__(*args, **kwargs)
-
-
-class ThumbnailField(BaseThumbnailField):
-    """
-    avatar = ThumbnailField(
-        upload_to='uploads',
-        size=(200, 200),
-        options=('crop',),
-        extra_thumbnails={
-            'admin': {'size': (70, 50), 'options': (crop, 'sharpen')},
-        }
-    )
-    """
-    attr_class = ThumbnailFieldFile
-
-    def __init__(self, *args, **kwargs):
-        self.thumbnail = {}
-        for attr in ALL_ARGS:
-            if attr in kwargs:
-                self.thumbnail[attr] = kwargs.pop(attr)
-        super(ThumbnailField, self).__init__(*args, **kwargs)
-
-
-def _verify_thumbnail_attrs(attrs, name="'thumbnail'"):
-    for arg in REQUIRED_ARGS:
-        if arg not in attrs:
-            raise TypeError('Required attr %r missing in %s arg' % (arg, name))
-    for attr in attrs:
-        if attr not in ALL_ARGS:
-            raise TypeError('Invalid attr %r found in %s arg' % (arg, name))
diff --git a/apps/sorl/thumbnail/main.py b/apps/sorl/thumbnail/main.py
deleted file mode 100644 (file)
index a59b64f..0000000
+++ /dev/null
@@ -1,115 +0,0 @@
-import os
-
-from django.conf import settings
-from django.utils.encoding import iri_to_uri, force_unicode
-
-from sorl.thumbnail.base import Thumbnail
-from sorl.thumbnail.processors import dynamic_import
-from sorl.thumbnail import defaults
-
-
-def get_thumbnail_setting(setting, override=None):
-    """
-    Get a thumbnail setting from Django settings module, falling back to the
-    default.
-
-    If override is not None, it will be used instead of the setting.
-    """
-    if override is not None:
-        return override
-    if hasattr(settings, 'THUMBNAIL_%s' % setting):
-        return getattr(settings, 'THUMBNAIL_%s' % setting)
-    else:
-        return getattr(defaults, setting)
-
-
-def build_thumbnail_name(source_name, size, options=None,
-                         quality=None, basedir=None, subdir=None, prefix=None,
-                         extension=None):
-    quality = get_thumbnail_setting('QUALITY', quality)
-    basedir = get_thumbnail_setting('BASEDIR', basedir)
-    subdir = get_thumbnail_setting('SUBDIR', subdir)
-    prefix = get_thumbnail_setting('PREFIX', prefix)
-    extension = get_thumbnail_setting('EXTENSION', extension)
-    path, filename = os.path.split(source_name)
-    basename, ext = os.path.splitext(filename)
-    name = '%s%s' % (basename, ext.replace(os.extsep, '_'))
-    size = '%sx%s' % tuple(size)
-
-    # Handle old list format for opts.
-    options = options or {}
-    if isinstance(options, (list, tuple)):
-        options = dict([(opt, None) for opt in options])
-
-    opts = options.items()
-    opts.sort()   # options are sorted so the filename is consistent
-    opts = ['%s_' % (v is not None and '%s-%s' % (k, v) or k)
-            for k, v in opts]
-    opts = ''.join(opts)
-    extension = extension and '.%s' % extension
-    thumbnail_filename = '%s%s_%s_%sq%s%s' % (prefix, name, size, opts,
-                                              quality, extension)
-    return os.path.join(basedir, path, subdir, thumbnail_filename)
-
-
-class DjangoThumbnail(Thumbnail):
-    imagemagick_file_types = get_thumbnail_setting('IMAGEMAGICK_FILE_TYPES')
-
-    def __init__(self, relative_source, requested_size, opts=None,
-                 quality=None, basedir=None, subdir=None, prefix=None,
-                 relative_dest=None, processors=None, extension=None):
-        relative_source = force_unicode(relative_source)
-        # Set the absolute filename for the source file
-        source = self._absolute_path(relative_source)
-
-        quality = get_thumbnail_setting('QUALITY', quality)
-        convert_path = get_thumbnail_setting('CONVERT')
-        wvps_path = get_thumbnail_setting('WVPS')
-        if processors is None:
-            processors = dynamic_import(get_thumbnail_setting('PROCESSORS'))
-
-        # Call super().__init__ now to set the opts attribute. generate() won't
-        # get called because we are not setting the dest attribute yet.
-        super(DjangoThumbnail, self).__init__(source, requested_size,
-            opts=opts, quality=quality, convert_path=convert_path,
-            wvps_path=wvps_path, processors=processors)
-
-        # Get the relative filename for the thumbnail image, then set the
-        # destination filename
-        if relative_dest is None:
-            relative_dest = \
-               self._get_relative_thumbnail(relative_source, basedir=basedir,
-                                            subdir=subdir, prefix=prefix,
-                                            extension=extension)
-        filelike = not isinstance(relative_dest, basestring)
-        if filelike:
-            self.dest = relative_dest
-        else:
-            self.dest = self._absolute_path(relative_dest)
-
-        # Call generate now that the dest attribute has been set
-        self.generate()
-
-        # Set the relative & absolute url to the thumbnail
-        if not filelike:
-            self.relative_url = \
-                iri_to_uri('/'.join(relative_dest.split(os.sep)))
-            self.absolute_url = '%s%s' % (settings.MEDIA_URL,
-                                          self.relative_url)
-
-    def _get_relative_thumbnail(self, relative_source,
-                                basedir=None, subdir=None, prefix=None,
-                                extension=None):
-        """
-        Returns the thumbnail filename including relative path.
-        """
-        return build_thumbnail_name(relative_source, self.requested_size,
-                                    self.opts, self.quality, basedir, subdir,
-                                    prefix, extension)
-
-    def _absolute_path(self, filename):
-        absolute_filename = os.path.join(settings.MEDIA_ROOT, filename)
-        return absolute_filename.encode(settings.FILE_CHARSET)
-
-    def __unicode__(self):
-        return self.absolute_url
diff --git a/apps/sorl/thumbnail/management/__init__.py b/apps/sorl/thumbnail/management/__init__.py
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/apps/sorl/thumbnail/management/commands/__init__.py b/apps/sorl/thumbnail/management/commands/__init__.py
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/apps/sorl/thumbnail/management/commands/thumbnail_cleanup.py b/apps/sorl/thumbnail/management/commands/thumbnail_cleanup.py
deleted file mode 100644 (file)
index 690c42c..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-import os
-import re
-from django.db import models
-from django.conf import settings
-from django.core.management.base import NoArgsCommand
-from sorl.thumbnail.main import get_thumbnail_setting
-
-
-try:
-    set
-except NameError:
-    from sets import Set as set     # For Python 2.3
-
-thumb_re = re.compile(r'^%s(.*)_\d{1,}x\d{1,}_[-\w]*q([1-9]\d?|100)\.jpg' %
-                      get_thumbnail_setting('PREFIX'))
-
-
-def get_thumbnail_path(path):
-    basedir = get_thumbnail_setting('BASEDIR')
-    subdir = get_thumbnail_setting('SUBDIR')
-    return os.path.join(basedir, path, subdir)
-
-
-def clean_up():
-    paths = set()
-    for app in models.get_apps():
-        model_list = models.get_models(app)
-        for model in model_list:
-            for field in model._meta.fields:
-                if isinstance(field, models.ImageField):
-                    #TODO: take care of date formatted and callable upload_to.
-                    if (not callable(field.upload_to) and
-                            field.upload_to.find("%") == -1):
-                        paths = paths.union((field.upload_to,))
-    paths = list(paths)
-    for path in paths:
-        thumbnail_path = get_thumbnail_path(path)
-        try:
-            file_list = os.listdir(os.path.join(settings.MEDIA_ROOT,
-                                                thumbnail_path))
-        except OSError:
-            continue # Dir doesn't exists, no thumbnails here.
-        for fn in file_list:
-            m = thumb_re.match(fn)
-            if m:
-                # Due to that the naming of thumbnails replaces the dot before
-                # extension with an underscore we have 2 possibilities for the
-                # original filename. If either present we do not delete
-                # suspected thumbnail.
-                # org_fn is the expected original filename w/o extension
-                # org_fn_alt is the expected original filename with extension
-                org_fn = m.group(1)
-                org_fn_exists = os.path.isfile(
-                            os.path.join(settings.MEDIA_ROOT, path, org_fn))
-
-                usc_pos = org_fn.rfind("_")
-                if usc_pos != -1:
-                    org_fn_alt = "%s.%s" % (org_fn[0:usc_pos],
-                                            org_fn[usc_pos+1:])
-                    org_fn_alt_exists = os.path.isfile(
-                        os.path.join(settings.MEDIA_ROOT, path, org_fn_alt))
-                else:
-                    org_fn_alt_exists = False
-                if not org_fn_exists and not org_fn_alt_exists:
-                    del_me = os.path.join(settings.MEDIA_ROOT,
-                                          thumbnail_path, fn)
-                    os.remove(del_me)
-
-
-class Command(NoArgsCommand):
-    help = "Deletes thumbnails that no longer have an original file."
-    requires_model_validation = False
-
-    def handle_noargs(self, **options):
-        clean_up()
diff --git a/apps/sorl/thumbnail/models.py b/apps/sorl/thumbnail/models.py
deleted file mode 100644 (file)
index ec325fd..0000000
+++ /dev/null
@@ -1 +0,0 @@
-# Needs a models.py file so that tests are picked up.
diff --git a/apps/sorl/thumbnail/processors.py b/apps/sorl/thumbnail/processors.py
deleted file mode 100644 (file)
index a6c1741..0000000
+++ /dev/null
@@ -1,130 +0,0 @@
-from PIL import Image, ImageFilter, ImageChops
-from sorl.thumbnail import utils
-import re
-
-
-def dynamic_import(names):
-    imported = []
-    for name in names:
-        # Use rfind rather than rsplit for Python 2.3 compatibility.
-        lastdot = name.rfind('.')
-        modname, attrname = name[:lastdot], name[lastdot + 1:]
-        mod = __import__(modname, {}, {}, [''])
-        imported.append(getattr(mod, attrname))
-    return imported
-
-
-def get_valid_options(processors):
-    """
-    Returns a list containing unique valid options from a list of processors
-    in correct order.
-    """
-    valid_options = []
-    for processor in processors:
-        if hasattr(processor, 'valid_options'):
-            valid_options.extend([opt for opt in processor.valid_options
-                                  if opt not in valid_options])
-    return valid_options
-
-
-def colorspace(im, requested_size, opts):
-    if 'bw' in opts and im.mode != "L":
-        im = im.convert("L")
-    elif im.mode not in ("L", "RGB", "RGBA"):
-        im = im.convert("RGB")
-    return im
-colorspace.valid_options = ('bw',)
-
-
-def autocrop(im, requested_size, opts):
-    if 'autocrop' in opts:
-        bw = im.convert("1")
-        bw = bw.filter(ImageFilter.MedianFilter)
-        # white bg
-        bg = Image.new("1", im.size, 255)
-        diff = ImageChops.difference(bw, bg)
-        bbox = diff.getbbox()
-        if bbox:
-            im = im.crop(bbox)
-    return im
-autocrop.valid_options = ('autocrop',)
-
-
-def scale_and_crop(im, requested_size, opts):
-    x, y = [float(v) for v in im.size]
-    xr, yr = [float(v) for v in requested_size]
-
-    if 'crop' in opts or 'max' in opts:
-        r = max(xr / x, yr / y)
-    else:
-        r = min(xr / x, yr / y)
-
-    if r < 1.0 or (r > 1.0 and 'upscale' in opts):
-        im = im.resize((int(x * r), int(y * r)), resample=Image.ANTIALIAS)
-
-    crop = opts.get('crop') or 'crop' in opts
-    if crop:
-        # Difference (for x and y) between new image size and requested size.
-        x, y = [float(v) for v in im.size]
-        dx, dy = (x - min(x, xr)), (y - min(y, yr))
-        if dx or dy:
-            # Center cropping (default).
-            ex, ey = dx / 2, dy / 2
-            box = [ex, ey, x - ex, y - ey]
-            # See if an edge cropping argument was provided.
-            edge_crop = (isinstance(crop, basestring) and
-                           re.match(r'(?:(-?)(\d+))?,(?:(-?)(\d+))?$', crop))
-            if edge_crop and filter(None, edge_crop.groups()):
-                x_right, x_crop, y_bottom, y_crop = edge_crop.groups()
-                if x_crop:
-                    offset = min(x * int(x_crop) / 100, dx)
-                    if x_right:
-                        box[0] = dx - offset
-                        box[2] = x - offset
-                    else:
-                        box[0] = offset
-                        box[2] = x - (dx - offset)
-                if y_crop:
-                    offset = min(y * int(y_crop) / 100, dy)
-                    if y_bottom:
-                        box[1] = dy - offset
-                        box[3] = y - offset
-                    else:
-                        box[1] = offset
-                        box[3] = y - (dy - offset)
-            # See if the image should be "smart cropped".
-            elif crop == 'smart':
-                left = top = 0
-                right, bottom = x, y
-                while dx:
-                    slice = min(dx, 10)
-                    l_sl = im.crop((0, 0, slice, y))
-                    r_sl = im.crop((x - slice, 0, x, y))
-                    if utils.image_entropy(l_sl) >= utils.image_entropy(r_sl):
-                        right -= slice
-                    else:
-                        left += slice
-                    dx -= slice
-                while dy:
-                    slice = min(dy, 10)
-                    t_sl = im.crop((0, 0, x, slice))
-                    b_sl = im.crop((0, y - slice, x, y))
-                    if utils.image_entropy(t_sl) >= utils.image_entropy(b_sl):
-                        bottom -= slice
-                    else:
-                        top += slice
-                    dy -= slice
-                box = (left, top, right, bottom)
-            # Finally, crop the image!
-            im = im.crop([int(v) for v in box])
-    return im
-scale_and_crop.valid_options = ('crop', 'upscale', 'max')
-
-
-def filters(im, requested_size, opts):
-    if 'detail' in opts:
-        im = im.filter(ImageFilter.DETAIL)
-    if 'sharpen' in opts:
-        im = im.filter(ImageFilter.SHARPEN)
-    return im
-filters.valid_options = ('detail', 'sharpen')
diff --git a/apps/sorl/thumbnail/templatetags/__init__.py b/apps/sorl/thumbnail/templatetags/__init__.py
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/apps/sorl/thumbnail/templatetags/thumbnail.py b/apps/sorl/thumbnail/templatetags/thumbnail.py
deleted file mode 100755 (executable)
index e7c2177..0000000
+++ /dev/null
@@ -1,251 +0,0 @@
-import re
-import math
-from django.template import Library, Node, VariableDoesNotExist, \
-    TemplateSyntaxError
-from sorl.thumbnail.main import DjangoThumbnail, get_thumbnail_setting
-from sorl.thumbnail.processors import dynamic_import, get_valid_options
-from sorl.thumbnail.utils import split_args
-
-register = Library()
-
-size_pat = re.compile(r'(\d+)x(\d+)$')
-
-filesize_formats = ['k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y']
-filesize_long_formats = {
-    'k': 'kilo', 'M': 'mega', 'G': 'giga', 'T': 'tera', 'P': 'peta',
-    'E': 'exa', 'Z': 'zetta', 'Y': 'yotta',
-}
-
-try:
-    PROCESSORS = dynamic_import(get_thumbnail_setting('PROCESSORS'))
-    VALID_OPTIONS = get_valid_options(PROCESSORS)
-except:
-    if get_thumbnail_setting('DEBUG'):
-        raise
-    else:
-        PROCESSORS = []
-        VALID_OPTIONS = []
-TAG_SETTINGS = ['quality']
-
-
-class ThumbnailNode(Node):
-    def __init__(self, source_var, size_var, opts=None,
-                 context_name=None, **kwargs):
-        self.source_var = source_var
-        self.size_var = size_var
-        self.opts = opts
-        self.context_name = context_name
-        self.kwargs = kwargs
-
-    def render(self, context):
-        # Note that this isn't a global constant because we need to change the
-        # value for tests.
-        DEBUG = get_thumbnail_setting('DEBUG')
-        try:
-            # A file object will be allowed in DjangoThumbnail class
-            relative_source = self.source_var.resolve(context)
-        except VariableDoesNotExist:
-            if DEBUG:
-                raise VariableDoesNotExist("Variable '%s' does not exist." %
-                        self.source_var)
-            else:
-                relative_source = None
-        try:
-            requested_size = self.size_var.resolve(context)
-        except VariableDoesNotExist:
-            if DEBUG:
-                raise TemplateSyntaxError("Size argument '%s' is not a"
-                        " valid size nor a valid variable." % self.size_var)
-            else:
-                requested_size = None
-        # Size variable can be either a tuple/list of two integers or a valid
-        # string, only the string is checked.
-        else:
-            if isinstance(requested_size, basestring):
-                m = size_pat.match(requested_size)
-                if m:
-                    requested_size = (int(m.group(1)), int(m.group(2)))
-                elif DEBUG:
-                    raise TemplateSyntaxError("Variable '%s' was resolved but "
-                            "'%s' is not a valid size." %
-                            (self.size_var, requested_size))
-                else:
-                    requested_size = None
-        if relative_source is None or requested_size is None:
-            thumbnail = ''
-        else:
-            try:
-                kwargs = {}
-                for key, value in self.kwargs.items():
-                    kwargs[key] = value.resolve(context)
-                opts = dict([(k, v and v.resolve(context))
-                             for k, v in self.opts.items()])
-                thumbnail = DjangoThumbnail(relative_source, requested_size,
-                                opts=opts, processors=PROCESSORS, **kwargs)
-            except:
-                if DEBUG:
-                    raise
-                else:
-                    thumbnail = ''
-        # Return the thumbnail class, or put it on the context
-        if self.context_name is None:
-            return thumbnail
-        # We need to get here so we don't have old values in the context
-        # variable.
-        context[self.context_name] = thumbnail
-        return ''
-
-
-def thumbnail(parser, token):
-    """
-    Creates a thumbnail of for an ImageField.
-
-    To just output the absolute url to the thumbnail::
-
-        {% thumbnail image 80x80 %}
-
-    After the image path and dimensions, you can put any options::
-
-        {% thumbnail image 80x80 quality=95 crop %}
-
-    To put the DjangoThumbnail class on the context instead of just rendering
-    the absolute url, finish the tag with ``as [context_var_name]``::
-
-        {% thumbnail image 80x80 as thumb %}
-        {{ thumb.width }} x {{ thumb.height }}
-    """
-    args = token.split_contents()
-    tag = args[0]
-    # Check to see if we're setting to a context variable.
-    if len(args) > 4 and args[-2] == 'as':
-        context_name = args[-1]
-        args = args[:-2]
-    else:
-        context_name = None
-
-    if len(args) < 3:
-        raise TemplateSyntaxError("Invalid syntax. Expected "
-            "'{%% %s source size [option1 option2 ...] %%}' or "
-            "'{%% %s source size [option1 option2 ...] as variable %%}'" %
-            (tag, tag))
-
-    # Get the source image path and requested size.
-    source_var = parser.compile_filter(args[1])
-    # If the size argument was a correct static format, wrap it in quotes so
-    # that it is compiled correctly.
-    m = size_pat.match(args[2])
-    if m:
-        args[2] = '"%s"' % args[2]
-    size_var = parser.compile_filter(args[2])
-
-    # Get the options.
-    args_list = split_args(args[3:]).items()
-
-    # Check the options.
-    opts = {}
-    kwargs = {} # key,values here override settings and defaults
-
-    for arg, value in args_list:
-        value = value and parser.compile_filter(value)
-        if arg in TAG_SETTINGS and value is not None:
-            kwargs[str(arg)] = value
-            continue
-        if arg in VALID_OPTIONS:
-            opts[arg] = value
-        else:
-            raise TemplateSyntaxError("'%s' tag received a bad argument: "
-                                      "'%s'" % (tag, arg))
-    return ThumbnailNode(source_var, size_var, opts=opts,
-                         context_name=context_name, **kwargs)
-
-
-def filesize(bytes, format='auto1024'):
-    """
-    Returns the number of bytes in either the nearest unit or a specific unit
-    (depending on the chosen format method).
-
-    Acceptable formats are:
-
-    auto1024, auto1000
-      convert to the nearest unit, appending the abbreviated unit name to the
-      string (e.g. '2 KiB' or '2 kB').
-      auto1024 is the default format.
-    auto1024long, auto1000long
-      convert to the nearest multiple of 1024 or 1000, appending the correctly
-      pluralized unit name to the string (e.g. '2 kibibytes' or '2 kilobytes').
-    kB, MB, GB, TB, PB, EB, ZB or YB
-      convert to the exact unit (using multiples of 1000).
-    KiB, MiB, GiB, TiB, PiB, EiB, ZiB or YiB
-      convert to the exact unit (using multiples of 1024).
-
-    The auto1024 and auto1000 formats return a string, appending the correct
-    unit to the value. All other formats return the floating point value.
-
-    If an invalid format is specified, the bytes are returned unchanged.
-    """
-    format_len = len(format)
-    # Check for valid format
-    if format_len in (2, 3):
-        if format_len == 3 and format[0] == 'K':
-            format = 'k%s' % format[1:]
-        if not format[-1] == 'B' or format[0] not in filesize_formats:
-            return bytes
-        if format_len == 3 and format[1] != 'i':
-            return bytes
-    elif format not in ('auto1024', 'auto1000',
-                        'auto1024long', 'auto1000long'):
-        return bytes
-    # Check for valid bytes
-    try:
-        bytes = long(bytes)
-    except (ValueError, TypeError):
-        return bytes
-
-    # Auto multiple of 1000 or 1024
-    if format.startswith('auto'):
-        if format[4:8] == '1000':
-            base = 1000
-        else:
-            base = 1024
-        logarithm = bytes and math.log(bytes, base) or 0
-        index = min(int(logarithm) - 1, len(filesize_formats) - 1)
-        if index >= 0:
-            if base == 1000:
-                bytes = bytes and bytes / math.pow(1000, index + 1)
-            else:
-                bytes = bytes >> (10 * (index))
-                bytes = bytes and bytes / 1024.0
-            unit = filesize_formats[index]
-        else:
-            # Change the base to 1000 so the unit will just output 'B' not 'iB'
-            base = 1000
-            unit = ''
-        if bytes >= 10 or ('%.1f' % bytes).endswith('.0'):
-            bytes = '%.0f' % bytes
-        else:
-            bytes = '%.1f' % bytes
-        if format.endswith('long'):
-            unit = filesize_long_formats.get(unit, '')
-            if base == 1024 and unit:
-                unit = '%sbi' % unit[:2]
-            unit = '%sbyte%s' % (unit, bytes != '1' and 's' or '')
-        else:
-            unit = '%s%s' % (base == 1024 and unit.upper() or unit,
-                             base == 1024 and 'iB' or 'B')
-
-        return '%s %s' % (bytes, unit)
-
-    if bytes == 0:
-        return bytes
-    base = filesize_formats.index(format[0]) + 1
-    # Exact multiple of 1000
-    if format_len == 2:
-        return bytes / (1000.0 ** base)
-    # Exact multiple of 1024
-    elif format_len == 3:
-        bytes = bytes >> (10 * (base - 1))
-        return bytes / 1024.0
-
-
-register.tag(thumbnail)
-register.filter(filesize)
diff --git a/apps/sorl/thumbnail/tests/__init__.py b/apps/sorl/thumbnail/tests/__init__.py
deleted file mode 100644 (file)
index 98f1cbd..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-# For these tests to run successfully, two conditions must be met:
-# 1. MEDIA_URL and MEDIA_ROOT must be set in settings
-# 2. The user running the tests must have read/write access to MEDIA_ROOT
-
-# Unit tests:
-from sorl.thumbnail.tests.classes import ThumbnailTest, DjangoThumbnailTest
-from sorl.thumbnail.tests.templatetags import ThumbnailTagTest
-from sorl.thumbnail.tests.fields import FieldTest, \
-    ImageWithThumbnailsFieldTest, ThumbnailFieldTest
-# Doc tests:
-from sorl.thumbnail.tests.utils import utils_tests
-from sorl.thumbnail.tests.templatetags import filesize_tests
-__test__ = {
-    'utils_tests': utils_tests,
-    'filesize_tests': filesize_tests,
-}
diff --git a/apps/sorl/thumbnail/tests/base.py b/apps/sorl/thumbnail/tests/base.py
deleted file mode 100644 (file)
index 44a2fa2..0000000
+++ /dev/null
@@ -1,105 +0,0 @@
-import unittest
-import os
-from PIL import Image
-from django.conf import settings
-from sorl.thumbnail.base import Thumbnail
-
-try:
-    set
-except NameError:
-    from sets import Set as set     # For Python 2.3
-
-
-def get_default_settings():
-    from sorl.thumbnail import defaults
-    def_settings = {}
-    for key in dir(defaults):
-        if key == key.upper() and key not in ['WVPS', 'CONVERT']:
-            def_settings[key] = getattr(defaults, key)
-    return def_settings
-
-
-DEFAULT_THUMBNAIL_SETTINGS = get_default_settings()
-RELATIVE_PIC_NAME = "sorl-thumbnail-test_source.jpg"
-PIC_NAME = os.path.join(settings.MEDIA_ROOT, RELATIVE_PIC_NAME)
-THUMB_NAME = os.path.join(settings.MEDIA_ROOT, "sorl-thumbnail-test_%02d.jpg")
-PIC_SIZE = (800, 600)
-
-
-class ChangeSettings:
-    def __init__(self):
-        self.default_settings = DEFAULT_THUMBNAIL_SETTINGS.copy()
-
-    def change(self, override=None):
-        if override is not None:
-            self.default_settings.update(override)
-        for setting, default in self.default_settings.items():
-            settings_s = 'THUMBNAIL_%s' % setting
-            self_s = 'original_%s' % setting
-            if hasattr(settings, settings_s) and not hasattr(self, self_s):
-                setattr(self, self_s, getattr(settings, settings_s))
-            if hasattr(settings, settings_s) or \
-               default != DEFAULT_THUMBNAIL_SETTINGS[setting]:
-                setattr(settings, settings_s, default)
-
-    def revert(self):
-        for setting in self.default_settings:
-            settings_s = 'THUMBNAIL_%s' % setting
-            self_s = 'original_%s' % setting
-            if hasattr(self, self_s):
-                setattr(settings, settings_s, getattr(self, self_s))
-                delattr(self, self_s)
-
-
-class BaseTest(unittest.TestCase):
-    def setUp(self):
-        self.images_to_delete = set()
-        # Create the test image
-        Image.new('RGB', PIC_SIZE).save(PIC_NAME, 'JPEG')
-        self.images_to_delete.add(PIC_NAME)
-        # Change settings so we know they will be constant
-        self.change_settings = ChangeSettings()
-        self.change_settings.change()
-
-    def verify_thumbnail(self, expected_size, thumbnail=None,
-                         expected_filename=None, expected_mode=None):
-        assert thumbnail is not None or expected_filename is not None, \
-            'verify_thumbnail should be passed at least a thumbnail or an' \
-            'expected filename.'
-
-        if thumbnail is not None:
-            # Verify that the templatetag method returned a Thumbnail instance
-            self.assertTrue(isinstance(thumbnail, Thumbnail))
-            thumb_name = thumbnail.dest
-        else:
-            thumb_name = expected_filename
-
-        if isinstance(thumb_name, basestring):
-            # Verify that the thumbnail file exists
-            self.assert_(os.path.isfile(thumb_name),
-                         'Thumbnail file not found')
-
-            # Remember to delete the file
-            self.images_to_delete.add(thumb_name)
-
-            # If we got an expected_filename, check that it is right
-            if expected_filename is not None and thumbnail is not None:
-                self.assertEqual(thumbnail.dest, expected_filename)
-
-        image = Image.open(thumb_name)
-
-        # Verify the thumbnail has the expected dimensions
-        self.assertEqual(image.size, expected_size)
-
-        if expected_mode is not None:
-            self.assertEqual(image.mode, expected_mode)
-
-    def tearDown(self):
-        # Remove all the files that have been created
-        for image in self.images_to_delete:
-            try:
-                os.remove(image)
-            except:
-                pass
-        # Change settings back to original
-        self.change_settings.revert()
diff --git a/apps/sorl/thumbnail/tests/classes.py b/apps/sorl/thumbnail/tests/classes.py
deleted file mode 100644 (file)
index d15dd19..0000000
+++ /dev/null
@@ -1,175 +0,0 @@
-# -*- coding: utf-8 -*-
-import os
-import time
-from StringIO import StringIO
-
-from PIL import Image
-from django.conf import settings
-
-from sorl.thumbnail.base import Thumbnail
-from sorl.thumbnail.main import DjangoThumbnail, get_thumbnail_setting
-from sorl.thumbnail.processors import dynamic_import, get_valid_options
-from sorl.thumbnail.tests.base import BaseTest, RELATIVE_PIC_NAME, PIC_NAME,\
-    THUMB_NAME, PIC_SIZE
-
-
-class ThumbnailTest(BaseTest):
-    def testThumbnails(self):
-        # Thumbnail
-        thumb = Thumbnail(source=PIC_NAME, dest=THUMB_NAME % 1,
-                          requested_size=(240, 240))
-        self.verify_thumbnail((240, 180), thumb)
-
-        # Cropped thumbnail
-        thumb = Thumbnail(source=PIC_NAME, dest=THUMB_NAME % 2,
-                          requested_size=(240, 240), opts=['crop'])
-        self.verify_thumbnail((240, 240), thumb)
-
-        # Thumbnail with altered JPEG quality
-        thumb = Thumbnail(source=PIC_NAME, dest=THUMB_NAME % 3,
-                          requested_size=(240, 240), quality=95)
-        self.verify_thumbnail((240, 180), thumb)
-
-    def testRegeneration(self):
-        # Create thumbnail
-        thumb_name = THUMB_NAME % 4
-        thumb_size = (240, 240)
-        Thumbnail(source=PIC_NAME, dest=thumb_name, requested_size=thumb_size)
-        self.images_to_delete.add(thumb_name)
-        thumb_mtime = os.path.getmtime(thumb_name)
-        time.sleep(1)
-
-        # Create another instance, shouldn't generate a new thumb
-        Thumbnail(source=PIC_NAME, dest=thumb_name, requested_size=thumb_size)
-        self.assertEqual(os.path.getmtime(thumb_name), thumb_mtime)
-
-        # Recreate the source image, then see if a new thumb is generated
-        Image.new('RGB', PIC_SIZE).save(PIC_NAME, 'JPEG')
-        Thumbnail(source=PIC_NAME, dest=thumb_name, requested_size=thumb_size)
-        self.assertNotEqual(os.path.getmtime(thumb_name), thumb_mtime)
-
-    def testFilelikeDest(self):
-        # Thumbnail
-        filelike_dest = StringIO()
-        thumb = Thumbnail(source=PIC_NAME, dest=filelike_dest,
-                          requested_size=(240, 240))
-        self.verify_thumbnail((240, 180), thumb)
-
-    def testRGBA(self):
-        # RGBA image
-        rgba_pic_name = os.path.join(settings.MEDIA_ROOT,
-                                     'sorl-thumbnail-test_rgba_source.png')
-        Image.new('RGBA', PIC_SIZE).save(rgba_pic_name)
-        self.images_to_delete.add(rgba_pic_name)
-        # Create thumb and verify it's still RGBA
-        rgba_thumb_name = os.path.join(settings.MEDIA_ROOT,
-                                       'sorl-thumbnail-test_rgba_dest.png')
-        thumb = Thumbnail(source=rgba_pic_name, dest=rgba_thumb_name,
-                          requested_size=(240, 240))
-        self.verify_thumbnail((240, 180), thumb, expected_mode='RGBA')
-
-
-class DjangoThumbnailTest(BaseTest):
-    def setUp(self):
-        super(DjangoThumbnailTest, self).setUp()
-        # Add another source image in a sub-directory for testing subdir and
-        # basedir.
-        self.sub_dir = os.path.join(settings.MEDIA_ROOT, 'test_thumbnail')
-        try:
-            os.mkdir(self.sub_dir)
-        except OSError:
-            pass
-        self.pic_subdir = os.path.join(self.sub_dir, RELATIVE_PIC_NAME)
-        Image.new('RGB', PIC_SIZE).save(self.pic_subdir, 'JPEG')
-        self.images_to_delete.add(self.pic_subdir)
-
-    def testFilenameGeneration(self):
-        basename = RELATIVE_PIC_NAME.replace('.', '_')
-        # Basic filename
-        thumb = DjangoThumbnail(relative_source=RELATIVE_PIC_NAME,
-                                requested_size=(240, 120))
-        expected = os.path.join(settings.MEDIA_ROOT, basename)
-        expected += '_240x120_q85.jpg'
-        self.verify_thumbnail((160, 120), thumb, expected_filename=expected)
-
-        # Changed quality and cropped
-        thumb = DjangoThumbnail(relative_source=RELATIVE_PIC_NAME,
-                                requested_size=(240, 120), opts=['crop'],
-                                quality=95)
-        expected = os.path.join(settings.MEDIA_ROOT, basename)
-        expected += '_240x120_crop_q95.jpg'
-        self.verify_thumbnail((240, 120), thumb, expected_filename=expected)
-
-        # All options on
-        processors = dynamic_import(get_thumbnail_setting('PROCESSORS'))
-        valid_options = get_valid_options(processors)
-
-        thumb = DjangoThumbnail(relative_source=RELATIVE_PIC_NAME,
-                                requested_size=(240, 120), opts=valid_options)
-        expected = (os.path.join(settings.MEDIA_ROOT, basename) + '_240x120_'
-                    'autocrop_bw_crop_detail_max_sharpen_upscale_q85.jpg')
-        self.verify_thumbnail((240, 120), thumb, expected_filename=expected)
-
-        # Different basedir
-        basedir = 'sorl-thumbnail-test-basedir'
-        self.change_settings.change({'BASEDIR': basedir})
-        thumb = DjangoThumbnail(relative_source=self.pic_subdir,
-                                requested_size=(240, 120))
-        expected = os.path.join(basedir, self.sub_dir, basename)
-        expected += '_240x120_q85.jpg'
-        self.verify_thumbnail((160, 120), thumb, expected_filename=expected)
-        # Different subdir
-        self.change_settings.change({'BASEDIR': '', 'SUBDIR': 'subdir'})
-        thumb = DjangoThumbnail(relative_source=self.pic_subdir,
-                                requested_size=(240, 120))
-        expected = os.path.join(settings.MEDIA_ROOT,
-                                os.path.basename(self.sub_dir), 'subdir',
-                                basename)
-        expected += '_240x120_q85.jpg'
-        self.verify_thumbnail((160, 120), thumb, expected_filename=expected)
-        # Different prefix
-        self.change_settings.change({'SUBDIR': '', 'PREFIX': 'prefix-'})
-        thumb = DjangoThumbnail(relative_source=self.pic_subdir,
-                                requested_size=(240, 120))
-        expected = os.path.join(self.sub_dir, 'prefix-' + basename)
-        expected += '_240x120_q85.jpg'
-        self.verify_thumbnail((160, 120), thumb, expected_filename=expected)
-
-    def testAlternateExtension(self):
-        basename = RELATIVE_PIC_NAME.replace('.', '_')
-        # Control JPG
-        thumb = DjangoThumbnail(relative_source=RELATIVE_PIC_NAME,
-                                requested_size=(240, 120))
-        expected = os.path.join(settings.MEDIA_ROOT, basename)
-        expected += '_240x120_q85.jpg'
-        expected_jpg = expected
-        self.verify_thumbnail((160, 120), thumb, expected_filename=expected)
-        # Test PNG
-        thumb = DjangoThumbnail(relative_source=RELATIVE_PIC_NAME,
-                                requested_size=(240, 120), extension='png')
-        expected = os.path.join(settings.MEDIA_ROOT, basename)
-        expected += '_240x120_q85.png'
-        self.verify_thumbnail((160, 120), thumb, expected_filename=expected)
-        # Compare the file size to make sure it's not just saving as a JPG with
-        # a different extension.
-        self.assertNotEqual(os.path.getsize(expected_jpg),
-                            os.path.getsize(expected))
-
-    def testUnicodeName(self):
-        unicode_name = 'sorl-thumbnail-ążśź_source.jpg'
-        unicode_path = os.path.join(settings.MEDIA_ROOT, unicode_name)
-        Image.new('RGB', PIC_SIZE).save(unicode_path)
-        self.images_to_delete.add(unicode_path)
-        thumb = DjangoThumbnail(relative_source=unicode_name,
-                                requested_size=(240, 120))
-        base_name = unicode_name.replace('.', '_')
-        expected = os.path.join(settings.MEDIA_ROOT,
-                                base_name + '_240x120_q85.jpg')
-        self.verify_thumbnail((160, 120), thumb, expected_filename=expected)
-
-    def tearDown(self):
-        super(DjangoThumbnailTest, self).tearDown()
-        subdir = os.path.join(self.sub_dir, 'subdir')
-        if os.path.exists(subdir):
-            os.rmdir(subdir)
-        os.rmdir(self.sub_dir)
diff --git a/apps/sorl/thumbnail/tests/fields.py b/apps/sorl/thumbnail/tests/fields.py
deleted file mode 100644 (file)
index 425f555..0000000
+++ /dev/null
@@ -1,131 +0,0 @@
-import os.path
-
-from django.db import models
-from django.conf import settings
-from django.core.files.base import ContentFile
-
-from sorl.thumbnail.fields import ImageWithThumbnailsField, ThumbnailField
-from sorl.thumbnail.tests.base import BaseTest, RELATIVE_PIC_NAME, PIC_NAME
-
-thumbnail = {
-    'size': (50, 50),
-}
-extra_thumbnails = {
-    'admin': {
-        'size': (30, 30),
-        'options': ('crop',),
-    }
-}
-extension_thumbnail = thumbnail.copy()
-extension_thumbnail['extension'] = 'png'
-
-
-# Temporary models for field_tests
-class TestThumbnailFieldModel(models.Model):
-    avatar = ThumbnailField(upload_to='test', size=(300, 300))
-    photo = ImageWithThumbnailsField(upload_to='test', thumbnail=thumbnail,
-                                     extra_thumbnails=extra_thumbnails)
-
-
-class TestThumbnailFieldExtensionModel(models.Model):
-    photo = ImageWithThumbnailsField(upload_to='test',
-                                     thumbnail=extension_thumbnail,
-                                     extra_thumbnails=extra_thumbnails)
-
-
-class TestThumbnailFieldGenerateModel(models.Model):
-    photo = ImageWithThumbnailsField(upload_to='test', thumbnail=thumbnail,
-                                     extra_thumbnails=extra_thumbnails,
-                                     generate_on_save=True)
-
-
-class FieldTest(BaseTest):
-    """
-    Test the base field functionality. These use an ImageWithThumbnailsField
-    but all the functionality tested is from BaseThumbnailField.
-    """
-    def test_extra_thumbnails(self):
-        model = TestThumbnailFieldModel(photo=RELATIVE_PIC_NAME)
-        self.assertTrue('admin' in model.photo.extra_thumbnails)
-        thumb = model.photo.extra_thumbnails['admin']
-        tag = model.photo.extra_thumbnails_tag['admin']
-        expected_filename = os.path.join(settings.MEDIA_ROOT,
-            'sorl-thumbnail-test_source_jpg_30x30_crop_q85.jpg')
-        self.verify_thumbnail((30, 30), thumb, expected_filename)
-        expected_tag = '<img src="%s" width="30" height="30" alt="" />' % \
-            '/'.join((settings.MEDIA_URL.rstrip('/'),
-                      'sorl-thumbnail-test_source_jpg_30x30_crop_q85.jpg'))
-        self.assertEqual(tag, expected_tag)
-
-    def test_extension(self):
-        model = TestThumbnailFieldExtensionModel(photo=RELATIVE_PIC_NAME)
-        thumb = model.photo.thumbnail
-        tag = model.photo.thumbnail_tag
-        expected_filename = os.path.join(settings.MEDIA_ROOT,
-            'sorl-thumbnail-test_source_jpg_50x50_q85.png')
-        self.verify_thumbnail((50, 37), thumb, expected_filename)
-        expected_tag = '<img src="%s" width="50" height="37" alt="" />' % \
-            '/'.join((settings.MEDIA_URL.rstrip('/'),
-                      'sorl-thumbnail-test_source_jpg_50x50_q85.png'))
-        self.assertEqual(tag, expected_tag)
-
-    def test_delete_thumbnails(self):
-        model = TestThumbnailFieldModel(photo=RELATIVE_PIC_NAME)
-        thumb_file = model.photo.thumbnail.dest
-        open(thumb_file, 'wb').close()
-        self.assert_(os.path.exists(thumb_file))
-        model.photo.delete(save=False)
-        self.assertFalse(os.path.exists(thumb_file))
-
-    def test_generate_on_save(self):
-        main_thumb = os.path.join(settings.MEDIA_ROOT, 'test',
-                        'sorl-thumbnail-test_source_jpg_50x50_q85.jpg')
-        admin_thumb = os.path.join(settings.MEDIA_ROOT, 'test',
-                        'sorl-thumbnail-test_source_jpg_30x30_crop_q85.jpg')
-        self.images_to_delete.add(main_thumb)
-        self.images_to_delete.add(admin_thumb)
-        # Default setting is to only generate when the thumbnail is used.
-        model = TestThumbnailFieldModel()
-        source = ContentFile(open(PIC_NAME).read())
-        model.photo.save(RELATIVE_PIC_NAME, source, save=False)
-        self.images_to_delete.add(model.photo.path)
-        self.assertFalse(os.path.exists(main_thumb))
-        self.assertFalse(os.path.exists(admin_thumb))
-        os.remove(model.photo.path)
-        # But it's easy to set it up the other way...
-        model = TestThumbnailFieldGenerateModel()
-        source = ContentFile(open(PIC_NAME).read())
-        model.photo.save(RELATIVE_PIC_NAME, source, save=False)
-        self.assert_(os.path.exists(main_thumb))
-        self.assert_(os.path.exists(admin_thumb))
-
-
-class ImageWithThumbnailsFieldTest(BaseTest):
-    def test_thumbnail(self):
-        model = TestThumbnailFieldModel(photo=RELATIVE_PIC_NAME)
-        thumb = model.photo.thumbnail
-        tag = model.photo.thumbnail_tag
-        base_name = RELATIVE_PIC_NAME.replace('.', '_')
-        expected_filename = os.path.join(settings.MEDIA_ROOT,
-                                         '%s_50x50_q85.jpg' % base_name)
-        self.verify_thumbnail((50, 37), thumb, expected_filename)
-        expected_tag = ('<img src="%s" width="50" height="37" alt="" />' %
-                        '/'.join([settings.MEDIA_URL.rstrip('/'),
-                                  '%s_50x50_q85.jpg' % base_name]))
-        self.assertEqual(tag, expected_tag)
-
-
-class ThumbnailFieldTest(BaseTest):
-    def test_thumbnail(self):
-        model = TestThumbnailFieldModel()
-        source = ContentFile(open(PIC_NAME).read())
-        dest_name = 'sorl-thumbnail-test_dest.jpg'
-        model.avatar.save(dest_name, source, save=False)
-        expected_filename = os.path.join(model.avatar.path)
-        self.verify_thumbnail((300, 225), expected_filename=expected_filename)
-
-        tag = model.avatar.thumbnail_tag
-        expected_tag = ('<img src="%s" width="300" height="225" alt="" />' %
-                        '/'.join([settings.MEDIA_URL.rstrip('/'), 'test',
-                                  dest_name]))
-        self.assertEqual(tag, expected_tag)
diff --git a/apps/sorl/thumbnail/tests/templatetags.py b/apps/sorl/thumbnail/tests/templatetags.py
deleted file mode 100644 (file)
index 5d1a1cb..0000000
+++ /dev/null
@@ -1,312 +0,0 @@
-import os
-from django.conf import settings
-from django.template import Template, Context, TemplateSyntaxError
-from sorl.thumbnail.tests.classes import BaseTest, RELATIVE_PIC_NAME
-
-
-class ThumbnailTagTest(BaseTest):
-    def render_template(self, source):
-        context = Context({
-            'source': RELATIVE_PIC_NAME,
-            'invalid_source': 'not%s' % RELATIVE_PIC_NAME,
-            'size': (90, 100),
-            'invalid_size': (90, 'fish'),
-            'strsize': '80x90',
-            'invalid_strsize': ('1notasize2'),
-            'invalid_q': 'notanumber'})
-        source = '{% load thumbnail %}' + source
-        return Template(source).render(context)
-
-    def testTagInvalid(self):
-        # No args, or wrong number of args
-        src = '{% thumbnail %}'
-        self.assertRaises(TemplateSyntaxError, self.render_template, src)
-        src = '{% thumbnail source %}'
-        self.assertRaises(TemplateSyntaxError, self.render_template, src)
-        src = '{% thumbnail source 80x80 as variable crop %}'
-        self.assertRaises(TemplateSyntaxError, self.render_template, src)
-
-        # Invalid option
-        src = '{% thumbnail source 240x200 invalid %}'
-        self.assertRaises(TemplateSyntaxError, self.render_template, src)
-
-        # Old comma separated options format can only have an = for quality
-        src = '{% thumbnail source 80x80 crop=1,quality=1 %}'
-        self.assertRaises(TemplateSyntaxError, self.render_template, src)
-
-        # Invalid quality
-        src_invalid = '{% thumbnail source 240x200 quality=invalid_q %}'
-        src_missing = '{% thumbnail source 240x200 quality=missing_q %}'
-        # ...with THUMBNAIL_DEBUG = False
-        self.assertEqual(self.render_template(src_invalid), '')
-        self.assertEqual(self.render_template(src_missing), '')
-        # ...and with THUMBNAIL_DEBUG = True
-        self.change_settings.change({'DEBUG': True})
-        self.assertRaises(TemplateSyntaxError, self.render_template,
-                          src_invalid)
-        self.assertRaises(TemplateSyntaxError, self.render_template,
-                          src_missing)
-
-        # Invalid source
-        src = '{% thumbnail invalid_source 80x80 %}'
-        src_on_context = '{% thumbnail invalid_source 80x80 as thumb %}'
-        # ...with THUMBNAIL_DEBUG = False
-        self.change_settings.change({'DEBUG': False})
-        self.assertEqual(self.render_template(src), '')
-        # ...and with THUMBNAIL_DEBUG = True
-        self.change_settings.change({'DEBUG': True})
-        self.assertRaises(TemplateSyntaxError, self.render_template, src)
-        self.assertRaises(TemplateSyntaxError, self.render_template,
-                          src_on_context)
-
-        # Non-existant source
-        src = '{% thumbnail non_existant_source 80x80 %}'
-        src_on_context = '{% thumbnail non_existant_source 80x80 as thumb %}'
-        # ...with THUMBNAIL_DEBUG = False
-        self.change_settings.change({'DEBUG': False})
-        self.assertEqual(self.render_template(src), '')
-        # ...and with THUMBNAIL_DEBUG = True
-        self.change_settings.change({'DEBUG': True})
-        self.assertRaises(TemplateSyntaxError, self.render_template, src)
-
-        # Invalid size as a tuple:
-        src = '{% thumbnail source invalid_size %}'
-        # ...with THUMBNAIL_DEBUG = False
-        self.change_settings.change({'DEBUG': False})
-        self.assertEqual(self.render_template(src), '')
-        # ...and THUMBNAIL_DEBUG = True
-        self.change_settings.change({'DEBUG': True})
-        self.assertRaises(TemplateSyntaxError, self.render_template, src)
-        # Invalid size as a string:
-        src = '{% thumbnail source invalid_strsize %}'
-        # ...with THUMBNAIL_DEBUG = False
-        self.change_settings.change({'DEBUG': False})
-        self.assertEqual(self.render_template(src), '')
-        # ...and THUMBNAIL_DEBUG = True
-        self.change_settings.change({'DEBUG': True})
-        self.assertRaises(TemplateSyntaxError, self.render_template, src)
-
-        # Non-existant size
-        src = '{% thumbnail source non_existant_size %}'
-        # ...with THUMBNAIL_DEBUG = False
-        self.change_settings.change({'DEBUG': False})
-        self.assertEqual(self.render_template(src), '')
-        # ...and THUMBNAIL_DEBUG = True
-        self.change_settings.change({'DEBUG': True})
-        self.assertRaises(TemplateSyntaxError, self.render_template, src)
-
-    def testTag(self):
-        expected_base = RELATIVE_PIC_NAME.replace('.', '_')
-        # Set DEBUG = True to make it easier to trace any failures
-        self.change_settings.change({'DEBUG': True})
-
-        # Basic
-        output = self.render_template('src="'
-            '{% thumbnail source 240x240 %}"')
-        expected = '%s_240x240_q85.jpg' % expected_base
-        expected_fn = os.path.join(settings.MEDIA_ROOT, expected)
-        self.verify_thumbnail((240, 180), expected_filename=expected_fn)
-        expected_url = ''.join((settings.MEDIA_URL, expected))
-        self.assertEqual(output, 'src="%s"' % expected_url)
-
-        # Size from context variable
-        # as a tuple:
-        output = self.render_template('src="'
-            '{% thumbnail source size %}"')
-        expected = '%s_90x100_q85.jpg' % expected_base
-        expected_fn = os.path.join(settings.MEDIA_ROOT, expected)
-        self.verify_thumbnail((90, 67), expected_filename=expected_fn)
-        expected_url = ''.join((settings.MEDIA_URL, expected))
-        self.assertEqual(output, 'src="%s"' % expected_url)
-        # as a string:
-        output = self.render_template('src="'
-            '{% thumbnail source strsize %}"')
-        expected = '%s_80x90_q85.jpg' % expected_base
-        expected_fn = os.path.join(settings.MEDIA_ROOT, expected)
-        self.verify_thumbnail((80, 60), expected_filename=expected_fn)
-        expected_url = ''.join((settings.MEDIA_URL, expected))
-        self.assertEqual(output, 'src="%s"' % expected_url)
-
-        # On context
-        output = self.render_template('height:'
-            '{% thumbnail source 240x240 as thumb %}{{ thumb.height }}')
-        self.assertEqual(output, 'height:180')
-
-        # With options and quality
-        output = self.render_template('src="'
-            '{% thumbnail source 240x240 sharpen crop quality=95 %}"')
-        # Note that the opts are sorted to ensure a consistent filename.
-        expected = '%s_240x240_crop_sharpen_q95.jpg' % expected_base
-        expected_fn = os.path.join(settings.MEDIA_ROOT, expected)
-        self.verify_thumbnail((240, 240), expected_filename=expected_fn)
-        expected_url = ''.join((settings.MEDIA_URL, expected))
-        self.assertEqual(output, 'src="%s"' % expected_url)
-
-        # With option and quality on context (also using its unicode method to
-        # display the url)
-        output = self.render_template(
-            '{% thumbnail source 240x240 sharpen crop quality=95 as thumb %}'
-            'width:{{ thumb.width }}, url:{{ thumb }}')
-        self.assertEqual(output, 'width:240, url:%s' % expected_url)
-
-        # Old comma separated format for options is still supported.
-        output = self.render_template(
-            '{% thumbnail source 240x240 sharpen,crop,quality=95 as thumb %}'
-            'width:{{ thumb.width }}, url:{{ thumb }}')
-        self.assertEqual(output, 'width:240, url:%s' % expected_url)
-
-filesize_tests = r"""
->>> from sorl.thumbnail.templatetags.thumbnail import filesize
-
->>> filesize('abc')
-'abc'
->>> filesize(100, 'invalid')
-100
-
->>> bytes = 20
->>> filesize(bytes)
-'20 B'
->>> filesize(bytes, 'auto1000')
-'20 B'
-
->>> bytes = 1001
->>> filesize(bytes)
-'1001 B'
->>> filesize(bytes, 'auto1000')
-'1 kB'
-
->>> bytes = 10100
->>> filesize(bytes)
-'9.9 KiB'
-
-# Note that the decimal place is only used if < 10
->>> filesize(bytes, 'auto1000')
-'10 kB'
-
->>> bytes = 190000000
->>> filesize(bytes)
-'181 MiB'
->>> filesize(bytes, 'auto1000')
-'190 MB'
-
-# 'auto*long' methods use pluralisation:
->>> filesize(1, 'auto1024long')
-'1 byte'
->>> filesize(1, 'auto1000long')
-'1 byte'
->>> filesize(2, 'auto1024long')
-'2 bytes'
->>> filesize(0, 'auto1000long')
-'0 bytes'
-
-# Test all 'auto*long' output:
->>> for i in range(1,10):
-...     print '%s, %s' % (filesize(1024**i, 'auto1024long'),
-...                       filesize(1000**i, 'auto1000long'))
-1 kibibyte, 1 kilobyte
-1 mebibyte, 1 megabyte
-1 gibibyte, 1 gigabyte
-1 tebibyte, 1 terabyte
-1 pebibyte, 1 petabyte
-1 exbibyte, 1 exabyte
-1 zebibyte, 1 zettabyte
-1 yobibyte, 1 yottabyte
-1024 yobibytes, 1000 yottabytes
-
-# Test all fixed outputs (eg 'kB' or 'MiB')
->>> from sorl.thumbnail.templatetags.thumbnail import filesize_formats,\
-...    filesize_long_formats
->>> for f in filesize_formats:
-...     print '%s (%siB, %sB):' % (filesize_long_formats[f], f.upper(), f)
-...     for i in range(0, 10):
-...         print ' %s, %s' % (filesize(1024**i, '%siB' % f.upper()),
-...                            filesize(1000**i, '%sB' % f))
-kilo (KiB, kB):
- 0.0009765625, 0.001
- 1.0, 1.0
- 1024.0, 1000.0
- 1048576.0, 1000000.0
- 1073741824.0, 1000000000.0
- 1.09951162778e+12, 1e+12
- 1.12589990684e+15, 1e+15
- 1.15292150461e+18, 1e+18
- 1.18059162072e+21, 1e+21
- 1.20892581961e+24, 1e+24
-mega (MiB, MB):
- 0.0, 1e-06
- 0.0009765625, 0.001
- 1.0, 1.0
- 1024.0, 1000.0
- 1048576.0, 1000000.0
- 1073741824.0, 1000000000.0
- 1.09951162778e+12, 1e+12
- 1.12589990684e+15, 1e+15
- 1.15292150461e+18, 1e+18
- 1.18059162072e+21, 1e+21
-giga (GiB, GB):
- 0.0, 1e-09
- 0.0, 1e-06
- 0.0009765625, 0.001
- 1.0, 1.0
- 1024.0, 1000.0
- 1048576.0, 1000000.0
- 1073741824.0, 1000000000.0
- 1.09951162778e+12, 1e+12
- 1.12589990684e+15, 1e+15
- 1.15292150461e+18, 1e+18
-tera (TiB, TB):
- 0.0, 1e-12
- 0.0, 1e-09
- 0.0, 1e-06
- 0.0009765625, 0.001
- 1.0, 1.0
- 1024.0, 1000.0
- 1048576.0, 1000000.0
- 1073741824.0, 1000000000.0
- 1.09951162778e+12, 1e+12
- 1.12589990684e+15, 1e+15
-peta (PiB, PB):
- 0.0, 1e-15
- 0.0, 1e-12
- 0.0, 1e-09
- 0.0, 1e-06
- 0.0009765625, 0.001
- 1.0, 1.0
- 1024.0, 1000.0
- 1048576.0, 1000000.0
- 1073741824.0, 1000000000.0
- 1.09951162778e+12, 1e+12
-exa (EiB, EB):
- 0.0, 1e-18
- 0.0, 1e-15
- 0.0, 1e-12
- 0.0, 1e-09
- 0.0, 1e-06
- 0.0009765625, 0.001
- 1.0, 1.0
- 1024.0, 1000.0
- 1048576.0, 1000000.0
- 1073741824.0, 1000000000.0
-zetta (ZiB, ZB):
- 0.0, 1e-21
- 0.0, 1e-18
- 0.0, 1e-15
- 0.0, 1e-12
- 0.0, 1e-09
- 0.0, 1e-06
- 0.0009765625, 0.001
- 1.0, 1.0
- 1024.0, 1000.0
- 1048576.0, 1000000.0
-yotta (YiB, YB):
- 0.0, 1e-24
- 0.0, 1e-21
- 0.0, 1e-18
- 0.0, 1e-15
- 0.0, 1e-12
- 0.0, 1e-09
- 0.0, 1e-06
- 0.0009765625, 0.001
- 1.0, 1.0
- 1024.0, 1000.0
-"""
diff --git a/apps/sorl/thumbnail/tests/utils.py b/apps/sorl/thumbnail/tests/utils.py
deleted file mode 100644 (file)
index 3a20cbb..0000000
+++ /dev/null
@@ -1,149 +0,0 @@
-from django.conf import settings
-from sorl.thumbnail.utils import *
-
-try:
-    set
-except NameError:
-    from sets import Set as set     # For Python 2.3
-
-MEDIA_ROOT_LENGTH = len(os.path.normpath(settings.MEDIA_ROOT))
-
-utils_tests = r"""
->>> from sorl.thumbnail.tests.utils import *
->>> from sorl.thumbnail.tests.base import ChangeSettings
->>> from django.conf import settings
-
->>> change_settings = ChangeSettings()
->>> change_settings.change()
-
->>> media_root = settings.MEDIA_ROOT.rstrip('/')
-
-#==============================================================================
-# Set up test images
-#==============================================================================
-
->>> make_image('test-thumbnail-utils/subdir/test_jpg_110x110_q85.jpg')
->>> make_image('test-thumbnail-utils/test_jpg_80x80_q85.jpg')
->>> make_image('test-thumbnail-utils/test_jpg_80x80_q95.jpg')
->>> make_image('test-thumbnail-utils/another_test_jpg_80x80_q85.jpg')
->>> make_image('test-thumbnail-utils/test_with_opts_jpg_80x80_crop_bw_q85.jpg')
->>> make_image('test-thumbnail-basedir/test-thumbnail-utils/test_jpg_100x100_'
-...            'q85.jpg')
->>> make_image('test-thumbnail-utils/prefix-test_jpg_120x120_q85.jpg')
-
-#==============================================================================
-# all_thumbnails()
-#==============================================================================
-
-# Find all thumbs
->>> thumb_dir = os.path.join(settings.MEDIA_ROOT, 'test-thumbnail-utils')
->>> thumbs = all_thumbnails(thumb_dir)
->>> k = thumbs.keys()
->>> k.sort()
->>> [consistent_slash(path) for path in k]
-['another_test.jpg', 'prefix-test.jpg', 'subdir/test.jpg', 'test.jpg',
- 'test_with_opts.jpg']
-
-# Find all thumbs, no recurse
->>> thumbs = all_thumbnails(thumb_dir, recursive=False)
->>> k = thumbs.keys()
->>> k.sort()
->>> k
-['another_test.jpg', 'prefix-test.jpg', 'test.jpg', 'test_with_opts.jpg']
-
-#==============================================================================
-# thumbnails_for_file()
-#==============================================================================
-
->>> output = []
->>> for thumb in thumbs['test.jpg']:
-...     thumb['rel_fn'] = strip_media_root(thumb['filename'])
-...     output.append('%(x)sx%(y)s %(quality)s %(rel_fn)s' % thumb)
->>> output.sort()
->>> output
-['80x80 85 test-thumbnail-utils/test_jpg_80x80_q85.jpg',
- '80x80 95 test-thumbnail-utils/test_jpg_80x80_q95.jpg']
-
-# Thumbnails for file
->>> output = []
->>> for thumb in thumbnails_for_file('test-thumbnail-utils/test.jpg'):
-...    output.append(strip_media_root(thumb['filename']))
->>> output.sort()
->>> output
-['test-thumbnail-utils/test_jpg_80x80_q85.jpg',
- 'test-thumbnail-utils/test_jpg_80x80_q95.jpg']
-
-# Thumbnails for file - shouldn't choke on non-existant file
->>> thumbnails_for_file('test-thumbnail-utils/non-existant.jpg')
-[]
-
-# Thumbnails for file, with basedir setting
->>> change_settings.change({'BASEDIR': 'test-thumbnail-basedir'})
->>> for thumb in thumbnails_for_file('test-thumbnail-utils/test.jpg'):
-...    print strip_media_root(thumb['filename'])
-test-thumbnail-basedir/test-thumbnail-utils/test_jpg_100x100_q85.jpg
-
-# Thumbnails for file, with subdir setting
->>> change_settings.change({'SUBDIR': 'subdir', 'BASEDIR': ''})
->>> for thumb in thumbnails_for_file('test-thumbnail-utils/test.jpg'):
-...    print strip_media_root(thumb['filename'])
-test-thumbnail-utils/subdir/test_jpg_110x110_q85.jpg
-
-# Thumbnails for file, with prefix setting
->>> change_settings.change({'PREFIX': 'prefix-', 'SUBDIR': ''})
->>> for thumb in thumbnails_for_file('test-thumbnail-utils/test.jpg'):
-...    print strip_media_root(thumb['filename'])
-test-thumbnail-utils/prefix-test_jpg_120x120_q85.jpg
-
-#==============================================================================
-# Clean up images / directories
-#==============================================================================
-
->>> clean_up()
-"""
-
-images_to_delete = set()
-dirs_to_delete = []
-
-
-def make_image(relative_image):
-    absolute_image = os.path.join(settings.MEDIA_ROOT, relative_image)
-    make_dirs(os.path.dirname(relative_image))
-    open(absolute_image, 'w').close()
-    images_to_delete.add(absolute_image)
-
-
-def make_dirs(relative_path):
-    if not relative_path:
-        return
-    absolute_path = os.path.join(settings.MEDIA_ROOT, relative_path)
-    if os.path.isdir(absolute_path):
-        return
-    if absolute_path not in dirs_to_delete:
-        dirs_to_delete.append(absolute_path)
-    make_dirs(os.path.dirname(relative_path))
-    os.mkdir(absolute_path)
-
-
-def clean_up():
-    for image in images_to_delete:
-        os.remove(image)
-    for path in dirs_to_delete:
-        os.rmdir(path)
-
-
-def strip_media_root(path):
-    path = os.path.normpath(path)
-    # chop off the MEDIA_ROOT and strip any leading os.sep
-    path = path[MEDIA_ROOT_LENGTH:].lstrip(os.sep)
-    return consistent_slash(path)
-
-
-def consistent_slash(path):
-    """
-    Ensure we're always testing against the '/' os separator (otherwise tests
-    fail against Windows).
-    """
-    if os.sep != '/':
-        path = path.replace(os.sep, '/')
-    return path
diff --git a/apps/sorl/thumbnail/utils.py b/apps/sorl/thumbnail/utils.py
deleted file mode 100644 (file)
index 18b18b0..0000000
+++ /dev/null
@@ -1,170 +0,0 @@
-import math
-import os
-import re
-
-
-re_thumbnail_file = re.compile(r'(?P<source_filename>.+)_(?P<x>\d+)x(?P<y>\d+)'
-                               r'(?:_(?P<options>\w+))?_q(?P<quality>\d+)'
-                               r'(?:.[^.]+)?$')
-re_new_args = re.compile('(?<!quality)=')
-
-
-def all_thumbnails(path, recursive=True, prefix=None, subdir=None):
-    """
-    Return a dictionary referencing all files which match the thumbnail format.
-
-    Each key is a source image filename, relative to path.
-    Each value is a list of dictionaries as explained in `thumbnails_for_file`.
-    """
-    # Fall back to using thumbnail settings. These are local imports so that
-    # there is no requirement of Django to use the utils module.
-    if prefix is None:
-        from sorl.thumbnail.main import get_thumbnail_setting
-        prefix = get_thumbnail_setting('PREFIX')
-    if subdir is None:
-        from sorl.thumbnail.main import get_thumbnail_setting
-        subdir = get_thumbnail_setting('SUBDIR')
-    thumbnail_files = {}
-    if not path.endswith('/'):
-        path = '%s/' % path
-    len_path = len(path)
-    if recursive:
-        all = os.walk(path)
-    else:
-        files = []
-        for file in os.listdir(path):
-            if os.path.isfile(os.path.join(path, file)):
-                files.append(file)
-        all = [(path, [], files)]
-    for dir_, subdirs, files in all:
-        rel_dir = dir_[len_path:]
-        for file in files:
-            thumb = re_thumbnail_file.match(file)
-            if not thumb:
-                continue
-            d = thumb.groupdict()
-            source_filename = d.pop('source_filename')
-            if prefix:
-                source_path, source_filename = os.path.split(source_filename)
-                if not source_filename.startswith(prefix):
-                    continue
-                source_filename = os.path.join(source_path,
-                    source_filename[len(prefix):])
-            d['options'] = d['options'] and d['options'].split('_') or []
-            if subdir and rel_dir.endswith(subdir):
-                rel_dir = rel_dir[:-len(subdir)]
-            # Corner-case bug: if the filename didn't have an extension but did
-            # have an underscore, the last underscore will get converted to a
-            # '.'.
-            m = re.match(r'(.*)_(.*)', source_filename)
-            if m:
-                source_filename = '%s.%s' % m.groups()
-            filename = os.path.join(rel_dir, source_filename)
-            thumbnail_file = thumbnail_files.setdefault(filename, [])
-            d['filename'] = os.path.join(dir_, file)
-            thumbnail_file.append(d)
-    return thumbnail_files
-
-
-def thumbnails_for_file(relative_source_path, root=None, basedir=None,
-                        subdir=None, prefix=None):
-    """
-    Return a list of dictionaries, one for each thumbnail belonging to the
-    source image.
-
-    The following list explains each key of the dictionary:
-
-      `filename`  -- absolute thumbnail path
-      `x` and `y` -- the size of the thumbnail
-      `options`   -- list of options for this thumbnail
-      `quality`   -- quality setting for this thumbnail
-    """
-    # Fall back to using thumbnail settings. These are local imports so that
-    # there is no requirement of Django to use the utils module.
-    if root is None:
-        from django.conf import settings
-        root = settings.MEDIA_ROOT
-    if prefix is None:
-        from sorl.thumbnail.main import get_thumbnail_setting
-        prefix = get_thumbnail_setting('PREFIX')
-    if subdir is None:
-        from sorl.thumbnail.main import get_thumbnail_setting
-        subdir = get_thumbnail_setting('SUBDIR')
-    if basedir is None:
-        from sorl.thumbnail.main import get_thumbnail_setting
-        basedir = get_thumbnail_setting('BASEDIR')
-    source_dir, filename = os.path.split(relative_source_path)
-    thumbs_path = os.path.join(root, basedir, source_dir, subdir)
-    if not os.path.isdir(thumbs_path):
-        return []
-    files = all_thumbnails(thumbs_path, recursive=False, prefix=prefix,
-                           subdir='')
-    return files.get(filename, [])
-
-
-def delete_thumbnails(relative_source_path, root=None, basedir=None,
-                      subdir=None, prefix=None):
-    """
-    Delete all thumbnails for a source image.
-    """
-    thumbs = thumbnails_for_file(relative_source_path, root, basedir, subdir,
-                                 prefix)
-    return _delete_using_thumbs_list(thumbs)
-
-
-def _delete_using_thumbs_list(thumbs):
-    deleted = 0
-    for thumb_dict in thumbs:
-        filename = thumb_dict['filename']
-        try:
-            os.remove(filename)
-        except:
-            pass
-        else:
-            deleted += 1
-    return deleted
-
-
-def delete_all_thumbnails(path, recursive=True):
-    """
-    Delete all files within a path which match the thumbnails pattern.
-
-    By default, matching files from all sub-directories are also removed. To
-    only remove from the path directory, set recursive=False.
-    """
-    total = 0
-    for thumbs in all_thumbnails(path, recursive=recursive).values():
-        total += _delete_using_thumbs_list(thumbs)
-    return total
-
-
-def split_args(args):
-    """
-    Split a list of argument strings into a dictionary where each key is an
-    argument name.
-
-    An argument looks like ``crop``, ``crop="some option"`` or ``crop=my_var``.
-    Arguments which provide no value get a value of ``None``.
-    """
-    if not args:
-        return {}
-    # Handle the old comma separated argument format.
-    if len(args) == 1 and not re_new_args.search(args[0]):
-        args = args[0].split(',')
-    # Separate out the key and value for each argument.
-    args_dict = {}
-    for arg in args:
-        split_arg = arg.split('=', 1)
-        value = len(split_arg) > 1 and split_arg[1] or None
-        args_dict[split_arg[0]] = value
-    return args_dict
-
-
-def image_entropy(im):
-    """
-    Calculate the entropy of an image. Used for "smart cropping".
-    """
-    hist = im.histogram()
-    hist_size = float(sum(hist))
-    hist = [h / hist_size for h in hist]
-    return -sum([p * math.log(p, 2) for p in hist if p != 0])
diff --git a/apps/south/__init__.py b/apps/south/__init__.py
deleted file mode 100644 (file)
index 3e5972e..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-"""
-South - Useable migrations for Django apps
-"""
-
-__version__ = "0.4"
-__authors__ = ["Andrew Godwin <andrew@aeracode.org>", "Andy McCurdy <andy@andymccurdy.com>"]
diff --git a/apps/south/db/__init__.py b/apps/south/db/__init__.py
deleted file mode 100644 (file)
index 8e4d773..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-
-# Establish the common DatabaseOperations instance, which we call 'db'.
-# This code somewhat lifted from django evolution
-from django.conf import settings
-import sys
-module_name = ['south.db', settings.DATABASE_ENGINE]
-try:
-    module = __import__('.'.join(module_name),{},{},[''])
-except ImportError:
-    sys.stderr.write("There is no South database module for the engine '%s'. Please either choose a supported one, or remove South from INSTALLED_APPS.\n" % settings.DATABASE_ENGINE)
-    sys.exit(1)
-db = module.DatabaseOperations()
\ No newline at end of file
diff --git a/apps/south/db/generic.py b/apps/south/db/generic.py
deleted file mode 100644 (file)
index 4a5b512..0000000
+++ /dev/null
@@ -1,543 +0,0 @@
-
-import datetime
-from django.core.management.color import no_style
-from django.db import connection, transaction, models
-from django.db.backends.util import truncate_name
-from django.db.models.fields import NOT_PROVIDED
-from django.dispatch import dispatcher
-from django.conf import settings
-
-
-def alias(attrname):
-    """
-    Returns a function which calls 'attrname' - for function aliasing.
-    We can't just use foo = bar, as this breaks subclassing.
-    """
-    def func(self, *args, **kwds):
-        return getattr(self, attrname)(*args, **kwds)
-    return func
-
-
-class DatabaseOperations(object):
-
-    """
-    Generic SQL implementation of the DatabaseOperations.
-    Some of this code comes from Django Evolution.
-    """
-
-    # We assume the generic DB can handle DDL transactions. MySQL wil change this.
-    has_ddl_transactions = True
-
-    def __init__(self):
-        self.debug = False
-        self.deferred_sql = []
-        self.dry_run = False
-        self.pending_create_signals = []
-
-    def execute(self, sql, params=[]):
-        """
-        Executes the given SQL statement, with optional parameters.
-        If the instance's debug attribute is True, prints out what it executes.
-        """
-        cursor = connection.cursor()
-        if self.debug:
-            print "   = %s" % sql, params
-
-        if self.dry_run:
-            return []
-
-        cursor.execute(sql, params)
-        try:
-            return cursor.fetchall()
-        except:
-            return []
-
-
-    def add_deferred_sql(self, sql):
-        """
-        Add a SQL statement to the deferred list, that won't be executed until
-        this instance's execute_deferred_sql method is run.
-        """
-        self.deferred_sql.append(sql)
-
-
-    def execute_deferred_sql(self):
-        """
-        Executes all deferred SQL, resetting the deferred_sql list
-        """
-        for sql in self.deferred_sql:
-            self.execute(sql)
-
-        self.deferred_sql = []
-
-
-    def clear_deferred_sql(self):
-        """
-        Resets the deferred_sql list to empty.
-        """
-        self.deferred_sql = []
-    
-    
-    def clear_run_data(self):
-        """
-        Resets variables to how they should be before a run. Used for dry runs.
-        """
-        self.clear_deferred_sql()
-        self.pending_create_signals = []
-
-
-    def create_table(self, table_name, fields):
-        """
-        Creates the table 'table_name'. 'fields' is a tuple of fields,
-        each repsented by a 2-part tuple of field name and a
-        django.db.models.fields.Field object
-        """
-        qn = connection.ops.quote_name
-
-        # allow fields to be a dictionary
-        # removed for now - philosophical reasons (this is almost certainly not what you want)
-        #try:
-        #    fields = fields.items()
-        #except AttributeError:
-        #    pass
-
-        columns = [
-            self.column_sql(table_name, field_name, field)
-            for field_name, field in fields
-        ]
-
-        self.execute('CREATE TABLE %s (%s);' % (qn(table_name), ', '.join([col for col in columns if col])))
-
-    add_table = alias('create_table') # Alias for consistency's sake
-
-
-    def rename_table(self, old_table_name, table_name):
-        """
-        Renames the table 'old_table_name' to 'table_name'.
-        """
-        if old_table_name == table_name:
-            # No Operation
-            return
-        qn = connection.ops.quote_name
-        params = (qn(old_table_name), qn(table_name))
-        self.execute('ALTER TABLE %s RENAME TO %s;' % params)
-
-
-    def delete_table(self, table_name):
-        """
-        Deletes the table 'table_name'.
-        """
-        qn = connection.ops.quote_name
-        params = (qn(table_name), )
-        self.execute('DROP TABLE %s;' % params)
-
-    drop_table = alias('delete_table')
-
-
-    def clear_table(self, table_name):
-        """
-        Deletes all rows from 'table_name'.
-        """
-        qn = connection.ops.quote_name
-        params = (qn(table_name), )
-        self.execute('DELETE FROM %s;' % params)
-
-    add_column_string = 'ALTER TABLE %s ADD COLUMN %s;'
-
-    def add_column(self, table_name, name, field, keep_default=True):
-        """
-        Adds the column 'name' to the table 'table_name'.
-        Uses the 'field' paramater, a django.db.models.fields.Field instance,
-        to generate the necessary sql
-
-        @param table_name: The name of the table to add the column to
-        @param name: The name of the column to add
-        @param field: The field to use
-        """
-        qn = connection.ops.quote_name
-        sql = self.column_sql(table_name, name, field)
-        if sql:
-            params = (
-                qn(table_name),
-                sql,
-            )
-            sql = self.add_column_string % params
-            self.execute(sql)
-
-            # Now, drop the default if we need to
-            if not keep_default and field.default:
-                field.default = NOT_PROVIDED
-                self.alter_column(table_name, name, field, explicit_name=False)
-
-    alter_string_set_type = 'ALTER COLUMN %(column)s TYPE %(type)s'
-    alter_string_set_null = 'ALTER COLUMN %(column)s DROP NOT NULL'
-    alter_string_drop_null = 'ALTER COLUMN %(column)s SET NOT NULL'
-    allows_combined_alters = True
-
-    def alter_column(self, table_name, name, field, explicit_name=True):
-        """
-        Alters the given column name so it will match the given field.
-        Note that conversion between the two by the database must be possible.
-        Will not automatically add _id by default; to have this behavour, pass
-        explicit_name=False.
-
-        @param table_name: The name of the table to add the column to
-        @param name: The name of the column to alter
-        @param field: The new field definition to use
-        """
-
-        # hook for the field to do any resolution prior to it's attributes being queried
-        if hasattr(field, 'south_init'):
-            field.south_init()
-
-        qn = connection.ops.quote_name
-        
-        # Add _id or whatever if we need to
-        if not explicit_name:
-            field.set_attributes_from_name(name)
-            name = field.column
-
-        # First, change the type
-        params = {
-            "column": qn(name),
-            "type": field.db_type(),
-        }
-
-        # SQLs is a list of (SQL, values) pairs.
-        sqls = [(self.alter_string_set_type % params, [])]
-
-        # Next, set any default
-        if not field.null and field.has_default():
-            default = field.get_default()
-            sqls.append(('ALTER COLUMN %s SET DEFAULT %%s ' % (qn(name),), [default]))
-        else:
-            sqls.append(('ALTER COLUMN %s DROP DEFAULT' % (qn(name),), []))
-
-
-        # Next, nullity
-        params = {
-            "column": qn(name),
-            "type": field.db_type(),
-        }
-        if field.null:
-            sqls.append((self.alter_string_set_null % params, []))
-        else:
-            sqls.append((self.alter_string_drop_null % params, []))
-
-
-        # TODO: Unique
-
-        if self.allows_combined_alters:
-            sqls, values = zip(*sqls)
-            self.execute(
-                "ALTER TABLE %s %s;" % (qn(table_name), ", ".join(sqls)),
-                flatten(values),
-            )
-        else:
-            # Databases like e.g. MySQL don't like more than one alter at once.
-            for sql, values in sqls:
-                self.execute("ALTER TABLE %s %s;" % (qn(table_name), sql), values)
-
-
-    def column_sql(self, table_name, field_name, field, tablespace=''):
-        """
-        Creates the SQL snippet for a column. Used by add_column and add_table.
-        """
-        qn = connection.ops.quote_name
-
-        field.set_attributes_from_name(field_name)
-
-        # hook for the field to do any resolution prior to it's attributes being queried
-        if hasattr(field, 'south_init'):
-            field.south_init()
-
-        sql = field.db_type()
-        if sql:        
-            field_output = [qn(field.column), sql]
-            field_output.append('%sNULL' % (not field.null and 'NOT ' or ''))
-            if field.primary_key:
-                field_output.append('PRIMARY KEY')
-            elif field.unique:
-                # Instead of using UNIQUE, add a unique index with a predictable name
-                self.add_deferred_sql(
-                    self.create_index_sql(
-                        table_name,
-                        [field.column],
-                        unique = True,
-                        db_tablespace = tablespace,
-                    )
-                )
-
-            tablespace = field.db_tablespace or tablespace
-            if tablespace and connection.features.supports_tablespaces and field.unique:
-                # We must specify the index tablespace inline, because we
-                # won't be generating a CREATE INDEX statement for this field.
-                field_output.append(connection.ops.tablespace_sql(tablespace, inline=True))
-
-            sql = ' '.join(field_output)
-            sqlparams = ()
-            # if the field is "NOT NULL" and a default value is provided, create the column with it
-            # this allows the addition of a NOT NULL field to a table with existing rows
-            if not field.null and field.has_default():
-                default = field.get_default()
-                # If the default is a callable, then call it!
-                if callable(default):
-                    default = default()
-                # Now do some very cheap quoting. TODO: Redesign return values to avoid this.
-                if isinstance(default, basestring):
-                    default = "'%s'" % default.replace("'", "''")
-                elif isinstance(default, datetime.date):
-                    default = "'%s'" % default
-                sql += " DEFAULT %s"
-                sqlparams = (default)
-
-            if field.rel and self.supports_foreign_keys:
-                self.add_deferred_sql(
-                    self.foreign_key_sql(
-                        table_name,
-                        field.column,
-                        field.rel.to._meta.db_table,
-                        field.rel.to._meta.get_field(field.rel.field_name).column
-                    )
-                )
-
-            if field.db_index and not field.unique:
-                self.add_deferred_sql(self.create_index_sql(table_name, [field.column]))
-
-        if hasattr(field, 'post_create_sql'):
-            style = no_style()
-            for stmt in field.post_create_sql(style, table_name):
-                self.add_deferred_sql(stmt)
-
-        if sql:
-            return sql % sqlparams
-        else:
-            return None
-
-
-    supports_foreign_keys = True
-
-    def foreign_key_sql(self, from_table_name, from_column_name, to_table_name, to_column_name):
-        """
-        Generates a full SQL statement to add a foreign key constraint
-        """
-        qn = connection.ops.quote_name
-        constraint_name = '%s_refs_%s_%x' % (from_column_name, to_column_name, abs(hash((from_table_name, to_table_name))))
-        return 'ALTER TABLE %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s)%s;' % (
-            qn(from_table_name),
-            qn(truncate_name(constraint_name, connection.ops.max_name_length())),
-            qn(from_column_name),
-            qn(to_table_name),
-            qn(to_column_name),
-            connection.ops.deferrable_sql() # Django knows this
-        )
-
-
-    def create_index_name(self, table_name, column_names):
-        """
-        Generate a unique name for the index
-        """
-        index_unique_name = ''
-        if len(column_names) > 1:
-            index_unique_name = '_%x' % abs(hash((table_name, ','.join(column_names))))
-
-        return '%s_%s%s' % (table_name, column_names[0], index_unique_name)
-
-
-    def create_index_sql(self, table_name, column_names, unique=False, db_tablespace=''):
-        """
-        Generates a create index statement on 'table_name' for a list of 'column_names'
-        """
-        qn = connection.ops.quote_name
-        if not column_names:
-            print "No column names supplied on which to create an index"
-            return ''
-
-        if db_tablespace and connection.features.supports_tablespaces:
-            tablespace_sql = ' ' + connection.ops.tablespace_sql(db_tablespace)
-        else:
-            tablespace_sql = ''
-
-        index_name = self.create_index_name(table_name, column_names)
-        qn = connection.ops.quote_name
-        return 'CREATE %sINDEX %s ON %s (%s)%s;' % (
-            unique and 'UNIQUE ' or '',
-            qn(index_name),
-            qn(table_name),
-            ','.join([qn(field) for field in column_names]),
-            tablespace_sql
-        )
-
-    def create_index(self, table_name, column_names, unique=False, db_tablespace=''):
-        """ Executes a create index statement """
-        sql = self.create_index_sql(table_name, column_names, unique, db_tablespace)
-        self.execute(sql)
-
-
-    drop_index_string = 'DROP INDEX %(index_name)s'
-
-    def delete_index(self, table_name, column_names, db_tablespace=''):
-        """
-        Deletes an index created with create_index.
-        This is possible using only columns due to the deterministic
-        index naming function which relies on column names.
-        """
-        if isinstance(column_names, (str, unicode)):
-            column_names = [column_names]
-        name = self.create_index_name(table_name, column_names)
-        qn = connection.ops.quote_name
-        sql = self.drop_index_string % {"index_name": qn(name), "table_name": qn(table_name)}
-        self.execute(sql)
-
-    drop_index = alias('delete_index')
-
-    delete_column_string = 'ALTER TABLE %s DROP COLUMN %s CASCADE;'
-
-    def delete_column(self, table_name, name):
-        """
-        Deletes the column 'column_name' from the table 'table_name'.
-        """
-        qn = connection.ops.quote_name
-        params = (qn(table_name), qn(name))
-        self.execute(self.delete_column_string % params, [])
-
-    drop_column = alias('delete_column')
-
-
-    def rename_column(self, table_name, old, new):
-        """
-        Renames the column 'old' from the table 'table_name' to 'new'.
-        """
-        raise NotImplementedError("rename_column has no generic SQL syntax")
-
-
-    def start_transaction(self):
-        """
-        Makes sure the following commands are inside a transaction.
-        Must be followed by a (commit|rollback)_transaction call.
-        """
-        if self.dry_run:
-            return
-        transaction.commit_unless_managed()
-        transaction.enter_transaction_management()
-        transaction.managed(True)
-
-
-    def commit_transaction(self):
-        """
-        Commits the current transaction.
-        Must be preceded by a start_transaction call.
-        """
-        if self.dry_run:
-            return
-        transaction.commit()
-        transaction.leave_transaction_management()
-
-
-    def rollback_transaction(self):
-        """
-        Rolls back the current transaction.
-        Must be preceded by a start_transaction call.
-        """
-        if self.dry_run:
-            return
-        transaction.rollback()
-        transaction.leave_transaction_management()
-
-
-    def send_create_signal(self, app_label, model_names):
-        self.pending_create_signals.append((app_label, model_names))
-
-
-    def send_pending_create_signals(self):
-        for (app_label, model_names) in self.pending_create_signals:
-            self.really_send_create_signal(app_label, model_names)
-        self.pending_create_signals = []
-
-
-    def really_send_create_signal(self, app_label, model_names):
-        """
-        Sends a post_syncdb signal for the model specified.
-
-        If the model is not found (perhaps it's been deleted?),
-        no signal is sent.
-
-        TODO: The behavior of django.contrib.* apps seems flawed in that
-        they don't respect created_models.  Rather, they blindly execute
-        over all models within the app sending the signal.  This is a
-        patch we should push Django to make  For now, this should work.
-        """
-        if self.debug:
-            print " - Sending post_syncdb signal for %s: %s" % (app_label, model_names)
-        app = models.get_app(app_label)
-        if not app:
-            return
-
-        created_models = []
-        for model_name in model_names:
-            model = models.get_model(app_label, model_name)
-            if model:
-                created_models.append(model)
-
-        if created_models:
-            # syncdb defaults -- perhaps take these as options?
-            verbosity = 1
-            interactive = True
-
-            if hasattr(dispatcher, "send"):
-                dispatcher.send(signal=models.signals.post_syncdb, sender=app,
-                                app=app, created_models=created_models,
-                                verbosity=verbosity, interactive=interactive)
-            else:
-                models.signals.post_syncdb.send(sender=app,
-                                                app=app, created_models=created_models,
-                                                verbosity=verbosity, interactive=interactive)
-
-    def mock_model(self, model_name, db_table, db_tablespace='', 
-                   pk_field_name='id', pk_field_type=models.AutoField,
-                   pk_field_args=[], pk_field_kwargs={}):
-        """
-        Generates a MockModel class that provides enough information
-        to be used by a foreign key/many-to-many relationship.
-
-        Migrations should prefer to use these rather than actual models
-        as models could get deleted over time, but these can remain in
-        migration files forever.
-        """
-        class MockOptions(object):
-            def __init__(self):
-                self.db_table = db_table
-                self.db_tablespace = db_tablespace or settings.DEFAULT_TABLESPACE
-                self.object_name = model_name
-                self.module_name = model_name.lower()
-
-                if pk_field_type == models.AutoField:
-                    pk_field_kwargs['primary_key'] = True
-
-                self.pk = pk_field_type(*pk_field_args, **pk_field_kwargs)
-                self.pk.set_attributes_from_name(pk_field_name)
-                self.abstract = False
-
-            def get_field_by_name(self, field_name):
-                # we only care about the pk field
-                return (self.pk, self.model, True, False)
-
-            def get_field(self, name):
-                # we only care about the pk field
-                return self.pk
-
-        class MockModel(object):
-            _meta = None
-
-        # We need to return an actual class object here, not an instance
-        MockModel._meta = MockOptions()
-        MockModel._meta.model = MockModel
-        return MockModel
-
-# Single-level flattening of lists
-def flatten(ls):
-    nl = []
-    for l in ls:
-        nl += l
-    return nl
-
diff --git a/apps/south/db/mysql.py b/apps/south/db/mysql.py
deleted file mode 100644 (file)
index a05c071..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-
-from django.db import connection
-from django.conf import settings
-from south.db import generic
-
-class DatabaseOperations(generic.DatabaseOperations):
-
-    """
-    MySQL implementation of database operations.
-    """
-    
-    alter_string_set_type = ''
-    alter_string_set_null = 'MODIFY %(column)s %(type)s NULL;'
-    alter_string_drop_null = 'MODIFY %(column)s %(type)s NOT NULL;'
-    drop_index_string = 'DROP INDEX %(index_name)s ON %(table_name)s'
-    allows_combined_alters = False
-    has_ddl_transactions = False
-    
-    def execute(self, sql, params=[]):
-        if hasattr(settings, "DATABASE_STORAGE_ENGINE") and \
-           settings.DATABASE_STORAGE_ENGINE:
-            generic.DatabaseOperations.execute(self, "SET storage_engine=%s;" %
-                settings.DATABASE_STORAGE_ENGINE)
-        return generic.DatabaseOperations.execute(self, sql, params)
-    execute.__doc__ = generic.DatabaseOperations.execute.__doc__
-
-    def rename_column(self, table_name, old, new):
-        if old == new or self.dry_run:
-            return []
-        
-        qn = connection.ops.quote_name
-        
-        rows = [x for x in self.execute('DESCRIBE %s' % (qn(table_name),)) if x[0] == old]
-        
-        if not rows:
-            raise ValueError("No column '%s' in '%s'." % (old, table_name))
-        
-        params = (
-            qn(table_name),
-            qn(old),
-            qn(new),
-            rows[0][1],
-            rows[0][2] == "YES" and "NULL" or "NOT NULL",
-            rows[0][3] == "PRI" and "PRIMARY KEY" or "",
-            rows[0][4] and "DEFAULT " or "",
-            rows[0][4] and "%s" or "",
-            rows[0][5] or "",
-        )
-        
-        sql = 'ALTER TABLE %s CHANGE COLUMN %s %s %s %s %s %s %s %s;' % params
-        
-        if rows[0][4]:
-            self.execute(sql, (rows[0][4],))
-        else:
-            self.execute(sql)
-    
-    
-    def rename_table(self, old_table_name, table_name):
-        """
-        Renames the table 'old_table_name' to 'table_name'.
-        """
-        if old_table_name == table_name:
-            # No Operation
-            return
-        qn = connection.ops.quote_name
-        params = (qn(old_table_name), qn(table_name))
-        self.execute('RENAME TABLE %s TO %s;' % params)
diff --git a/apps/south/db/postgresql_psycopg2.py b/apps/south/db/postgresql_psycopg2.py
deleted file mode 100644 (file)
index 839b4b1..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-
-from django.db import connection
-from south.db import generic
-
-class DatabaseOperations(generic.DatabaseOperations):
-
-    """
-    PsycoPG2 implementation of database operations.
-    """
-
-    def rename_column(self, table_name, old, new):
-        if old == new:
-            return []
-        qn = connection.ops.quote_name
-        params = (qn(table_name), qn(old), qn(new))
-        self.execute('ALTER TABLE %s RENAME COLUMN %s TO %s;' % params)
-    
-    def rename_table(self, old_table_name, table_name):
-        "will rename the table and an associated ID sequence and primary key index"
-        # First, rename the table
-        generic.DatabaseOperations.rename_table(self, old_table_name, table_name)
-        # Then, try renaming the ID sequence
-        # (if you're using other AutoFields... your problem, unfortunately)
-        self.commit_transaction()
-        self.start_transaction()
-        try:
-            generic.DatabaseOperations.rename_table(self, old_table_name+"_id_seq", table_name+"_id_seq")
-        except:
-            if self.debug:
-                print "   ~ No such sequence (ignoring error)"
-            self.rollback_transaction()
-        else:
-            self.commit_transaction()
-        self.start_transaction()
-
-        # Rename primary key index, will not rename other indices on
-        # the table that are used by django (e.g. foreign keys). Until
-        # figure out how, you need to do this yourself.
-        try:
-            generic.DatabaseOperations.rename_table(self, old_table_name+"_pkey", table_name+ "_pkey")
-        except:
-            if self.debug:
-                print "   ~ No such primary key (ignoring error)"
-            self.rollback_transaction()
-        else:
-            self.commit_transaction()
-        self.start_transaction()
-
-
-    def rename_index(self, old_index_name, index_name):
-        "Rename an index individually"
-        generic.DatabaseOperations.rename_table(self, old_index_name, index_name)
diff --git a/apps/south/db/sql_server/__init__.py b/apps/south/db/sql_server/__init__.py
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/apps/south/db/sql_server/pyodbc.py b/apps/south/db/sql_server/pyodbc.py
deleted file mode 100644 (file)
index 58c5166..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-from django.db import connection
-from django.db.models.fields import *
-from south.db import generic
-
-class DatabaseOperations(generic.DatabaseOperations):
-    """
-    django-pyodbc (sql_server.pyodbc) implementation of database operations.
-    """
-    
-    add_column_string = 'ALTER TABLE %s ADD %s;'
-    alter_string_set_type = 'ALTER COLUMN %(column)s %(type)s'
-    allows_combined_alters = False
-    delete_column_string = 'ALTER TABLE %s DROP COLUMN %s;'
-
-    def create_table(self, table_name, fields):
-        # Tweak stuff as needed
-        for name,f in fields:
-            if isinstance(f, BooleanField):
-                if f.default == True:
-                    f.default = 1
-                if f.default == False:
-                    f.default = 0
-
-        # Run
-        generic.DatabaseOperations.create_table(self, table_name, fields)
diff --git a/apps/south/db/sqlite3.py b/apps/south/db/sqlite3.py
deleted file mode 100644 (file)
index 1fac1b8..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-
-from django.db import connection
-from south.db import generic
-
-class DatabaseOperations(generic.DatabaseOperations):
-
-    """
-    SQLite3 implementation of database operations.
-    """
-
-    # SQLite ignores foreign key constraints. I wish I could.
-    supports_foreign_keys = False
-    
-    # You can't add UNIQUE columns with an ALTER TABLE.
-    def add_column(self, table_name, name, field, *args, **kwds):
-        # Run ALTER TABLE with no unique column
-        unique, field._unique, field.db_index = field.unique, False, False
-        generic.DatabaseOperations.add_column(self, table_name, name, field, *args, **kwds)
-        # If it _was_ unique, make an index on it.
-        if unique:
-            self.create_index(table_name, [name], unique=True)
-    
-    # SQLite doesn't have ALTER COLUMN
-    def alter_column(self, table_name, name, field, explicit_name=True):
-        """
-        Not supported under SQLite.
-        """
-        raise NotImplementedError("SQLite does not support altering columns.")
-    
-    # Nor DROP COLUMN
-    def delete_column(self, table_name, name, field):
-        """
-        Not supported under SQLite.
-        """
-        raise NotImplementedError("SQLite does not support deleting columns.")
-    
-    # Nor RENAME COLUMN
-    def rename_column(self, table_name, old, new):
-        """
-        Not supported under SQLite.
-        """
-        raise NotImplementedError("SQLite does not support renaming columns.")
\ No newline at end of file
diff --git a/apps/south/docs/CHANGELOG b/apps/south/docs/CHANGELOG
deleted file mode 100644 (file)
index fa106f9..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-0.3
-===
-
-The yay-dependencies release.
-
-New features:
-
- - Dependency support for migrations
- - Fields are now used for declaring columns and tables
-
-
-0.2
-===
-
-The oh-i'm-sorry-mysql-users release.
-
-New features:
-
- - MySQL support up to the same level as PostgreSQL
- - New --all option to ./manage.py startmigration, which creates a migration
-   for every model in the given app. For project starts.
- - Project status upgraded to 'beta'. Next up, a colour-coded
-   release level system.
-
-Fixed bugs:
-
- - A few typos in various column methods
- - ManyToMany tables weren't created by startmigration migrations.
-
-Known bugs:
-
- - None
-
-
-0.1
-===
-
-Initial release.
diff --git a/apps/south/docs/CONTRIBUTING b/apps/south/docs/CONTRIBUTING
deleted file mode 100644 (file)
index 56dd525..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-
-Contributing to South
----------------------
-
-Contributions to South are very welcome.
-
-
-You can find more info on our site at http://south.aeracode.org/wiki/Contributing
diff --git a/apps/south/docs/LICENSE b/apps/south/docs/LICENSE
deleted file mode 100644 (file)
index 1914f85..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-Apache License
-Version 2.0, January 2004
-http://www.apache.org/licenses/
-
-TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
-1. Definitions.
-
-"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
-
-"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
-
-"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
-
-"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
-
-"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
-
-"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
-
-"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
-
-"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
-
-"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
-
-"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
-
-2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
-
-3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
-
-4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
-
-   1. You must give any other recipients of the Work or Derivative Works a copy of this License; and
-
-   2. You must cause any modified files to carry prominent notices stating that You changed the files; and
-
-   3. You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
-
-   4. If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License.
-
-You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
-
-5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
-
-6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
-
-7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
-
-8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
-
-9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.
-
-END OF TERMS AND CONDITIONS
diff --git a/apps/south/docs/README b/apps/south/docs/README
deleted file mode 100644 (file)
index 99d3f20..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-This is South, a Django application to provide migrations in a sane way.
-
-By sane, we mean that the status of every migration is tracked individually,
-rather than just the number of the top migration reached; this means South
-can detect when you have an unapplied migration that's sitting in the middle
-of a whole load of applied ones, and will let you apply it straight off,
-or let you roll back to it, and apply from there forward.
-
-Documentation on South is currently available on our project site;
-you can find it at http://south.aeracode.org/wiki/Documentation
diff --git a/apps/south/management/__init__.py b/apps/south/management/__init__.py
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/apps/south/management/commands/__init__.py b/apps/south/management/commands/__init__.py
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/apps/south/management/commands/migrate.py b/apps/south/management/commands/migrate.py
deleted file mode 100644 (file)
index 1cc2a29..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-from django.core.management.base import BaseCommand
-from django.core.management.color import no_style
-from django.conf import settings
-from django.db import models
-from optparse import make_option
-from south import migration
-import sys
-
-class Command(BaseCommand):
-    option_list = BaseCommand.option_list + (
-        make_option('--skip', action='store_true', dest='skip', default=False,
-            help='Will skip over out-of-order missing migrations'),
-        make_option('--merge', action='store_true', dest='merge', default=False,
-            help='Will run out-of-order missing migrations as they are - no rollbacks.'),
-        make_option('--only', action='store_true', dest='only', default=False,
-            help='Only runs or rolls back the migration specified, and none around it.'),
-        make_option('--fake', action='store_true', dest='fake', default=False,
-            help="Pretends to do the migrations, but doesn't actually execute them."),
-
-        make_option('--db-dry-run', action='store_true', dest='db_dry_run', default=False,
-            help="Doesn't execute the SQL generated by the db methods, and doesn't store a record that the migration(s) occurred. Useful to test migrations before applying them."),
-    )
-    if '--verbosity' not in [opt.get_opt_string() for opt in BaseCommand.option_list]:
-        option_list += (
-            make_option('--verbosity', action='store', dest='verbosity', default='1',
-            type='choice', choices=['0', '1', '2'],
-            help='Verbosity level; 0=minimal output, 1=normal output, 2=all output'),
-        )
-    help = "Runs migrations for all apps."
-
-    def handle(self, app=None, target=None, skip=False, merge=False, only=False, backwards=False, fake=False, db_dry_run=False, **options):
-
-        # Work out what the resolve mode is
-        resolve_mode = merge and "merge" or (skip and "skip" or None)
-        # Turn on db debugging
-        from south.db import db
-        db.debug = True
-        
-        # NOTE: THIS IS DUPLICATED FROM django.core.management.commands.syncdb
-        # This code imports any module named 'management' in INSTALLED_APPS.
-        # The 'management' module is the preferred way of listening to post_syncdb
-        # signals, and since we're sending those out with create_table migrations,
-        # we need apps to behave correctly.
-        for app_name in settings.INSTALLED_APPS:
-            try:
-                __import__(app_name + '.management', {}, {}, [''])
-            except ImportError, exc:
-                msg = exc.args[0]
-                if not msg.startswith('No module named') or 'management' not in msg:
-                    raise
-        # END DJANGO DUPE CODE
-        
-        # Migrate each app
-        if app:
-            apps = [migration.get_app(app)]
-        else:
-            apps = migration.get_migrated_apps()
-        silent = options.get('verbosity', 0) == 0
-        for app in apps:
-            migration.migrate_app(
-                app,
-                resolve_mode = resolve_mode,
-                target_name = target,
-                fake = fake,
-                db_dry_run = db_dry_run,
-                silent = silent,
-                load_inital_data = True,
-            )
diff --git a/apps/south/management/commands/startmigration.py b/apps/south/management/commands/startmigration.py
deleted file mode 100644 (file)
index 1a8da99..0000000
+++ /dev/null
@@ -1,491 +0,0 @@
-from django.core.management.base import BaseCommand
-from django.core.management.color import no_style
-from django.db import models
-from django.db.models.fields.related import RECURSIVE_RELATIONSHIP_CONSTANT
-from django.contrib.contenttypes.generic import GenericRelation
-from django.db.models.fields import FieldDoesNotExist
-from optparse import make_option
-from south import migration
-import sys
-import os
-import re
-import string
-import random
-import inspect
-import parser
-
-class Command(BaseCommand):
-    option_list = BaseCommand.option_list + (
-        make_option('--model', action='append', dest='model_list', type='string',
-            help='Generate a Create Table migration for the specified model.  Add multiple models to this migration with subsequent --model parameters.'),
-        make_option('--add-field', action='append', dest='field_list', type='string',
-            help='Generate an Add Column migration for the specified modelname.fieldname - you can use this multiple times to add more than one column.'),
-        make_option('--initial', action='store_true', dest='initial', default=False,
-            help='Generate the initial schema for the app.'),
-    )
-    help = "Creates a new template migration for the given app"
-    
-    def handle(self, app=None, name="", model_list=None, field_list=None, initial=False, **options):
-        
-        # If model_list is None, then it's an empty list
-        model_list = model_list or []
-        
-        # If field_list is None, then it's an empty list
-        field_list = field_list or []
-        
-        # make sure --model and --all aren't both specified
-        if initial and (model_list or field_list):
-            print "You cannot use --initial and other options together"
-            return
-            
-        # specify the default name 'initial' if a name wasn't specified and we're
-        # doing a migration for an entire app
-        if not name and initial:
-            name = 'initial'
-            
-        # if not name, there's an error
-        if not name:
-            print "You must name this migration"
-            return
-        
-        if not app:
-            print "Please provide an app in which to create the migration."
-            return
-            
-        # See if the app exists
-        app_models_module = models.get_app(app)
-        if not app_models_module:
-            print "App '%s' doesn't seem to exist, isn't in INSTALLED_APPS, or has no models." % app
-            return
-            
-        # Determine what models should be included in this migration.
-        models_to_migrate = []
-        if initial:
-            models_to_migrate = models.get_models(app_models_module)
-            if not models_to_migrate:
-                print "No models found in app '%s'" % (app)
-                return
-        else:
-            for model_name in model_list:
-                model = models.get_model(app, model_name)
-                if not model:
-                    print "Couldn't find model '%s' in app '%s'" % (model_name, app)
-                    return
-                    
-                models_to_migrate.append(model)
-        
-        # See what fields need to be included
-        fields_to_add = []
-        for field_spec in field_list:
-            model_name, field_name = field_spec.split(".", 1)
-            model = models.get_model(app, model_name)
-            if not model:
-                print "Couldn't find model '%s' in app '%s'" % (model_name, app)
-                return
-            try:
-                field = model._meta.get_field(field_name)
-            except FieldDoesNotExist:
-                print "Model '%s' doesn't have a field '%s'" % (model_name, field_name)
-                return
-            fields_to_add.append((model, field_name, field))
-        
-        # Make the migrations directory if it's not there
-        app_module_path = app_models_module.__name__.split('.')[0:-1]
-        try:
-            app_module = __import__('.'.join(app_module_path), {}, {}, [''])
-        except ImportError:
-            print "Couldn't find path to App '%s'." % app
-            return
-            
-        migrations_dir = os.path.join(
-            os.path.dirname(app_module.__file__),
-            "migrations",
-        )
-        # Make sure there's a migrations directory and __init__.py
-        if not os.path.isdir(migrations_dir):
-            print "Creating migrations directory at '%s'..." % migrations_dir
-            os.mkdir(migrations_dir)
-        init_path = os.path.join(migrations_dir, "__init__.py")
-        if not os.path.isfile(init_path):
-            # Touch the init py file
-            print "Creating __init__.py in '%s'..." % migrations_dir
-            open(init_path, "w").close()
-        # See what filename is next in line. We assume they use numbers.
-        migrations = migration.get_migration_names(migration.get_app(app))
-        highest_number = 0
-        for migration_name in migrations:
-            try:
-                number = int(migration_name.split("_")[0])
-                highest_number = max(highest_number, number)
-            except ValueError:
-                pass
-        # Make the new filename
-        new_filename = "%04i%s_%s.py" % (
-            highest_number + 1,
-            "".join([random.choice(string.letters.lower()) for i in range(0)]), # Possible random stuff insertion
-            name,
-        )
-        # If there's a model, make the migration skeleton, else leave it bare
-        forwards, backwards = '', ''
-        if fields_to_add:
-            # First, do the added fields
-            for model, field_name, field in fields_to_add:
-                field_definition = generate_field_definition(model, field)
-                
-                if isinstance(field, models.ManyToManyField):
-                    # Make a mock model for each side
-                    mock_model = "\n".join([
-                        create_mock_model(model, "        "), 
-                        create_mock_model(field.rel.to, "        ")
-                    ])
-                    # And a field defn, that's actually a table creation
-                    forwards += '''
-        # Mock Model
-%s
-        # Adding ManyToManyField '%s.%s'
-        db.create_table('%s', (
-            ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
-            ('%s', models.ForeignKey(%s, null=False)),
-            ('%s', models.ForeignKey(%s, null=False))
-        )) ''' % (
-                mock_model,
-                model._meta.object_name,
-                field.name,
-                field.m2m_db_table(),
-                field.m2m_column_name()[:-3], # strip off the '_id' at the end
-                model._meta.object_name,
-                field.m2m_reverse_name()[:-3], # strip off the '_id' at the ned
-                field.rel.to._meta.object_name
-                )
-                    backwards += '''
-        # Dropping ManyToManyField '%s.%s'
-        db.drop_table('%s')''' % (
-                        model._meta.object_name,
-                        field.name,
-                        field.m2m_db_table()
-                    )
-                    continue
-                elif field.rel: # ForeignKey, etc.
-                    mock_model = create_mock_model(field.rel.to, "        ")
-                    field_definition = related_field_definition(field, field_definition)
-                else:
-                    mock_model = None
-                
-                # If we can't get it (inspect madness?) then insert placeholder
-                if not field_definition:
-                    print "Warning: Could not generate field definition for %s.%s, manual editing of migration required." % \
-                                (model._meta.object_name, field.name)
-                    field_definition = '<<< REPLACE THIS WITH FIELD DEFINITION FOR %s.%s >>>' % (model._meta.object_name, f.name)
-                
-                if mock_model:
-                    forwards += '''
-        # Mock model
-%s
-        ''' % (mock_model)
-                
-                forwards += '''
-        # Adding field '%s.%s'
-        db.add_column(%r, %r, %s)
-        ''' % (
-            model._meta.object_name,
-            field.name,
-            model._meta.db_table,
-            field.name,
-            field_definition,
-        )
-                backwards += '''
-        # Deleting field '%s.%s'
-        db.delete_column(%r, %r)
-        ''' % (
-            model._meta.object_name,
-            field.name,
-            model._meta.db_table,
-            field.column,
-        )
-        
-        if models_to_migrate:
-            # Now, do the added models
-            for model in models_to_migrate:
-                table_name = model._meta.db_table
-                mock_models = []
-                fields = []
-                for f in model._meta.local_fields:
-                    
-                    # Look up the field definition to see how this was created
-                    field_definition = generate_field_definition(model, f)
-                    
-                    # If it's a OneToOneField, and ends in _ptr, just use it
-                    if isinstance(f, models.OneToOneField) and f.name.endswith("_ptr"):
-                        mock_models.append(create_mock_model(f.rel.to, "        "))
-                        field_definition = "models.OneToOneField(%s)" % f.rel.to.__name__
-                    
-                    # It's probably normal then
-                    elif field_definition:
-                        
-                        if isinstance(f, models.ForeignKey):
-                            mock_models.append(create_mock_model(f.rel.to, "        "))
-                            field_definition = related_field_definition(f, field_definition)
-                    
-                    # Oh noes, no defn found
-                    else:
-                        print "Warning: Could not generate field definition for %s.%s, manual editing of migration required." % \
-                                (model._meta.object_name, f.name)
-                        print f, type(f)
-                                
-                        field_definition = '<<< REPLACE THIS WITH FIELD DEFINITION FOR %s.%s >>>' % (model._meta.object_name, f.name)
-                                                
-                    fields.append((f.name, field_definition))
-                    
-                if mock_models:
-                    forwards += '''
-        
-        # Mock Models
-%s
-        ''' % "\n".join(mock_models)
-        
-                forwards += '''
-        # Model '%s'
-        db.create_table(%r, (
-            %s
-        ))''' % (
-                    model._meta.object_name,
-                    table_name,
-                    "\n            ".join(["('%s', %s)," % (f[0], f[1]) for f in fields]),
-                )
-
-                backwards = ('''db.delete_table('%s')
-        ''' % table_name) + backwards
-        
-                # Now go through local M2Ms and add extra stuff for them
-                for m in model._meta.local_many_to_many:
-                    # ignore generic relations
-                    if isinstance(m, GenericRelation):
-                        continue
-
-                    # if the 'through' option is specified, the table will
-                    # be created through the normal model creation above.
-                    if m.rel.through:
-                        continue
-                        
-                    mock_models = [create_mock_model(model, "        "), create_mock_model(m.rel.to, "        ")]
-                    
-                    forwards += '''
-        # Mock Models
-%s
-        
-        # M2M field '%s.%s'
-        db.create_table('%s', (
-            ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
-            ('%s', models.ForeignKey(%s, null=False)),
-            ('%s', models.ForeignKey(%s, null=False))
-        )) ''' % (
-                        "\n".join(mock_models),
-                        model._meta.object_name,
-                        m.name,
-                        m.m2m_db_table(),
-                        m.m2m_column_name()[:-3], # strip off the '_id' at the end
-                        model._meta.object_name,
-                        m.m2m_reverse_name()[:-3], # strip off the '_id' at the ned
-                        m.rel.to._meta.object_name
-                )
-                
-                    backwards = '''db.delete_table('%s')
-        ''' % m.m2m_db_table() + backwards
-                
-                if model._meta.unique_together:
-                    ut = model._meta.unique_together
-                    if not isinstance(ut[0], (list, tuple)):
-                        ut = (ut,)
-                        
-                    for unique in ut:
-                        columns = ["'%s'" % model._meta.get_field(f).column for f in unique]
-                        
-                        forwards += '''
-        db.create_index('%s', [%s], unique=True, db_tablespace='%s')
-        ''' %   (
-                        table_name,
-                        ','.join(columns),
-                        model._meta.db_tablespace
-                )
-                
-                
-            forwards += '''
-        
-        db.send_create_signal('%s', ['%s'])''' % (
-                app, 
-                "','".join(model._meta.object_name for model in models_to_migrate)
-                )
-        
-        # Try sniffing the encoding using PEP 0263's method
-        encoding = None
-        first_two_lines = inspect.getsourcelines(app_models_module)[0][:2]
-        for line in first_two_lines:
-            if re.search("coding[:=]\s*([-\w.]+)", line):
-                encoding = line
-        
-        if (not forwards) and (not backwards):
-            forwards = '"Write your forwards migration here"'
-            backwards = '"Write your backwards migration here"'
-        fp = open(os.path.join(migrations_dir, new_filename), "w")
-        fp.write("""%s
-from south.db import db
-from django.db import models
-from %s.models import *
-
-class Migration:
-    
-    def forwards(self):
-        %s
-    
-    def backwards(self):
-        %s
-""" % (encoding or "", '.'.join(app_module_path), forwards, backwards))
-        fp.close()
-        print "Created %s." % new_filename
-
-
-def generate_field_definition(model, field):
-    """
-    Inspects the source code of 'model' to find the code used to generate 'field'
-    """
-    def test_field(field_definition):
-        try:
-            parser.suite(field_definition)
-            return True
-        except SyntaxError:
-            return False
-            
-    def strip_comments(field_definition):
-        # remove any comments at the end of the field definition string.
-        field_definition = field_definition.strip()
-        if '#' not in field_definition:
-            return field_definition
-            
-        index = field_definition.index('#')
-        while index:
-            stripped_definition = field_definition[:index].strip()
-            # if the stripped definition is parsable, then we've removed
-            # the correct comment.
-            if test_field(stripped_definition):
-                return stripped_definition
-            
-            try:    
-                index = field_definition.index('#', index+1)
-            except ValueError:
-                break
-            
-        return field_definition
-        
-    # give field subclasses a chance to do anything tricky
-    # with the field definition
-    if hasattr(field, 'south_field_definition'):
-        return field.south_field_definition()
-    
-    field_pieces = []
-    found_field = False
-    source = inspect.getsourcelines(model)
-    if not source:
-        raise Exception("Could not find source to model: '%s'" % (model.__name__))
-    
-    # look for a line starting with the field name
-    start_field_re = re.compile(r'\s*%s\s*=\s*(.*)' % field.name)
-    for line in source[0]:
-        # if the field was found during a previous iteration, 
-        # we're here because the field spans across multiple lines
-        # append the current line and try again
-        if found_field:
-            field_pieces.append(line.strip())
-            if test_field(' '.join(field_pieces)):
-                return strip_comments(' '.join(field_pieces))
-            continue
-        
-        match = start_field_re.match(line)
-        if match:
-            found_field = True
-            field_pieces.append(match.groups()[0].strip())
-            if test_field(' '.join(field_pieces)):
-                return strip_comments(' '.join(field_pieces))
-    
-    # the 'id' field never gets defined, so return what django does by default
-    # django.db.models.options::_prepare
-    if field.name == 'id' and field.__class__ == models.AutoField:
-        return "models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)"
-    
-    # search this classes parents
-    for base in model.__bases__:
-        # we don't want to scan the django base model
-        if base == models.Model:
-            continue
-            
-        field_definition = generate_field_definition(base, field)
-        if field_definition:
-            return field_definition
-            
-    return None
-    
-def replace_model_string(field_definition, search_string, model_name):
-    # wrap 'search_string' in both ' and " chars when searching
-    quotes = ["'", '"']
-    for quote in quotes:
-        test = "%s%s%s" % (quote, search_string, quote)
-        if test in field_definition:
-            return field_definition.replace(test, model_name)
-            
-    return None
-        
-def related_field_definition(field, field_definition):
-    # if the field definition contains any of the following strings,
-    # replace them with the model definition:
-    #   applabel.modelname
-    #   modelname
-    #   django.db.models.fields.related.RECURSIVE_RELATIONSHIP_CONSTANT
-    strings = [
-        '%s.%s' % (field.rel.to._meta.app_label, field.rel.to._meta.object_name),
-        '%s' % field.rel.to._meta.object_name,
-        RECURSIVE_RELATIONSHIP_CONSTANT
-    ]
-    
-    for test in strings:
-        fd = replace_model_string(field_definition, test, field.rel.to._meta.object_name)
-        if fd:
-            return fd
-    
-    return field_definition
-
-def create_mock_model(model, indent="        "):
-    # produce a string representing the python syntax necessary for creating
-    # a mock model using the supplied real model
-    if not model._meta.pk.__class__.__module__.startswith('django.db.models.fields'):
-        # we can fix this with some clever imports, but it doesn't seem necessary to
-        # spend time on just yet
-        print "Can't generate a mock model for %s because it's primary key isn't a default django field; it's type %s." % (model, model._meta.pk.__class__)
-        sys.exit()
-    
-    pk_field_args = []
-    pk_field_kwargs = {}
-    other_mocks = []
-    # If it's a OneToOneField or ForeignKey, take it's first arg
-    if model._meta.pk.__class__.__name__ in ["OneToOneField", "ForeignKey"]:
-        if model._meta.pk.rel.to == model:
-            pk_field_args += ["'self'"]
-        else:
-            pk_field_args += [model._meta.pk.rel.to._meta.object_name]
-            other_mocks += [model._meta.pk.rel.to]
-    
-    # Perhaps it has a max_length set?
-    if model._meta.pk.max_length:
-        pk_field_kwargs["max_length"] = model._meta.pk.max_length
-    
-    return "%s%s%s = db.mock_model(model_name='%s', db_table='%s', db_tablespace='%s', pk_field_name='%s', pk_field_type=models.%s, pk_field_args=[%s], pk_field_kwargs=%r)" % \
-        (
-        "\n".join([create_mock_model(m, indent) for m in other_mocks]+[""]),
-        indent,
-        model._meta.object_name,
-        model._meta.object_name,
-        model._meta.db_table,
-        model._meta.db_tablespace,
-        model._meta.pk.name,
-        model._meta.pk.__class__.__name__,
-        ", ".join(pk_field_args),
-        pk_field_kwargs,
-        )
diff --git a/apps/south/management/commands/syncdb.py b/apps/south/management/commands/syncdb.py
deleted file mode 100644 (file)
index 7b160c2..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-from django.core.management.base import NoArgsCommand, BaseCommand 
-from django.core.management.color import no_style
-from django.utils.datastructures import SortedDict
-from optparse import make_option
-from south import migration
-from django.core.management.commands import syncdb
-from django.conf import settings
-from django.db import models
-from django.db.models.loading import cache
-from django.core import management
-import sys
-
-def get_app_name(app):
-    return '.'.join( app.__name__.split('.')[0:-1] )
-
-class Command(NoArgsCommand):
-    option_list = NoArgsCommand.option_list + (
-        make_option('--noinput', action='store_false', dest='interactive', default=True,
-            help='Tells Django to NOT prompt the user for input of any kind.'),
-        make_option('--migrate', action='store_true', dest='migrate', default=False,
-            help='Tells South to also perform migrations after the sync. Default for during testing, and other internal calls.'),
-    )
-    if '--verbosity' not in [opt.get_opt_string() for opt in BaseCommand.option_list]:
-        option_list += (
-            make_option('--verbosity', action='store', dest='verbosity', default='1',
-            type='choice', choices=['0', '1', '2'],
-            help='Verbosity level; 0=minimal output, 1=normal output, 2=all output'),
-        )
-    help = "Create the database tables for all apps in INSTALLED_APPS whose tables haven't already been created, except those which use migrations."
-
-    def handle_noargs(self, **options):
-        # Work out what uses migrations and so doesn't need syncing
-        apps_needing_sync = []
-        apps_migrated = []
-        for app in models.get_apps():
-            app_name = get_app_name(app)
-            migrations = migration.get_app(app)
-            if migrations is None:
-                apps_needing_sync.append(app_name)
-            else:
-                # This is a migrated app, leave it
-                apps_migrated.append(app_name)
-        verbosity = int(options.get('verbosity', 0))
-        # Run syncdb on only the ones needed
-        if verbosity > 0:
-            print "Syncing..."
-        old_installed, settings.INSTALLED_APPS = settings.INSTALLED_APPS, apps_needing_sync
-        old_app_store, cache.app_store = cache.app_store, SortedDict([
-            (k, v) for (k, v) in cache.app_store.items()
-            if get_app_name(k) in apps_needing_sync
-        ])
-        syncdb.Command().execute(**options)
-        settings.INSTALLED_APPS = old_installed
-        cache.app_store = old_app_store
-        # Migrate if needed
-        if options.get('migrate', True):
-            if verbosity > 0:
-                print "Migrating..."
-            management.call_command('migrate', **options)
-        # Be obvious about what we did
-        if verbosity > 0:
-            print "\nSynced:\n > %s" % "\n > ".join(apps_needing_sync)
-        
-        if options.get('migrate', True):
-            if verbosity > 0:
-                print "\nMigrated:\n - %s" % "\n - ".join(apps_migrated)
-        else:
-            if verbosity > 0:
-                print "\nNot synced (use migrations):\n - %s" % "\n - ".join(apps_migrated)
-                print "(use ./manage.py migrate to migrate these)"
diff --git a/apps/south/management/commands/test.py b/apps/south/management/commands/test.py
deleted file mode 100644 (file)
index eef8f31..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-from django.core import management
-from django.core.management.commands import test
-from django.core.management.commands import syncdb
-
-class Command(test.Command):
-    
-    def handle(self, *args, **kwargs):
-        # point at the core syncdb command when creating tests
-        # tests should always be up to date with the most recent model structure
-        management.get_commands()
-        management._commands['syncdb'] = 'django.core'
-        super(Command, self).handle(*args, **kwargs)
\ No newline at end of file
diff --git a/apps/south/migration.py b/apps/south/migration.py
deleted file mode 100644 (file)
index 6452442..0000000
+++ /dev/null
@@ -1,528 +0,0 @@
-
-import datetime
-import os
-import sys
-import traceback
-from django.conf import settings
-from django.db import models
-from django.core.exceptions import ImproperlyConfigured
-from django.core.management import call_command
-from models import MigrationHistory
-from south.db import db
-
-
-def get_app(app):
-    """
-    Returns the migrations module for the given app model name/module, or None
-    if it does not use migrations.
-    """
-    if isinstance(app, (str, unicode)):
-        # If it's a string, use the models module
-        app = models.get_app(app)
-    mod = __import__(app.__name__[:-7], {}, {}, ['migrations'])
-    if hasattr(mod, 'migrations'):
-        return getattr(mod, 'migrations')
-
-
-def get_migrated_apps():
-    """
-    Returns all apps with migrations.
-    """
-    for mapp in models.get_apps():
-        app = get_app(mapp)
-        if app:
-            yield app
-
-
-def get_app_name(app):
-    """
-    Returns the _internal_ app name for the given app module.
-    i.e. for <module django.contrib.auth.models> will return 'auth'
-    """
-    return app.__name__.split('.')[-2]
-
-
-def get_app_fullname(app):
-    """
-    Returns the full python name of an app - e.g. django.contrib.auth
-    """
-    return app.__name__[:-11]
-
-
-def short_from_long(app_name):
-    return app_name.split(".")[-1]
-
-
-def get_migration_names(app):
-    """
-    Returns a list of migration file names for the given app.
-    """
-    return sorted([
-        filename[:-3]
-        for filename in os.listdir(os.path.dirname(app.__file__))
-        if filename.endswith(".py") and filename != "__init__.py" and not filename.startswith(".")
-    ])
-
-
-def get_migration_classes(app):
-    """
-    Returns a list of migration classes (one for each migration) for the app.
-    """
-    for name in get_migration_names(app):
-        yield get_migration(app, name)
-
-
-def get_migration(app, name):
-    """
-    Returns the migration class implied by 'name'.
-    """
-    try:
-        module = __import__(app.__name__ + "." + name, '', '', ['Migration'])
-        return module.Migration
-    except ImportError:
-        print " ! Migration %s:%s probably doesn't exist." % (get_app_name(app), name)
-        print " - Traceback:"
-        raise
-
-
-def all_migrations():
-    return dict([
-        (app, dict([(name, get_migration(app, name)) for name in get_migration_names(app)]))
-        for app in get_migrated_apps()
-    ])
-
-
-def dependency_tree():
-    tree = all_migrations()
-    
-    # Annotate tree with 'backwards edges'
-    for app, classes in tree.items():
-        for name, cls in classes.items():
-            cls.needs = []
-            if not hasattr(cls, "needed_by"):
-                cls.needed_by = []
-            if hasattr(cls, "depends_on"):
-                for dapp, dname in cls.depends_on:
-                    dapp = get_app(dapp)
-                    if dapp not in tree:
-                        print "Migration %s in app %s depends on unmigrated app %s." % (
-                            name,
-                            get_app_name(app),
-                            dapp,
-                        )
-                        sys.exit(1)
-                    if dname not in tree[dapp]:
-                        print "Migration %s in app %s depends on nonexistent migration %s in app %s." % (
-                            name,
-                            get_app_name(app),
-                            dname,
-                            get_app_name(dapp),
-                        )
-                        sys.exit(1)
-                    cls.needs.append((dapp, dname))
-                    if not hasattr(tree[dapp][dname], "needed_by"):
-                        tree[dapp][dname].needed_by = []
-                    tree[dapp][dname].needed_by.append((app, name))
-    
-    # Sanity check whole tree
-    for app, classes in tree.items():
-        for name, cls in classes.items():
-            cls.dependencies = dependencies(tree, app, name)
-    
-    return tree
-
-
-def nice_trace(trace):
-    return " -> ".join([str((get_app_name(a), n)) for a, n in trace])
-
-
-def dependencies(tree, app, name, trace=[]):
-    # Copy trace to stop pass-by-ref problems
-    trace = trace[:]
-    # Sanity check
-    for papp, pname in trace:
-        if app == papp:
-            if pname == name:
-                print "Found circular dependency: %s" % nice_trace(trace + [(app,name)])
-                sys.exit(1)
-            else:
-                # See if they depend in the same app the wrong way
-                migrations = get_migration_names(app)
-                if migrations.index(name) > migrations.index(pname):
-                    print "Found a lower migration (%s) depending on a higher migration (%s) in the same app (%s)." % (pname, name, get_app_name(app))
-                    print "Path: %s" % nice_trace(trace + [(app,name)])
-                    sys.exit(1)
-    # Get the dependencies of a migration
-    deps = []
-    migration = tree[app][name]
-    for dapp, dname in migration.needs:
-        deps.extend(
-            dependencies(tree, dapp, dname, trace+[(app,name)])
-        )
-    return deps
-
-
-def remove_duplicates(l):
-    m = []
-    for x in l:
-        if x not in m:
-            m.append(x)
-    return m
-
-
-def needed_before_forwards(tree, app, name, sameapp=True):
-    """
-    Returns a list of migrations that must be applied before (app, name),
-    in the order they should be applied.
-    Used to make sure a migration can be applied (and to help apply up to it).
-    """
-    app_migrations = get_migration_names(app)
-    needed = []
-    if sameapp:
-        for aname in app_migrations[:app_migrations.index(name)]:
-            needed += needed_before_forwards(tree, app, aname, False)
-            needed += [(app, aname)]
-    for dapp, dname in tree[app][name].needs:
-        needed += needed_before_forwards(tree, dapp, dname)
-        needed += [(dapp, dname)]
-    return remove_duplicates(needed)
-
-
-def needed_before_backwards(tree, app, name, sameapp=True):
-    """
-    Returns a list of migrations that must be unapplied before (app, name) is,
-    in the order they should be unapplied.
-    Used to make sure a migration can be unapplied (and to help unapply up to it).
-    """
-    app_migrations = get_migration_names(app)
-    needed = []
-    if sameapp:
-        for aname in reversed(app_migrations[app_migrations.index(name)+1:]):
-            needed += needed_before_backwards(tree, app, aname, False)
-            needed += [(app, aname)]
-    for dapp, dname in tree[app][name].needed_by:
-        needed += needed_before_backwards(tree, dapp, dname)
-        needed += [(dapp, dname)]
-    return remove_duplicates(needed)
-
-
-def run_migrations(toprint, torun, recorder, app, migrations, fake=False, db_dry_run=False, silent=False):
-    """
-    Runs the specified migrations forwards, in order.
-    """
-    for migration in migrations:
-        app_name = get_app_name(app)
-        if not silent:
-            print toprint % (app_name, migration)
-        klass = get_migration(app, migration)
-
-        if fake:
-            if not silent:
-                print "   (faked)"
-        else:
-            
-            # If the database doesn't support running DDL inside a transaction
-            # *cough*MySQL*cough* then do a dry run first.
-            if not db.has_ddl_transactions:
-                db.dry_run = True
-                db.debug, old_debug = False, db.debug
-                try:
-                    getattr(klass(), torun)()
-                except:
-                    traceback.print_exc()
-                    print " ! Error found during dry run of migration! Aborting."
-                    return False
-                db.debug = old_debug
-                db.clear_run_data()
-            
-            db.dry_run = bool(db_dry_run)
-            
-            if db.has_ddl_transactions:
-                db.start_transaction()
-            try:
-                getattr(klass(), torun)()
-                db.execute_deferred_sql()
-            except:
-                if db.has_ddl_transactions:
-                    db.rollback_transaction()
-                    raise
-                else:
-                    traceback.print_exc()
-                    print " ! Error found during real run of migration! Aborting."
-                    print
-                    print " ! Since you have a database that does not support running"
-                    print " ! schema-altering statements in transactions, we have had to"
-                    print " ! leave it in an interim state between migrations."
-                    if torun == "forwards":
-                        print
-                        print " ! You *might* be able to recover with:"
-                        db.debug = db.dry_run = True
-                        klass().backwards()
-                    print
-                    print " ! The South developers regret this has happened, and would"
-                    print " ! like to gently persuade you to consider a slightly"
-                    print " ! easier-to-deal-with DBMS."
-                    return False
-            else:
-                if db.has_ddl_transactions:
-                    db.commit_transaction()
-
-        if not db_dry_run:
-            # Record us as having done this
-            recorder(app_name, migration)
-
-
-def run_forwards(app, migrations, fake=False, db_dry_run=False, silent=False):
-    """
-    Runs the specified migrations forwards, in order.
-    """
-    
-    def record(app_name, migration):
-        # Record us as having done this
-        record = MigrationHistory.for_migration(app_name, migration)
-        record.applied = datetime.datetime.utcnow()
-        record.save()
-    
-    return run_migrations(
-        toprint = " > %s: %s",
-        torun = "forwards",
-        recorder = record,
-        app = app,
-        migrations = migrations,
-        fake = fake,
-        db_dry_run = db_dry_run,
-        silent = silent,
-    )
-
-
-def run_backwards(app, migrations, ignore=[], fake=False, db_dry_run=False, silent=False):
-    """
-    Runs the specified migrations backwards, in order, skipping those
-    migrations in 'ignore'.
-    """
-    
-    def record(app_name, migration):
-        # Record us as having not done this
-        record = MigrationHistory.for_migration(app_name, migration)
-        record.delete()
-    
-    return run_migrations(
-        toprint = " < %s: %s",
-        torun = "backwards",
-        recorder = record,
-        app = app,
-        migrations = [x for x in migrations if x not in ignore],
-        fake = fake,
-        db_dry_run = db_dry_run,
-        silent = silent,
-    )
-
-
-def right_side_of(x, y):
-    return left_side_of(reversed(x), reversed(y))
-
-
-def left_side_of(x, y):
-    return list(y)[:len(x)] == list(x)
-
-
-def forwards_problems(tree, forwards, done, silent=False):
-    problems = []
-    for app, name in forwards:
-        if (app, name) not in done:
-            for dapp, dname in needed_before_backwards(tree, app, name):
-                if (dapp, dname) in done:
-                    if not silent:
-                        print " ! Migration (%s, %s) should not have been applied before (%s, %s) but was." % (get_app_name(dapp), dname, get_app_name(app), name)
-                    problems.append(((app, name), (dapp, dname)))
-    return problems
-
-
-
-def backwards_problems(tree, backwards, done, silent=False):
-    problems = []
-    for app, name in backwards:
-        if (app, name) in done:
-            for dapp, dname in needed_before_forwards(tree, app, name):
-                if (dapp, dname) not in done:
-                    if not silent:
-                        print " ! Migration (%s, %s) should have been applied before (%s, %s) but wasn't." % (get_app_name(dapp), dname, get_app_name(app), name)
-                    problems.append(((app, name), (dapp, dname)))
-    return problems
-
-
-def migrate_app(app, target_name=None, resolve_mode=None, fake=False, db_dry_run=False, yes=False, silent=False, load_inital_data=False):
-    
-    app_name = get_app_name(app)
-    
-    db.debug = not silent
-    
-    # If any of their app names in the DB contain a ., they're 0.2 or below, so migrate em
-    longuns = MigrationHistory.objects.filter(app_name__contains=".")
-    if longuns:
-        for mh in longuns:
-            mh.app_name = short_from_long(mh.app_name)
-            mh.save()
-        if not silent:
-            print "- Updated your South 0.2 database."
-    
-    # Find out what delightful migrations we have
-    tree = dependency_tree()
-    migrations = get_migration_names(app)
-    
-    # If there aren't any, quit quizically
-    if not migrations:
-        if not silent:
-            print "? You have no migrations for the '%s' app. You might want some." % app_name
-        return
-    
-    if target_name not in migrations and target_name not in ["zero", None]:
-        matches = [x for x in migrations if x.startswith(target_name)]
-        if len(matches) == 1:
-            target = migrations.index(matches[0]) + 1
-            if not silent:
-                print " - Soft matched migration %s to %s." % (
-                    target_name,
-                    matches[0]
-                )
-            target_name = matches[0]
-        elif len(matches) > 1:
-            if not silent:
-                print " - Prefix %s matches more than one migration:" % target_name
-                print "     " + "\n     ".join(matches)
-            return
-        else:
-            if not silent:
-                print " ! '%s' is not a migration." % target_name
-            return
-    
-    # Check there's no strange ones in the database
-    ghost_migrations = []
-    for m in MigrationHistory.objects.filter(applied__isnull = False):
-        try:
-            if get_app(m.app_name) not in tree or m.migration not in tree[get_app(m.app_name)]:
-                ghost_migrations.append(m)
-        except ImproperlyConfigured:
-            pass
-            
-        
-    if ghost_migrations:
-        if not silent:
-            print " ! These migrations are in the database but not on disk:"
-            print "   - " + "\n   - ".join(["%s: %s" % (x.app_name, x.migration) for x in ghost_migrations])
-            print " ! I'm not trusting myself; fix this yourself by fiddling"
-            print " ! with the south_migrationhistory table."
-        return
-    
-    # Say what we're doing
-    if not silent:
-        print "Running migrations for %s:" % app_name
-    
-    # Get the forwards and reverse dependencies for this target
-    if target_name == None:
-        target_name = migrations[-1]
-    if target_name == "zero":
-        forwards = []
-        backwards = needed_before_backwards(tree, app, migrations[0]) + [(app, migrations[0])]
-    else:
-        forwards = needed_before_forwards(tree, app, target_name) + [(app, target_name)]
-        # When migrating backwards we want to remove up to and including
-        # the next migration up in this app (not the next one, that includes other apps)
-        try:
-            migration_before_here = migrations[migrations.index(target_name)+1]
-            backwards = needed_before_backwards(tree, app, migration_before_here) + [(app, migration_before_here)]
-        except IndexError:
-            backwards = []
-    
-    # Get the list of currently applied migrations from the db
-    current_migrations = []
-    for m in MigrationHistory.objects.filter(applied__isnull = False):
-        try:
-            current_migrations.append((get_app(m.app_name), m.migration))
-        except ImproperlyConfigured:
-            pass
-    
-    direction = None
-    bad = False
-    
-    # Work out the direction
-    applied_for_this_app = list(MigrationHistory.objects.filter(app_name=app_name, applied__isnull=False).order_by("migration"))
-    if target_name == "zero":
-        direction = -1
-    elif not applied_for_this_app:
-        direction = 1
-    elif migrations.index(target_name) > migrations.index(applied_for_this_app[-1].migration):
-        direction = 1
-    elif migrations.index(target_name) < migrations.index(applied_for_this_app[-1].migration):
-        direction = -1
-    else:
-        direction = None
-    
-    # Is the whole forward branch applied?
-    missing = [step for step in forwards if step not in current_migrations]
-    # If they're all applied, we only know it's not backwards
-    if not missing:
-        direction = None
-    # If the remaining migrations are strictly a right segment of the forwards
-    # trace, we just need to go forwards to our target (and check for badness)
-    else:
-        problems = forwards_problems(tree, forwards, current_migrations, silent=silent)
-        if problems:
-            bad = True
-        direction = 1
-    
-    # What about the whole backward trace then?
-    if not bad:
-        missing = [step for step in backwards if step not in current_migrations]
-        # If they're all missing, stick with the forwards decision
-        if missing == backwards:
-            pass
-        # If what's missing is a strict left segment of backwards (i.e.
-        # all the higher migrations) then we need to go backwards
-        else:
-            problems = backwards_problems(tree, backwards, current_migrations, silent=silent)
-            if problems:
-                bad = True
-            direction = -1
-    
-    if bad and resolve_mode not in ['merge']:
-        if not silent:
-            print " ! Inconsistent migration history"
-            print " ! The following options are available:"
-            print "    --merge: will just attempt the migration ignoring any potential dependency conflicts."
-        sys.exit(1)
-    
-    if direction == 1:
-        if not silent:
-            print " - Migrating forwards to %s." % target_name
-        try:
-            for mapp, mname in forwards:
-                if (mapp, mname) not in current_migrations:
-                    result = run_forwards(mapp, [mname], fake=fake, db_dry_run=db_dry_run, silent=silent)
-                    if result is False: # The migrations errored, but nicely.
-                        return
-        finally:
-            # Call any pending post_syncdb signals
-            db.send_pending_create_signals()
-        # Now load initial data, only if we're really doing things and ended up at current
-        if not fake and not db_dry_run and load_inital_data and target_name == migrations[-1]:
-            print " - Loading initial data for %s." % app_name
-            # Override Django's get_apps call temporarily to only load from the
-            # current app
-            old_get_apps, models.get_apps = (
-                models.get_apps,
-                lambda: [models.get_app(get_app_name(app))],
-            )
-            # Load the initial fixture
-            call_command('loaddata', 'initial_data', verbosity=1)
-            # Un-override
-            models.get_apps = old_get_apps
-    elif direction == -1:
-        if not silent:
-            print " - Migrating backwards to just after %s." % target_name
-        for mapp, mname in backwards:
-            if (mapp, mname) in current_migrations:
-                run_backwards(mapp, [mname], fake=fake, db_dry_run=db_dry_run, silent=silent)
-    else:
-        if not silent:
-            print "- Nothing to migrate."
diff --git a/apps/south/models.py b/apps/south/models.py
deleted file mode 100644 (file)
index e95c79a..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-from django.db import models
-
-class MigrationHistory(models.Model):
-    app_name = models.CharField(max_length=255)
-    migration = models.CharField(max_length=255)
-    applied = models.DateTimeField(blank=True, null=True)
-
-    @classmethod
-    def for_migration(cls, app_name, migration):
-        try:
-            return cls.objects.get(
-                app_name = app_name,
-                migration = migration,
-            )
-        except cls.DoesNotExist:
-            return cls(
-                app_name = app_name,
-                migration = migration,
-            )
\ No newline at end of file
diff --git a/apps/south/setup.py b/apps/south/setup.py
deleted file mode 100755 (executable)
index 9e09583..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-#!/usr/bin/python
-
-from setuptools import setup, find_packages
-
-setup(
-    name='South',
-    version='0.4',
-    description='South: Migrations for Django',
-    long_description='South is an intelligent database migrations library for the Django web framework. It is database-independent and DVCS-friendly, as well as a whole host of other features.',
-    author='Andrew Godwin & Andy McCurdy',
-    author_email='south@aeracode.org',
-    url='http://south.aeracode.org/',
-    download_url='http://south.aeracode.org/wiki/Download',
-    classifiers=[
-        "Development Status :: 5 - Production/Stable",
-        "Framework :: Django",
-        "Intended Audience :: Developers",
-        "Intended Audience :: System Administrators",
-        "Intended Audience :: System Administrators",
-        "License :: OSI Approved :: Apache Software License",
-        "Operating System :: OS Independent",
-        "Topic :: Software Development"
-    ],
-    packages=["south", "south.db", "south.management", "south.management.commands", "south.tests", "south.tests.fakeapp", "south.tests.fakeapp.migrations"],
-    package_dir = {"south" : ""},
-)
diff --git a/apps/south/tests/__init__.py b/apps/south/tests/__init__.py
deleted file mode 100644 (file)
index d8953fe..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-
-from django.conf import settings
-
-try:
-    skiptest = settings.SKIP_SOUTH_TESTS
-except:
-    skiptest = False
-
-if not skiptest:
-    from south.tests.db import *
-    from south.tests.logic import *
\ No newline at end of file
diff --git a/apps/south/tests/db.py b/apps/south/tests/db.py
deleted file mode 100644 (file)
index b7bb145..0000000
+++ /dev/null
@@ -1,185 +0,0 @@
-import unittest
-
-from south.db import db
-from django.db import connection, models
-
-# Create a list of error classes from the various database libraries
-errors = []
-try:
-    from psycopg2 import ProgrammingError
-    errors.append(ProgrammingError)
-except ImportError:
-    pass
-errors = tuple(errors)
-
-class TestOperations(unittest.TestCase):
-
-    """
-    Tests if the various DB abstraction calls work.
-    Can only test a limited amount due to DB differences.
-    """
-
-    def setUp(self):
-        db.debug = False
-        db.clear_deferred_sql()
-
-    def test_create(self):
-        """
-        Test creation and deletion of tables.
-        """
-        cursor = connection.cursor()
-        # It needs to take at least 2 args
-        self.assertRaises(TypeError, db.create_table)
-        self.assertRaises(TypeError, db.create_table, "test1")
-        # Empty tables (i.e. no columns) are not fine, so make at least 1
-        db.create_table("test1", [('email_confirmed', models.BooleanField(default=False))])
-        db.start_transaction()
-        # And should exist
-        cursor.execute("SELECT * FROM test1")
-        # Make sure we can't do the same query on an empty table
-        try:
-            cursor.execute("SELECT * FROM nottheretest1")
-            self.fail("Non-existent table could be selected!")
-        except:
-            pass
-        # Clear the dirty transaction
-        db.rollback_transaction()
-        db.start_transaction()
-        # Remove the table
-        db.drop_table("test1")
-        # Make sure it went
-        try:
-            cursor.execute("SELECT * FROM test1")
-            self.fail("Just-deleted table could be selected!")
-        except:
-            pass
-        # Clear the dirty transaction
-        db.rollback_transaction()
-        db.start_transaction()
-        # Try deleting a nonexistent one
-        try:
-            db.delete_table("nottheretest1")
-            self.fail("Non-existent table could be deleted!")
-        except:
-            pass
-        db.rollback_transaction()
-    
-    def test_foreign_keys(self):
-        """
-        Tests foreign key creation, especially uppercase (see #61)
-        """
-        Test = db.mock_model(model_name='Test', db_table='test5a',
-                             db_tablespace='', pk_field_name='ID',
-                             pk_field_type=models.AutoField, pk_field_args=[])
-        cursor = connection.cursor()
-        db.start_transaction()
-        db.create_table("test5a", [('ID', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True))])
-        db.create_table("test5b", [
-            ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
-            ('UNIQUE', models.ForeignKey(Test)),
-        ])
-        db.execute_deferred_sql()
-        db.rollback_transaction()
-    
-    def test_rename(self):
-        """
-        Test column renaming
-        """
-        cursor = connection.cursor()
-        db.create_table("test2", [('spam', models.BooleanField(default=False))])
-        db.start_transaction()
-        # Make sure we can select the column
-        cursor.execute("SELECT spam FROM test2")
-        # Rename it
-        db.rename_column("test2", "spam", "eggs")
-        cursor.execute("SELECT eggs FROM test2")
-        try:
-            cursor.execute("SELECT spam FROM test2")
-            self.fail("Just-renamed column could be selected!")
-        except:
-            pass
-        db.rollback_transaction()
-        db.delete_table("test2")
-    
-    def test_dry_rename(self):
-        """
-        Test column renaming while --dry-run is turned on (should do nothing)
-        See ticket #65
-        """
-        cursor = connection.cursor()
-        db.create_table("test2", [('spam', models.BooleanField(default=False))])
-        db.start_transaction()
-        # Make sure we can select the column
-        cursor.execute("SELECT spam FROM test2")
-        # Rename it
-        db.dry_run = True
-        db.rename_column("test2", "spam", "eggs")
-        db.dry_run = False
-        cursor.execute("SELECT spam FROM test2")
-        try:
-            cursor.execute("SELECT eggs FROM test2")
-            self.fail("Dry-renamed new column could be selected!")
-        except:
-            pass
-        db.rollback_transaction()
-        db.delete_table("test2")
-    
-    def test_table_rename(self):
-        """
-        Test column renaming
-        """
-        cursor = connection.cursor()
-        db.create_table("testtr", [('spam', models.BooleanField(default=False))])
-        db.start_transaction()
-        # Make sure we can select the column
-        cursor.execute("SELECT spam FROM testtr")
-        # Rename it
-        db.rename_table("testtr", "testtr2")
-        cursor.execute("SELECT spam FROM testtr2")
-        try:
-            cursor.execute("SELECT spam FROM testtr")
-            self.fail("Just-renamed column could be selected!")
-        except:
-            pass
-        db.rollback_transaction()
-        db.delete_table("testtr2")
-    
-    def test_index(self):
-        """
-        Test the index operations
-        """
-        db.create_table("test3", [
-            ('SELECT', models.BooleanField(default=False)),
-            ('eggs', models.IntegerField(unique=True)),
-        ])
-        db.execute_deferred_sql()
-        db.start_transaction()
-        # Add an index on that column
-        db.create_index("test3", ["SELECT"])
-        # Add another index on two columns
-        db.create_index("test3", ["SELECT", "eggs"])
-        # Delete them both
-        db.delete_index("test3", ["SELECT"])
-        db.delete_index("test3", ["SELECT", "eggs"])
-        # Delete the unique index
-        db.delete_index("test3", ["eggs"])
-        db.rollback_transaction()
-        db.delete_table("test3")
-    
-    def test_alter(self):
-        """
-        Test altering columns/tables
-        """
-        db.create_table("test4", [
-            ('spam', models.BooleanField(default=False)),
-            ('eggs', models.IntegerField()),
-        ])
-        db.start_transaction()
-        # Add a column
-        db.add_column("test4", "add1", models.IntegerField(default=3), keep_default=False)
-        # Add a FK with keep_default=False (#69)
-        User = db.mock_model(model_name='User', db_table='auth_user', db_tablespace='', pk_field_name='id', pk_field_type=models.AutoField, pk_field_args=[], pk_field_kwargs={})
-        db.add_column("test4", "user", models.ForeignKey(User), keep_default=False)
-        
-        db.rollback_transaction()
-        db.delete_table("test4")
\ No newline at end of file
diff --git a/apps/south/tests/fakeapp/__init__.py b/apps/south/tests/fakeapp/__init__.py
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/apps/south/tests/fakeapp/migrations/0001_spam.py b/apps/south/tests/fakeapp/migrations/0001_spam.py
deleted file mode 100644 (file)
index d814548..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-from south.db import db
-from django.db import models
-
-class Migration:
-    
-    def forwards(self):
-        
-        # Model 'Spam'
-        db.create_table("southtest_spam", (
-            ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
-            ('weight', models.FloatField()),
-            ('expires', models.DateTimeField()),
-            ('name', models.CharField(max_length=255))
-        ))
-    
-    def backwards(self):
-        
-        db.delete_table("southtest_spam")
-
diff --git a/apps/south/tests/fakeapp/migrations/0002_eggs.py b/apps/south/tests/fakeapp/migrations/0002_eggs.py
deleted file mode 100644 (file)
index 3ec8399..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-from south.db import db
-from django.db import models
-
-class Migration:
-    
-    def forwards(self):
-        
-        Spam = db.mock_model(model_name='Spam', db_table='southtest_spam', db_tablespace='', pk_field_name='id', pk_field_type=models.AutoField)
-        
-        db.create_table("southtest_eggs", (
-            ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
-            ('size', models.FloatField()),
-            ('quantity', models.IntegerField()),
-            ('spam', models.ForeignKey(Spam)),
-        ))
-    
-    def backwards(self):
-        
-        db.delete_table("southtest_eggs")
-
diff --git a/apps/south/tests/fakeapp/migrations/0003_alter_spam.py b/apps/south/tests/fakeapp/migrations/0003_alter_spam.py
deleted file mode 100644 (file)
index 3a9aea4..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-from south.db import db
-from django.db import models
-
-class Migration:
-    
-    def forwards(self):
-        
-        db.alter_column("southtest_spam", 'name', models.CharField(max_length=255, null=True))
-    
-    def backwards(self):
-        
-        db.alter_column("southtest_spam", 'name', models.CharField(max_length=255))
diff --git a/apps/south/tests/fakeapp/migrations/__init__.py b/apps/south/tests/fakeapp/migrations/__init__.py
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/apps/south/tests/fakeapp/models.py b/apps/south/tests/fakeapp/models.py
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/apps/south/tests/logic.py b/apps/south/tests/logic.py
deleted file mode 100644 (file)
index 862c52d..0000000
+++ /dev/null
@@ -1,292 +0,0 @@
-import unittest
-import datetime
-import sys
-import os
-
-from south import migration
-
-# Add the tests directory so fakeapp is on sys.path
-test_root = os.path.dirname(__file__)
-sys.path.append(test_root)
-
-
-class TestMigrationLogic(unittest.TestCase):
-
-    """
-    Tests if the various logic functions in migration actually work.
-    """
-
-    def create_fake_app(self, name):
-        
-        class Fake:
-            pass
-        
-        fake = Fake()
-        fake.__name__ = name
-        return fake
-
-
-    def create_test_app(self):
-        
-        class Fake:
-            pass
-        
-        fake = Fake()
-        fake.__name__ = "fakeapp.migrations"
-        fake.__file__ = os.path.join(test_root, "fakeapp", "migrations", "__init__.py")
-        return fake
-    
-    
-    def monkeypatch(self):
-        """Swaps out various Django calls for fake ones for our own nefarious purposes."""
-        
-        def new_get_apps():
-            return ['fakeapp']
-        
-        from django.db import models
-        from django.conf import settings
-        models.get_apps_old, models.get_apps = models.get_apps, new_get_apps
-        settings.INSTALLED_APPS, settings.OLD_INSTALLED_APPS = (
-            ["fakeapp"],
-            settings.INSTALLED_APPS,
-        )
-        self.redo_app_cache()
-    setUp = monkeypatch
-    
-    
-    def unmonkeypatch(self):
-        """Undoes what monkeypatch did."""
-        
-        from django.db import models
-        from django.conf import settings
-        models.get_apps = models.get_apps_old
-        settings.INSTALLED_APPS = settings.OLD_INSTALLED_APPS
-        self.redo_app_cache()
-    tearDown = unmonkeypatch
-    
-    
-    def redo_app_cache(self):
-        from django.db.models.loading import AppCache
-        a = AppCache()
-        a.loaded = False
-        a._populate()
-    
-
-    def test_get_app_name(self):
-        self.assertEqual(
-            "southtest",
-            migration.get_app_name(self.create_fake_app("southtest.migrations")),
-        )
-        self.assertEqual(
-            "baz",
-            migration.get_app_name(self.create_fake_app("foo.bar.baz.migrations")),
-        )
-    
-    
-    def test_get_migrated_apps(self):
-        
-        P1 = __import__("fakeapp.migrations", {}, {}, [''])
-        
-        self.assertEqual(
-            [P1],
-            list(migration.get_migrated_apps()),
-        )
-    
-    
-    def test_get_app(self):
-        
-        P1 = __import__("fakeapp.migrations", {}, {}, [''])
-        
-        self.assertEqual(P1, migration.get_app("fakeapp"))
-        self.assertEqual(P1, migration.get_app(self.create_fake_app("fakeapp.models")))
-    
-    
-    def test_get_app_fullname(self):
-        self.assertEqual(
-            "southtest",
-            migration.get_app_fullname(self.create_fake_app("southtest.migrations")),
-        )
-        self.assertEqual(
-            "foo.bar.baz",
-            migration.get_app_fullname(self.create_fake_app("foo.bar.baz.migrations")),
-        )
-    
-    
-    def test_get_migration_names(self):
-        
-        app = self.create_test_app()
-        
-        self.assertEqual(
-            ["0001_spam", "0002_eggs", "0003_alter_spam"],
-            migration.get_migration_names(app),
-        )
-    
-    
-    def test_get_migration_classes(self):
-        
-        app = self.create_test_app()
-        
-        # Can't use vanilla import, modules beginning with numbers aren't in grammar
-        M1 = __import__("fakeapp.migrations.0001_spam", {}, {}, ['Migration']).Migration
-        M2 = __import__("fakeapp.migrations.0002_eggs", {}, {}, ['Migration']).Migration
-        M3 = __import__("fakeapp.migrations.0003_alter_spam", {}, {}, ['Migration']).Migration
-        
-        self.assertEqual(
-            [M1, M2, M3],
-            list(migration.get_migration_classes(app)),
-        )
-    
-    
-    def test_get_migration(self):
-        
-        app = self.create_test_app()
-        
-        # Can't use vanilla import, modules beginning with numbers aren't in grammar
-        M1 = __import__("fakeapp.migrations.0001_spam", {}, {}, ['Migration']).Migration
-        M2 = __import__("fakeapp.migrations.0002_eggs", {}, {}, ['Migration']).Migration
-        
-        self.assertEqual(M1, migration.get_migration(app, "0001_spam"))
-        self.assertEqual(M2, migration.get_migration(app, "0002_eggs"))
-        
-        self.assertRaises((ImportError, ValueError), migration.get_migration, app, "0001_jam")
-    
-    
-    def test_all_migrations(self):
-        
-        app = migration.get_app("fakeapp")
-        
-        self.assertEqual(
-            {app: {
-                "0001_spam": migration.get_migration(app, "0001_spam"),
-                "0002_eggs": migration.get_migration(app, "0002_eggs"),
-                "0003_alter_spam": migration.get_migration(app, "0003_alter_spam"),
-            }},
-            migration.all_migrations(),
-        )
-    
-    
-    def assertListEqual(self, list1, list2):
-        list1 = list(list1)
-        list2 = list(list2)
-        list1.sort()
-        list2.sort()
-        return self.assertEqual(list1, list2)
-    
-    
-    def test_apply_migrations(self):
-        
-        app = migration.get_app("fakeapp")
-        
-        # We should start with no migrations
-        self.assertEqual(list(migration.MigrationHistory.objects.all()), [])
-        
-        # Apply them normally
-        migration.migrate_app(app, target_name=None, resolve_mode=None, fake=False, silent=True)
-        
-        # We should finish with all migrations
-        self.assertListEqual(
-            (
-                (u"fakeapp", u"0001_spam"),
-                (u"fakeapp", u"0002_eggs"),
-                (u"fakeapp", u"0003_alter_spam"),
-            ),
-            migration.MigrationHistory.objects.values_list("app_name", "migration"),
-        )
-        
-        # Now roll them backwards
-        migration.migrate_app(app, target_name="zero", resolve_mode=None, fake=False, silent=True)
-        
-        # Finish with none
-        self.assertEqual(list(migration.MigrationHistory.objects.all()), [])
-    
-    
-    def test_migration_merge_forwards(self):
-        
-        app = migration.get_app("fakeapp")
-        
-        # We should start with no migrations
-        self.assertEqual(list(migration.MigrationHistory.objects.all()), [])
-        
-        # Insert one in the wrong order
-        migration.MigrationHistory.objects.create(
-            app_name = "fakeapp",
-            migration = "0002_eggs",
-            applied = datetime.datetime.now(),
-        )
-        
-        # Did it go in?
-        self.assertListEqual(
-            (
-                (u"fakeapp", u"0002_eggs"),
-            ),
-            migration.MigrationHistory.objects.values_list("app_name", "migration"),
-        )
-        
-        # Apply them normally
-        try:
-            migration.migrate_app(app, target_name=None, resolve_mode=None, fake=False, silent=True)
-        except SystemExit:
-            pass
-        
-        # Nothing should have changed (no merge mode!)
-        self.assertListEqual(
-            (
-                (u"fakeapp", u"0002_eggs"),
-            ),
-            migration.MigrationHistory.objects.values_list("app_name", "migration"),
-        )
-        
-        # Apply with merge
-        migration.migrate_app(app, target_name=None, resolve_mode="merge", fake=False, silent=True)
-        
-        # We should finish with all migrations
-        self.assertListEqual(
-            (
-                (u"fakeapp", u"0001_spam"),
-                (u"fakeapp", u"0002_eggs"),
-                (u"fakeapp", u"0003_alter_spam"),
-            ),
-            migration.MigrationHistory.objects.values_list("app_name", "migration"),
-        )
-        
-        # Now roll them backwards
-        migration.migrate_app(app, target_name="0002", resolve_mode=None, fake=False, silent=True)
-        migration.migrate_app(app, target_name="0001", resolve_mode=None, fake=True, silent=True)
-        migration.migrate_app(app, target_name="zero", resolve_mode=None, fake=False, silent=True)
-        
-        # Finish with none
-        self.assertEqual(list(migration.MigrationHistory.objects.all()), [])
-    
-    def test_alter_column_null(self):
-        def null_ok():
-            from django.db import connection, transaction
-            # the DBAPI introspection module fails on postgres NULLs.
-            cursor = connection.cursor()
-            try:
-                cursor.execute("INSERT INTO southtest_spam (id, weight, expires, name) VALUES (100, 10.1, now(), NULL);")
-            except:
-                transaction.rollback()
-                return False
-            else:
-                cursor.execute("DELETE FROM southtest_spam")
-                transaction.commit()
-                return True
-        
-        app = migration.get_app("fakeapp")
-        self.assertEqual(list(migration.MigrationHistory.objects.all()), [])
-        
-        # by default name is NOT NULL
-        migration.migrate_app(app, target_name="0002", resolve_mode=None, fake=False, silent=True)
-        self.failIf(null_ok())
-        
-        # after 0003, it should be NULL
-        migration.migrate_app(app, target_name="0003", resolve_mode=None, fake=False, silent=True)
-        self.assert_(null_ok())
-
-        # make sure it is NOT NULL again
-        migration.migrate_app(app, target_name="0002", resolve_mode=None, fake=False, silent=True)
-        self.failIf(null_ok(), 'name not null after migration')
-        
-        # finish with no migrations, otherwise other tests fail...
-        migration.migrate_app(app, target_name="zero", resolve_mode=None, fake=False, silent=True)
-        self.assertEqual(list(migration.MigrationHistory.objects.all()), [])
\ No newline at end of file
index f39d8b4..f6a851d 100644 (file)
@@ -1,3 +1,6 @@
-# -*- encoding: utf-8 -*-
+# -*- coding: utf-8 -*-
+# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
 __author__ = u'Marek Stępniowski, <marek@stepniowski.com>'
 __version__ = '0.1'
index 55af9d7..897c221 100644 (file)
@@ -1,3 +1,7 @@
+# -*- coding: utf-8 -*-
+# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
 from django.contrib import admin
 from django.conf import settings
 
@@ -15,7 +19,7 @@ class SponsorAdmin(admin.ModelAdmin):
 class SponsorPageAdmin(admin.ModelAdmin):
     formfield_overrides = {
         fields.JSONField: {'widget': widgets.SponsorPageWidget},
-    }   
+    }
     list_display = ('name',)
     search_fields = ('name',)
     ordering = ('name',)
index 678788e..c2098ec 100644 (file)
@@ -1,10 +1,14 @@
-# -*- encoding: utf-8 -*-
+# -*- coding: utf-8 -*-
+# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
 import datetime
 
 from django.conf import settings
 from django.db import models
 from django import forms
 from django.utils import simplejson as json
+from south.modelsinspector import add_introspection_rules
 
 
 class JSONEncoder(json.JSONEncoder):
@@ -28,7 +32,7 @@ def loads(str):
 
 class JSONFormField(forms.CharField):
     widget = forms.Textarea
-    
+
     def clean(self, value):
         try:
             loads(value)
@@ -51,7 +55,7 @@ class JSONField(models.TextField):
 
     def contribute_to_class(self, cls, name):
         super(JSONField, self).contribute_to_class(cls, name)
-        
+
         def get_value(model_instance):
             return loads(getattr(model_instance, self.attname, None))
         setattr(cls, 'get_%s_value' % self.name, get_value)
@@ -59,3 +63,5 @@ class JSONField(models.TextField):
         def set_value(model_instance, json):
             return setattr(model_instance, self.attname, dumps(json))
         setattr(cls, 'set_%s_value' % self.name, set_value)
+
+add_introspection_rules([], [r"^sponsors\.fields\.JSONField"])
diff --git a/apps/sponsors/locale/de/LC_MESSAGES/django.mo b/apps/sponsors/locale/de/LC_MESSAGES/django.mo
new file mode 100644 (file)
index 0000000..d9cbba0
Binary files /dev/null and b/apps/sponsors/locale/de/LC_MESSAGES/django.mo differ
diff --git a/apps/sponsors/locale/de/LC_MESSAGES/django.po b/apps/sponsors/locale/de/LC_MESSAGES/django.po
new file mode 100644 (file)
index 0000000..1bf484a
--- /dev/null
@@ -0,0 +1,38 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-05-25 14:24+0200\n"
+"PO-Revision-Date: 2010-06-23 11:48+0100\n"
+"Last-Translator: Iwona Fiałkowska <ifialkowska@gmail.com>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: models.py:14
+#: models.py:37
+msgid "name"
+msgstr "Name"
+
+#: models.py:15
+msgid "description"
+msgstr "Beschreibung"
+
+#: models.py:17
+msgid "logo"
+msgstr "Logo"
+
+#: models.py:24
+msgid "url"
+msgstr "URL"
+
+#: models.py:38
+msgid "sponsors"
+msgstr "Sponsoren"
+
diff --git a/apps/sponsors/locale/en/LC_MESSAGES/django.mo b/apps/sponsors/locale/en/LC_MESSAGES/django.mo
new file mode 100644 (file)
index 0000000..2cdddba
Binary files /dev/null and b/apps/sponsors/locale/en/LC_MESSAGES/django.mo differ
diff --git a/apps/sponsors/locale/en/LC_MESSAGES/django.po b/apps/sponsors/locale/en/LC_MESSAGES/django.po
new file mode 100644 (file)
index 0000000..8d43d85
--- /dev/null
@@ -0,0 +1,38 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-05-25 14:24+0200\n"
+"PO-Revision-Date: 2010-06-09 16:53+0100\n"
+"Last-Translator: K Izdebska <villdeo.tess@gmail.com>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: models.py:14
+#: models.py:37
+msgid "name"
+msgstr "name"
+
+#: models.py:15
+msgid "description"
+msgstr "description"
+
+#: models.py:17
+msgid "logo"
+msgstr "logo"
+
+#: models.py:24
+msgid "url"
+msgstr "url"
+
+#: models.py:38
+msgid "sponsors"
+msgstr "sponsors"
+
diff --git a/apps/sponsors/locale/es/LC_MESSAGES/django.mo b/apps/sponsors/locale/es/LC_MESSAGES/django.mo
new file mode 100644 (file)
index 0000000..beb52ee
Binary files /dev/null and b/apps/sponsors/locale/es/LC_MESSAGES/django.mo differ
diff --git a/apps/sponsors/locale/es/LC_MESSAGES/django.po b/apps/sponsors/locale/es/LC_MESSAGES/django.po
new file mode 100644 (file)
index 0000000..2c2c922
--- /dev/null
@@ -0,0 +1,38 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-05-25 14:24+0200\n"
+"PO-Revision-Date: 2010-08-11 10:11+0100\n"
+"Last-Translator: Katarzyna Flis <kas.flis@gmail.com>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: models.py:14
+#: models.py:37
+msgid "name"
+msgstr "nombre"
+
+#: models.py:15
+msgid "description"
+msgstr "descripción"
+
+#: models.py:17
+msgid "logo"
+msgstr "logotipo"
+
+#: models.py:24
+msgid "url"
+msgstr "url"
+
+#: models.py:38
+msgid "sponsors"
+msgstr "patrocinadores"
+
diff --git a/apps/sponsors/locale/fr/LC_MESSAGES/django.mo b/apps/sponsors/locale/fr/LC_MESSAGES/django.mo
new file mode 100644 (file)
index 0000000..7c0109c
Binary files /dev/null and b/apps/sponsors/locale/fr/LC_MESSAGES/django.mo differ
diff --git a/apps/sponsors/locale/fr/LC_MESSAGES/django.po b/apps/sponsors/locale/fr/LC_MESSAGES/django.po
new file mode 100644 (file)
index 0000000..1a325ff
--- /dev/null
@@ -0,0 +1,38 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-05-25 14:24+0200\n"
+"PO-Revision-Date: 2010-05-25 21:57+0100\n"
+"Last-Translator: Natalia Kertyczak <natalczyk@o2.pl>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: models.py:14
+#: models.py:37
+msgid "name"
+msgstr "nom"
+
+#: models.py:15
+msgid "description"
+msgstr "description"
+
+#: models.py:17
+msgid "logo"
+msgstr "logo"
+
+#: models.py:24
+msgid "url"
+msgstr "url"
+
+#: models.py:38
+msgid "sponsors"
+msgstr "sponsors"
+
diff --git a/apps/sponsors/locale/lt/LC_MESSAGES/django.mo b/apps/sponsors/locale/lt/LC_MESSAGES/django.mo
new file mode 100644 (file)
index 0000000..6129a2c
Binary files /dev/null and b/apps/sponsors/locale/lt/LC_MESSAGES/django.mo differ
diff --git a/apps/sponsors/locale/lt/LC_MESSAGES/django.po b/apps/sponsors/locale/lt/LC_MESSAGES/django.po
new file mode 100644 (file)
index 0000000..34af316
--- /dev/null
@@ -0,0 +1,39 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-05-18 11:04+0200\n"
+"PO-Revision-Date: 2010-07-09 23:01+0100\n"
+"Last-Translator: Alicja Sinkiewicz <alicja.sinkiewicz@gmail.com>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Translated-Using: django-rosetta 0.5.3\n"
+
+#: models.py:14
+#: models.py:37
+msgid "name"
+msgstr "pavadinimas"
+
+#: models.py:15
+msgid "description"
+msgstr "aprašimas"
+
+#: models.py:17
+msgid "logo"
+msgstr "logotipas"
+
+#: models.py:24
+msgid "url"
+msgstr "url"
+
+#: models.py:38
+msgid "sponsors"
+msgstr "rėmėjai"
+
diff --git a/apps/sponsors/locale/pl/LC_MESSAGES/django.mo b/apps/sponsors/locale/pl/LC_MESSAGES/django.mo
new file mode 100644 (file)
index 0000000..c0885fe
Binary files /dev/null and b/apps/sponsors/locale/pl/LC_MESSAGES/django.mo differ
diff --git a/apps/sponsors/locale/pl/LC_MESSAGES/django.po b/apps/sponsors/locale/pl/LC_MESSAGES/django.po
new file mode 100644 (file)
index 0000000..9c0e94d
--- /dev/null
@@ -0,0 +1,37 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+# 
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-05-18 11:04+0200\n"
+"PO-Revision-Date: 2010-05-19 16:18\n"
+"Last-Translator: <radoslaw.czajka@nowoczesnapolska.org.pl>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Translated-Using: django-rosetta 0.5.3\n"
+
+#: models.py:14 models.py:37
+msgid "name"
+msgstr "nazwa"
+
+#: models.py:15
+msgid "description"
+msgstr "opis"
+
+#: models.py:17
+msgid "logo"
+msgstr "logo"
+
+#: models.py:24
+msgid "url"
+msgstr "url"
+
+#: models.py:38
+msgid "sponsors"
+msgstr "sponsorzy"
diff --git a/apps/sponsors/locale/ru/LC_MESSAGES/django.mo b/apps/sponsors/locale/ru/LC_MESSAGES/django.mo
new file mode 100644 (file)
index 0000000..a84f758
Binary files /dev/null and b/apps/sponsors/locale/ru/LC_MESSAGES/django.mo differ
diff --git a/apps/sponsors/locale/ru/LC_MESSAGES/django.po b/apps/sponsors/locale/ru/LC_MESSAGES/django.po
new file mode 100644 (file)
index 0000000..bf3fb13
--- /dev/null
@@ -0,0 +1,38 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-05-25 14:24+0200\n"
+"PO-Revision-Date: 2010-06-02 17:08+0100\n"
+"Last-Translator: I <moth_04@yahoo.pl>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: models.py:14
+#: models.py:37
+msgid "name"
+msgstr "Ф.И.О./название"
+
+#: models.py:15
+msgid "description"
+msgstr "описание"
+
+#: models.py:17
+msgid "logo"
+msgstr "логотип"
+
+#: models.py:24
+msgid "url"
+msgstr "url"
+
+#: models.py:38
+msgid "sponsors"
+msgstr "покровители"
+
diff --git a/apps/sponsors/locale/uk/LC_MESSAGES/django.mo b/apps/sponsors/locale/uk/LC_MESSAGES/django.mo
new file mode 100644 (file)
index 0000000..1f49319
Binary files /dev/null and b/apps/sponsors/locale/uk/LC_MESSAGES/django.mo differ
diff --git a/apps/sponsors/locale/uk/LC_MESSAGES/django.po b/apps/sponsors/locale/uk/LC_MESSAGES/django.po
new file mode 100644 (file)
index 0000000..fcf90e9
--- /dev/null
@@ -0,0 +1,38 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-05-25 14:24+0200\n"
+"PO-Revision-Date: 2010-08-08 18:29+0100\n"
+"Last-Translator: Natalia Kertyczak <natalczyk@o2.pl>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: models.py:14
+#: models.py:37
+msgid "name"
+msgstr "назва"
+
+#: models.py:15
+msgid "description"
+msgstr "опис"
+
+#: models.py:17
+msgid "logo"
+msgstr "логотип"
+
+#: models.py:24
+msgid "url"
+msgstr "url"
+
+#: models.py:38
+msgid "sponsors"
+msgstr "спонсори"
+
diff --git a/apps/sponsors/migrations/0001_initial.py b/apps/sponsors/migrations/0001_initial.py
new file mode 100644 (file)
index 0000000..daccec5
--- /dev/null
@@ -0,0 +1,58 @@
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+class Migration(SchemaMigration):
+
+    def forwards(self, orm):
+
+        # Adding model 'Sponsor'
+        db.create_table('sponsors_sponsor', (
+            ('url', self.gf('django.db.models.fields.URLField')(max_length=200, blank=True)),
+            ('logo', self.gf('django.db.models.fields.files.ImageField')(max_length=100)),
+            ('_description', self.gf('django.db.models.fields.CharField')(max_length=255, blank=True)),
+            ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+            ('name', self.gf('django.db.models.fields.CharField')(max_length=120)),
+        ))
+        db.send_create_signal('sponsors', ['Sponsor'])
+
+        # Adding model 'SponsorPage'
+        db.create_table('sponsors_sponsorpage', (
+            ('_html', self.gf('django.db.models.fields.TextField')(blank=True)),
+            ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+            ('sponsors', self.gf('sponsors.fields.JSONField')(default={})),
+            ('name', self.gf('django.db.models.fields.CharField')(max_length=120)),
+        ))
+        db.send_create_signal('sponsors', ['SponsorPage'])
+
+
+    def backwards(self, orm):
+
+        # Deleting model 'Sponsor'
+        db.delete_table('sponsors_sponsor')
+
+        # Deleting model 'SponsorPage'
+        db.delete_table('sponsors_sponsorpage')
+
+
+    models = {
+        'sponsors.sponsor': {
+            'Meta': {'object_name': 'Sponsor'},
+            '_description': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'logo': ('django.db.models.fields.files.ImageField', [], {'max_length': '100'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
+            'url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})
+        },
+        'sponsors.sponsorpage': {
+            'Meta': {'object_name': 'SponsorPage'},
+            '_html': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
+            'sponsors': ('sponsors.fields.JSONField', [], {'default': '{}'})
+        }
+    }
+
+    complete_apps = ['sponsors']
diff --git a/apps/sponsors/migrations/__init__.py b/apps/sponsors/migrations/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
index ec0db3f..a2e3e08 100644 (file)
@@ -1,3 +1,7 @@
+# -*- coding: utf-8 -*-
+# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
 from django.db import models
 from django.utils.translation import ugettext_lazy as _
 from django.template.loader import render_to_string
@@ -13,12 +17,12 @@ class Sponsor(models.Model):
         _('logo'),
         upload_to='sponsorzy/sponsor/logo',
         thumbnail={
-            'size': (120, 60),
+            'size': (120, 120),
             'extension': 'png',
             'options': ['pad', 'detail'],
         })
     url = models.URLField(_('url'), blank=True, verify_exists=False)
-    
+
     def __unicode__(self):
         return self.name
 
@@ -33,7 +37,7 @@ class SponsorPage(models.Model):
     name = models.CharField(_('name'), max_length=120)
     sponsors = JSONField(_('sponsors'), default={})
     _html = models.TextField(blank=True, editable=False)
-    
+
     def populated_sponsors(self):
         result = []
         for column in self.get_sponsors_value():
@@ -46,7 +50,7 @@ class SponsorPage(models.Model):
                     pass
             result.append(result_group)
         return result
-    
+
     def html(self):
         return self._html
     html = property(fget=html)
@@ -56,7 +60,7 @@ class SponsorPage(models.Model):
             'sponsors': self.populated_sponsors(),
         })
         return super(SponsorPage, self).save(*args, **kwargs)
-    
+
     def __unicode__(self):
         return self.name
 
index 8c3d74c..112241d 100644 (file)
@@ -1,3 +1,7 @@
+# -*- coding: utf-8 -*-
+# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
 from PIL import Image, ImageFilter, ImageChops
 
 
index 0e2a01e..1277bd2 100644 (file)
     margin: 0;
     padding: 2px;
     list-style: none;
-    min-height: 320px;
+    min-height: 400px;
 }
 
 .sponsors-sponsor {
     margin: 0 40px 2px 0;
     width: 120px;
-    height: 60px;
+    height: 120px;
     border: 1px solid #CCC;
     background-color: #EEE;
     cursor: default;
index 4cb5eb6..33c794a 100644 (file)
@@ -4,12 +4,12 @@
       sponsors: []
     };
     $.extend(settings, options);
-    
+
     var input = $(this).hide();
-    
+
     var container = $('<div class="sponsors"></div>').appendTo(input.parent());
     var groups = $.evalJSON(input.val());
-    
+
     var unusedDiv = $('<div class="sponsors-sponsor-group sponsors-unused-sponsor-group"></div>')
       .appendTo(container)
       .append('<p class="sponsors-sponsor-group-name sponsors-unused-sponsor-group-name">dostępni sponsorzy</p>');
         .sortable({
           connectWith: '.sponsors-sponsor-group-list'
                });
-    
+
     // Edit group name inline
     function editNameInline(name) {
       name.unbind('click.sponsorsFooter');
       var inlineInput = $('<input></input>').val(name.html());
       name.html('');
-      
+
       function endEditing() {
         name.html(inlineInput.val());
         inlineInput.remove();
         input.parents('form').unbind('submit.sponsorsFooter', endEditing);
         return false;
       }
-      
+
       inlineInput.appendTo(name).focus().blur(endEditing);
       input.parents('form').bind('submit.sponsorsFooter', endEditing);
     }
-    
+
     // Remove sponsor with passed id from sponsors array and return it
     function popSponsor(id) {
       for (var i=0; i < settings.sponsors.length; i++) {
       }
       return null;
     }
-    
+
     // Create sponsor group and bind events
     function createGroup(name, sponsors) {
       if (!sponsors) {
         sponsors = [];
       }
-      
+
       var groupDiv = $('<div class="sponsors-sponsor-group"></div>');
-      
+
       $('<a class="sponsors-remove-sponsor-group">X</a>')
         .click(function() {
           groupDiv.fadeOut('slow', function() {
             groupDiv.remove();
           });
         }).appendTo(groupDiv);
-      
+
       $('<p class="sponsors-sponsor-group-name">' + name + '</p>')
         .bind('click.sponsorsFooter', function() {
           editNameInline($(this));
         }).appendTo(groupDiv);
-      
+
       var groupList = $('<ol class="sponsors-sponsor-group-list"></ol>')
         .appendTo(groupDiv)
         .sortable({
           connectWith: '.sponsors-sponsor-group-list'
                });
-      
-      
+
+
       for (var i = 0; i < sponsors.length; i++) {
         $('<li class="sponsors-sponsor"><img src="' + sponsors[i].image + '" alt="' + sponsors[i].name + '"/></li>')
           .data('obj_id', sponsors[i].id)
       }
       return groupDiv;
     }
-    
+
     // Create groups from data in input value
     for (var i = 0; i < groups.length; i++) {
       var group = groups[i];
       var sponsors = [];
-      
+
       for (var j = 0; j < group.sponsors.length; j++) {
         var s = popSponsor(group.sponsors[j]);
         if (s) {
       }
       createGroup(group.name, sponsors).appendTo(container);
     }
-    
+
     // Serialize input value before submiting form
     input.parents('form').submit(function(event) {
       var groups = [];
       });
       input.val($.toJSON(groups));
     });
-    
+
     for (i = 0; i < settings.sponsors.length; i++) {
       $('<li class="sponsors-sponsor"><img src="' + settings.sponsors[i].image + '" alt="' + settings.sponsors[i].name + '"/></li>')
         .data('obj_id', settings.sponsors[i].id)
         .appendTo(unusedList);
     }
-    
+
     $('<button type="button">Dodaj nową grupę</button>')
       .click(function() {
         var newGroup = createGroup('').appendTo(container);
         editNameInline($('.sponsors-sponsor-group-name', newGroup));
       }).prependTo(input.parent());
-    
+
     input.parent().append('<div style="clear: both"></div>');
   };
 })(jQuery);
index 96beb36..77624fb 100644 (file)
@@ -1,11 +1,10 @@
-<div class="sponsors-sponsor-page">
+<marquee scrollamount='2' width='800'>
 {% for column in sponsors %}
-       <div class="sponsors-sponsor-column" style="width: 150px">
-               <p class="sponsors-sponsor-column-name">{{ column.name|default:"&nbsp;" }}</p>
-               {% for sponsor in column.sponsors %}
-                       <div class="sponsors-sponsor">{% if sponsor.url %}<a style="sponsors-sponsor-link" href="{{ sponsor.url }}" >{% endif %}<img class="sponsors-sponsor-logo" src="{{ sponsor.logo.thumbnail }}" alt="{{ sponsor.description }}"/>{% if sponsor.url %}</a>{% endif %}</div>
-               {% endfor %}
-       </div>
+  <span class="sponsors-sponsor-column">
+    <span class="sponsors-sponsor-column-name">{{ column.name }}</span>
+    {% for sponsor in column.sponsors %}
+      {% if sponsor.url %}<a style="sponsors-sponsor-link" href="{{ sponsor.url }}" title="{{ sponsor.description }}" >{% endif %}<img class="sponsors-sponsor-logo" src="{{ sponsor.logo.thumbnail }}" alt="{{ sponsor.name }}"/>{% if sponsor.url %}</a>{% endif %}
+    {% endfor %}
+  </span>
 {% endfor %}
-<div style="clear: both"></div>
-</div>
+</marquee>
index c1d18d1..3670123 100644 (file)
@@ -1,3 +1,7 @@
+# -*- coding: utf-8 -*-
+# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
 from django import template
 from django.utils.safestring import mark_safe
 
@@ -13,5 +17,5 @@ def sponsor_page(name):
     except:
         return u''
     return mark_safe(page.html)
-    
+
 sponsor_page = register.simple_tag(sponsor_page)
index ed06ba6..e4b30bb 100644 (file)
@@ -1,3 +1,7 @@
+# -*- coding: utf-8 -*-
+# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
 from django.conf import settings
 from django import forms
 from django.utils.safestring import mark_safe
@@ -24,6 +28,6 @@ class SponsorPageWidget(forms.Textarea):
         output.append(u'<script type="text/javascript">addEvent(window, "load", function(e) {')
         # TODO: "id_" is hard-coded here. This should instead use the correct
         # API to determine the ID dynamically.
-        output.append(u'$("#id_%s").sponsorsFooter({sponsors: [%s]}); });</script>\n' % 
+        output.append(u'$("#id_%s").sponsorsFooter({sponsors: [%s]}); });</script>\n' %
             (name, sponsors_js))
         return mark_safe(u''.join(output))
diff --git a/apps/suggest/__init__.py b/apps/suggest/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/apps/suggest/admin.py b/apps/suggest/admin.py
new file mode 100644 (file)
index 0000000..d1ce07b
--- /dev/null
@@ -0,0 +1,12 @@
+# -*- coding: utf-8 -*-
+# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
+from django.contrib import admin
+
+from suggest.models import Suggestion
+
+class SuggestionAdmin(admin.ModelAdmin):
+    list_display = ('created_at', 'contact', 'user', 'description')
+
+admin.site.register(Suggestion, SuggestionAdmin)
diff --git a/apps/suggest/forms.py b/apps/suggest/forms.py
new file mode 100644 (file)
index 0000000..7084eff
--- /dev/null
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
+from django import forms
+from django.utils.translation import ugettext_lazy as _
+
+class SuggestForm(forms.Form):
+    contact = forms.CharField(label=_('Contact'), max_length=120, required=False)
+    description = forms.CharField(label=_('Description'), widget=forms.Textarea, required=True)
diff --git a/apps/suggest/locale/de/LC_MESSAGES/django.mo b/apps/suggest/locale/de/LC_MESSAGES/django.mo
new file mode 100644 (file)
index 0000000..2e4e772
Binary files /dev/null and b/apps/suggest/locale/de/LC_MESSAGES/django.mo differ
diff --git a/apps/suggest/locale/de/LC_MESSAGES/django.po b/apps/suggest/locale/de/LC_MESSAGES/django.po
new file mode 100644 (file)
index 0000000..d6068e8
--- /dev/null
@@ -0,0 +1,61 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-06-02 10:44+0200\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: forms.py:9
+msgid "Contact"
+msgstr ""
+
+#: forms.py:10
+msgid "Description"
+msgstr ""
+
+#: models.py:10
+msgid "contact"
+msgstr ""
+
+#: models.py:11
+msgid "description"
+msgstr ""
+
+#: models.py:12
+msgid "creation date"
+msgstr ""
+
+#: models.py:13
+msgid "IP address"
+msgstr ""
+
+#: models.py:18
+msgid "suggestion"
+msgstr ""
+
+#: models.py:19
+msgid "suggestions"
+msgstr ""
+
+#: views.py:31
+msgid "Report was sent successfully."
+msgstr ""
+
+#: templates/suggest.html:2
+msgid "Report a bug or suggestion"
+msgstr ""
+
+#: templates/suggest.html:7
+msgid "Send report"
+msgstr ""
diff --git a/apps/suggest/locale/en/LC_MESSAGES/django.mo b/apps/suggest/locale/en/LC_MESSAGES/django.mo
new file mode 100644 (file)
index 0000000..2e4e772
Binary files /dev/null and b/apps/suggest/locale/en/LC_MESSAGES/django.mo differ
diff --git a/apps/suggest/locale/en/LC_MESSAGES/django.po b/apps/suggest/locale/en/LC_MESSAGES/django.po
new file mode 100644 (file)
index 0000000..d6068e8
--- /dev/null
@@ -0,0 +1,61 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-06-02 10:44+0200\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: forms.py:9
+msgid "Contact"
+msgstr ""
+
+#: forms.py:10
+msgid "Description"
+msgstr ""
+
+#: models.py:10
+msgid "contact"
+msgstr ""
+
+#: models.py:11
+msgid "description"
+msgstr ""
+
+#: models.py:12
+msgid "creation date"
+msgstr ""
+
+#: models.py:13
+msgid "IP address"
+msgstr ""
+
+#: models.py:18
+msgid "suggestion"
+msgstr ""
+
+#: models.py:19
+msgid "suggestions"
+msgstr ""
+
+#: views.py:31
+msgid "Report was sent successfully."
+msgstr ""
+
+#: templates/suggest.html:2
+msgid "Report a bug or suggestion"
+msgstr ""
+
+#: templates/suggest.html:7
+msgid "Send report"
+msgstr ""
diff --git a/apps/suggest/locale/es/LC_MESSAGES/django.mo b/apps/suggest/locale/es/LC_MESSAGES/django.mo
new file mode 100644 (file)
index 0000000..2e4e772
Binary files /dev/null and b/apps/suggest/locale/es/LC_MESSAGES/django.mo differ
diff --git a/apps/suggest/locale/es/LC_MESSAGES/django.po b/apps/suggest/locale/es/LC_MESSAGES/django.po
new file mode 100644 (file)
index 0000000..d6068e8
--- /dev/null
@@ -0,0 +1,61 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-06-02 10:44+0200\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: forms.py:9
+msgid "Contact"
+msgstr ""
+
+#: forms.py:10
+msgid "Description"
+msgstr ""
+
+#: models.py:10
+msgid "contact"
+msgstr ""
+
+#: models.py:11
+msgid "description"
+msgstr ""
+
+#: models.py:12
+msgid "creation date"
+msgstr ""
+
+#: models.py:13
+msgid "IP address"
+msgstr ""
+
+#: models.py:18
+msgid "suggestion"
+msgstr ""
+
+#: models.py:19
+msgid "suggestions"
+msgstr ""
+
+#: views.py:31
+msgid "Report was sent successfully."
+msgstr ""
+
+#: templates/suggest.html:2
+msgid "Report a bug or suggestion"
+msgstr ""
+
+#: templates/suggest.html:7
+msgid "Send report"
+msgstr ""
diff --git a/apps/suggest/locale/fr/LC_MESSAGES/django.mo b/apps/suggest/locale/fr/LC_MESSAGES/django.mo
new file mode 100644 (file)
index 0000000..2e4e772
Binary files /dev/null and b/apps/suggest/locale/fr/LC_MESSAGES/django.mo differ
diff --git a/apps/suggest/locale/fr/LC_MESSAGES/django.po b/apps/suggest/locale/fr/LC_MESSAGES/django.po
new file mode 100644 (file)
index 0000000..d6068e8
--- /dev/null
@@ -0,0 +1,61 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-06-02 10:44+0200\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: forms.py:9
+msgid "Contact"
+msgstr ""
+
+#: forms.py:10
+msgid "Description"
+msgstr ""
+
+#: models.py:10
+msgid "contact"
+msgstr ""
+
+#: models.py:11
+msgid "description"
+msgstr ""
+
+#: models.py:12
+msgid "creation date"
+msgstr ""
+
+#: models.py:13
+msgid "IP address"
+msgstr ""
+
+#: models.py:18
+msgid "suggestion"
+msgstr ""
+
+#: models.py:19
+msgid "suggestions"
+msgstr ""
+
+#: views.py:31
+msgid "Report was sent successfully."
+msgstr ""
+
+#: templates/suggest.html:2
+msgid "Report a bug or suggestion"
+msgstr ""
+
+#: templates/suggest.html:7
+msgid "Send report"
+msgstr ""
diff --git a/apps/suggest/locale/lt/LC_MESSAGES/django.mo b/apps/suggest/locale/lt/LC_MESSAGES/django.mo
new file mode 100644 (file)
index 0000000..2e4e772
Binary files /dev/null and b/apps/suggest/locale/lt/LC_MESSAGES/django.mo differ
diff --git a/apps/suggest/locale/lt/LC_MESSAGES/django.po b/apps/suggest/locale/lt/LC_MESSAGES/django.po
new file mode 100644 (file)
index 0000000..d6068e8
--- /dev/null
@@ -0,0 +1,61 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-06-02 10:44+0200\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: forms.py:9
+msgid "Contact"
+msgstr ""
+
+#: forms.py:10
+msgid "Description"
+msgstr ""
+
+#: models.py:10
+msgid "contact"
+msgstr ""
+
+#: models.py:11
+msgid "description"
+msgstr ""
+
+#: models.py:12
+msgid "creation date"
+msgstr ""
+
+#: models.py:13
+msgid "IP address"
+msgstr ""
+
+#: models.py:18
+msgid "suggestion"
+msgstr ""
+
+#: models.py:19
+msgid "suggestions"
+msgstr ""
+
+#: views.py:31
+msgid "Report was sent successfully."
+msgstr ""
+
+#: templates/suggest.html:2
+msgid "Report a bug or suggestion"
+msgstr ""
+
+#: templates/suggest.html:7
+msgid "Send report"
+msgstr ""
diff --git a/apps/suggest/locale/pl/LC_MESSAGES/django.mo b/apps/suggest/locale/pl/LC_MESSAGES/django.mo
new file mode 100644 (file)
index 0000000..f03afa8
Binary files /dev/null and b/apps/suggest/locale/pl/LC_MESSAGES/django.mo differ
diff --git a/apps/suggest/locale/pl/LC_MESSAGES/django.po b/apps/suggest/locale/pl/LC_MESSAGES/django.po
new file mode 100644 (file)
index 0000000..2ac4c45
--- /dev/null
@@ -0,0 +1,62 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+# 
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-06-02 10:44+0200\n"
+"PO-Revision-Date: 2010-06-02 10:45\n"
+"Last-Translator: <radek.czajka@gmail.com>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Translated-Using: django-rosetta 0.5.3\n"
+
+#: forms.py:9
+msgid "Contact"
+msgstr "Kontakt"
+
+#: forms.py:10
+msgid "Description"
+msgstr "Opis"
+
+#: models.py:10
+msgid "contact"
+msgstr "kontakt"
+
+#: models.py:11
+msgid "description"
+msgstr "opis"
+
+#: models.py:12
+msgid "creation date"
+msgstr "data utworzenia"
+
+#: models.py:13
+msgid "IP address"
+msgstr "adres IP"
+
+#: models.py:18
+msgid "suggestion"
+msgstr "sugestia"
+
+#: models.py:19
+msgid "suggestions"
+msgstr "sugestie"
+
+#: views.py:31
+msgid "Report was sent successfully."
+msgstr "Zgłoszenie zostało wysłane."
+
+#: templates/suggest.html:2
+msgid "Report a bug or suggestion"
+msgstr "Zgłoś błąd lub sugestię"
+
+#: templates/suggest.html:7
+msgid "Send report"
+msgstr "Wyślij zgłoszenie"
+
diff --git a/apps/suggest/locale/ru/LC_MESSAGES/django.mo b/apps/suggest/locale/ru/LC_MESSAGES/django.mo
new file mode 100644 (file)
index 0000000..2e4e772
Binary files /dev/null and b/apps/suggest/locale/ru/LC_MESSAGES/django.mo differ
diff --git a/apps/suggest/locale/ru/LC_MESSAGES/django.po b/apps/suggest/locale/ru/LC_MESSAGES/django.po
new file mode 100644 (file)
index 0000000..d6068e8
--- /dev/null
@@ -0,0 +1,61 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-06-02 10:44+0200\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: forms.py:9
+msgid "Contact"
+msgstr ""
+
+#: forms.py:10
+msgid "Description"
+msgstr ""
+
+#: models.py:10
+msgid "contact"
+msgstr ""
+
+#: models.py:11
+msgid "description"
+msgstr ""
+
+#: models.py:12
+msgid "creation date"
+msgstr ""
+
+#: models.py:13
+msgid "IP address"
+msgstr ""
+
+#: models.py:18
+msgid "suggestion"
+msgstr ""
+
+#: models.py:19
+msgid "suggestions"
+msgstr ""
+
+#: views.py:31
+msgid "Report was sent successfully."
+msgstr ""
+
+#: templates/suggest.html:2
+msgid "Report a bug or suggestion"
+msgstr ""
+
+#: templates/suggest.html:7
+msgid "Send report"
+msgstr ""
diff --git a/apps/suggest/locale/uk/LC_MESSAGES/django.mo b/apps/suggest/locale/uk/LC_MESSAGES/django.mo
new file mode 100644 (file)
index 0000000..2e4e772
Binary files /dev/null and b/apps/suggest/locale/uk/LC_MESSAGES/django.mo differ
diff --git a/apps/suggest/locale/uk/LC_MESSAGES/django.po b/apps/suggest/locale/uk/LC_MESSAGES/django.po
new file mode 100644 (file)
index 0000000..d6068e8
--- /dev/null
@@ -0,0 +1,61 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-06-02 10:44+0200\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: forms.py:9
+msgid "Contact"
+msgstr ""
+
+#: forms.py:10
+msgid "Description"
+msgstr ""
+
+#: models.py:10
+msgid "contact"
+msgstr ""
+
+#: models.py:11
+msgid "description"
+msgstr ""
+
+#: models.py:12
+msgid "creation date"
+msgstr ""
+
+#: models.py:13
+msgid "IP address"
+msgstr ""
+
+#: models.py:18
+msgid "suggestion"
+msgstr ""
+
+#: models.py:19
+msgid "suggestions"
+msgstr ""
+
+#: views.py:31
+msgid "Report was sent successfully."
+msgstr ""
+
+#: templates/suggest.html:2
+msgid "Report a bug or suggestion"
+msgstr ""
+
+#: templates/suggest.html:7
+msgid "Send report"
+msgstr ""
diff --git a/apps/suggest/migrations/0001_initial.py b/apps/suggest/migrations/0001_initial.py
new file mode 100644 (file)
index 0000000..a25297a
--- /dev/null
@@ -0,0 +1,77 @@
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+class Migration(SchemaMigration):
+
+    def forwards(self, orm):
+
+        # Adding model 'Suggestion'
+        db.create_table('suggest_suggestion', (
+            ('description', self.gf('django.db.models.fields.TextField')(blank=True)),
+            ('ip', self.gf('django.db.models.fields.IPAddressField')(max_length=15)),
+            ('created_at', self.gf('django.db.models.fields.DateTimeField')(auto_now=True, blank=True)),
+            ('contact', self.gf('django.db.models.fields.CharField')(max_length=120, blank=True)),
+            ('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'], null=True, blank=True)),
+            ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+        ))
+        db.send_create_signal('suggest', ['Suggestion'])
+
+
+    def backwards(self, orm):
+
+        # Deleting model 'Suggestion'
+        db.delete_table('suggest_suggestion')
+
+
+    models = {
+        'auth.group': {
+            'Meta': {'object_name': 'Group'},
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+            'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'})
+        },
+        'auth.permission': {
+            'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+            'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+        },
+        'auth.user': {
+            'Meta': {'object_name': 'User'},
+            'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+            'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+            'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+            'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+            'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+            'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+            'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+            'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+            'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+            'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}),
+            'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+        },
+        'contenttypes.contenttype': {
+            'Meta': {'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+            'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+        },
+        'suggest.suggestion': {
+            'Meta': {'object_name': 'Suggestion'},
+            'contact': ('django.db.models.fields.CharField', [], {'max_length': '120', 'blank': 'True'}),
+            'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
+            'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'ip': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}),
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'})
+        }
+    }
+
+    complete_apps = ['suggest']
diff --git a/apps/suggest/migrations/__init__.py b/apps/suggest/migrations/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/apps/suggest/models.py b/apps/suggest/models.py
new file mode 100644 (file)
index 0000000..e24afae
--- /dev/null
@@ -0,0 +1,22 @@
+# -*- coding: utf-8 -*-
+# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
+from django.db import models
+from django.contrib.auth.models import User
+from django.utils.translation import ugettext_lazy as _
+
+class Suggestion(models.Model):
+    contact = models.CharField(_('contact'), blank=True, max_length=120)
+    description = models.TextField(_('description'), blank=True)
+    created_at = models.DateTimeField(_('creation date'), auto_now=True)
+    ip = models.IPAddressField(_('IP address'))
+    user = models.ForeignKey(User, blank=True, null=True)
+
+    class Meta:
+        ordering = ('-created_at',)
+        verbose_name = _('suggestion')
+        verbose_name_plural = _('suggestions')
+
+    def __unicode__(self):
+        return unicode(self.created_at)
diff --git a/apps/suggest/templates/suggest.html b/apps/suggest/templates/suggest.html
new file mode 100644 (file)
index 0000000..c7fdd81
--- /dev/null
@@ -0,0 +1,9 @@
+{% load i18n %}
+<h2>{% trans "Report a bug or suggestion" %}</h2>
+<form id='suggest-form' action="{% url suggest.views.report %}" method="post" accept-charset="utf-8" class="cuteform">
+<ol>
+    <li><label for="id_contact">{{ form.contact.label }}</label> {{ form.contact }}</li>
+       <li><label for="id_description">{{ form.description.label }}</label> {{ form.description }}</li>
+    <li><input type="submit" value="{% trans "Send report" %}"/></li>
+</ol>
+</form>
\ No newline at end of file
diff --git a/apps/suggest/urls.py b/apps/suggest/urls.py
new file mode 100644 (file)
index 0000000..d5982cf
--- /dev/null
@@ -0,0 +1,14 @@
+# -*- coding: utf-8 -*-
+# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
+from django.conf.urls.defaults import *
+from django.views.generic.simple import direct_to_template
+from suggest.forms import SuggestForm
+
+urlpatterns = patterns('',
+    url(r'^$', 'django.views.generic.simple.direct_to_template',
+        {'template': 'suggest.html', 'extra_context': {'form': SuggestForm }}, name='suggest'),
+    url(r'^wyslij/$', 'suggest.views.report', name='report'),
+)
+
diff --git a/apps/suggest/views.py b/apps/suggest/views.py
new file mode 100644 (file)
index 0000000..5d007f6
--- /dev/null
@@ -0,0 +1,35 @@
+# -*- coding: utf-8 -*-
+# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
+from django.http import HttpResponse, HttpResponseRedirect
+from django.views.decorators import cache
+from django.views.decorators.http import require_POST
+from django.utils.translation import ugettext as _
+
+from suggest import forms
+from suggest.models import Suggestion
+
+# FIXME - shouldn't be in catalogue
+from catalogue.views import LazyEncoder
+
+
+#@require_POST
+@cache.never_cache
+def report(request):
+    suggest_form = forms.SuggestForm(request.POST)
+    if suggest_form.is_valid():
+        contact = suggest_form.cleaned_data['contact']
+        description = suggest_form.cleaned_data['description']
+
+        suggestion = Suggestion(contact=contact,
+            description=description, ip=request.META['REMOTE_ADDR'])
+        if request.user.is_authenticated():
+            suggestion.user = request.user
+        suggestion.save()
+
+        response_data = {'success': True, 'message': _('Report was sent successfully.')}
+    else:
+        response_data = {'success': False, 'errors': suggest_form.errors}
+    print LazyEncoder(ensure_ascii=False).encode(response_data)
+    return HttpResponse(LazyEncoder(ensure_ascii=False).encode(response_data))
diff --git a/deployment.py b/deployment.py
new file mode 100755 (executable)
index 0000000..ab19880
--- /dev/null
@@ -0,0 +1,67 @@
+#!/srv/library/wolnelektury/pythonenv/bin/python
+from __future__ import with_statement
+
+import shutil
+import os
+import sys
+
+from string import Template
+
+def render_template(source, dest, context={}):
+    print "Rendering template:",
+    with open(source, 'rb') as source_file:
+        t = Template(source_file.read())
+    with open(dest, 'wb') as dest_file:
+        dest_file.write(t.safe_substitute(context))
+    print "done."
+
+def restart_wsgi():
+    print "Restarting wsgi application:",
+    os.system("touch %s" % WSGI_TARGET)
+    print "done."
+
+def update_application():
+    print "Updating repository.",
+    os.system("cd %s; git pull" % PROJECT_ROOT)
+
+    print "Installing requirements"
+    os.system("%s install -r %s" % (PIP, os.path.join(PROJECT_ROOT, 'requirements.txt')))
+
+    print "Installing local requirements"
+    os.system("%s install -r %s" % (PIP, os.path.join(ROOT, 'etc', 'requirements.txt')))
+    print "done."
+
+ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+
+PYTHON = os.path.join(ROOT, 'pythonenv', 'bin', 'python')
+PIP = os.path.join(ROOT, 'pythonenv', 'bin', 'pip')
+PYTHON_SITE = os.path.join(ROOT, 'pythonenv', 'lib', 'python2.6', 'site-packages')
+
+PROJECT_NAME = 'wolnelektury'
+PROJECT_ROOT = os.path.join(ROOT, 'application')
+
+MEDIA_ROOT = os.path.join(ROOT, 'www', 'media')
+
+ADMIN_EMAIL = 'lrekucki@gmail.com'
+
+WSGI_TARGET = os.path.join(ROOT, 'www', 'wsgi', PROJECT_NAME + '.wsgi')
+WSGI_DIR = os.path.dirname(WSGI_TARGET)
+
+WSGI_USER = PROJECT_NAME
+WSGI_PROCESSES = 5
+WSGI_THREADS = 1
+
+DOMAIN = 'lektury.staging.nowoczesnapolska.org.pl'
+
+#
+# Load local configuration
+#
+sys.path = [ os.path.join(ROOT, 'etc') ] + sys.path
+
+from local_deployment import *
+
+if __name__ == '__main__':
+    update_application()
+    render_template(os.path.join(PROJECT_ROOT, PROJECT_NAME + '.wsgi.tmpl'), WSGI_TARGET, context=globals())
+    render_template(os.path.join(PROJECT_ROOT, PROJECT_NAME + '.vhost.tmpl'), os.path.join(ROOT, 'etc', PROJECT_NAME + '.vhost'), context=globals())
+    restart_wsgi()
index 1305177..855d6bd 100644 (file)
@@ -21,7 +21,7 @@ def staging():
     env.python = '/usr/bin/python'
     env.virtualenv = '/usr/bin/virtualenv'
     env.pip = '/usr/bin/pip'
-    
+
 def production():
     """Use production server"""
     env.hosts = ['wolnelektury.pl:22123']
@@ -54,8 +54,8 @@ def setup():
 
 def deploy():
     """
-    Deploy the latest version of the site to the servers, 
-    install any required third party modules, 
+    Deploy the latest version of the site to the servers,
+    install any required third party modules,
     install the virtual host and then restart the webserver
     """
     require('hosts', 'path', provided_by=[staging, production])
@@ -99,10 +99,11 @@ def rollback():
 # = Helpers. These are called by other functions rather than directly =
 # =====================================================================
 def upload_tar_from_git():
-    "Create an archive from the current Git master branch and upload it"
+    "Create an archive from the current Git branch and upload it"
     print '>>> upload tar from git'
     require('release', provided_by=[deploy])
-    local('git archive --format=tar master | gzip > %(release)s.tar.gz' % env)
+    local('git-archive-all.sh --format tar %(release)s.tar' % env)
+    local('gzip %(release)s.tar' % env)
     run('mkdir -p %(path)s/releases/%(release)s' % env, pty=True)
     run('mkdir -p %(path)s/packages' % env, pty=True)
     put('%(release)s.tar.gz' % env, '%(path)s/packages/' % env)
diff --git a/lib/feedparser.py b/lib/feedparser.py
deleted file mode 100644 (file)
index bb802df..0000000
+++ /dev/null
@@ -1,2858 +0,0 @@
-#!/usr/bin/env python
-"""Universal feed parser
-
-Handles RSS 0.9x, RSS 1.0, RSS 2.0, CDF, Atom 0.3, and Atom 1.0 feeds
-
-Visit http://feedparser.org/ for the latest version
-Visit http://feedparser.org/docs/ for the latest documentation
-
-Required: Python 2.1 or later
-Recommended: Python 2.3 or later
-Recommended: CJKCodecs and iconv_codec <http://cjkpython.i18n.org/>
-"""
-
-__version__ = "4.1"# + "$Revision: 1.92 $"[11:15] + "-cvs"
-__license__ = """Copyright (c) 2002-2006, Mark Pilgrim, 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
-  and/or other materials provided with the distribution.
-
-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 OWNER 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."""
-__author__ = "Mark Pilgrim <http://diveintomark.org/>"
-__contributors__ = ["Jason Diamond <http://injektilo.org/>",
-                    "John Beimler <http://john.beimler.org/>",
-                    "Fazal Majid <http://www.majid.info/mylos/weblog/>",
-                    "Aaron Swartz <http://aaronsw.com/>",
-                    "Kevin Marks <http://epeus.blogspot.com/>"]
-_debug = 0
-
-# HTTP "User-Agent" header to send to servers when downloading feeds.
-# If you are embedding feedparser in a larger application, you should
-# change this to your application name and URL.
-USER_AGENT = "UniversalFeedParser/%s +http://feedparser.org/" % __version__
-
-# HTTP "Accept" header to send to servers when downloading feeds.  If you don't
-# want to send an Accept header, set this to None.
-ACCEPT_HEADER = "application/atom+xml,application/rdf+xml,application/rss+xml,application/x-netcdf,application/xml;q=0.9,text/xml;q=0.2,*/*;q=0.1"
-
-# List of preferred XML parsers, by SAX driver name.  These will be tried first,
-# but if they're not installed, Python will keep searching through its own list
-# of pre-installed parsers until it finds one that supports everything we need.
-PREFERRED_XML_PARSERS = ["drv_libxml2"]
-
-# If you want feedparser to automatically run HTML markup through HTML Tidy, set
-# this to 1.  Requires mxTidy <http://www.egenix.com/files/python/mxTidy.html>
-# or utidylib <http://utidylib.berlios.de/>.
-TIDY_MARKUP = 0
-
-# List of Python interfaces for HTML Tidy, in order of preference.  Only useful
-# if TIDY_MARKUP = 1
-PREFERRED_TIDY_INTERFACES = ["uTidy", "mxTidy"]
-
-# ---------- required modules (should come with any Python distribution) ----------
-import sgmllib, re, sys, copy, urlparse, time, rfc822, types, cgi, urllib, urllib2
-try:
-    from cStringIO import StringIO as _StringIO
-except:
-    from StringIO import StringIO as _StringIO
-
-# ---------- optional modules (feedparser will work without these, but with reduced functionality) ----------
-
-# gzip is included with most Python distributions, but may not be available if you compiled your own
-try:
-    import gzip
-except:
-    gzip = None
-try:
-    import zlib
-except:
-    zlib = None
-
-# If a real XML parser is available, feedparser will attempt to use it.  feedparser has
-# been tested with the built-in SAX parser, PyXML, and libxml2.  On platforms where the
-# Python distribution does not come with an XML parser (such as Mac OS X 10.2 and some
-# versions of FreeBSD), feedparser will quietly fall back on regex-based parsing.
-try:
-    import xml.sax
-    xml.sax.make_parser(PREFERRED_XML_PARSERS) # test for valid parsers
-    from xml.sax.saxutils import escape as _xmlescape
-    _XML_AVAILABLE = 1
-except:
-    _XML_AVAILABLE = 0
-    def _xmlescape(data):
-        data = data.replace('&', '&amp;')
-        data = data.replace('>', '&gt;')
-        data = data.replace('<', '&lt;')
-        return data
-
-# base64 support for Atom feeds that contain embedded binary data
-try:
-    import base64, binascii
-except:
-    base64 = binascii = None
-
-# cjkcodecs and iconv_codec provide support for more character encodings.
-# Both are available from http://cjkpython.i18n.org/
-try:
-    import cjkcodecs.aliases
-except:
-    pass
-try:
-    import iconv_codec
-except:
-    pass
-
-# chardet library auto-detects character encodings
-# Download from http://chardet.feedparser.org/
-try:
-    import chardet
-    if _debug:
-        import chardet.constants
-        chardet.constants._debug = 1
-except:
-    chardet = None
-
-# ---------- don't touch these ----------
-class ThingsNobodyCaresAboutButMe(Exception): pass
-class CharacterEncodingOverride(ThingsNobodyCaresAboutButMe): pass
-class CharacterEncodingUnknown(ThingsNobodyCaresAboutButMe): pass
-class NonXMLContentType(ThingsNobodyCaresAboutButMe): pass
-class UndeclaredNamespace(Exception): pass
-
-sgmllib.tagfind = re.compile('[a-zA-Z][-_.:a-zA-Z0-9]*')
-sgmllib.special = re.compile('<!')
-sgmllib.charref = re.compile('&#(x?[0-9A-Fa-f]+)[^0-9A-Fa-f]')
-
-SUPPORTED_VERSIONS = {'': 'unknown',
-                      'rss090': 'RSS 0.90',
-                      'rss091n': 'RSS 0.91 (Netscape)',
-                      'rss091u': 'RSS 0.91 (Userland)',
-                      'rss092': 'RSS 0.92',
-                      'rss093': 'RSS 0.93',
-                      'rss094': 'RSS 0.94',
-                      'rss20': 'RSS 2.0',
-                      'rss10': 'RSS 1.0',
-                      'rss': 'RSS (unknown version)',
-                      'atom01': 'Atom 0.1',
-                      'atom02': 'Atom 0.2',
-                      'atom03': 'Atom 0.3',
-                      'atom10': 'Atom 1.0',
-                      'atom': 'Atom (unknown version)',
-                      'cdf': 'CDF',
-                      'hotrss': 'Hot RSS'
-                      }
-
-try:
-    UserDict = dict
-except NameError:
-    # Python 2.1 does not have dict
-    from UserDict import UserDict
-    def dict(aList):
-        rc = {}
-        for k, v in aList:
-            rc[k] = v
-        return rc
-
-class FeedParserDict(UserDict):
-    keymap = {'channel': 'feed',
-              'items': 'entries',
-              'guid': 'id',
-              'date': 'updated',
-              'date_parsed': 'updated_parsed',
-              'description': ['subtitle', 'summary'],
-              'url': ['href'],
-              'modified': 'updated',
-              'modified_parsed': 'updated_parsed',
-              'issued': 'published',
-              'issued_parsed': 'published_parsed',
-              'copyright': 'rights',
-              'copyright_detail': 'rights_detail',
-              'tagline': 'subtitle',
-              'tagline_detail': 'subtitle_detail'}
-    def __getitem__(self, key):
-        if key == 'category':
-            return UserDict.__getitem__(self, 'tags')[0]['term']
-        if key == 'categories':
-            return [(tag['scheme'], tag['term']) for tag in UserDict.__getitem__(self, 'tags')]
-        realkey = self.keymap.get(key, key)
-        if type(realkey) == types.ListType:
-            for k in realkey:
-                if UserDict.has_key(self, k):
-                    return UserDict.__getitem__(self, k)
-        if UserDict.has_key(self, key):
-            return UserDict.__getitem__(self, key)
-        return UserDict.__getitem__(self, realkey)
-
-    def __setitem__(self, key, value):
-        for k in self.keymap.keys():
-            if key == k:
-                key = self.keymap[k]
-                if type(key) == types.ListType:
-                    key = key[0]
-        return UserDict.__setitem__(self, key, value)
-
-    def get(self, key, default=None):
-        if self.has_key(key):
-            return self[key]
-        else:
-            return default
-
-    def setdefault(self, key, value):
-        if not self.has_key(key):
-            self[key] = value
-        return self[key]
-        
-    def has_key(self, key):
-        try:
-            return hasattr(self, key) or UserDict.has_key(self, key)
-        except AttributeError:
-            return False
-        
-    def __getattr__(self, key):
-        try:
-            return self.__dict__[key]
-        except KeyError:
-            pass
-        try:
-            assert not key.startswith('_')
-            return self.__getitem__(key)
-        except:
-            raise AttributeError, "object has no attribute '%s'" % key
-
-    def __setattr__(self, key, value):
-        if key.startswith('_') or key == 'data':
-            self.__dict__[key] = value
-        else:
-            return self.__setitem__(key, value)
-
-    def __contains__(self, key):
-        return self.has_key(key)
-
-def zopeCompatibilityHack():
-    global FeedParserDict
-    del FeedParserDict
-    def FeedParserDict(aDict=None):
-        rc = {}
-        if aDict:
-            rc.update(aDict)
-        return rc
-
-_ebcdic_to_ascii_map = None
-def _ebcdic_to_ascii(s):
-    global _ebcdic_to_ascii_map
-    if not _ebcdic_to_ascii_map:
-        emap = (
-            0,1,2,3,156,9,134,127,151,141,142,11,12,13,14,15,
-            16,17,18,19,157,133,8,135,24,25,146,143,28,29,30,31,
-            128,129,130,131,132,10,23,27,136,137,138,139,140,5,6,7,
-            144,145,22,147,148,149,150,4,152,153,154,155,20,21,158,26,
-            32,160,161,162,163,164,165,166,167,168,91,46,60,40,43,33,
-            38,169,170,171,172,173,174,175,176,177,93,36,42,41,59,94,
-            45,47,178,179,180,181,182,183,184,185,124,44,37,95,62,63,
-            186,187,188,189,190,191,192,193,194,96,58,35,64,39,61,34,
-            195,97,98,99,100,101,102,103,104,105,196,197,198,199,200,201,
-            202,106,107,108,109,110,111,112,113,114,203,204,205,206,207,208,
-            209,126,115,116,117,118,119,120,121,122,210,211,212,213,214,215,
-            216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,
-            123,65,66,67,68,69,70,71,72,73,232,233,234,235,236,237,
-            125,74,75,76,77,78,79,80,81,82,238,239,240,241,242,243,
-            92,159,83,84,85,86,87,88,89,90,244,245,246,247,248,249,
-            48,49,50,51,52,53,54,55,56,57,250,251,252,253,254,255
-            )
-        import string
-        _ebcdic_to_ascii_map = string.maketrans( \
-            ''.join(map(chr, range(256))), ''.join(map(chr, emap)))
-    return s.translate(_ebcdic_to_ascii_map)
-
-_urifixer = re.compile('^([A-Za-z][A-Za-z0-9+-.]*://)(/*)(.*?)')
-def _urljoin(base, uri):
-    uri = _urifixer.sub(r'\1\3', uri)
-    return urlparse.urljoin(base, uri)
-
-class _FeedParserMixin:
-    namespaces = {'': '',
-                  'http://backend.userland.com/rss': '',
-                  'http://blogs.law.harvard.edu/tech/rss': '',
-                  'http://purl.org/rss/1.0/': '',
-                  'http://my.netscape.com/rdf/simple/0.9/': '',
-                  'http://example.com/newformat#': '',
-                  'http://example.com/necho': '',
-                  'http://purl.org/echo/': '',
-                  'uri/of/echo/namespace#': '',
-                  'http://purl.org/pie/': '',
-                  'http://purl.org/atom/ns#': '',
-                  'http://www.w3.org/2005/Atom': '',
-                  'http://purl.org/rss/1.0/modules/rss091#': '',
-                  
-                  'http://webns.net/mvcb/':                               'admin',
-                  'http://purl.org/rss/1.0/modules/aggregation/':         'ag',
-                  'http://purl.org/rss/1.0/modules/annotate/':            'annotate',
-                  'http://media.tangent.org/rss/1.0/':                    'audio',
-                  'http://backend.userland.com/blogChannelModule':        'blogChannel',
-                  'http://web.resource.org/cc/':                          'cc',
-                  'http://backend.userland.com/creativeCommonsRssModule': 'creativeCommons',
-                  'http://purl.org/rss/1.0/modules/company':              'co',
-                  'http://purl.org/rss/1.0/modules/content/':             'content',
-                  'http://my.theinfo.org/changed/1.0/rss/':               'cp',
-                  'http://purl.org/dc/elements/1.1/':                     'dc',
-                  'http://purl.org/dc/terms/':                            'dcterms',
-                  'http://purl.org/rss/1.0/modules/email/':               'email',
-                  'http://purl.org/rss/1.0/modules/event/':               'ev',
-                  'http://rssnamespace.org/feedburner/ext/1.0':           'feedburner',
-                  'http://freshmeat.net/rss/fm/':                         'fm',
-                  'http://xmlns.com/foaf/0.1/':                           'foaf',
-                  'http://www.w3.org/2003/01/geo/wgs84_pos#':             'geo',
-                  'http://postneo.com/icbm/':                             'icbm',
-                  'http://purl.org/rss/1.0/modules/image/':               'image',
-                  'http://www.itunes.com/DTDs/PodCast-1.0.dtd':           'itunes',
-                  'http://example.com/DTDs/PodCast-1.0.dtd':              'itunes',
-                  'http://purl.org/rss/1.0/modules/link/':                'l',
-                  'http://search.yahoo.com/mrss':                         'media',
-                  'http://madskills.com/public/xml/rss/module/pingback/': 'pingback',
-                  'http://prismstandard.org/namespaces/1.2/basic/':       'prism',
-                  'http://www.w3.org/1999/02/22-rdf-syntax-ns#':          'rdf',
-                  'http://www.w3.org/2000/01/rdf-schema#':                'rdfs',
-                  'http://purl.org/rss/1.0/modules/reference/':           'ref',
-                  'http://purl.org/rss/1.0/modules/richequiv/':           'reqv',
-                  'http://purl.org/rss/1.0/modules/search/':              'search',
-                  'http://purl.org/rss/1.0/modules/slash/':               'slash',
-                  'http://schemas.xmlsoap.org/soap/envelope/':            'soap',
-                  'http://purl.org/rss/1.0/modules/servicestatus/':       'ss',
-                  'http://hacks.benhammersley.com/rss/streaming/':        'str',
-                  'http://purl.org/rss/1.0/modules/subscription/':        'sub',
-                  'http://purl.org/rss/1.0/modules/syndication/':         'sy',
-                  'http://purl.org/rss/1.0/modules/taxonomy/':            'taxo',
-                  'http://purl.org/rss/1.0/modules/threading/':           'thr',
-                  'http://purl.org/rss/1.0/modules/textinput/':           'ti',
-                  'http://madskills.com/public/xml/rss/module/trackback/':'trackback',
-                  'http://wellformedweb.org/commentAPI/':                 'wfw',
-                  'http://purl.org/rss/1.0/modules/wiki/':                'wiki',
-                  'http://www.w3.org/1999/xhtml':                         'xhtml',
-                  'http://www.w3.org/XML/1998/namespace':                 'xml',
-                  'http://schemas.pocketsoap.com/rss/myDescModule/':      'szf'
-}
-    _matchnamespaces = {}
-
-    can_be_relative_uri = ['link', 'id', 'wfw_comment', 'wfw_commentrss', 'docs', 'url', 'href', 'comments', 'license', 'icon', 'logo']
-    can_contain_relative_uris = ['content', 'title', 'summary', 'info', 'tagline', 'subtitle', 'copyright', 'rights', 'description']
-    can_contain_dangerous_markup = ['content', 'title', 'summary', 'info', 'tagline', 'subtitle', 'copyright', 'rights', 'description']
-    html_types = ['text/html', 'application/xhtml+xml']
-    
-    def __init__(self, baseuri=None, baselang=None, encoding='utf-8'):
-        if _debug: sys.stderr.write('initializing FeedParser\n')
-        if not self._matchnamespaces:
-            for k, v in self.namespaces.items():
-                self._matchnamespaces[k.lower()] = v
-        self.feeddata = FeedParserDict() # feed-level data
-        self.encoding = encoding # character encoding
-        self.entries = [] # list of entry-level data
-        self.version = '' # feed type/version, see SUPPORTED_VERSIONS
-        self.namespacesInUse = {} # dictionary of namespaces defined by the feed
-
-        # the following are used internally to track state;
-        # this is really out of control and should be refactored
-        self.infeed = 0
-        self.inentry = 0
-        self.incontent = 0
-        self.intextinput = 0
-        self.inimage = 0
-        self.inauthor = 0
-        self.incontributor = 0
-        self.inpublisher = 0
-        self.insource = 0
-        self.sourcedata = FeedParserDict()
-        self.contentparams = FeedParserDict()
-        self._summaryKey = None
-        self.namespacemap = {}
-        self.elementstack = []
-        self.basestack = []
-        self.langstack = []
-        self.baseuri = baseuri or ''
-        self.lang = baselang or None
-        if baselang:
-            self.feeddata['language'] = baselang
-
-    def unknown_starttag(self, tag, attrs):
-        if _debug: sys.stderr.write('start %s with %s\n' % (tag, attrs))
-        # normalize attrs
-        attrs = [(k.lower(), v) for k, v in attrs]
-        attrs = [(k, k in ('rel', 'type') and v.lower() or v) for k, v in attrs]
-        
-        # track xml:base and xml:lang
-        attrsD = dict(attrs)
-        baseuri = attrsD.get('xml:base', attrsD.get('base')) or self.baseuri
-        self.baseuri = _urljoin(self.baseuri, baseuri)
-        lang = attrsD.get('xml:lang', attrsD.get('lang'))
-        if lang == '':
-            # xml:lang could be explicitly set to '', we need to capture that
-            lang = None
-        elif lang is None:
-            # if no xml:lang is specified, use parent lang
-            lang = self.lang
-        if lang:
-            if tag in ('feed', 'rss', 'rdf:RDF'):
-                self.feeddata['language'] = lang
-        self.lang = lang
-        self.basestack.append(self.baseuri)
-        self.langstack.append(lang)
-        
-        # track namespaces
-        for prefix, uri in attrs:
-            if prefix.startswith('xmlns:'):
-                self.trackNamespace(prefix[6:], uri)
-            elif prefix == 'xmlns':
-                self.trackNamespace(None, uri)
-
-        # track inline content
-        if self.incontent and self.contentparams.has_key('type') and not self.contentparams.get('type', 'xml').endswith('xml'):
-            # element declared itself as escaped markup, but it isn't really
-            self.contentparams['type'] = 'application/xhtml+xml'
-        if self.incontent and self.contentparams.get('type') == 'application/xhtml+xml':
-            # Note: probably shouldn't simply recreate localname here, but
-            # our namespace handling isn't actually 100% correct in cases where
-            # the feed redefines the default namespace (which is actually
-            # the usual case for inline content, thanks Sam), so here we
-            # cheat and just reconstruct the element based on localname
-            # because that compensates for the bugs in our namespace handling.
-            # This will horribly munge inline content with non-empty qnames,
-            # but nobody actually does that, so I'm not fixing it.
-            tag = tag.split(':')[-1]
-            return self.handle_data('<%s%s>' % (tag, ''.join([' %s="%s"' % t for t in attrs])), escape=0)
-
-        # match namespaces
-        if tag.find(':') <> -1:
-            prefix, suffix = tag.split(':', 1)
-        else:
-            prefix, suffix = '', tag
-        prefix = self.namespacemap.get(prefix, prefix)
-        if prefix:
-            prefix = prefix + '_'
-
-        # special hack for better tracking of empty textinput/image elements in illformed feeds
-        if (not prefix) and tag not in ('title', 'link', 'description', 'name'):
-            self.intextinput = 0
-        if (not prefix) and tag not in ('title', 'link', 'description', 'url', 'href', 'width', 'height'):
-            self.inimage = 0
-        
-        # call special handler (if defined) or default handler
-        methodname = '_start_' + prefix + suffix
-        try:
-            method = getattr(self, methodname)
-            return method(attrsD)
-        except AttributeError:
-            return self.push(prefix + suffix, 1)
-
-    def unknown_endtag(self, tag):
-        if _debug: sys.stderr.write('end %s\n' % tag)
-        # match namespaces
-        if tag.find(':') <> -1:
-            prefix, suffix = tag.split(':', 1)
-        else:
-            prefix, suffix = '', tag
-        prefix = self.namespacemap.get(prefix, prefix)
-        if prefix:
-            prefix = prefix + '_'
-
-        # call special handler (if defined) or default handler
-        methodname = '_end_' + prefix + suffix
-        try:
-            method = getattr(self, methodname)
-            method()
-        except AttributeError:
-            self.pop(prefix + suffix)
-
-        # track inline content
-        if self.incontent and self.contentparams.has_key('type') and not self.contentparams.get('type', 'xml').endswith('xml'):
-            # element declared itself as escaped markup, but it isn't really
-            self.contentparams['type'] = 'application/xhtml+xml'
-        if self.incontent and self.contentparams.get('type') == 'application/xhtml+xml':
-            tag = tag.split(':')[-1]
-            self.handle_data('</%s>' % tag, escape=0)
-
-        # track xml:base and xml:lang going out of scope
-        if self.basestack:
-            self.basestack.pop()
-            if self.basestack and self.basestack[-1]:
-                self.baseuri = self.basestack[-1]
-        if self.langstack:
-            self.langstack.pop()
-            if self.langstack: # and (self.langstack[-1] is not None):
-                self.lang = self.langstack[-1]
-
-    def handle_charref(self, ref):
-        # called for each character reference, e.g. for '&#160;', ref will be '160'
-        if not self.elementstack: return
-        ref = ref.lower()
-        if ref in ('34', '38', '39', '60', '62', 'x22', 'x26', 'x27', 'x3c', 'x3e'):
-            text = '&#%s;' % ref
-        else:
-            if ref[0] == 'x':
-                c = int(ref[1:], 16)
-            else:
-                c = int(ref)
-            text = unichr(c).encode('utf-8')
-        self.elementstack[-1][2].append(text)
-
-    def handle_entityref(self, ref):
-        # called for each entity reference, e.g. for '&copy;', ref will be 'copy'
-        if not self.elementstack: return
-        if _debug: sys.stderr.write('entering handle_entityref with %s\n' % ref)
-        if ref in ('lt', 'gt', 'quot', 'amp', 'apos'):
-            text = '&%s;' % ref
-        else:
-            # entity resolution graciously donated by Aaron Swartz
-            def name2cp(k):
-                import htmlentitydefs
-                if hasattr(htmlentitydefs, 'name2codepoint'): # requires Python 2.3
-                    return htmlentitydefs.name2codepoint[k]
-                k = htmlentitydefs.entitydefs[k]
-                if k.startswith('&#') and k.endswith(';'):
-                    return int(k[2:-1]) # not in latin-1
-                return ord(k)
-            try: name2cp(ref)
-            except KeyError: text = '&%s;' % ref
-            else: text = unichr(name2cp(ref)).encode('utf-8')
-        self.elementstack[-1][2].append(text)
-
-    def handle_data(self, text, escape=1):
-        # called for each block of plain text, i.e. outside of any tag and
-        # not containing any character or entity references
-        if not self.elementstack: return
-        if escape and self.contentparams.get('type') == 'application/xhtml+xml':
-            text = _xmlescape(text)
-        self.elementstack[-1][2].append(text)
-
-    def handle_comment(self, text):
-        # called for each comment, e.g. <!-- insert message here -->
-        pass
-
-    def handle_pi(self, text):
-        # called for each processing instruction, e.g. <?instruction>
-        pass
-
-    def handle_decl(self, text):
-        pass
-
-    def parse_declaration(self, i):
-        # override internal declaration handler to handle CDATA blocks
-        if _debug: sys.stderr.write('entering parse_declaration\n')
-        if self.rawdata[i:i+9] == '<![CDATA[':
-            k = self.rawdata.find(']]>', i)
-            if k == -1: k = len(self.rawdata)
-            self.handle_data(_xmlescape(self.rawdata[i+9:k]), 0)
-            return k+3
-        else:
-            k = self.rawdata.find('>', i)
-            return k+1
-
-    def mapContentType(self, contentType):
-        contentType = contentType.lower()
-        if contentType == 'text':
-            contentType = 'text/plain'
-        elif contentType == 'html':
-            contentType = 'text/html'
-        elif contentType == 'xhtml':
-            contentType = 'application/xhtml+xml'
-        return contentType
-    
-    def trackNamespace(self, prefix, uri):
-        loweruri = uri.lower()
-        if (prefix, loweruri) == (None, 'http://my.netscape.com/rdf/simple/0.9/') and not self.version:
-            self.version = 'rss090'
-        if loweruri == 'http://purl.org/rss/1.0/' and not self.version:
-            self.version = 'rss10'
-        if loweruri == 'http://www.w3.org/2005/atom' and not self.version:
-            self.version = 'atom10'
-        if loweruri.find('backend.userland.com/rss') <> -1:
-            # match any backend.userland.com namespace
-            uri = 'http://backend.userland.com/rss'
-            loweruri = uri
-        if self._matchnamespaces.has_key(loweruri):
-            self.namespacemap[prefix] = self._matchnamespaces[loweruri]
-            self.namespacesInUse[self._matchnamespaces[loweruri]] = uri
-        else:
-            self.namespacesInUse[prefix or ''] = uri
-
-    def resolveURI(self, uri):
-        return _urljoin(self.baseuri or '', uri)
-    
-    def decodeEntities(self, element, data):
-        return data
-
-    def push(self, element, expectingText):
-        self.elementstack.append([element, expectingText, []])
-
-    def pop(self, element, stripWhitespace=1):
-        if not self.elementstack: return
-        if self.elementstack[-1][0] != element: return
-        
-        element, expectingText, pieces = self.elementstack.pop()
-        output = ''.join(pieces)
-        if stripWhitespace:
-            output = output.strip()
-        if not expectingText: return output
-
-        # decode base64 content
-        if base64 and self.contentparams.get('base64', 0):
-            try:
-                output = base64.decodestring(output)
-            except binascii.Error:
-                pass
-            except binascii.Incomplete:
-                pass
-                
-        # resolve relative URIs
-        if (element in self.can_be_relative_uri) and output:
-            output = self.resolveURI(output)
-        
-        # decode entities within embedded markup
-        if not self.contentparams.get('base64', 0):
-            output = self.decodeEntities(element, output)
-
-        # remove temporary cruft from contentparams
-        try:
-            del self.contentparams['mode']
-        except KeyError:
-            pass
-        try:
-            del self.contentparams['base64']
-        except KeyError:
-            pass
-
-        # resolve relative URIs within embedded markup
-        if self.mapContentType(self.contentparams.get('type', 'text/html')) in self.html_types:
-            if element in self.can_contain_relative_uris:
-                output = _resolveRelativeURIs(output, self.baseuri, self.encoding)
-        
-        # sanitize embedded markup
-        if self.mapContentType(self.contentparams.get('type', 'text/html')) in self.html_types:
-            if element in self.can_contain_dangerous_markup:
-                output = _sanitizeHTML(output, self.encoding)
-
-        if self.encoding and type(output) != type(u''):
-            try:
-                output = unicode(output, self.encoding)
-            except:
-                pass
-
-        # categories/tags/keywords/whatever are handled in _end_category
-        if element == 'category':
-            return output
-        
-        # store output in appropriate place(s)
-        if self.inentry and not self.insource:
-            if element == 'content':
-                self.entries[-1].setdefault(element, [])
-                contentparams = copy.deepcopy(self.contentparams)
-                contentparams['value'] = output
-                self.entries[-1][element].append(contentparams)
-            elif element == 'link':
-                self.entries[-1][element] = output
-                if output:
-                    self.entries[-1]['links'][-1]['href'] = output
-            else:
-                if element == 'description':
-                    element = 'summary'
-                self.entries[-1][element] = output
-                if self.incontent:
-                    contentparams = copy.deepcopy(self.contentparams)
-                    contentparams['value'] = output
-                    self.entries[-1][element + '_detail'] = contentparams
-        elif (self.infeed or self.insource) and (not self.intextinput) and (not self.inimage):
-            context = self._getContext()
-            if element == 'description':
-                element = 'subtitle'
-            context[element] = output
-            if element == 'link':
-                context['links'][-1]['href'] = output
-            elif self.incontent:
-                contentparams = copy.deepcopy(self.contentparams)
-                contentparams['value'] = output
-                context[element + '_detail'] = contentparams
-        return output
-
-    def pushContent(self, tag, attrsD, defaultContentType, expectingText):
-        self.incontent += 1
-        self.contentparams = FeedParserDict({
-            'type': self.mapContentType(attrsD.get('type', defaultContentType)),
-            'language': self.lang,
-            'base': self.baseuri})
-        self.contentparams['base64'] = self._isBase64(attrsD, self.contentparams)
-        self.push(tag, expectingText)
-
-    def popContent(self, tag):
-        value = self.pop(tag)
-        self.incontent -= 1
-        self.contentparams.clear()
-        return value
-        
-    def _mapToStandardPrefix(self, name):
-        colonpos = name.find(':')
-        if colonpos <> -1:
-            prefix = name[:colonpos]
-            suffix = name[colonpos+1:]
-            prefix = self.namespacemap.get(prefix, prefix)
-            name = prefix + ':' + suffix
-        return name
-        
-    def _getAttribute(self, attrsD, name):
-        return attrsD.get(self._mapToStandardPrefix(name))
-
-    def _isBase64(self, attrsD, contentparams):
-        if attrsD.get('mode', '') == 'base64':
-            return 1
-        if self.contentparams['type'].startswith('text/'):
-            return 0
-        if self.contentparams['type'].endswith('+xml'):
-            return 0
-        if self.contentparams['type'].endswith('/xml'):
-            return 0
-        return 1
-
-    def _itsAnHrefDamnIt(self, attrsD):
-        href = attrsD.get('url', attrsD.get('uri', attrsD.get('href', None)))
-        if href:
-            try:
-                del attrsD['url']
-            except KeyError:
-                pass
-            try:
-                del attrsD['uri']
-            except KeyError:
-                pass
-            attrsD['href'] = href
-        return attrsD
-    
-    def _save(self, key, value):
-        context = self._getContext()
-        context.setdefault(key, value)
-
-    def _start_rss(self, attrsD):
-        versionmap = {'0.91': 'rss091u',
-                      '0.92': 'rss092',
-                      '0.93': 'rss093',
-                      '0.94': 'rss094'}
-        if not self.version:
-            attr_version = attrsD.get('version', '')
-            version = versionmap.get(attr_version)
-            if version:
-                self.version = version
-            elif attr_version.startswith('2.'):
-                self.version = 'rss20'
-            else:
-                self.version = 'rss'
-    
-    def _start_dlhottitles(self, attrsD):
-        self.version = 'hotrss'
-
-    def _start_channel(self, attrsD):
-        self.infeed = 1
-        self._cdf_common(attrsD)
-    _start_feedinfo = _start_channel
-
-    def _cdf_common(self, attrsD):
-        if attrsD.has_key('lastmod'):
-            self._start_modified({})
-            self.elementstack[-1][-1] = attrsD['lastmod']
-            self._end_modified()
-        if attrsD.has_key('href'):
-            self._start_link({})
-            self.elementstack[-1][-1] = attrsD['href']
-            self._end_link()
-    
-    def _start_feed(self, attrsD):
-        self.infeed = 1
-        versionmap = {'0.1': 'atom01',
-                      '0.2': 'atom02',
-                      '0.3': 'atom03'}
-        if not self.version:
-            attr_version = attrsD.get('version')
-            version = versionmap.get(attr_version)
-            if version:
-                self.version = version
-            else:
-                self.version = 'atom'
-
-    def _end_channel(self):
-        self.infeed = 0
-    _end_feed = _end_channel
-    
-    def _start_image(self, attrsD):
-        self.inimage = 1
-        self.push('image', 0)
-        context = self._getContext()
-        context.setdefault('image', FeedParserDict())
-            
-    def _end_image(self):
-        self.pop('image')
-        self.inimage = 0
-
-    def _start_textinput(self, attrsD):
-        self.intextinput = 1
-        self.push('textinput', 0)
-        context = self._getContext()
-        context.setdefault('textinput', FeedParserDict())
-    _start_textInput = _start_textinput
-    
-    def _end_textinput(self):
-        self.pop('textinput')
-        self.intextinput = 0
-    _end_textInput = _end_textinput
-
-    def _start_author(self, attrsD):
-        self.inauthor = 1
-        self.push('author', 1)
-    _start_managingeditor = _start_author
-    _start_dc_author = _start_author
-    _start_dc_creator = _start_author
-    _start_itunes_author = _start_author
-
-    def _end_author(self):
-        self.pop('author')
-        self.inauthor = 0
-        self._sync_author_detail()
-    _end_managingeditor = _end_author
-    _end_dc_author = _end_author
-    _end_dc_creator = _end_author
-    _end_itunes_author = _end_author
-
-    def _start_itunes_owner(self, attrsD):
-        self.inpublisher = 1
-        self.push('publisher', 0)
-
-    def _end_itunes_owner(self):
-        self.pop('publisher')
-        self.inpublisher = 0
-        self._sync_author_detail('publisher')
-
-    def _start_contributor(self, attrsD):
-        self.incontributor = 1
-        context = self._getContext()
-        context.setdefault('contributors', [])
-        context['contributors'].append(FeedParserDict())
-        self.push('contributor', 0)
-
-    def _end_contributor(self):
-        self.pop('contributor')
-        self.incontributor = 0
-
-    def _start_dc_contributor(self, attrsD):
-        self.incontributor = 1
-        context = self._getContext()
-        context.setdefault('contributors', [])
-        context['contributors'].append(FeedParserDict())
-        self.push('name', 0)
-
-    def _end_dc_contributor(self):
-        self._end_name()
-        self.incontributor = 0
-
-    def _start_name(self, attrsD):
-        self.push('name', 0)
-    _start_itunes_name = _start_name
-
-    def _end_name(self):
-        value = self.pop('name')
-        if self.inpublisher:
-            self._save_author('name', value, 'publisher')
-        elif self.inauthor:
-            self._save_author('name', value)
-        elif self.incontributor:
-            self._save_contributor('name', value)
-        elif self.intextinput:
-            context = self._getContext()
-            context['textinput']['name'] = value
-    _end_itunes_name = _end_name
-
-    def _start_width(self, attrsD):
-        self.push('width', 0)
-
-    def _end_width(self):
-        value = self.pop('width')
-        try:
-            value = int(value)
-        except:
-            value = 0
-        if self.inimage:
-            context = self._getContext()
-            context['image']['width'] = value
-
-    def _start_height(self, attrsD):
-        self.push('height', 0)
-
-    def _end_height(self):
-        value = self.pop('height')
-        try:
-            value = int(value)
-        except:
-            value = 0
-        if self.inimage:
-            context = self._getContext()
-            context['image']['height'] = value
-
-    def _start_url(self, attrsD):
-        self.push('href', 1)
-    _start_homepage = _start_url
-    _start_uri = _start_url
-
-    def _end_url(self):
-        value = self.pop('href')
-        if self.inauthor:
-            self._save_author('href', value)
-        elif self.incontributor:
-            self._save_contributor('href', value)
-        elif self.inimage:
-            context = self._getContext()
-            context['image']['href'] = value
-        elif self.intextinput:
-            context = self._getContext()
-            context['textinput']['link'] = value
-    _end_homepage = _end_url
-    _end_uri = _end_url
-
-    def _start_email(self, attrsD):
-        self.push('email', 0)
-    _start_itunes_email = _start_email
-
-    def _end_email(self):
-        value = self.pop('email')
-        if self.inpublisher:
-            self._save_author('email', value, 'publisher')
-        elif self.inauthor:
-            self._save_author('email', value)
-        elif self.incontributor:
-            self._save_contributor('email', value)
-    _end_itunes_email = _end_email
-
-    def _getContext(self):
-        if self.insource:
-            context = self.sourcedata
-        elif self.inentry:
-            context = self.entries[-1]
-        else:
-            context = self.feeddata
-        return context
-
-    def _save_author(self, key, value, prefix='author'):
-        context = self._getContext()
-        context.setdefault(prefix + '_detail', FeedParserDict())
-        context[prefix + '_detail'][key] = value
-        self._sync_author_detail()
-
-    def _save_contributor(self, key, value):
-        context = self._getContext()
-        context.setdefault('contributors', [FeedParserDict()])
-        context['contributors'][-1][key] = value
-
-    def _sync_author_detail(self, key='author'):
-        context = self._getContext()
-        detail = context.get('%s_detail' % key)
-        if detail:
-            name = detail.get('name')
-            email = detail.get('email')
-            if name and email:
-                context[key] = '%s (%s)' % (name, email)
-            elif name:
-                context[key] = name
-            elif email:
-                context[key] = email
-        else:
-            author = context.get(key)
-            if not author: return
-            emailmatch = re.search(r'''(([a-zA-Z0-9\_\-\.\+]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?))''', author)
-            if not emailmatch: return
-            email = emailmatch.group(0)
-            # probably a better way to do the following, but it passes all the tests
-            author = author.replace(email, '')
-            author = author.replace('()', '')
-            author = author.strip()
-            if author and (author[0] == '('):
-                author = author[1:]
-            if author and (author[-1] == ')'):
-                author = author[:-1]
-            author = author.strip()
-            context.setdefault('%s_detail' % key, FeedParserDict())
-            context['%s_detail' % key]['name'] = author
-            context['%s_detail' % key]['email'] = email
-
-    def _start_subtitle(self, attrsD):
-        self.pushContent('subtitle', attrsD, 'text/plain', 1)
-    _start_tagline = _start_subtitle
-    _start_itunes_subtitle = _start_subtitle
-
-    def _end_subtitle(self):
-        self.popContent('subtitle')
-    _end_tagline = _end_subtitle
-    _end_itunes_subtitle = _end_subtitle
-            
-    def _start_rights(self, attrsD):
-        self.pushContent('rights', attrsD, 'text/plain', 1)
-    _start_dc_rights = _start_rights
-    _start_copyright = _start_rights
-
-    def _end_rights(self):
-        self.popContent('rights')
-    _end_dc_rights = _end_rights
-    _end_copyright = _end_rights
-
-    def _start_item(self, attrsD):
-        self.entries.append(FeedParserDict())
-        self.push('item', 0)
-        self.inentry = 1
-        self.guidislink = 0
-        id = self._getAttribute(attrsD, 'rdf:about')
-        if id:
-            context = self._getContext()
-            context['id'] = id
-        self._cdf_common(attrsD)
-    _start_entry = _start_item
-    _start_product = _start_item
-
-    def _end_item(self):
-        self.pop('item')
-        self.inentry = 0
-    _end_entry = _end_item
-
-    def _start_dc_language(self, attrsD):
-        self.push('language', 1)
-    _start_language = _start_dc_language
-
-    def _end_dc_language(self):
-        self.lang = self.pop('language')
-    _end_language = _end_dc_language
-
-    def _start_dc_publisher(self, attrsD):
-        self.push('publisher', 1)
-    _start_webmaster = _start_dc_publisher
-
-    def _end_dc_publisher(self):
-        self.pop('publisher')
-        self._sync_author_detail('publisher')
-    _end_webmaster = _end_dc_publisher
-
-    def _start_published(self, attrsD):
-        self.push('published', 1)
-    _start_dcterms_issued = _start_published
-    _start_issued = _start_published
-
-    def _end_published(self):
-        value = self.pop('published')
-        self._save('published_parsed', _parse_date(value))
-    _end_dcterms_issued = _end_published
-    _end_issued = _end_published
-
-    def _start_updated(self, attrsD):
-        self.push('updated', 1)
-    _start_modified = _start_updated
-    _start_dcterms_modified = _start_updated
-    _start_pubdate = _start_updated
-    _start_dc_date = _start_updated
-
-    def _end_updated(self):
-        value = self.pop('updated')
-        parsed_value = _parse_date(value)
-        self._save('updated_parsed', parsed_value)
-    _end_modified = _end_updated
-    _end_dcterms_modified = _end_updated
-    _end_pubdate = _end_updated
-    _end_dc_date = _end_updated
-
-    def _start_created(self, attrsD):
-        self.push('created', 1)
-    _start_dcterms_created = _start_created
-
-    def _end_created(self):
-        value = self.pop('created')
-        self._save('created_parsed', _parse_date(value))
-    _end_dcterms_created = _end_created
-
-    def _start_expirationdate(self, attrsD):
-        self.push('expired', 1)
-
-    def _end_expirationdate(self):
-        self._save('expired_parsed', _parse_date(self.pop('expired')))
-
-    def _start_cc_license(self, attrsD):
-        self.push('license', 1)
-        value = self._getAttribute(attrsD, 'rdf:resource')
-        if value:
-            self.elementstack[-1][2].append(value)
-        self.pop('license')
-        
-    def _start_creativecommons_license(self, attrsD):
-        self.push('license', 1)
-
-    def _end_creativecommons_license(self):
-        self.pop('license')
-
-    def _addTag(self, term, scheme, label):
-        context = self._getContext()
-        tags = context.setdefault('tags', [])
-        if (not term) and (not scheme) and (not label): return
-        value = FeedParserDict({'term': term, 'scheme': scheme, 'label': label})
-        if value not in tags:
-            tags.append(FeedParserDict({'term': term, 'scheme': scheme, 'label': label}))
-
-    def _start_category(self, attrsD):
-        if _debug: sys.stderr.write('entering _start_category with %s\n' % repr(attrsD))
-        term = attrsD.get('term')
-        scheme = attrsD.get('scheme', attrsD.get('domain'))
-        label = attrsD.get('label')
-        self._addTag(term, scheme, label)
-        self.push('category', 1)
-    _start_dc_subject = _start_category
-    _start_keywords = _start_category
-        
-    def _end_itunes_keywords(self):
-        for term in self.pop('itunes_keywords').split():
-            self._addTag(term, 'http://www.itunes.com/', None)
-        
-    def _start_itunes_category(self, attrsD):
-        self._addTag(attrsD.get('text'), 'http://www.itunes.com/', None)
-        self.push('category', 1)
-        
-    def _end_category(self):
-        value = self.pop('category')
-        if not value: return
-        context = self._getContext()
-        tags = context['tags']
-        if value and len(tags) and not tags[-1]['term']:
-            tags[-1]['term'] = value
-        else:
-            self._addTag(value, None, None)
-    _end_dc_subject = _end_category
-    _end_keywords = _end_category
-    _end_itunes_category = _end_category
-
-    def _start_cloud(self, attrsD):
-        self._getContext()['cloud'] = FeedParserDict(attrsD)
-        
-    def _start_link(self, attrsD):
-        attrsD.setdefault('rel', 'alternate')
-        attrsD.setdefault('type', 'text/html')
-        attrsD = self._itsAnHrefDamnIt(attrsD)
-        if attrsD.has_key('href'):
-            attrsD['href'] = self.resolveURI(attrsD['href'])
-        expectingText = self.infeed or self.inentry or self.insource
-        context = self._getContext()
-        context.setdefault('links', [])
-        context['links'].append(FeedParserDict(attrsD))
-        if attrsD['rel'] == 'enclosure':
-            self._start_enclosure(attrsD)
-        if attrsD.has_key('href'):
-            expectingText = 0
-            if (attrsD.get('rel') == 'alternate') and (self.mapContentType(attrsD.get('type')) in self.html_types):
-                context['link'] = attrsD['href']
-        else:
-            self.push('link', expectingText)
-    _start_producturl = _start_link
-
-    def _end_link(self):
-        value = self.pop('link')
-        context = self._getContext()
-        if self.intextinput:
-            context['textinput']['link'] = value
-        if self.inimage:
-            context['image']['link'] = value
-    _end_producturl = _end_link
-
-    def _start_guid(self, attrsD):
-        self.guidislink = (attrsD.get('ispermalink', 'true') == 'true')
-        self.push('id', 1)
-
-    def _end_guid(self):
-        value = self.pop('id')
-        self._save('guidislink', self.guidislink and not self._getContext().has_key('link'))
-        if self.guidislink:
-            # guid acts as link, but only if 'ispermalink' is not present or is 'true',
-            # and only if the item doesn't already have a link element
-            self._save('link', value)
-
-    def _start_title(self, attrsD):
-        self.pushContent('title', attrsD, 'text/plain', self.infeed or self.inentry or self.insource)
-    _start_dc_title = _start_title
-    _start_media_title = _start_title
-
-    def _end_title(self):
-        value = self.popContent('title')
-        context = self._getContext()
-        if self.intextinput:
-            context['textinput']['title'] = value
-        elif self.inimage:
-            context['image']['title'] = value
-    _end_dc_title = _end_title
-    _end_media_title = _end_title
-
-    def _start_description(self, attrsD):
-        context = self._getContext()
-        if context.has_key('summary'):
-            self._summaryKey = 'content'
-            self._start_content(attrsD)
-        else:
-            self.pushContent('description', attrsD, 'text/html', self.infeed or self.inentry or self.insource)
-
-    def _start_abstract(self, attrsD):
-        self.pushContent('description', attrsD, 'text/plain', self.infeed or self.inentry or self.insource)
-
-    def _end_description(self):
-        if self._summaryKey == 'content':
-            self._end_content()
-        else:
-            value = self.popContent('description')
-            context = self._getContext()
-            if self.intextinput:
-                context['textinput']['description'] = value
-            elif self.inimage:
-                context['image']['description'] = value
-        self._summaryKey = None
-    _end_abstract = _end_description
-
-    def _start_info(self, attrsD):
-        self.pushContent('info', attrsD, 'text/plain', 1)
-    _start_feedburner_browserfriendly = _start_info
-
-    def _end_info(self):
-        self.popContent('info')
-    _end_feedburner_browserfriendly = _end_info
-
-    def _start_generator(self, attrsD):
-        if attrsD:
-            attrsD = self._itsAnHrefDamnIt(attrsD)
-            if attrsD.has_key('href'):
-                attrsD['href'] = self.resolveURI(attrsD['href'])
-        self._getContext()['generator_detail'] = FeedParserDict(attrsD)
-        self.push('generator', 1)
-
-    def _end_generator(self):
-        value = self.pop('generator')
-        context = self._getContext()
-        if context.has_key('generator_detail'):
-            context['generator_detail']['name'] = value
-            
-    def _start_admin_generatoragent(self, attrsD):
-        self.push('generator', 1)
-        value = self._getAttribute(attrsD, 'rdf:resource')
-        if value:
-            self.elementstack[-1][2].append(value)
-        self.pop('generator')
-        self._getContext()['generator_detail'] = FeedParserDict({'href': value})
-
-    def _start_admin_errorreportsto(self, attrsD):
-        self.push('errorreportsto', 1)
-        value = self._getAttribute(attrsD, 'rdf:resource')
-        if value:
-            self.elementstack[-1][2].append(value)
-        self.pop('errorreportsto')
-        
-    def _start_summary(self, attrsD):
-        context = self._getContext()
-        if context.has_key('summary'):
-            self._summaryKey = 'content'
-            self._start_content(attrsD)
-        else:
-            self._summaryKey = 'summary'
-            self.pushContent(self._summaryKey, attrsD, 'text/plain', 1)
-    _start_itunes_summary = _start_summary
-
-    def _end_summary(self):
-        if self._summaryKey == 'content':
-            self._end_content()
-        else:
-            self.popContent(self._summaryKey or 'summary')
-        self._summaryKey = None
-    _end_itunes_summary = _end_summary
-        
-    def _start_enclosure(self, attrsD):
-        attrsD = self._itsAnHrefDamnIt(attrsD)
-        self._getContext().setdefault('enclosures', []).append(FeedParserDict(attrsD))
-        href = attrsD.get('href')
-        if href:
-            context = self._getContext()
-            if not context.get('id'):
-                context['id'] = href
-            
-    def _start_source(self, attrsD):
-        self.insource = 1
-
-    def _end_source(self):
-        self.insource = 0
-        self._getContext()['source'] = copy.deepcopy(self.sourcedata)
-        self.sourcedata.clear()
-
-    def _start_content(self, attrsD):
-        self.pushContent('content', attrsD, 'text/plain', 1)
-        src = attrsD.get('src')
-        if src:
-            self.contentparams['src'] = src
-        self.push('content', 1)
-
-    def _start_prodlink(self, attrsD):
-        self.pushContent('content', attrsD, 'text/html', 1)
-
-    def _start_body(self, attrsD):
-        self.pushContent('content', attrsD, 'application/xhtml+xml', 1)
-    _start_xhtml_body = _start_body
-
-    def _start_content_encoded(self, attrsD):
-        self.pushContent('content', attrsD, 'text/html', 1)
-    _start_fullitem = _start_content_encoded
-
-    def _end_content(self):
-        copyToDescription = self.mapContentType(self.contentparams.get('type')) in (['text/plain'] + self.html_types)
-        value = self.popContent('content')
-        if copyToDescription:
-            self._save('description', value)
-    _end_body = _end_content
-    _end_xhtml_body = _end_content
-    _end_content_encoded = _end_content
-    _end_fullitem = _end_content
-    _end_prodlink = _end_content
-
-    def _start_itunes_image(self, attrsD):
-        self.push('itunes_image', 0)
-        self._getContext()['image'] = FeedParserDict({'href': attrsD.get('href')})
-    _start_itunes_link = _start_itunes_image
-        
-    def _end_itunes_block(self):
-        value = self.pop('itunes_block', 0)
-        self._getContext()['itunes_block'] = (value == 'yes') and 1 or 0
-
-    def _end_itunes_explicit(self):
-        value = self.pop('itunes_explicit', 0)
-        self._getContext()['itunes_explicit'] = (value == 'yes') and 1 or 0
-
-if _XML_AVAILABLE:
-    class _StrictFeedParser(_FeedParserMixin, xml.sax.handler.ContentHandler):
-        def __init__(self, baseuri, baselang, encoding):
-            if _debug: sys.stderr.write('trying StrictFeedParser\n')
-            xml.sax.handler.ContentHandler.__init__(self)
-            _FeedParserMixin.__init__(self, baseuri, baselang, encoding)
-            self.bozo = 0
-            self.exc = None
-        
-        def startPrefixMapping(self, prefix, uri):
-            self.trackNamespace(prefix, uri)
-        
-        def startElementNS(self, name, qname, attrs):
-            namespace, localname = name
-            lowernamespace = str(namespace or '').lower()
-            if lowernamespace.find('backend.userland.com/rss') <> -1:
-                # match any backend.userland.com namespace
-                namespace = 'http://backend.userland.com/rss'
-                lowernamespace = namespace
-            if qname and qname.find(':') > 0:
-                givenprefix = qname.split(':')[0]
-            else:
-                givenprefix = None
-            prefix = self._matchnamespaces.get(lowernamespace, givenprefix)
-            if givenprefix and (prefix == None or (prefix == '' and lowernamespace == '')) and not self.namespacesInUse.has_key(givenprefix):
-                    raise UndeclaredNamespace, "'%s' is not associated with a namespace" % givenprefix
-            if prefix:
-                localname = prefix + ':' + localname
-            localname = str(localname).lower()
-            if _debug: sys.stderr.write('startElementNS: qname = %s, namespace = %s, givenprefix = %s, prefix = %s, attrs = %s, localname = %s\n' % (qname, namespace, givenprefix, prefix, attrs.items(), localname))
-
-            # qname implementation is horribly broken in Python 2.1 (it
-            # doesn't report any), and slightly broken in Python 2.2 (it
-            # doesn't report the xml: namespace). So we match up namespaces
-            # with a known list first, and then possibly override them with
-            # the qnames the SAX parser gives us (if indeed it gives us any
-            # at all).  Thanks to MatejC for helping me test this and
-            # tirelessly telling me that it didn't work yet.
-            attrsD = {}
-            for (namespace, attrlocalname), attrvalue in attrs._attrs.items():
-                lowernamespace = (namespace or '').lower()
-                prefix = self._matchnamespaces.get(lowernamespace, '')
-                if prefix:
-                    attrlocalname = prefix + ':' + attrlocalname
-                attrsD[str(attrlocalname).lower()] = attrvalue
-            for qname in attrs.getQNames():
-                attrsD[str(qname).lower()] = attrs.getValueByQName(qname)
-            self.unknown_starttag(localname, attrsD.items())
-
-        def characters(self, text):
-            self.handle_data(text)
-
-        def endElementNS(self, name, qname):
-            namespace, localname = name
-            lowernamespace = str(namespace or '').lower()
-            if qname and qname.find(':') > 0:
-                givenprefix = qname.split(':')[0]
-            else:
-                givenprefix = ''
-            prefix = self._matchnamespaces.get(lowernamespace, givenprefix)
-            if prefix:
-                localname = prefix + ':' + localname
-            localname = str(localname).lower()
-            self.unknown_endtag(localname)
-
-        def error(self, exc):
-            self.bozo = 1
-            self.exc = exc
-            
-        def fatalError(self, exc):
-            self.error(exc)
-            raise exc
-
-class _BaseHTMLProcessor(sgmllib.SGMLParser):
-    elements_no_end_tag = ['area', 'base', 'basefont', 'br', 'col', 'frame', 'hr',
-      'img', 'input', 'isindex', 'link', 'meta', 'param']
-    
-    def __init__(self, encoding):
-        self.encoding = encoding
-        if _debug: sys.stderr.write('entering BaseHTMLProcessor, encoding=%s\n' % self.encoding)
-        sgmllib.SGMLParser.__init__(self)
-        
-    def reset(self):
-        self.pieces = []
-        sgmllib.SGMLParser.reset(self)
-
-    def _shorttag_replace(self, match):
-        tag = match.group(1)
-        if tag in self.elements_no_end_tag:
-            return '<' + tag + ' />'
-        else:
-            return '<' + tag + '></' + tag + '>'
-        
-    def feed(self, data):
-        data = re.compile(r'<!((?!DOCTYPE|--|\[))', re.IGNORECASE).sub(r'&lt;!\1', data)
-        #data = re.sub(r'<(\S+?)\s*?/>', self._shorttag_replace, data) # bug [ 1399464 ] Bad regexp for _shorttag_replace
-        data = re.sub(r'<([^<\s]+?)\s*/>', self._shorttag_replace, data) 
-        data = data.replace('&#39;', "'")
-        data = data.replace('&#34;', '"')
-        if self.encoding and type(data) == type(u''):
-            data = data.encode(self.encoding)
-        sgmllib.SGMLParser.feed(self, data)
-
-    def normalize_attrs(self, attrs):
-        # utility method to be called by descendants
-        attrs = [(k.lower(), v) for k, v in attrs]
-        attrs = [(k, k in ('rel', 'type') and v.lower() or v) for k, v in attrs]
-        return attrs
-
-    def unknown_starttag(self, tag, attrs):
-        # called for each start tag
-        # attrs is a list of (attr, value) tuples
-        # e.g. for <pre class='screen'>, tag='pre', attrs=[('class', 'screen')]
-        if _debug: sys.stderr.write('_BaseHTMLProcessor, unknown_starttag, tag=%s\n' % tag)
-        uattrs = []
-        # thanks to Kevin Marks for this breathtaking hack to deal with (valid) high-bit attribute values in UTF-8 feeds
-        for key, value in attrs:
-            if type(value) != type(u''):
-                value = unicode(value, self.encoding)
-            uattrs.append((unicode(key, self.encoding), value))
-        strattrs = u''.join([u' %s="%s"' % (key, value) for key, value in uattrs]).encode(self.encoding)
-        if tag in self.elements_no_end_tag:
-            self.pieces.append('<%(tag)s%(strattrs)s />' % locals())
-        else:
-            self.pieces.append('<%(tag)s%(strattrs)s>' % locals())
-
-    def unknown_endtag(self, tag):
-        # called for each end tag, e.g. for </pre>, tag will be 'pre'
-        # Reconstruct the original end tag.
-        if tag not in self.elements_no_end_tag:
-            self.pieces.append("</%(tag)s>" % locals())
-
-    def handle_charref(self, ref):
-        # called for each character reference, e.g. for '&#160;', ref will be '160'
-        # Reconstruct the original character reference.
-        self.pieces.append('&#%(ref)s;' % locals())
-        
-    def handle_entityref(self, ref):
-        # called for each entity reference, e.g. for '&copy;', ref will be 'copy'
-        # Reconstruct the original entity reference.
-        self.pieces.append('&%(ref)s;' % locals())
-
-    def handle_data(self, text):
-        # called for each block of plain text, i.e. outside of any tag and
-        # not containing any character or entity references
-        # Store the original text verbatim.
-        if _debug: sys.stderr.write('_BaseHTMLProcessor, handle_text, text=%s\n' % text)
-        self.pieces.append(text)
-        
-    def handle_comment(self, text):
-        # called for each HTML comment, e.g. <!-- insert Javascript code here -->
-        # Reconstruct the original comment.
-        self.pieces.append('<!--%(text)s-->' % locals())
-        
-    def handle_pi(self, text):
-        # called for each processing instruction, e.g. <?instruction>
-        # Reconstruct original processing instruction.
-        self.pieces.append('<?%(text)s>' % locals())
-
-    def handle_decl(self, text):
-        # called for the DOCTYPE, if present, e.g.
-        # <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
-        #     "http://www.w3.org/TR/html4/loose.dtd">
-        # Reconstruct original DOCTYPE
-        self.pieces.append('<!%(text)s>' % locals())
-        
-    _new_declname_match = re.compile(r'[a-zA-Z][-_.a-zA-Z0-9:]*\s*').match
-    def _scan_name(self, i, declstartpos):
-        rawdata = self.rawdata
-        n = len(rawdata)
-        if i == n:
-            return None, -1
-        m = self._new_declname_match(rawdata, i)
-        if m:
-            s = m.group()
-            name = s.strip()
-            if (i + len(s)) == n:
-                return None, -1  # end of buffer
-            return name.lower(), m.end()
-        else:
-            self.handle_data(rawdata)
-#            self.updatepos(declstartpos, i)
-            return None, -1
-
-    def output(self):
-        '''Return processed HTML as a single string'''
-        return ''.join([str(p) for p in self.pieces])
-
-class _LooseFeedParser(_FeedParserMixin, _BaseHTMLProcessor):
-    def __init__(self, baseuri, baselang, encoding):
-        sgmllib.SGMLParser.__init__(self)
-        _FeedParserMixin.__init__(self, baseuri, baselang, encoding)
-
-    def decodeEntities(self, element, data):
-        data = data.replace('&#60;', '&lt;')
-        data = data.replace('&#x3c;', '&lt;')
-        data = data.replace('&#62;', '&gt;')
-        data = data.replace('&#x3e;', '&gt;')
-        data = data.replace('&#38;', '&amp;')
-        data = data.replace('&#x26;', '&amp;')
-        data = data.replace('&#34;', '&quot;')
-        data = data.replace('&#x22;', '&quot;')
-        data = data.replace('&#39;', '&apos;')
-        data = data.replace('&#x27;', '&apos;')
-        if self.contentparams.has_key('type') and not self.contentparams.get('type', 'xml').endswith('xml'):
-            data = data.replace('&lt;', '<')
-            data = data.replace('&gt;', '>')
-            data = data.replace('&amp;', '&')
-            data = data.replace('&quot;', '"')
-            data = data.replace('&apos;', "'")
-        return data
-        
-class _RelativeURIResolver(_BaseHTMLProcessor):
-    relative_uris = [('a', 'href'),
-                     ('applet', 'codebase'),
-                     ('area', 'href'),
-                     ('blockquote', 'cite'),
-                     ('body', 'background'),
-                     ('del', 'cite'),
-                     ('form', 'action'),
-                     ('frame', 'longdesc'),
-                     ('frame', 'src'),
-                     ('iframe', 'longdesc'),
-                     ('iframe', 'src'),
-                     ('head', 'profile'),
-                     ('img', 'longdesc'),
-                     ('img', 'src'),
-                     ('img', 'usemap'),
-                     ('input', 'src'),
-                     ('input', 'usemap'),
-                     ('ins', 'cite'),
-                     ('link', 'href'),
-                     ('object', 'classid'),
-                     ('object', 'codebase'),
-                     ('object', 'data'),
-                     ('object', 'usemap'),
-                     ('q', 'cite'),
-                     ('script', 'src')]
-
-    def __init__(self, baseuri, encoding):
-        _BaseHTMLProcessor.__init__(self, encoding)
-        self.baseuri = baseuri
-
-    def resolveURI(self, uri):
-        return _urljoin(self.baseuri, uri)
-    
-    def unknown_starttag(self, tag, attrs):
-        attrs = self.normalize_attrs(attrs)
-        attrs = [(key, ((tag, key) in self.relative_uris) and self.resolveURI(value) or value) for key, value in attrs]
-        _BaseHTMLProcessor.unknown_starttag(self, tag, attrs)
-        
-def _resolveRelativeURIs(htmlSource, baseURI, encoding):
-    if _debug: sys.stderr.write('entering _resolveRelativeURIs\n')
-    p = _RelativeURIResolver(baseURI, encoding)
-    p.feed(htmlSource)
-    return p.output()
-
-class _HTMLSanitizer(_BaseHTMLProcessor):
-    acceptable_elements = ['a', 'abbr', 'acronym', 'address', 'area', 'b', 'big',
-      'blockquote', 'br', 'button', 'caption', 'center', 'cite', 'code', 'col',
-      'colgroup', 'dd', 'del', 'dfn', 'dir', 'div', 'dl', 'dt', 'em', 'fieldset',
-      'font', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'hr', 'i', 'img', 'input',
-      'ins', 'kbd', 'label', 'legend', 'li', 'map', 'menu', 'ol', 'optgroup',
-      'option', 'p', 'pre', 'q', 's', 'samp', 'select', 'small', 'span', 'strike',
-      'strong', 'sub', 'sup', 'table', 'tbody', 'td', 'textarea', 'tfoot', 'th',
-      'thead', 'tr', 'tt', 'u', 'ul', 'var']
-
-    acceptable_attributes = ['abbr', 'accept', 'accept-charset', 'accesskey',
-      'action', 'align', 'alt', 'axis', 'border', 'cellpadding', 'cellspacing',
-      'char', 'charoff', 'charset', 'checked', 'cite', 'class', 'clear', 'cols',
-      'colspan', 'color', 'compact', 'coords', 'datetime', 'dir', 'disabled',
-      'enctype', 'for', 'frame', 'headers', 'height', 'href', 'hreflang', 'hspace',
-      'id', 'ismap', 'label', 'lang', 'longdesc', 'maxlength', 'media', 'method',
-      'multiple', 'name', 'nohref', 'noshade', 'nowrap', 'prompt', 'readonly',
-      'rel', 'rev', 'rows', 'rowspan', 'rules', 'scope', 'selected', 'shape', 'size',
-      'span', 'src', 'start', 'summary', 'tabindex', 'target', 'title', 'type',
-      'usemap', 'valign', 'value', 'vspace', 'width']
-
-    unacceptable_elements_with_end_tag = ['script', 'applet']
-
-    def reset(self):
-        _BaseHTMLProcessor.reset(self)
-        self.unacceptablestack = 0
-        
-    def unknown_starttag(self, tag, attrs):
-        if not tag in self.acceptable_elements:
-            if tag in self.unacceptable_elements_with_end_tag:
-                self.unacceptablestack += 1
-            return
-        attrs = self.normalize_attrs(attrs)
-        attrs = [(key, value) for key, value in attrs if key in self.acceptable_attributes]
-        _BaseHTMLProcessor.unknown_starttag(self, tag, attrs)
-        
-    def unknown_endtag(self, tag):
-        if not tag in self.acceptable_elements:
-            if tag in self.unacceptable_elements_with_end_tag:
-                self.unacceptablestack -= 1
-            return
-        _BaseHTMLProcessor.unknown_endtag(self, tag)
-
-    def handle_pi(self, text):
-        pass
-
-    def handle_decl(self, text):
-        pass
-
-    def handle_data(self, text):
-        if not self.unacceptablestack:
-            _BaseHTMLProcessor.handle_data(self, text)
-
-def _sanitizeHTML(htmlSource, encoding):
-    p = _HTMLSanitizer(encoding)
-    p.feed(htmlSource)
-    data = p.output()
-    if TIDY_MARKUP:
-        # loop through list of preferred Tidy interfaces looking for one that's installed,
-        # then set up a common _tidy function to wrap the interface-specific API.
-        _tidy = None
-        for tidy_interface in PREFERRED_TIDY_INTERFACES:
-            try:
-                if tidy_interface == "uTidy":
-                    from tidy import parseString as _utidy
-                    def _tidy(data, **kwargs):
-                        return str(_utidy(data, **kwargs))
-                    break
-                elif tidy_interface == "mxTidy":
-                    from mx.Tidy import Tidy as _mxtidy
-                    def _tidy(data, **kwargs):
-                        nerrors, nwarnings, data, errordata = _mxtidy.tidy(data, **kwargs)
-                        return data
-                    break
-            except:
-                pass
-        if _tidy:
-            utf8 = type(data) == type(u'')
-            if utf8:
-                data = data.encode('utf-8')
-            data = _tidy(data, output_xhtml=1, numeric_entities=1, wrap=0, char_encoding="utf8")
-            if utf8:
-                data = unicode(data, 'utf-8')
-            if data.count('<body'):
-                data = data.split('<body', 1)[1]
-                if data.count('>'):
-                    data = data.split('>', 1)[1]
-            if data.count('</body'):
-                data = data.split('</body', 1)[0]
-    data = data.strip().replace('\r\n', '\n')
-    return data
-
-class _FeedURLHandler(urllib2.HTTPDigestAuthHandler, urllib2.HTTPRedirectHandler, urllib2.HTTPDefaultErrorHandler):
-    def http_error_default(self, req, fp, code, msg, headers):
-        if ((code / 100) == 3) and (code != 304):
-            return self.http_error_302(req, fp, code, msg, headers)
-        infourl = urllib.addinfourl(fp, headers, req.get_full_url())
-        infourl.status = code
-        return infourl
-
-    def http_error_302(self, req, fp, code, msg, headers):
-        if headers.dict.has_key('location'):
-            infourl = urllib2.HTTPRedirectHandler.http_error_302(self, req, fp, code, msg, headers)
-        else:
-            infourl = urllib.addinfourl(fp, headers, req.get_full_url())
-        if not hasattr(infourl, 'status'):
-            infourl.status = code
-        return infourl
-
-    def http_error_301(self, req, fp, code, msg, headers):
-        if headers.dict.has_key('location'):
-            infourl = urllib2.HTTPRedirectHandler.http_error_301(self, req, fp, code, msg, headers)
-        else:
-            infourl = urllib.addinfourl(fp, headers, req.get_full_url())
-        if not hasattr(infourl, 'status'):
-            infourl.status = code
-        return infourl
-
-    http_error_300 = http_error_302
-    http_error_303 = http_error_302
-    http_error_307 = http_error_302
-        
-    def http_error_401(self, req, fp, code, msg, headers):
-        # Check if
-        # - server requires digest auth, AND
-        # - we tried (unsuccessfully) with basic auth, AND
-        # - we're using Python 2.3.3 or later (digest auth is irreparably broken in earlier versions)
-        # If all conditions hold, parse authentication information
-        # out of the Authorization header we sent the first time
-        # (for the username and password) and the WWW-Authenticate
-        # header the server sent back (for the realm) and retry
-        # the request with the appropriate digest auth headers instead.
-        # This evil genius hack has been brought to you by Aaron Swartz.
-        host = urlparse.urlparse(req.get_full_url())[1]
-        try:
-            assert sys.version.split()[0] >= '2.3.3'
-            assert base64 != None
-            user, passw = base64.decodestring(req.headers['Authorization'].split(' ')[1]).split(':')
-            realm = re.findall('realm="([^"]*)"', headers['WWW-Authenticate'])[0]
-            self.add_password(realm, host, user, passw)
-            retry = self.http_error_auth_reqed('www-authenticate', host, req, headers)
-            self.reset_retry_count()
-            return retry
-        except:
-            return self.http_error_default(req, fp, code, msg, headers)
-
-def _open_resource(url_file_stream_or_string, etag, modified, agent, referrer, handlers):
-    """URL, filename, or string --> stream
-
-    This function lets you define parsers that take any input source
-    (URL, pathname to local or network file, or actual data as a string)
-    and deal with it in a uniform manner.  Returned object is guaranteed
-    to have all the basic stdio read methods (read, readline, readlines).
-    Just .close() the object when you're done with it.
-
-    If the etag argument is supplied, it will be used as the value of an
-    If-None-Match request header.
-
-    If the modified argument is supplied, it must be a tuple of 9 integers
-    as returned by gmtime() in the standard Python time module. This MUST
-    be in GMT (Greenwich Mean Time). The formatted date/time will be used
-    as the value of an If-Modified-Since request header.
-
-    If the agent argument is supplied, it will be used as the value of a
-    User-Agent request header.
-
-    If the referrer argument is supplied, it will be used as the value of a
-    Referer[sic] request header.
-
-    If handlers is supplied, it is a list of handlers used to build a
-    urllib2 opener.
-    """
-
-    if hasattr(url_file_stream_or_string, 'read'):
-        return url_file_stream_or_string
-
-    if url_file_stream_or_string == '-':
-        return sys.stdin
-
-    if urlparse.urlparse(url_file_stream_or_string)[0] in ('http', 'https', 'ftp'):
-        if not agent:
-            agent = USER_AGENT
-        # test for inline user:password for basic auth
-        auth = None
-        if base64:
-            urltype, rest = urllib.splittype(url_file_stream_or_string)
-            realhost, rest = urllib.splithost(rest)
-            if realhost:
-                user_passwd, realhost = urllib.splituser(realhost)
-                if user_passwd:
-                    url_file_stream_or_string = '%s://%s%s' % (urltype, realhost, rest)
-                    auth = base64.encodestring(user_passwd).strip()
-        # try to open with urllib2 (to use optional headers)
-        request = urllib2.Request(url_file_stream_or_string)
-        request.add_header('User-Agent', agent)
-        if etag:
-            request.add_header('If-None-Match', etag)
-        if modified:
-            # format into an RFC 1123-compliant timestamp. We can't use
-            # time.strftime() since the %a and %b directives can be affected
-            # by the current locale, but RFC 2616 states that dates must be
-            # in English.
-            short_weekdays = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
-            months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
-            request.add_header('If-Modified-Since', '%s, %02d %s %04d %02d:%02d:%02d GMT' % (short_weekdays[modified[6]], modified[2], months[modified[1] - 1], modified[0], modified[3], modified[4], modified[5]))
-        if referrer:
-            request.add_header('Referer', referrer)
-        if gzip and zlib:
-            request.add_header('Accept-encoding', 'gzip, deflate')
-        elif gzip:
-            request.add_header('Accept-encoding', 'gzip')
-        elif zlib:
-            request.add_header('Accept-encoding', 'deflate')
-        else:
-            request.add_header('Accept-encoding', '')
-        if auth:
-            request.add_header('Authorization', 'Basic %s' % auth)
-        if ACCEPT_HEADER:
-            request.add_header('Accept', ACCEPT_HEADER)
-        request.add_header('A-IM', 'feed') # RFC 3229 support
-        opener = apply(urllib2.build_opener, tuple([_FeedURLHandler()] + handlers))
-        opener.addheaders = [] # RMK - must clear so we only send our custom User-Agent
-        try:
-            return opener.open(request)
-        finally:
-            opener.close() # JohnD
-    
-    # try to open with native open function (if url_file_stream_or_string is a filename)
-    try:
-        return open(url_file_stream_or_string)
-    except:
-        pass
-
-    # treat url_file_stream_or_string as string
-    return _StringIO(str(url_file_stream_or_string))
-
-_date_handlers = []
-def registerDateHandler(func):
-    '''Register a date handler function (takes string, returns 9-tuple date in GMT)'''
-    _date_handlers.insert(0, func)
-    
-# ISO-8601 date parsing routines written by Fazal Majid.
-# The ISO 8601 standard is very convoluted and irregular - a full ISO 8601
-# parser is beyond the scope of feedparser and would be a worthwhile addition
-# to the Python library.
-# A single regular expression cannot parse ISO 8601 date formats into groups
-# as the standard is highly irregular (for instance is 030104 2003-01-04 or
-# 0301-04-01), so we use templates instead.
-# Please note the order in templates is significant because we need a
-# greedy match.
-_iso8601_tmpl = ['YYYY-?MM-?DD', 'YYYY-MM', 'YYYY-?OOO',
-                'YY-?MM-?DD', 'YY-?OOO', 'YYYY', 
-                '-YY-?MM', '-OOO', '-YY',
-                '--MM-?DD', '--MM',
-                '---DD',
-                'CC', '']
-_iso8601_re = [
-    tmpl.replace(
-    'YYYY', r'(?P<year>\d{4})').replace(
-    'YY', r'(?P<year>\d\d)').replace(
-    'MM', r'(?P<month>[01]\d)').replace(
-    'DD', r'(?P<day>[0123]\d)').replace(
-    'OOO', r'(?P<ordinal>[0123]\d\d)').replace(
-    'CC', r'(?P<century>\d\d$)')
-    + r'(T?(?P<hour>\d{2}):(?P<minute>\d{2})'
-    + r'(:(?P<second>\d{2}))?'
-    + r'(?P<tz>[+-](?P<tzhour>\d{2})(:(?P<tzmin>\d{2}))?|Z)?)?'
-    for tmpl in _iso8601_tmpl]
-del tmpl
-_iso8601_matches = [re.compile(regex).match for regex in _iso8601_re]
-del regex
-def _parse_date_iso8601(dateString):
-    '''Parse a variety of ISO-8601-compatible formats like 20040105'''
-    m = None
-    for _iso8601_match in _iso8601_matches:
-        m = _iso8601_match(dateString)
-        if m: break
-    if not m: return
-    if m.span() == (0, 0): return
-    params = m.groupdict()
-    ordinal = params.get('ordinal', 0)
-    if ordinal:
-        ordinal = int(ordinal)
-    else:
-        ordinal = 0
-    year = params.get('year', '--')
-    if not year or year == '--':
-        year = time.gmtime()[0]
-    elif len(year) == 2:
-        # ISO 8601 assumes current century, i.e. 93 -> 2093, NOT 1993
-        year = 100 * int(time.gmtime()[0] / 100) + int(year)
-    else:
-        year = int(year)
-    month = params.get('month', '-')
-    if not month or month == '-':
-        # ordinals are NOT normalized by mktime, we simulate them
-        # by setting month=1, day=ordinal
-        if ordinal:
-            month = 1
-        else:
-            month = time.gmtime()[1]
-    month = int(month)
-    day = params.get('day', 0)
-    if not day:
-        # see above
-        if ordinal:
-            day = ordinal
-        elif params.get('century', 0) or \
-                 params.get('year', 0) or params.get('month', 0):
-            day = 1
-        else:
-            day = time.gmtime()[2]
-    else:
-        day = int(day)
-    # special case of the century - is the first year of the 21st century
-    # 2000 or 2001 ? The debate goes on...
-    if 'century' in params.keys():
-        year = (int(params['century']) - 1) * 100 + 1
-    # in ISO 8601 most fields are optional
-    for field in ['hour', 'minute', 'second', 'tzhour', 'tzmin']:
-        if not params.get(field, None):
-            params[field] = 0
-    hour = int(params.get('hour', 0))
-    minute = int(params.get('minute', 0))
-    second = int(params.get('second', 0))
-    # weekday is normalized by mktime(), we can ignore it
-    weekday = 0
-    # daylight savings is complex, but not needed for feedparser's purposes
-    # as time zones, if specified, include mention of whether it is active
-    # (e.g. PST vs. PDT, CET). Using -1 is implementation-dependent and
-    # and most implementations have DST bugs
-    daylight_savings_flag = 0
-    tm = [year, month, day, hour, minute, second, weekday,
-          ordinal, daylight_savings_flag]
-    # ISO 8601 time zone adjustments
-    tz = params.get('tz')
-    if tz and tz != 'Z':
-        if tz[0] == '-':
-            tm[3] += int(params.get('tzhour', 0))
-            tm[4] += int(params.get('tzmin', 0))
-        elif tz[0] == '+':
-            tm[3] -= int(params.get('tzhour', 0))
-            tm[4] -= int(params.get('tzmin', 0))
-        else:
-            return None
-    # Python's time.mktime() is a wrapper around the ANSI C mktime(3c)
-    # which is guaranteed to normalize d/m/y/h/m/s.
-    # Many implementations have bugs, but we'll pretend they don't.
-    return time.localtime(time.mktime(tm))
-registerDateHandler(_parse_date_iso8601)
-    
-# 8-bit date handling routines written by ytrewq1.
-_korean_year  = u'\ub144' # b3e2 in euc-kr
-_korean_month = u'\uc6d4' # bff9 in euc-kr
-_korean_day   = u'\uc77c' # c0cf in euc-kr
-_korean_am    = u'\uc624\uc804' # bfc0 c0fc in euc-kr
-_korean_pm    = u'\uc624\ud6c4' # bfc0 c8c4 in euc-kr
-
-_korean_onblog_date_re = \
-    re.compile('(\d{4})%s\s+(\d{2})%s\s+(\d{2})%s\s+(\d{2}):(\d{2}):(\d{2})' % \
-               (_korean_year, _korean_month, _korean_day))
-_korean_nate_date_re = \
-    re.compile(u'(\d{4})-(\d{2})-(\d{2})\s+(%s|%s)\s+(\d{,2}):(\d{,2}):(\d{,2})' % \
-               (_korean_am, _korean_pm))
-def _parse_date_onblog(dateString):
-    '''Parse a string according to the OnBlog 8-bit date format'''
-    m = _korean_onblog_date_re.match(dateString)
-    if not m: return
-    w3dtfdate = '%(year)s-%(month)s-%(day)sT%(hour)s:%(minute)s:%(second)s%(zonediff)s' % \
-                {'year': m.group(1), 'month': m.group(2), 'day': m.group(3),\
-                 'hour': m.group(4), 'minute': m.group(5), 'second': m.group(6),\
-                 'zonediff': '+09:00'}
-    if _debug: sys.stderr.write('OnBlog date parsed as: %s\n' % w3dtfdate)
-    return _parse_date_w3dtf(w3dtfdate)
-registerDateHandler(_parse_date_onblog)
-
-def _parse_date_nate(dateString):
-    '''Parse a string according to the Nate 8-bit date format'''
-    m = _korean_nate_date_re.match(dateString)
-    if not m: return
-    hour = int(m.group(5))
-    ampm = m.group(4)
-    if (ampm == _korean_pm):
-        hour += 12
-    hour = str(hour)
-    if len(hour) == 1:
-        hour = '0' + hour
-    w3dtfdate = '%(year)s-%(month)s-%(day)sT%(hour)s:%(minute)s:%(second)s%(zonediff)s' % \
-                {'year': m.group(1), 'month': m.group(2), 'day': m.group(3),\
-                 'hour': hour, 'minute': m.group(6), 'second': m.group(7),\
-                 'zonediff': '+09:00'}
-    if _debug: sys.stderr.write('Nate date parsed as: %s\n' % w3dtfdate)
-    return _parse_date_w3dtf(w3dtfdate)
-registerDateHandler(_parse_date_nate)
-
-_mssql_date_re = \
-    re.compile('(\d{4})-(\d{2})-(\d{2})\s+(\d{2}):(\d{2}):(\d{2})(\.\d+)?')
-def _parse_date_mssql(dateString):
-    '''Parse a string according to the MS SQL date format'''
-    m = _mssql_date_re.match(dateString)
-    if not m: return
-    w3dtfdate = '%(year)s-%(month)s-%(day)sT%(hour)s:%(minute)s:%(second)s%(zonediff)s' % \
-                {'year': m.group(1), 'month': m.group(2), 'day': m.group(3),\
-                 'hour': m.group(4), 'minute': m.group(5), 'second': m.group(6),\
-                 'zonediff': '+09:00'}
-    if _debug: sys.stderr.write('MS SQL date parsed as: %s\n' % w3dtfdate)
-    return _parse_date_w3dtf(w3dtfdate)
-registerDateHandler(_parse_date_mssql)
-
-# Unicode strings for Greek date strings
-_greek_months = \
-  { \
-   u'\u0399\u03b1\u03bd': u'Jan',       # c9e1ed in iso-8859-7
-   u'\u03a6\u03b5\u03b2': u'Feb',       # d6e5e2 in iso-8859-7
-   u'\u039c\u03ac\u03ce': u'Mar',       # ccdcfe in iso-8859-7
-   u'\u039c\u03b1\u03ce': u'Mar',       # cce1fe in iso-8859-7
-   u'\u0391\u03c0\u03c1': u'Apr',       # c1f0f1 in iso-8859-7
-   u'\u039c\u03ac\u03b9': u'May',       # ccdce9 in iso-8859-7
-   u'\u039c\u03b1\u03ca': u'May',       # cce1fa in iso-8859-7
-   u'\u039c\u03b1\u03b9': u'May',       # cce1e9 in iso-8859-7
-   u'\u0399\u03bf\u03cd\u03bd': u'Jun', # c9effded in iso-8859-7
-   u'\u0399\u03bf\u03bd': u'Jun',       # c9efed in iso-8859-7
-   u'\u0399\u03bf\u03cd\u03bb': u'Jul', # c9effdeb in iso-8859-7
-   u'\u0399\u03bf\u03bb': u'Jul',       # c9f9eb in iso-8859-7
-   u'\u0391\u03cd\u03b3': u'Aug',       # c1fde3 in iso-8859-7
-   u'\u0391\u03c5\u03b3': u'Aug',       # c1f5e3 in iso-8859-7
-   u'\u03a3\u03b5\u03c0': u'Sep',       # d3e5f0 in iso-8859-7
-   u'\u039f\u03ba\u03c4': u'Oct',       # cfeaf4 in iso-8859-7
-   u'\u039d\u03bf\u03ad': u'Nov',       # cdefdd in iso-8859-7
-   u'\u039d\u03bf\u03b5': u'Nov',       # cdefe5 in iso-8859-7
-   u'\u0394\u03b5\u03ba': u'Dec',       # c4e5ea in iso-8859-7
-  }
-
-_greek_wdays = \
-  { \
-   u'\u039a\u03c5\u03c1': u'Sun', # caf5f1 in iso-8859-7
-   u'\u0394\u03b5\u03c5': u'Mon', # c4e5f5 in iso-8859-7
-   u'\u03a4\u03c1\u03b9': u'Tue', # d4f1e9 in iso-8859-7
-   u'\u03a4\u03b5\u03c4': u'Wed', # d4e5f4 in iso-8859-7
-   u'\u03a0\u03b5\u03bc': u'Thu', # d0e5ec in iso-8859-7
-   u'\u03a0\u03b1\u03c1': u'Fri', # d0e1f1 in iso-8859-7
-   u'\u03a3\u03b1\u03b2': u'Sat', # d3e1e2 in iso-8859-7   
-  }
-
-_greek_date_format_re = \
-    re.compile(u'([^,]+),\s+(\d{2})\s+([^\s]+)\s+(\d{4})\s+(\d{2}):(\d{2}):(\d{2})\s+([^\s]+)')
-
-def _parse_date_greek(dateString):
-    '''Parse a string according to a Greek 8-bit date format.'''
-    m = _greek_date_format_re.match(dateString)
-    if not m: return
-    try:
-        wday = _greek_wdays[m.group(1)]
-        month = _greek_months[m.group(3)]
-    except:
-        return
-    rfc822date = '%(wday)s, %(day)s %(month)s %(year)s %(hour)s:%(minute)s:%(second)s %(zonediff)s' % \
-                 {'wday': wday, 'day': m.group(2), 'month': month, 'year': m.group(4),\
-                  'hour': m.group(5), 'minute': m.group(6), 'second': m.group(7),\
-                  'zonediff': m.group(8)}
-    if _debug: sys.stderr.write('Greek date parsed as: %s\n' % rfc822date)
-    return _parse_date_rfc822(rfc822date)
-registerDateHandler(_parse_date_greek)
-
-# Unicode strings for Hungarian date strings
-_hungarian_months = \
-  { \
-    u'janu\u00e1r':   u'01',  # e1 in iso-8859-2
-    u'febru\u00e1ri': u'02',  # e1 in iso-8859-2
-    u'm\u00e1rcius':  u'03',  # e1 in iso-8859-2
-    u'\u00e1prilis':  u'04',  # e1 in iso-8859-2
-    u'm\u00e1ujus':   u'05',  # e1 in iso-8859-2
-    u'j\u00fanius':   u'06',  # fa in iso-8859-2
-    u'j\u00falius':   u'07',  # fa in iso-8859-2
-    u'augusztus':     u'08',
-    u'szeptember':    u'09',
-    u'okt\u00f3ber':  u'10',  # f3 in iso-8859-2
-    u'november':      u'11',
-    u'december':      u'12',
-  }
-
-_hungarian_date_format_re = \
-  re.compile(u'(\d{4})-([^-]+)-(\d{,2})T(\d{,2}):(\d{2})((\+|-)(\d{,2}:\d{2}))')
-
-def _parse_date_hungarian(dateString):
-    '''Parse a string according to a Hungarian 8-bit date format.'''
-    m = _hungarian_date_format_re.match(dateString)
-    if not m: return
-    try:
-        month = _hungarian_months[m.group(2)]
-        day = m.group(3)
-        if len(day) == 1:
-            day = '0' + day
-        hour = m.group(4)
-        if len(hour) == 1:
-            hour = '0' + hour
-    except:
-        return
-    w3dtfdate = '%(year)s-%(month)s-%(day)sT%(hour)s:%(minute)s%(zonediff)s' % \
-                {'year': m.group(1), 'month': month, 'day': day,\
-                 'hour': hour, 'minute': m.group(5),\
-                 'zonediff': m.group(6)}
-    if _debug: sys.stderr.write('Hungarian date parsed as: %s\n' % w3dtfdate)
-    return _parse_date_w3dtf(w3dtfdate)
-registerDateHandler(_parse_date_hungarian)
-
-# W3DTF-style date parsing adapted from PyXML xml.utils.iso8601, written by
-# Drake and licensed under the Python license.  Removed all range checking
-# for month, day, hour, minute, and second, since mktime will normalize
-# these later
-def _parse_date_w3dtf(dateString):
-    def __extract_date(m):
-        year = int(m.group('year'))
-        if year < 100:
-            year = 100 * int(time.gmtime()[0] / 100) + int(year)
-        if year < 1000:
-            return 0, 0, 0
-        julian = m.group('julian')
-        if julian:
-            julian = int(julian)
-            month = julian / 30 + 1
-            day = julian % 30 + 1
-            jday = None
-            while jday != julian:
-                t = time.mktime((year, month, day, 0, 0, 0, 0, 0, 0))
-                jday = time.gmtime(t)[-2]
-                diff = abs(jday - julian)
-                if jday > julian:
-                    if diff < day:
-                        day = day - diff
-                    else:
-                        month = month - 1
-                        day = 31
-                elif jday < julian:
-                    if day + diff < 28:
-                       day = day + diff
-                    else:
-                        month = month + 1
-            return year, month, day
-        month = m.group('month')
-        day = 1
-        if month is None:
-            month = 1
-        else:
-            month = int(month)
-            day = m.group('day')
-            if day:
-                day = int(day)
-            else:
-                day = 1
-        return year, month, day
-
-    def __extract_time(m):
-        if not m:
-            return 0, 0, 0
-        hours = m.group('hours')
-        if not hours:
-            return 0, 0, 0
-        hours = int(hours)
-        minutes = int(m.group('minutes'))
-        seconds = m.group('seconds')
-        if seconds:
-            seconds = int(seconds)
-        else:
-            seconds = 0
-        return hours, minutes, seconds
-
-    def __extract_tzd(m):
-        '''Return the Time Zone Designator as an offset in seconds from UTC.'''
-        if not m:
-            return 0
-        tzd = m.group('tzd')
-        if not tzd:
-            return 0
-        if tzd == 'Z':
-            return 0
-        hours = int(m.group('tzdhours'))
-        minutes = m.group('tzdminutes')
-        if minutes:
-            minutes = int(minutes)
-        else:
-            minutes = 0
-        offset = (hours*60 + minutes) * 60
-        if tzd[0] == '+':
-            return -offset
-        return offset
-
-    __date_re = ('(?P<year>\d\d\d\d)'
-                 '(?:(?P<dsep>-|)'
-                 '(?:(?P<julian>\d\d\d)'
-                 '|(?P<month>\d\d)(?:(?P=dsep)(?P<day>\d\d))?))?')
-    __tzd_re = '(?P<tzd>[-+](?P<tzdhours>\d\d)(?::?(?P<tzdminutes>\d\d))|Z)'
-    __tzd_rx = re.compile(__tzd_re)
-    __time_re = ('(?P<hours>\d\d)(?P<tsep>:|)(?P<minutes>\d\d)'
-                 '(?:(?P=tsep)(?P<seconds>\d\d(?:[.,]\d+)?))?'
-                 + __tzd_re)
-    __datetime_re = '%s(?:T%s)?' % (__date_re, __time_re)
-    __datetime_rx = re.compile(__datetime_re)
-    m = __datetime_rx.match(dateString)
-    if (m is None) or (m.group() != dateString): return
-    gmt = __extract_date(m) + __extract_time(m) + (0, 0, 0)
-    if gmt[0] == 0: return
-    return time.gmtime(time.mktime(gmt) + __extract_tzd(m) - time.timezone)
-registerDateHandler(_parse_date_w3dtf)
-
-def _parse_date_rfc822(dateString):
-    '''Parse an RFC822, RFC1123, RFC2822, or asctime-style date'''
-    data = dateString.split()
-    if data[0][-1] in (',', '.') or data[0].lower() in rfc822._daynames:
-        del data[0]
-    if len(data) == 4:
-        s = data[3]
-        i = s.find('+')
-        if i > 0:
-            data[3:] = [s[:i], s[i+1:]]
-        else:
-            data.append('')
-        dateString = " ".join(data)
-    if len(data) < 5:
-        dateString += ' 00:00:00 GMT'
-    tm = rfc822.parsedate_tz(dateString)
-    if tm:
-        return time.gmtime(rfc822.mktime_tz(tm))
-# rfc822.py defines several time zones, but we define some extra ones.
-# 'ET' is equivalent to 'EST', etc.
-_additional_timezones = {'AT': -400, 'ET': -500, 'CT': -600, 'MT': -700, 'PT': -800}
-rfc822._timezones.update(_additional_timezones)
-registerDateHandler(_parse_date_rfc822)    
-
-def _parse_date(dateString):
-    '''Parses a variety of date formats into a 9-tuple in GMT'''
-    for handler in _date_handlers:
-        try:
-            date9tuple = handler(dateString)
-            if not date9tuple: continue
-            if len(date9tuple) != 9:
-                if _debug: sys.stderr.write('date handler function must return 9-tuple\n')
-                raise ValueError
-            map(int, date9tuple)
-            return date9tuple
-        except Exception, e:
-            if _debug: sys.stderr.write('%s raised %s\n' % (handler.__name__, repr(e)))
-            pass
-    return None
-
-def _getCharacterEncoding(http_headers, xml_data):
-    '''Get the character encoding of the XML document
-
-    http_headers is a dictionary
-    xml_data is a raw string (not Unicode)
-    
-    This is so much trickier than it sounds, it's not even funny.
-    According to RFC 3023 ('XML Media Types'), if the HTTP Content-Type
-    is application/xml, application/*+xml,
-    application/xml-external-parsed-entity, or application/xml-dtd,
-    the encoding given in the charset parameter of the HTTP Content-Type
-    takes precedence over the encoding given in the XML prefix within the
-    document, and defaults to 'utf-8' if neither are specified.  But, if
-    the HTTP Content-Type is text/xml, text/*+xml, or
-    text/xml-external-parsed-entity, the encoding given in the XML prefix
-    within the document is ALWAYS IGNORED and only the encoding given in
-    the charset parameter of the HTTP Content-Type header should be
-    respected, and it defaults to 'us-ascii' if not specified.
-
-    Furthermore, discussion on the atom-syntax mailing list with the
-    author of RFC 3023 leads me to the conclusion that any document
-    served with a Content-Type of text/* and no charset parameter
-    must be treated as us-ascii.  (We now do this.)  And also that it
-    must always be flagged as non-well-formed.  (We now do this too.)
-    
-    If Content-Type is unspecified (input was local file or non-HTTP source)
-    or unrecognized (server just got it totally wrong), then go by the
-    encoding given in the XML prefix of the document and default to
-    'iso-8859-1' as per the HTTP specification (RFC 2616).
-    
-    Then, assuming we didn't find a character encoding in the HTTP headers
-    (and the HTTP Content-type allowed us to look in the body), we need
-    to sniff the first few bytes of the XML data and try to determine
-    whether the encoding is ASCII-compatible.  Section F of the XML
-    specification shows the way here:
-    http://www.w3.org/TR/REC-xml/#sec-guessing-no-ext-info
-
-    If the sniffed encoding is not ASCII-compatible, we need to make it
-    ASCII compatible so that we can sniff further into the XML declaration
-    to find the encoding attribute, which will tell us the true encoding.
-
-    Of course, none of this guarantees that we will be able to parse the
-    feed in the declared character encoding (assuming it was declared
-    correctly, which many are not).  CJKCodecs and iconv_codec help a lot;
-    you should definitely install them if you can.
-    http://cjkpython.i18n.org/
-    '''
-
-    def _parseHTTPContentType(content_type):
-        '''takes HTTP Content-Type header and returns (content type, charset)
-
-        If no charset is specified, returns (content type, '')
-        If no content type is specified, returns ('', '')
-        Both return parameters are guaranteed to be lowercase strings
-        '''
-        content_type = content_type or ''
-        content_type, params = cgi.parse_header(content_type)
-        return content_type, params.get('charset', '').replace("'", '')
-
-    sniffed_xml_encoding = ''
-    xml_encoding = ''
-    true_encoding = ''
-    http_content_type, http_encoding = _parseHTTPContentType(http_headers.get('content-type'))
-    # Must sniff for non-ASCII-compatible character encodings before
-    # searching for XML declaration.  This heuristic is defined in
-    # section F of the XML specification:
-    # http://www.w3.org/TR/REC-xml/#sec-guessing-no-ext-info
-    try:
-        if xml_data[:4] == '\x4c\x6f\xa7\x94':
-            # EBCDIC
-            xml_data = _ebcdic_to_ascii(xml_data)
-        elif xml_data[:4] == '\x00\x3c\x00\x3f':
-            # UTF-16BE
-            sniffed_xml_encoding = 'utf-16be'
-            xml_data = unicode(xml_data, 'utf-16be').encode('utf-8')
-        elif (len(xml_data) >= 4) and (xml_data[:2] == '\xfe\xff') and (xml_data[2:4] != '\x00\x00'):
-            # UTF-16BE with BOM
-            sniffed_xml_encoding = 'utf-16be'
-            xml_data = unicode(xml_data[2:], 'utf-16be').encode('utf-8')
-        elif xml_data[:4] == '\x3c\x00\x3f\x00':
-            # UTF-16LE
-            sniffed_xml_encoding = 'utf-16le'
-            xml_data = unicode(xml_data, 'utf-16le').encode('utf-8')
-        elif (len(xml_data) >= 4) and (xml_data[:2] == '\xff\xfe') and (xml_data[2:4] != '\x00\x00'):
-            # UTF-16LE with BOM
-            sniffed_xml_encoding = 'utf-16le'
-            xml_data = unicode(xml_data[2:], 'utf-16le').encode('utf-8')
-        elif xml_data[:4] == '\x00\x00\x00\x3c':
-            # UTF-32BE
-            sniffed_xml_encoding = 'utf-32be'
-            xml_data = unicode(xml_data, 'utf-32be').encode('utf-8')
-        elif xml_data[:4] == '\x3c\x00\x00\x00':
-            # UTF-32LE
-            sniffed_xml_encoding = 'utf-32le'
-            xml_data = unicode(xml_data, 'utf-32le').encode('utf-8')
-        elif xml_data[:4] == '\x00\x00\xfe\xff':
-            # UTF-32BE with BOM
-            sniffed_xml_encoding = 'utf-32be'
-            xml_data = unicode(xml_data[4:], 'utf-32be').encode('utf-8')
-        elif xml_data[:4] == '\xff\xfe\x00\x00':
-            # UTF-32LE with BOM
-            sniffed_xml_encoding = 'utf-32le'
-            xml_data = unicode(xml_data[4:], 'utf-32le').encode('utf-8')
-        elif xml_data[:3] == '\xef\xbb\xbf':
-            # UTF-8 with BOM
-            sniffed_xml_encoding = 'utf-8'
-            xml_data = unicode(xml_data[3:], 'utf-8').encode('utf-8')
-        else:
-            # ASCII-compatible
-            pass
-        xml_encoding_match = re.compile('^<\?.*encoding=[\'"](.*?)[\'"].*\?>').match(xml_data)
-    except:
-        xml_encoding_match = None
-    if xml_encoding_match:
-        xml_encoding = xml_encoding_match.groups()[0].lower()
-        if sniffed_xml_encoding and (xml_encoding in ('iso-10646-ucs-2', 'ucs-2', 'csunicode', 'iso-10646-ucs-4', 'ucs-4', 'csucs4', 'utf-16', 'utf-32', 'utf_16', 'utf_32', 'utf16', 'u16')):
-            xml_encoding = sniffed_xml_encoding
-    acceptable_content_type = 0
-    application_content_types = ('application/xml', 'application/xml-dtd', 'application/xml-external-parsed-entity')
-    text_content_types = ('text/xml', 'text/xml-external-parsed-entity')
-    if (http_content_type in application_content_types) or \
-       (http_content_type.startswith('application/') and http_content_type.endswith('+xml')):
-        acceptable_content_type = 1
-        true_encoding = http_encoding or xml_encoding or 'utf-8'
-    elif (http_content_type in text_content_types) or \
-         (http_content_type.startswith('text/')) and http_content_type.endswith('+xml'):
-        acceptable_content_type = 1
-        true_encoding = http_encoding or 'us-ascii'
-    elif http_content_type.startswith('text/'):
-        true_encoding = http_encoding or 'us-ascii'
-    elif http_headers and (not http_headers.has_key('content-type')):
-        true_encoding = xml_encoding or 'iso-8859-1'
-    else:
-        true_encoding = xml_encoding or 'utf-8'
-    return true_encoding, http_encoding, xml_encoding, sniffed_xml_encoding, acceptable_content_type
-    
-def _toUTF8(data, encoding):
-    '''Changes an XML data stream on the fly to specify a new encoding
-
-    data is a raw sequence of bytes (not Unicode) that is presumed to be in %encoding already
-    encoding is a string recognized by encodings.aliases
-    '''
-    if _debug: sys.stderr.write('entering _toUTF8, trying encoding %s\n' % encoding)
-    # strip Byte Order Mark (if present)
-    if (len(data) >= 4) and (data[:2] == '\xfe\xff') and (data[2:4] != '\x00\x00'):
-        if _debug:
-            sys.stderr.write('stripping BOM\n')
-            if encoding != 'utf-16be':
-                sys.stderr.write('trying utf-16be instead\n')
-        encoding = 'utf-16be'
-        data = data[2:]
-    elif (len(data) >= 4) and (data[:2] == '\xff\xfe') and (data[2:4] != '\x00\x00'):
-        if _debug:
-            sys.stderr.write('stripping BOM\n')
-            if encoding != 'utf-16le':
-                sys.stderr.write('trying utf-16le instead\n')
-        encoding = 'utf-16le'
-        data = data[2:]
-    elif data[:3] == '\xef\xbb\xbf':
-        if _debug:
-            sys.stderr.write('stripping BOM\n')
-            if encoding != 'utf-8':
-                sys.stderr.write('trying utf-8 instead\n')
-        encoding = 'utf-8'
-        data = data[3:]
-    elif data[:4] == '\x00\x00\xfe\xff':
-        if _debug:
-            sys.stderr.write('stripping BOM\n')
-            if encoding != 'utf-32be':
-                sys.stderr.write('trying utf-32be instead\n')
-        encoding = 'utf-32be'
-        data = data[4:]
-    elif data[:4] == '\xff\xfe\x00\x00':
-        if _debug:
-            sys.stderr.write('stripping BOM\n')
-            if encoding != 'utf-32le':
-                sys.stderr.write('trying utf-32le instead\n')
-        encoding = 'utf-32le'
-        data = data[4:]
-    newdata = unicode(data, encoding)
-    if _debug: sys.stderr.write('successfully converted %s data to unicode\n' % encoding)
-    declmatch = re.compile('^<\?xml[^>]*?>')
-    newdecl = '''<?xml version='1.0' encoding='utf-8'?>'''
-    if declmatch.search(newdata):
-        newdata = declmatch.sub(newdecl, newdata)
-    else:
-        newdata = newdecl + u'\n' + newdata
-    return newdata.encode('utf-8')
-
-def _stripDoctype(data):
-    '''Strips DOCTYPE from XML document, returns (rss_version, stripped_data)
-
-    rss_version may be 'rss091n' or None
-    stripped_data is the same XML document, minus the DOCTYPE
-    '''
-    entity_pattern = re.compile(r'<!ENTITY([^>]*?)>', re.MULTILINE)
-    data = entity_pattern.sub('', data)
-    doctype_pattern = re.compile(r'<!DOCTYPE([^>]*?)>', re.MULTILINE)
-    doctype_results = doctype_pattern.findall(data)
-    doctype = doctype_results and doctype_results[0] or ''
-    if doctype.lower().count('netscape'):
-        version = 'rss091n'
-    else:
-        version = None
-    data = doctype_pattern.sub('', data)
-    return version, data
-    
-def parse(url_file_stream_or_string, etag=None, modified=None, agent=None, referrer=None, handlers=[]):
-    '''Parse a feed from a URL, file, stream, or string'''
-    result = FeedParserDict()
-    result['feed'] = FeedParserDict()
-    result['entries'] = []
-    if _XML_AVAILABLE:
-        result['bozo'] = 0
-    if type(handlers) == types.InstanceType:
-        handlers = [handlers]
-    try:
-        f = _open_resource(url_file_stream_or_string, etag, modified, agent, referrer, handlers)
-        data = f.read()
-    except Exception, e:
-        result['bozo'] = 1
-        result['bozo_exception'] = e
-        data = ''
-        f = None
-
-    # if feed is gzip-compressed, decompress it
-    if f and data and hasattr(f, 'headers'):
-        if gzip and f.headers.get('content-encoding', '') == 'gzip':
-            try:
-                data = gzip.GzipFile(fileobj=_StringIO(data)).read()
-            except Exception, e:
-                # Some feeds claim to be gzipped but they're not, so
-                # we get garbage.  Ideally, we should re-request the
-                # feed without the 'Accept-encoding: gzip' header,
-                # but we don't.
-                result['bozo'] = 1
-                result['bozo_exception'] = e
-                data = ''
-        elif zlib and f.headers.get('content-encoding', '') == 'deflate':
-            try:
-                data = zlib.decompress(data, -zlib.MAX_WBITS)
-            except Exception, e:
-                result['bozo'] = 1
-                result['bozo_exception'] = e
-                data = ''
-
-    # save HTTP headers
-    if hasattr(f, 'info'):
-        info = f.info()
-        result['etag'] = info.getheader('ETag')
-        last_modified = info.getheader('Last-Modified')
-        if last_modified:
-            result['modified'] = _parse_date(last_modified)
-    if hasattr(f, 'url'):
-        result['href'] = f.url
-        result['status'] = 200
-    if hasattr(f, 'status'):
-        result['status'] = f.status
-    if hasattr(f, 'headers'):
-        result['headers'] = f.headers.dict
-    if hasattr(f, 'close'):
-        f.close()
-
-    # there are four encodings to keep track of:
-    # - http_encoding is the encoding declared in the Content-Type HTTP header
-    # - xml_encoding is the encoding declared in the <?xml declaration
-    # - sniffed_encoding is the encoding sniffed from the first 4 bytes of the XML data
-    # - result['encoding'] is the actual encoding, as per RFC 3023 and a variety of other conflicting specifications
-    http_headers = result.get('headers', {})
-    result['encoding'], http_encoding, xml_encoding, sniffed_xml_encoding, acceptable_content_type = \
-        _getCharacterEncoding(http_headers, data)
-    if http_headers and (not acceptable_content_type):
-        if http_headers.has_key('content-type'):
-            bozo_message = '%s is not an XML media type' % http_headers['content-type']
-        else:
-            bozo_message = 'no Content-type specified'
-        result['bozo'] = 1
-        result['bozo_exception'] = NonXMLContentType(bozo_message)
-        
-    result['version'], data = _stripDoctype(data)
-
-    baseuri = http_headers.get('content-location', result.get('href'))
-    baselang = http_headers.get('content-language', None)
-
-    # if server sent 304, we're done
-    if result.get('status', 0) == 304:
-        result['version'] = ''
-        result['debug_message'] = 'The feed has not changed since you last checked, ' + \
-            'so the server sent no data.  This is a feature, not a bug!'
-        return result
-
-    # if there was a problem downloading, we're done
-    if not data:
-        return result
-
-    # determine character encoding
-    use_strict_parser = 0
-    known_encoding = 0
-    tried_encodings = []
-    # try: HTTP encoding, declared XML encoding, encoding sniffed from BOM
-    for proposed_encoding in (result['encoding'], xml_encoding, sniffed_xml_encoding):
-        if not proposed_encoding: continue
-        if proposed_encoding in tried_encodings: continue
-        tried_encodings.append(proposed_encoding)
-        try:
-            data = _toUTF8(data, proposed_encoding)
-            known_encoding = use_strict_parser = 1
-            break
-        except:
-            pass
-    # if no luck and we have auto-detection library, try that
-    if (not known_encoding) and chardet:
-        try:
-            proposed_encoding = chardet.detect(data)['encoding']
-            if proposed_encoding and (proposed_encoding not in tried_encodings):
-                tried_encodings.append(proposed_encoding)
-                data = _toUTF8(data, proposed_encoding)
-                known_encoding = use_strict_parser = 1
-        except:
-            pass
-    # if still no luck and we haven't tried utf-8 yet, try that
-    if (not known_encoding) and ('utf-8' not in tried_encodings):
-        try:
-            proposed_encoding = 'utf-8'
-            tried_encodings.append(proposed_encoding)
-            data = _toUTF8(data, proposed_encoding)
-            known_encoding = use_strict_parser = 1
-        except:
-            pass
-    # if still no luck and we haven't tried windows-1252 yet, try that
-    if (not known_encoding) and ('windows-1252' not in tried_encodings):
-        try:
-            proposed_encoding = 'windows-1252'
-            tried_encodings.append(proposed_encoding)
-            data = _toUTF8(data, proposed_encoding)
-            known_encoding = use_strict_parser = 1
-        except:
-            pass
-    # if still no luck, give up
-    if not known_encoding:
-        result['bozo'] = 1
-        result['bozo_exception'] = CharacterEncodingUnknown( \
-            'document encoding unknown, I tried ' + \
-            '%s, %s, utf-8, and windows-1252 but nothing worked' % \
-            (result['encoding'], xml_encoding))
-        result['encoding'] = ''
-    elif proposed_encoding != result['encoding']:
-        result['bozo'] = 1
-        result['bozo_exception'] = CharacterEncodingOverride( \
-            'documented declared as %s, but parsed as %s' % \
-            (result['encoding'], proposed_encoding))
-        result['encoding'] = proposed_encoding
-
-    if not _XML_AVAILABLE:
-        use_strict_parser = 0
-    if use_strict_parser:
-        # initialize the SAX parser
-        feedparser = _StrictFeedParser(baseuri, baselang, 'utf-8')
-        saxparser = xml.sax.make_parser(PREFERRED_XML_PARSERS)
-        saxparser.setFeature(xml.sax.handler.feature_namespaces, 1)
-        saxparser.setContentHandler(feedparser)
-        saxparser.setErrorHandler(feedparser)
-        source = xml.sax.xmlreader.InputSource()
-        source.setByteStream(_StringIO(data))
-        if hasattr(saxparser, '_ns_stack'):
-            # work around bug in built-in SAX parser (doesn't recognize xml: namespace)
-            # PyXML doesn't have this problem, and it doesn't have _ns_stack either
-            saxparser._ns_stack.append({'http://www.w3.org/XML/1998/namespace':'xml'})
-        try:
-            saxparser.parse(source)
-        except Exception, e:
-            if _debug:
-                import traceback
-                traceback.print_stack()
-                traceback.print_exc()
-                sys.stderr.write('xml parsing failed\n')
-            result['bozo'] = 1
-            result['bozo_exception'] = feedparser.exc or e
-            use_strict_parser = 0
-    if not use_strict_parser:
-        feedparser = _LooseFeedParser(baseuri, baselang, known_encoding and 'utf-8' or '')
-        feedparser.feed(data)
-    result['feed'] = feedparser.feeddata
-    result['entries'] = feedparser.entries
-    result['version'] = result['version'] or feedparser.version
-    result['namespaces'] = feedparser.namespacesInUse
-    return result
-
-if __name__ == '__main__':
-    if not sys.argv[1:]:
-        print __doc__
-        sys.exit(0)
-    else:
-        urls = sys.argv[1:]
-    zopeCompatibilityHack()
-    from pprint import pprint
-    for url in urls:
-        print url
-        print
-        result = parse(url)
-        pprint(result)
-        print
-
-#REVISION HISTORY
-#1.0 - 9/27/2002 - MAP - fixed namespace processing on prefixed RSS 2.0 elements,
-#  added Simon Fell's test suite
-#1.1 - 9/29/2002 - MAP - fixed infinite loop on incomplete CDATA sections
-#2.0 - 10/19/2002
-#  JD - use inchannel to watch out for image and textinput elements which can
-#  also contain title, link, and description elements
-#  JD - check for isPermaLink='false' attribute on guid elements
-#  JD - replaced openAnything with open_resource supporting ETag and
-#  If-Modified-Since request headers
-#  JD - parse now accepts etag, modified, agent, and referrer optional
-#  arguments
-#  JD - modified parse to return a dictionary instead of a tuple so that any
-#  etag or modified information can be returned and cached by the caller
-#2.0.1 - 10/21/2002 - MAP - changed parse() so that if we don't get anything
-#  because of etag/modified, return the old etag/modified to the caller to
-#  indicate why nothing is being returned
-#2.0.2 - 10/21/2002 - JB - added the inchannel to the if statement, otherwise its
-#  useless.  Fixes the problem JD was addressing by adding it.
-#2.1 - 11/14/2002 - MAP - added gzip support
-#2.2 - 1/27/2003 - MAP - added attribute support, admin:generatorAgent.
-#  start_admingeneratoragent is an example of how to handle elements with
-#  only attributes, no content.
-#2.3 - 6/11/2003 - MAP - added USER_AGENT for default (if caller doesn't specify);
-#  also, make sure we send the User-Agent even if urllib2 isn't available.
-#  Match any variation of backend.userland.com/rss namespace.
-#2.3.1 - 6/12/2003 - MAP - if item has both link and guid, return both as-is.
-#2.4 - 7/9/2003 - MAP - added preliminary Pie/Atom/Echo support based on Sam Ruby's
-#  snapshot of July 1 <http://www.intertwingly.net/blog/1506.html>; changed
-#  project name
-#2.5 - 7/25/2003 - MAP - changed to Python license (all contributors agree);
-#  removed unnecessary urllib code -- urllib2 should always be available anyway;
-#  return actual url, status, and full HTTP headers (as result['url'],
-#  result['status'], and result['headers']) if parsing a remote feed over HTTP --
-#  this should pass all the HTTP tests at <http://diveintomark.org/tests/client/http/>;
-#  added the latest namespace-of-the-week for RSS 2.0
-#2.5.1 - 7/26/2003 - RMK - clear opener.addheaders so we only send our custom
-#  User-Agent (otherwise urllib2 sends two, which confuses some servers)
-#2.5.2 - 7/28/2003 - MAP - entity-decode inline xml properly; added support for
-#  inline <xhtml:body> and <xhtml:div> as used in some RSS 2.0 feeds
-#2.5.3 - 8/6/2003 - TvdV - patch to track whether we're inside an image or
-#  textInput, and also to return the character encoding (if specified)
-#2.6 - 1/1/2004 - MAP - dc:author support (MarekK); fixed bug tracking
-#  nested divs within content (JohnD); fixed missing sys import (JohanS);
-#  fixed regular expression to capture XML character encoding (Andrei);
-#  added support for Atom 0.3-style links; fixed bug with textInput tracking;
-#  added support for cloud (MartijnP); added support for multiple
-#  category/dc:subject (MartijnP); normalize content model: 'description' gets
-#  description (which can come from description, summary, or full content if no
-#  description), 'content' gets dict of base/language/type/value (which can come
-#  from content:encoded, xhtml:body, content, or fullitem);
-#  fixed bug matching arbitrary Userland namespaces; added xml:base and xml:lang
-#  tracking; fixed bug tracking unknown tags; fixed bug tracking content when
-#  <content> element is not in default namespace (like Pocketsoap feed);
-#  resolve relative URLs in link, guid, docs, url, comments, wfw:comment,
-#  wfw:commentRSS; resolve relative URLs within embedded HTML markup in
-#  description, xhtml:body, content, content:encoded, title, subtitle,
-#  summary, info, tagline, and copyright; added support for pingback and
-#  trackback namespaces
-#2.7 - 1/5/2004 - MAP - really added support for trackback and pingback
-#  namespaces, as opposed to 2.6 when I said I did but didn't really;
-#  sanitize HTML markup within some elements; added mxTidy support (if
-#  installed) to tidy HTML markup within some elements; fixed indentation
-#  bug in _parse_date (FazalM); use socket.setdefaulttimeout if available
-#  (FazalM); universal date parsing and normalization (FazalM): 'created', modified',
-#  'issued' are parsed into 9-tuple date format and stored in 'created_parsed',
-#  'modified_parsed', and 'issued_parsed'; 'date' is duplicated in 'modified'
-#  and vice-versa; 'date_parsed' is duplicated in 'modified_parsed' and vice-versa
-#2.7.1 - 1/9/2004 - MAP - fixed bug handling &quot; and &apos;.  fixed memory
-#  leak not closing url opener (JohnD); added dc:publisher support (MarekK);
-#  added admin:errorReportsTo support (MarekK); Python 2.1 dict support (MarekK)
-#2.7.4 - 1/14/2004 - MAP - added workaround for improperly formed <br/> tags in
-#  encoded HTML (skadz); fixed unicode handling in normalize_attrs (ChrisL);
-#  fixed relative URI processing for guid (skadz); added ICBM support; added
-#  base64 support
-#2.7.5 - 1/15/2004 - MAP - added workaround for malformed DOCTYPE (seen on many
-#  blogspot.com sites); added _debug variable
-#2.7.6 - 1/16/2004 - MAP - fixed bug with StringIO importing
-#3.0b3 - 1/23/2004 - MAP - parse entire feed with real XML parser (if available);
-#  added several new supported namespaces; fixed bug tracking naked markup in
-#  description; added support for enclosure; added support for source; re-added
-#  support for cloud which got dropped somehow; added support for expirationDate
-#3.0b4 - 1/26/2004 - MAP - fixed xml:lang inheritance; fixed multiple bugs tracking
-#  xml:base URI, one for documents that don't define one explicitly and one for
-#  documents that define an outer and an inner xml:base that goes out of scope
-#  before the end of the document
-#3.0b5 - 1/26/2004 - MAP - fixed bug parsing multiple links at feed level
-#3.0b6 - 1/27/2004 - MAP - added feed type and version detection, result['version']
-#  will be one of SUPPORTED_VERSIONS.keys() or empty string if unrecognized;
-#  added support for creativeCommons:license and cc:license; added support for
-#  full Atom content model in title, tagline, info, copyright, summary; fixed bug
-#  with gzip encoding (not always telling server we support it when we do)
-#3.0b7 - 1/28/2004 - MAP - support Atom-style author element in author_detail
-#  (dictionary of 'name', 'url', 'email'); map author to author_detail if author
-#  contains name + email address
-#3.0b8 - 1/28/2004 - MAP - added support for contributor
-#3.0b9 - 1/29/2004 - MAP - fixed check for presence of dict function; added
-#  support for summary
-#3.0b10 - 1/31/2004 - MAP - incorporated ISO-8601 date parsing routines from
-#  xml.util.iso8601
-#3.0b11 - 2/2/2004 - MAP - added 'rights' to list of elements that can contain
-#  dangerous markup; fiddled with decodeEntities (not right); liberalized
-#  date parsing even further
-#3.0b12 - 2/6/2004 - MAP - fiddled with decodeEntities (still not right);
-#  added support to Atom 0.2 subtitle; added support for Atom content model
-#  in copyright; better sanitizing of dangerous HTML elements with end tags
-#  (script, frameset)
-#3.0b13 - 2/8/2004 - MAP - better handling of empty HTML tags (br, hr, img,
-#  etc.) in embedded markup, in either HTML or XHTML form (<br>, <br/>, <br />)
-#3.0b14 - 2/8/2004 - MAP - fixed CDATA handling in non-wellformed feeds under
-#  Python 2.1
-#3.0b15 - 2/11/2004 - MAP - fixed bug resolving relative links in wfw:commentRSS;
-#  fixed bug capturing author and contributor URL; fixed bug resolving relative
-#  links in author and contributor URL; fixed bug resolvin relative links in
-#  generator URL; added support for recognizing RSS 1.0; passed Simon Fell's
-#  namespace tests, and included them permanently in the test suite with his
-#  permission; fixed namespace handling under Python 2.1
-#3.0b16 - 2/12/2004 - MAP - fixed support for RSS 0.90 (broken in b15)
-#3.0b17 - 2/13/2004 - MAP - determine character encoding as per RFC 3023
-#3.0b18 - 2/17/2004 - MAP - always map description to summary_detail (Andrei);
-#  use libxml2 (if available)
-#3.0b19 - 3/15/2004 - MAP - fixed bug exploding author information when author
-#  name was in parentheses; removed ultra-problematic mxTidy support; patch to
-#  workaround crash in PyXML/expat when encountering invalid entities
-#  (MarkMoraes); support for textinput/textInput
-#3.0b20 - 4/7/2004 - MAP - added CDF support
-#3.0b21 - 4/14/2004 - MAP - added Hot RSS support
-#3.0b22 - 4/19/2004 - MAP - changed 'channel' to 'feed', 'item' to 'entries' in
-#  results dict; changed results dict to allow getting values with results.key
-#  as well as results[key]; work around embedded illformed HTML with half
-#  a DOCTYPE; work around malformed Content-Type header; if character encoding
-#  is wrong, try several common ones before falling back to regexes (if this
-#  works, bozo_exception is set to CharacterEncodingOverride); fixed character
-#  encoding issues in BaseHTMLProcessor by tracking encoding and converting
-#  from Unicode to raw strings before feeding data to sgmllib.SGMLParser;
-#  convert each value in results to Unicode (if possible), even if using
-#  regex-based parsing
-#3.0b23 - 4/21/2004 - MAP - fixed UnicodeDecodeError for feeds that contain
-#  high-bit characters in attributes in embedded HTML in description (thanks
-#  Thijs van de Vossen); moved guid, date, and date_parsed to mapped keys in
-#  FeedParserDict; tweaked FeedParserDict.has_key to return True if asking
-#  about a mapped key
-#3.0fc1 - 4/23/2004 - MAP - made results.entries[0].links[0] and
-#  results.entries[0].enclosures[0] into FeedParserDict; fixed typo that could
-#  cause the same encoding to be tried twice (even if it failed the first time);
-#  fixed DOCTYPE stripping when DOCTYPE contained entity declarations;
-#  better textinput and image tracking in illformed RSS 1.0 feeds
-#3.0fc2 - 5/10/2004 - MAP - added and passed Sam's amp tests; added and passed
-#  my blink tag tests
-#3.0fc3 - 6/18/2004 - MAP - fixed bug in _changeEncodingDeclaration that
-#  failed to parse utf-16 encoded feeds; made source into a FeedParserDict;
-#  duplicate admin:generatorAgent/@rdf:resource in generator_detail.url;
-#  added support for image; refactored parse() fallback logic to try other
-#  encodings if SAX parsing fails (previously it would only try other encodings
-#  if re-encoding failed); remove unichr madness in normalize_attrs now that
-#  we're properly tracking encoding in and out of BaseHTMLProcessor; set
-#  feed.language from root-level xml:lang; set entry.id from rdf:about;
-#  send Accept header
-#3.0 - 6/21/2004 - MAP - don't try iso-8859-1 (can't distinguish between
-#  iso-8859-1 and windows-1252 anyway, and most incorrectly marked feeds are
-#  windows-1252); fixed regression that could cause the same encoding to be
-#  tried twice (even if it failed the first time)
-#3.0.1 - 6/22/2004 - MAP - default to us-ascii for all text/* content types;
-#  recover from malformed content-type header parameter with no equals sign
-#  ('text/xml; charset:iso-8859-1')
-#3.1 - 6/28/2004 - MAP - added and passed tests for converting HTML entities
-#  to Unicode equivalents in illformed feeds (aaronsw); added and
-#  passed tests for converting character entities to Unicode equivalents
-#  in illformed feeds (aaronsw); test for valid parsers when setting
-#  XML_AVAILABLE; make version and encoding available when server returns
-#  a 304; add handlers parameter to pass arbitrary urllib2 handlers (like
-#  digest auth or proxy support); add code to parse username/password
-#  out of url and send as basic authentication; expose downloading-related
-#  exceptions in bozo_exception (aaronsw); added __contains__ method to
-#  FeedParserDict (aaronsw); added publisher_detail (aaronsw)
-#3.2 - 7/3/2004 - MAP - use cjkcodecs and iconv_codec if available; always
-#  convert feed to UTF-8 before passing to XML parser; completely revamped
-#  logic for determining character encoding and attempting XML parsing
-#  (much faster); increased default timeout to 20 seconds; test for presence
-#  of Location header on redirects; added tests for many alternate character
-#  encodings; support various EBCDIC encodings; support UTF-16BE and
-#  UTF16-LE with or without a BOM; support UTF-8 with a BOM; support
-#  UTF-32BE and UTF-32LE with or without a BOM; fixed crashing bug if no
-#  XML parsers are available; added support for 'Content-encoding: deflate';
-#  send blank 'Accept-encoding: ' header if neither gzip nor zlib modules
-#  are available
-#3.3 - 7/15/2004 - MAP - optimize EBCDIC to ASCII conversion; fix obscure
-#  problem tracking xml:base and xml:lang if element declares it, child
-#  doesn't, first grandchild redeclares it, and second grandchild doesn't;
-#  refactored date parsing; defined public registerDateHandler so callers
-#  can add support for additional date formats at runtime; added support
-#  for OnBlog, Nate, MSSQL, Greek, and Hungarian dates (ytrewq1); added
-#  zopeCompatibilityHack() which turns FeedParserDict into a regular
-#  dictionary, required for Zope compatibility, and also makes command-
-#  line debugging easier because pprint module formats real dictionaries
-#  better than dictionary-like objects; added NonXMLContentType exception,
-#  which is stored in bozo_exception when a feed is served with a non-XML
-#  media type such as 'text/plain'; respect Content-Language as default
-#  language if not xml:lang is present; cloud dict is now FeedParserDict;
-#  generator dict is now FeedParserDict; better tracking of xml:lang,
-#  including support for xml:lang='' to unset the current language;
-#  recognize RSS 1.0 feeds even when RSS 1.0 namespace is not the default
-#  namespace; don't overwrite final status on redirects (scenarios:
-#  redirecting to a URL that returns 304, redirecting to a URL that
-#  redirects to another URL with a different type of redirect); add
-#  support for HTTP 303 redirects
-#4.0 - MAP - support for relative URIs in xml:base attribute; fixed
-#  encoding issue with mxTidy (phopkins); preliminary support for RFC 3229;
-#  support for Atom 1.0; support for iTunes extensions; new 'tags' for
-#  categories/keywords/etc. as array of dict
-#  {'term': term, 'scheme': scheme, 'label': label} to match Atom 1.0
-#  terminology; parse RFC 822-style dates with no time; lots of other
-#  bug fixes
-#4.1 - MAP - removed socket timeout; added support for chardet library
diff --git a/lib/librarian b/lib/librarian
new file mode 160000 (submodule)
index 0000000..ae0e673
--- /dev/null
@@ -0,0 +1 @@
+Subproject commit ae0e673a17c3edcdca910fafb84eeff9dfe7b588
index 2ecf4cf..0e273f2 100644 (file)
@@ -7,27 +7,27 @@ import xml.sax
 
 class simpleHandler(xml.sax.ContentHandler):
     """A simple handler that provides us with indices of marked up content."""
-    def __init__(self):        
+    def __init__(self):
         self.elements = [] #this will contain a list of elements and their start/end indices
         self.open_elements = [] #this holds info on open elements while we wait for their close
         self.content = ""
 
-    def startElement(self,name,attrs):
-        if name=='foobar': return # we require an outer wrapper, which we promptly ignore.
+    def startElement(self, name, attrs):
+        if name == 'foobar': return # we require an outer wrapper, which we promptly ignore.
         self.open_elements.append({'name':name,
                                    'attrs':attrs.copy(),
                                    'start':len(self.content),
                                    })
 
     def endElement(self, name):
-        if name=='foobar': return # we require an outer wrapper, which we promptly ignore.
+        if name == 'foobar': return # we require an outer wrapper, which we promptly ignore.
         for i in range(len(self.open_elements)):
             e = self.open_elements[i]
-            if e['name']==name:
+            if e['name'] == name:
                 # append a  (start,end), name, attrs
                 self.elements.append(((e['start'], #start position
-                                       len(self.content)),# current (end) position
-                                      e['name'],e['attrs'])
+                                       len(self.content)), # current (end) position
+                                      e['name'], e['attrs'])
                                      )
                 del self.open_elements[i]
                 return
@@ -39,14 +39,14 @@ class simpleHandler(xml.sax.ContentHandler):
 class MarkupString(unicode):
     """A simple class for dealing with marked up strings. When we are sliced, we return
     valid marked up strings, preserving markup."""
-    def __init__(self, string):        
-        unicode.__init__(self, string)
+    def __init__(self, string):
+        unicode.__init__(self)
         self.handler = simpleHandler()
         xml.sax.parseString((u"<foobar>%s</foobar>" % string).encode('utf-8'), self.handler)
         self.raw = self.handler.content
 
     def __getitem__(self, n):
-        return self.__getslice__(n,n+1)
+        return self.__getslice__(n, n + 1)
 
     def __getslice__(self, s, e):
         # only include relevant elements
@@ -64,21 +64,21 @@ class MarkupString(unicode):
             name = el[1]
             attrs = el[2]
             # write our start tag <stag att="val"...>
-            stag = "<%s"%name
-            for k,v in attrs.items(): stag += " %s=%s"%(k,xml.sax.saxutils.quoteattr(v))
+            stag = "<%s" % name
+            for k, v in attrs.items(): stag += " %s=%s" % (k, xml.sax.saxutils.quoteattr(v))
             stag += ">"
-            etag = "</%s>"%name # simple end tag
+            etag = "</%s>" % name # simple end tag
             spos = pos[0]
             epos = pos[1]
-            if spos < s: spos=s
-            if epos > e: epos=e
+            if spos < s: spos = s
+            if epos > e: epos = e
             if epos != spos: # we don't care about tags that don't markup any text
-                if not starts.has_key(spos): starts[spos]=[]
+                if not starts.has_key(spos): starts[spos] = []
                 starts[spos].append(stag)
-                if not ends.has_key(epos): ends[epos]=[]
+                if not ends.has_key(epos): ends[epos] = []
                 ends[epos].append(etag)
         outbuf = "" # our actual output string
-        for pos in range(s,e): # we move through positions
+        for pos in range(s, e): # we move through positions
             char = self.raw[pos]
             if ends.has_key(pos):  # if there are endtags to insert...
                 for et in ends[pos]: outbuf += et
@@ -89,7 +89,7 @@ class MarkupString(unicode):
                 for st in mystarts: outbuf += st
             outbuf += char
         if ends.has_key(e):
-            for et in ends[e]: outbuf+= et
+            for et in ends[e]: outbuf += et
         return MarkupString(outbuf)
 
     def __len__(self):
index e7fa221..fe5c9e3 100644 (file)
@@ -5,7 +5,7 @@ from types import UnicodeType
 from django.template.defaultfilters import slugify
 
 # default unicode character mapping ( you may not see some chars, leave as is )
-char_map = {u'À': 'A', u'Á': 'A', u'Â': 'A', u'Ã': 'A', u'Ä': 'Ae', u'Å': 'A', u'Æ': 'A', u'Ā': 'A', u'Ą': 'A', u'Ă': 'A', u'Ç': 'C', u'Ć': 'C', u'Č': 'C', u'Ĉ': 'C', u'Ċ': 'C', u'Ď': 'D', u'Đ': 'D', u'È': 'E', u'É': 'E', u'Ê': 'E', u'Ë': 'E', u'Ē': 'E', u'Ę': 'E', u'Ě': 'E', u'Ĕ': 'E', u'Ė': 'E', u'Ĝ': 'G', u'Ğ': 'G', u'Ġ': 'G', u'Ģ': 'G', u'Ĥ': 'H', u'Ħ': 'H', u'Ì': 'I', u'Í': 'I', u'Î': 'I', u'Ï': 'I', u'Ī': 'I', u'Ĩ': 'I', u'Ĭ': 'I', u'Į': 'I', u'İ': 'I', u'IJ': 'IJ', u'Ĵ': 'J', u'Ķ': 'K', u'Ľ': 'K', u'Ĺ': 'K', u'Ļ': 'K', u'Ŀ': 'K', u'Ł': 'L', u'Ñ': 'N', u'Ń': 'N', u'Ň': 'N', u'Ņ': 'N', u'Ŋ': 'N', u'Ò': 'O', u'Ó': 'O', u'Ô': 'O', u'Õ': 'O', u'Ö': 'Oe', u'Ø': 'O', u'Ō': 'O', u'Ő': 'O', u'Ŏ': 'O', u'Œ': 'OE', u'Ŕ': 'R', u'Ř': 'R', u'Ŗ': 'R', u'Ś': 'S', u'Ş': 'S', u'Ŝ': 'S', u'Ș': 'S', u'Š': 'S', u'Ť': 'T', u'Ţ': 'T', u'Ŧ': 'T', u'Ț': 'T', u'Ù': 'U', u'Ú': 'U', u'Û': 'U', u'Ü': 'Ue', u'Ū': 'U', u'Ů': 'U', u'Ű': 'U', u'Ŭ': 'U', u'Ũ': 'U', u'Ų': 'U', u'Ŵ': 'W', u'Ŷ': 'Y', u'Ÿ': 'Y', u'Ý': 'Y', u'Ź': 'Z', u'Ż': 'Z', u'Ž': 'Z', u'à': 'a', u'á': 'a', u'â': 'a', u'ã': 'a', u'ä': 'ae', u'ā': 'a', u'ą': 'a', u'ă': 'a', u'å': 'a', u'æ': 'ae', u'ç': 'c', u'ć': 'c', u'č': 'c', u'ĉ': 'c', u'ċ': 'c', u'ď': 'd', u'đ': 'd', u'è': 'e', u'é': 'e', u'ê': 'e', u'ë': 'e', u'ē': 'e', u'ę': 'e', u'ě': 'e', u'ĕ': 'e', u'ė': 'e', u'ƒ': 'f', u'ĝ': 'g', u'ğ': 'g', u'ġ': 'g', u'ģ': 'g', u'ĥ': 'h', u'ħ': 'h', u'ì': 'i', u'í': 'i', u'î': 'i', u'ï': 'i', u'ī': 'i', u'ĩ': 'i', u'ĭ': 'i', u'į': 'i', u'ı': 'i', u'ij': 'ij', u'ĵ': 'j', u'ķ': 'k', u'ĸ': 'k', u'ł': 'l', u'ľ': 'l', u'ĺ': 'l', u'ļ': 'l', u'ŀ': 'l', u'ñ': 'n', u'ń': 'n', u'ň': 'n', u'ņ': 'n', u'ʼn': 'n', u'ŋ': 'n', u'ò': 'o', u'ó': 'o', u'ô': 'o', u'õ': 'o', u'ö': 'oe', u'ø': 'o', u'ō': 'o', u'ő': 'o', u'ŏ': 'o', u'œ': 'oe', u'ŕ': 'r', u'ř': 'r', u'ŗ': 'r', u'ś': 's', u'š': 's', u'ť': 't', u'ù': 'u', u'ú': 'u', u'û': 'u', u'ü': 'ue', u'ū': 'u', u'ů': 'u', u'ű': 'u', u'ŭ': 'u', u'ũ': 'u', u'ų': 'u', u'ŵ': 'w', u'ÿ': 'y', u'ý': 'y', u'ŷ': 'y', u'ż': 'z', u'ź': 'z', u'ž': 'z', u'ß': 'ss', u'ſ': 'ss', u'Α': 'A', u'Ά': 'A', u'Ἀ': 'A', u'Ἁ': 'A', u'Ἂ': 'A', u'Ἃ': 'A', u'Ἄ': 'A', u'Ἅ': 'A', u'Ἆ': 'A', u'Ἇ': 'A', u'ᾈ': 'A', u'ᾉ': 'A', u'ᾊ': 'A', u'ᾋ': 'A', u'ᾌ': 'A', u'ᾍ': 'A', u'ᾎ': 'A', u'ᾏ': 'A', u'Ᾰ': 'A', u'Ᾱ': 'A', u'Ὰ': 'A', u'Ά': 'A', u'ᾼ': 'A', u'Β': 'B', u'Γ': 'G', u'Δ': 'D', u'Ε': 'E', u'Έ': 'E', u'Ἐ': 'E', u'Ἑ': 'E', u'Ἒ': 'E', u'Ἓ': 'E', u'Ἔ': 'E', u'Ἕ': 'E', u'Έ': 'E', u'Ὲ': 'E', u'Ζ': 'Z', u'Η': 'I', u'Ή': 'I', u'Ἠ': 'I', u'Ἡ': 'I', u'Ἢ': 'I', u'Ἣ': 'I', u'Ἤ': 'I', u'Ἥ': 'I', u'Ἦ': 'I', u'Ἧ': 'I', u'ᾘ': 'I', u'ᾙ': 'I', u'ᾚ': 'I', u'ᾛ': 'I', u'ᾜ': 'I', u'ᾝ': 'I', u'ᾞ': 'I', u'ᾟ': 'I', u'Ὴ': 'I', u'Ή': 'I', u'ῌ': 'I', u'Θ': 'TH', u'Ι': 'I', u'Ί': 'I', u'Ϊ': 'I', u'Ἰ': 'I', u'Ἱ': 'I', u'Ἲ': 'I', u'Ἳ': 'I', u'Ἴ': 'I', u'Ἵ': 'I', u'Ἶ': 'I', u'Ἷ': 'I', u'Ῐ': 'I', u'Ῑ': 'I', u'Ὶ': 'I', u'Ί': 'I', u'Κ': 'K', u'Λ': 'L', u'Μ': 'M', u'Ν': 'N', u'Ξ': 'KS', u'Ο': 'O', u'Ό': 'O', u'Ὀ': 'O', u'Ὁ': 'O', u'Ὂ': 'O', u'Ὃ': 'O', u'Ὄ': 'O', u'Ὅ': 'O', u'Ὸ': 'O', u'Ό': 'O', u'Π': 'P', u'Ρ': 'R', u'Ῥ': 'R', u'Σ': 'S', u'Τ': 'T', u'Υ': 'Y', u'Ύ': 'Y', u'Ϋ': 'Y', u'Ὑ': 'Y', u'Ὓ': 'Y', u'Ὕ': 'Y', u'Ὗ': 'Y', u'Ῠ': 'Y', u'Ῡ': 'Y', u'Ὺ': 'Y', u'Ύ': 'Y', u'Φ': 'F', u'Χ': 'X', u'Ψ': 'PS', u'Ω': 'O', u'Ώ': 'O', u'Ὠ': 'O', u'Ὡ': 'O', u'Ὢ': 'O', u'Ὣ': 'O', u'Ὤ': 'O', u'Ὥ': 'O', u'Ὦ': 'O', u'Ὧ': 'O', u'ᾨ': 'O', u'ᾩ': 'O', u'ᾪ': 'O', u'ᾫ': 'O', u'ᾬ': 'O', u'ᾭ': 'O', u'ᾮ': 'O', u'ᾯ': 'O', u'Ὼ': 'O', u'Ώ': 'O', u'ῼ': 'O', u'α': 'a', u'ά': 'a', u'ἀ': 'a', u'ἁ': 'a', u'ἂ': 'a', u'ἃ': 'a', u'ἄ': 'a', u'ἅ': 'a', u'ἆ': 'a', u'ἇ': 'a', u'ᾀ': 'a', u'ᾁ': 'a', u'ᾂ': 'a', u'ᾃ': 'a', u'ᾄ': 'a', u'ᾅ': 'a', u'ᾆ': 'a', u'ᾇ': 'a', u'ὰ': 'a', u'ά': 'a', u'ᾰ': 'a', u'ᾱ': 'a', u'ᾲ': 'a', u'ᾳ': 'a', u'ᾴ': 'a', u'ᾶ': 'a', u'ᾷ': 'a', u'β': 'b', u'γ': 'g', u'δ': 'd', u'ε': 'e', u'έ': 'e', u'ἐ': 'e', u'ἑ': 'e', u'ἒ': 'e', u'ἓ': 'e', u'ἔ': 'e', u'ἕ': 'e', u'ὲ': 'e', u'έ': 'e', u'ζ': 'z', u'η': 'i', u'ή': 'i', u'ἠ': 'i', u'ἡ': 'i', u'ἢ': 'i', u'ἣ': 'i', u'ἤ': 'i', u'ἥ': 'i', u'ἦ': 'i', u'ἧ': 'i', u'ᾐ': 'i', u'ᾑ': 'i', u'ᾒ': 'i', u'ᾓ': 'i', u'ᾔ': 'i', u'ᾕ': 'i', u'ᾖ': 'i', u'ᾗ': 'i', u'ὴ': 'i', u'ή': 'i', u'ῂ': 'i', u'ῃ': 'i', u'ῄ': 'i', u'ῆ': 'i', u'ῇ': 'i', u'θ': 'th', u'ι': 'i', u'ί': 'i', u'ϊ': 'i', u'ΐ': 'i', u'ἰ': 'i', u'ἱ': 'i', u'ἲ': 'i', u'ἳ': 'i', u'ἴ': 'i', u'ἵ': 'i', u'ἶ': 'i', u'ἷ': 'i', u'ὶ': 'i', u'ί': 'i', u'ῐ': 'i', u'ῑ': 'i', u'ῒ': 'i', u'ΐ': 'i', u'ῖ': 'i', u'ῗ': 'i', u'κ': 'k', u'λ': 'l', u'μ': 'm', u'ν': 'n', u'ξ': 'ks', u'ο': 'o', u'ό': 'o', u'ὀ': 'o', u'ὁ': 'o', u'ὂ': 'o', u'ὃ': 'o', u'ὄ': 'o', u'ὅ': 'o', u'ὸ': 'o', u'ό': 'o', u'π': 'p', u'ρ': 'r', u'ῤ': 'r', u'ῥ': 'r', u'σ': 's', u'ς': 's', u'τ': 't', u'υ': 'y', u'ύ': 'y', u'ϋ': 'y', u'ΰ': 'y', u'ὐ': 'y', u'ὑ': 'y', u'ὒ': 'y', u'ὓ': 'y', u'ὔ': 'y', u'ὕ': 'y', u'ὖ': 'y', u'ὗ': 'y', u'ὺ': 'y', u'ύ': 'y', u'ῠ': 'y', u'ῡ': 'y', u'ῢ': 'y', u'ΰ': 'y', u'ῦ': 'y', u'ῧ': 'y', u'φ': 'f', u'χ': 'x', u'ψ': 'ps', u'ω': 'o', u'ώ': 'o', u'ὠ': 'o', u'ὡ': 'o', u'ὢ': 'o', u'ὣ': 'o', u'ὤ': 'o', u'ὥ': 'o', u'ὦ': 'o', u'ὧ': 'o', u'ᾠ': 'o', u'ᾡ': 'o', u'ᾢ': 'o', u'ᾣ': 'o', u'ᾤ': 'o', u'ᾥ': 'o', u'ᾦ': 'o', u'ᾧ': 'o', u'ὼ': 'o', u'ώ': 'o', u'ῲ': 'o', u'ῳ': 'o', u'ῴ': 'o', u'ῶ': 'o', u'ῷ': 'o', u'¨': '', u'΅': '', u'᾿': '', u'῾': '', u'῍': '', u'῝': '', u'῎': '', u'῞': '', u'῏': '', u'῟': '', u'῀': '', u'῁': '', u'΄': '', u'΅': '', u'`': '', u'῭': '', u'ͺ': '', u'᾽': '', u'А': 'A', u'Б': 'B', u'В': 'V', u'Г': 'G', u'Д': 'D', u'Е': 'E', u'Ё': 'E', u'Ж': 'ZH', u'З': 'Z', u'И': 'I', u'Й': 'I', u'К': 'K', u'Л': 'L', u'М': 'M', u'Н': 'N', u'О': 'O', u'П': 'P', u'Р': 'R', u'С': 'S', u'Т': 'T', u'У': 'U', u'Ф': 'F', u'Х': 'KH', u'Ц': 'TS', u'Ч': 'CH', u'Ш': 'SH', u'Щ': 'SHCH', u'Ы': 'Y', u'Э': 'E', u'Ю': 'YU', u'Я': 'YA', u'а': 'A', u'б': 'B', u'в': 'V', u'г': 'G', u'д': 'D', u'е': 'E', u'ё': 'E', u'ж': 'ZH', u'з': 'Z', u'и': 'I', u'й': 'I', u'к': 'K', u'л': 'L', u'м': 'M', u'н': 'N', u'о': 'O', u'п': 'P', u'р': 'R', u'с': 'S', u'т': 'T', u'у': 'U', u'ф': 'F', u'х': 'KH', u'ц': 'TS', u'ч': 'CH', u'ш': 'SH', u'щ': 'SHCH', u'ы': 'Y', u'э': 'E', u'ю': 'YU', u'я': 'YA', u'Ъ': '', u'ъ': '', u'Ь': '', u'ь': '', u'ð': 'd', u'Ð': 'D', u'þ': 'th', u'Þ': 'TH', 
+char_map = {u'À': 'A', u'Á': 'A', u'Â': 'A', u'Ã': 'A', u'Ä': 'Ae', u'Å': 'A', u'Æ': 'A', u'Ā': 'A', u'Ą': 'A', u'Ă': 'A', u'Ç': 'C', u'Ć': 'C', u'Č': 'C', u'Ĉ': 'C', u'Ċ': 'C', u'Ď': 'D', u'Đ': 'D', u'È': 'E', u'É': 'E', u'Ê': 'E', u'Ë': 'E', u'Ē': 'E', u'Ę': 'E', u'Ě': 'E', u'Ĕ': 'E', u'Ė': 'E', u'Ĝ': 'G', u'Ğ': 'G', u'Ġ': 'G', u'Ģ': 'G', u'Ĥ': 'H', u'Ħ': 'H', u'Ì': 'I', u'Í': 'I', u'Î': 'I', u'Ï': 'I', u'Ī': 'I', u'Ĩ': 'I', u'Ĭ': 'I', u'Į': 'I', u'İ': 'I', u'IJ': 'IJ', u'Ĵ': 'J', u'Ķ': 'K', u'Ľ': 'K', u'Ĺ': 'K', u'Ļ': 'K', u'Ŀ': 'K', u'Ł': 'L', u'Ñ': 'N', u'Ń': 'N', u'Ň': 'N', u'Ņ': 'N', u'Ŋ': 'N', u'Ò': 'O', u'Ó': 'O', u'Ô': 'O', u'Õ': 'O', u'Ö': 'Oe', u'Ø': 'O', u'Ō': 'O', u'Ő': 'O', u'Ŏ': 'O', u'Œ': 'OE', u'Ŕ': 'R', u'Ř': 'R', u'Ŗ': 'R', u'Ś': 'S', u'Ş': 'S', u'Ŝ': 'S', u'Ș': 'S', u'Š': 'S', u'Ť': 'T', u'Ţ': 'T', u'Ŧ': 'T', u'Ț': 'T', u'Ù': 'U', u'Ú': 'U', u'Û': 'U', u'Ü': 'Ue', u'Ū': 'U', u'Ů': 'U', u'Ű': 'U', u'Ŭ': 'U', u'Ũ': 'U', u'Ų': 'U', u'Ŵ': 'W', u'Ŷ': 'Y', u'Ÿ': 'Y', u'Ý': 'Y', u'Ź': 'Z', u'Ż': 'Z', u'Ž': 'Z', u'à': 'a', u'á': 'a', u'â': 'a', u'ã': 'a', u'ä': 'ae', u'ā': 'a', u'ą': 'a', u'ă': 'a', u'å': 'a', u'æ': 'ae', u'ç': 'c', u'ć': 'c', u'č': 'c', u'ĉ': 'c', u'ċ': 'c', u'ď': 'd', u'đ': 'd', u'è': 'e', u'é': 'e', u'ê': 'e', u'ë': 'e', u'ē': 'e', u'ę': 'e', u'ě': 'e', u'ĕ': 'e', u'ė': 'e', u'ƒ': 'f', u'ĝ': 'g', u'ğ': 'g', u'ġ': 'g', u'ģ': 'g', u'ĥ': 'h', u'ħ': 'h', u'ì': 'i', u'í': 'i', u'î': 'i', u'ï': 'i', u'ī': 'i', u'ĩ': 'i', u'ĭ': 'i', u'į': 'i', u'ı': 'i', u'ij': 'ij', u'ĵ': 'j', u'ķ': 'k', u'ĸ': 'k', u'ł': 'l', u'ľ': 'l', u'ĺ': 'l', u'ļ': 'l', u'ŀ': 'l', u'ñ': 'n', u'ń': 'n', u'ň': 'n', u'ņ': 'n', u'ʼn': 'n', u'ŋ': 'n', u'ò': 'o', u'ó': 'o', u'ô': 'o', u'õ': 'o', u'ö': 'oe', u'ø': 'o', u'ō': 'o', u'ő': 'o', u'ŏ': 'o', u'œ': 'oe', u'ŕ': 'r', u'ř': 'r', u'ŗ': 'r', u'ś': 's', u'š': 's', u'ť': 't', u'ù': 'u', u'ú': 'u', u'û': 'u', u'ü': 'ue', u'ū': 'u', u'ů': 'u', u'ű': 'u', u'ŭ': 'u', u'ũ': 'u', u'ų': 'u', u'ŵ': 'w', u'ÿ': 'y', u'ý': 'y', u'ŷ': 'y', u'ż': 'z', u'ź': 'z', u'ž': 'z', u'ß': 'ss', u'ſ': 'ss', u'Α': 'A', u'Ά': 'A', u'Ἀ': 'A', u'Ἁ': 'A', u'Ἂ': 'A', u'Ἃ': 'A', u'Ἄ': 'A', u'Ἅ': 'A', u'Ἆ': 'A', u'Ἇ': 'A', u'ᾈ': 'A', u'ᾉ': 'A', u'ᾊ': 'A', u'ᾋ': 'A', u'ᾌ': 'A', u'ᾍ': 'A', u'ᾎ': 'A', u'ᾏ': 'A', u'Ᾰ': 'A', u'Ᾱ': 'A', u'Ὰ': 'A', u'Ά': 'A', u'ᾼ': 'A', u'Β': 'B', u'Γ': 'G', u'Δ': 'D', u'Ε': 'E', u'Έ': 'E', u'Ἐ': 'E', u'Ἑ': 'E', u'Ἒ': 'E', u'Ἓ': 'E', u'Ἔ': 'E', u'Ἕ': 'E', u'Έ': 'E', u'Ὲ': 'E', u'Ζ': 'Z', u'Η': 'I', u'Ή': 'I', u'Ἠ': 'I', u'Ἡ': 'I', u'Ἢ': 'I', u'Ἣ': 'I', u'Ἤ': 'I', u'Ἥ': 'I', u'Ἦ': 'I', u'Ἧ': 'I', u'ᾘ': 'I', u'ᾙ': 'I', u'ᾚ': 'I', u'ᾛ': 'I', u'ᾜ': 'I', u'ᾝ': 'I', u'ᾞ': 'I', u'ᾟ': 'I', u'Ὴ': 'I', u'Ή': 'I', u'ῌ': 'I', u'Θ': 'TH', u'Ι': 'I', u'Ί': 'I', u'Ϊ': 'I', u'Ἰ': 'I', u'Ἱ': 'I', u'Ἲ': 'I', u'Ἳ': 'I', u'Ἴ': 'I', u'Ἵ': 'I', u'Ἶ': 'I', u'Ἷ': 'I', u'Ῐ': 'I', u'Ῑ': 'I', u'Ὶ': 'I', u'Ί': 'I', u'Κ': 'K', u'Λ': 'L', u'Μ': 'M', u'Ν': 'N', u'Ξ': 'KS', u'Ο': 'O', u'Ό': 'O', u'Ὀ': 'O', u'Ὁ': 'O', u'Ὂ': 'O', u'Ὃ': 'O', u'Ὄ': 'O', u'Ὅ': 'O', u'Ὸ': 'O', u'Ό': 'O', u'Π': 'P', u'Ρ': 'R', u'Ῥ': 'R', u'Σ': 'S', u'Τ': 'T', u'Υ': 'Y', u'Ύ': 'Y', u'Ϋ': 'Y', u'Ὑ': 'Y', u'Ὓ': 'Y', u'Ὕ': 'Y', u'Ὗ': 'Y', u'Ῠ': 'Y', u'Ῡ': 'Y', u'Ὺ': 'Y', u'Ύ': 'Y', u'Φ': 'F', u'Χ': 'X', u'Ψ': 'PS', u'Ω': 'O', u'Ώ': 'O', u'Ὠ': 'O', u'Ὡ': 'O', u'Ὢ': 'O', u'Ὣ': 'O', u'Ὤ': 'O', u'Ὥ': 'O', u'Ὦ': 'O', u'Ὧ': 'O', u'ᾨ': 'O', u'ᾩ': 'O', u'ᾪ': 'O', u'ᾫ': 'O', u'ᾬ': 'O', u'ᾭ': 'O', u'ᾮ': 'O', u'ᾯ': 'O', u'Ὼ': 'O', u'Ώ': 'O', u'ῼ': 'O', u'α': 'a', u'ά': 'a', u'ἀ': 'a', u'ἁ': 'a', u'ἂ': 'a', u'ἃ': 'a', u'ἄ': 'a', u'ἅ': 'a', u'ἆ': 'a', u'ἇ': 'a', u'ᾀ': 'a', u'ᾁ': 'a', u'ᾂ': 'a', u'ᾃ': 'a', u'ᾄ': 'a', u'ᾅ': 'a', u'ᾆ': 'a', u'ᾇ': 'a', u'ὰ': 'a', u'ά': 'a', u'ᾰ': 'a', u'ᾱ': 'a', u'ᾲ': 'a', u'ᾳ': 'a', u'ᾴ': 'a', u'ᾶ': 'a', u'ᾷ': 'a', u'β': 'b', u'γ': 'g', u'δ': 'd', u'ε': 'e', u'έ': 'e', u'ἐ': 'e', u'ἑ': 'e', u'ἒ': 'e', u'ἓ': 'e', u'ἔ': 'e', u'ἕ': 'e', u'ὲ': 'e', u'έ': 'e', u'ζ': 'z', u'η': 'i', u'ή': 'i', u'ἠ': 'i', u'ἡ': 'i', u'ἢ': 'i', u'ἣ': 'i', u'ἤ': 'i', u'ἥ': 'i', u'ἦ': 'i', u'ἧ': 'i', u'ᾐ': 'i', u'ᾑ': 'i', u'ᾒ': 'i', u'ᾓ': 'i', u'ᾔ': 'i', u'ᾕ': 'i', u'ᾖ': 'i', u'ᾗ': 'i', u'ὴ': 'i', u'ή': 'i', u'ῂ': 'i', u'ῃ': 'i', u'ῄ': 'i', u'ῆ': 'i', u'ῇ': 'i', u'θ': 'th', u'ι': 'i', u'ί': 'i', u'ϊ': 'i', u'ΐ': 'i', u'ἰ': 'i', u'ἱ': 'i', u'ἲ': 'i', u'ἳ': 'i', u'ἴ': 'i', u'ἵ': 'i', u'ἶ': 'i', u'ἷ': 'i', u'ὶ': 'i', u'ί': 'i', u'ῐ': 'i', u'ῑ': 'i', u'ῒ': 'i', u'ΐ': 'i', u'ῖ': 'i', u'ῗ': 'i', u'κ': 'k', u'λ': 'l', u'μ': 'm', u'ν': 'n', u'ξ': 'ks', u'ο': 'o', u'ό': 'o', u'ὀ': 'o', u'ὁ': 'o', u'ὂ': 'o', u'ὃ': 'o', u'ὄ': 'o', u'ὅ': 'o', u'ὸ': 'o', u'ό': 'o', u'π': 'p', u'ρ': 'r', u'ῤ': 'r', u'ῥ': 'r', u'σ': 's', u'ς': 's', u'τ': 't', u'υ': 'y', u'ύ': 'y', u'ϋ': 'y', u'ΰ': 'y', u'ὐ': 'y', u'ὑ': 'y', u'ὒ': 'y', u'ὓ': 'y', u'ὔ': 'y', u'ὕ': 'y', u'ὖ': 'y', u'ὗ': 'y', u'ὺ': 'y', u'ύ': 'y', u'ῠ': 'y', u'ῡ': 'y', u'ῢ': 'y', u'ΰ': 'y', u'ῦ': 'y', u'ῧ': 'y', u'φ': 'f', u'χ': 'x', u'ψ': 'ps', u'ω': 'o', u'ώ': 'o', u'ὠ': 'o', u'ὡ': 'o', u'ὢ': 'o', u'ὣ': 'o', u'ὤ': 'o', u'ὥ': 'o', u'ὦ': 'o', u'ὧ': 'o', u'ᾠ': 'o', u'ᾡ': 'o', u'ᾢ': 'o', u'ᾣ': 'o', u'ᾤ': 'o', u'ᾥ': 'o', u'ᾦ': 'o', u'ᾧ': 'o', u'ὼ': 'o', u'ώ': 'o', u'ῲ': 'o', u'ῳ': 'o', u'ῴ': 'o', u'ῶ': 'o', u'ῷ': 'o', u'¨': '', u'΅': '', u'᾿': '', u'῾': '', u'῍': '', u'῝': '', u'῎': '', u'῞': '', u'῏': '', u'῟': '', u'῀': '', u'῁': '', u'΄': '', u'΅': '', u'`': '', u'῭': '', u'ͺ': '', u'᾽': '', u'А': 'A', u'Б': 'B', u'В': 'V', u'Г': 'G', u'Д': 'D', u'Е': 'E', u'Ё': 'E', u'Ж': 'ZH', u'З': 'Z', u'И': 'I', u'Й': 'I', u'К': 'K', u'Л': 'L', u'М': 'M', u'Н': 'N', u'О': 'O', u'П': 'P', u'Р': 'R', u'С': 'S', u'Т': 'T', u'У': 'U', u'Ф': 'F', u'Х': 'KH', u'Ц': 'TS', u'Ч': 'CH', u'Ш': 'SH', u'Щ': 'SHCH', u'Ы': 'Y', u'Э': 'E', u'Ю': 'YU', u'Я': 'YA', u'а': 'A', u'б': 'B', u'в': 'V', u'г': 'G', u'д': 'D', u'е': 'E', u'ё': 'E', u'ж': 'ZH', u'з': 'Z', u'и': 'I', u'й': 'I', u'к': 'K', u'л': 'L', u'м': 'M', u'н': 'N', u'о': 'O', u'п': 'P', u'р': 'R', u'с': 'S', u'т': 'T', u'у': 'U', u'ф': 'F', u'х': 'KH', u'ц': 'TS', u'ч': 'CH', u'ш': 'SH', u'щ': 'SHCH', u'ы': 'Y', u'э': 'E', u'ю': 'YU', u'я': 'YA', u'Ъ': '', u'ъ': '', u'Ь': '', u'ь': '', u'ð': 'd', u'Ð': 'D', u'þ': 'th', u'Þ': 'TH',
             u'ა': 'a', u'ბ': 'b', u'გ': 'g', u'დ': 'd', u'ე': 'e', u'ვ': 'v', u'ზ': 'z', u'თ': 't', u'ი': 'i', u'კ': 'k', u'ლ': 'l', u'მ': 'm', u'ნ': 'n', u'ო': 'o', u'პ': 'p', u'ჟ': 'zh', u'რ': 'r', u'ს': 's', u'ტ': 't', u'უ': 'u', u'ფ': 'p', u'ქ': 'k', u'ღ': 'gh', u'ყ': 'q', u'შ': 'sh', u'ჩ': 'ch', u'ც': 'ts', u'ძ': 'dz', u'წ': 'ts', u'ჭ': 'ch', u'ხ': 'kh', u'ჯ': 'j', u'ჰ': 'h' }
 
 def replace_char(m):
@@ -14,43 +14,43 @@ def replace_char(m):
         return char_map[char]
     else:
         return char
-        
+
 def slughifi(value, do_slugify=True, overwrite_char_map={}):
     """
         High Fidelity slugify - slughifi.py, v 0.1
-        
+
         Examples :
-        
+
         >>> text = 'C\'est déjà l\'été.'
-        
+
         >>> slughifi(text)
         'cest-deja-lete'
-        
+
         >>> slughifi(text, overwrite_char_map={u'\'': '-',})
         'c-est-deja-l-ete'
-        
+
         >>> slughifi(text, do_slugify=False)
         "C'est deja l'ete."
-        
+
         # Normal slugify removes accented characters
         >>> slugify(text)
         'cest-dj-lt'
-        
+
     """
 
     # unicodification
     if type(value) != UnicodeType:
         value = unicode(value, 'utf-8', 'ignore')
-        
+
     # overwrite chararcter mapping
     char_map.update(overwrite_char_map)
 
     # try to replace chars
     value = re.sub('[^a-zA-Z0-9\\s\\-]{1}', replace_char, value)
-    
+
     # apply django default slugify
     if do_slugify:
         value = slugify(value)
-        
+
     return value.encode('ascii', 'ignore')
 
diff --git a/requirements-test.txt b/requirements-test.txt
new file mode 100644 (file)
index 0000000..f3c7e8e
--- /dev/null
@@ -0,0 +1 @@
+nose
index f2e3917..62485f3 100644 (file)
@@ -1,9 +1,22 @@
---find-links=http://stigma.nowoczesnapolska.org.pl/pypi/
 --find-links=http://www.pythonware.com/products/pil/
 
-Django==1.1.1
-librarian==1.2.6
-lxml==2.2.2
-Imaging==1.1.6
-mutagen==1.17
-MySQL-python>=1.2,<2.0
\ No newline at end of file
+# django
+Django>=1.1.1,<1.2
+South>=0.7 # migrations for django
+django-pagination>=1.0
+django-rosetta>=0.5.3
+django-maintenancemode>=0.9
+
+# Feedparser 
+Feedparser>=4.1
+
+# PIL 
+Imaging>=1.1.6
+mutagen>=1.17
+sorl-thumbnail>=3.2
+
+# home-brewed & dependencies
+lxml>=2.2.2
+# -e git+git://github.com/fnp/librarian.git@d43d87400dcc19851442#egg=librarian
+
+# MySQL-python>=1.2,<2.0
index 6114713..f798d69 100644 (file)
@@ -1,4 +1,8 @@
+#!/usr/bin/env python
 # -*- coding: utf-8 -*-
+# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
 from lxml import etree
 from slughifi import slughifi
 from django.core.management import setup_environ
@@ -13,13 +17,13 @@ doc = etree.parse('rodziny.xml')
 
 for element in doc.findall('//span'):
     themes = [s.strip() for s in element.text.split(',')]
-    
+
     element.text = u''
-    
+
     for theme in themes:
         try:
             Tag.objects.get(slug=slughifi(theme))
-        
+
             link = etree.SubElement(element, 'a', href=u'/katalog/%s' % slughifi(theme))
             link.text = theme
             link.tail = ', '
diff --git a/scripts/git-archive-all.sh b/scripts/git-archive-all.sh
new file mode 100755 (executable)
index 0000000..af97d96
--- /dev/null
@@ -0,0 +1,208 @@
+#!/bin/bash -
+#
+# File:        git-archive-all.sh
+#
+# Description: A utility script that builds an archive file(s) of all
+#              git repositories and submodules in the current path.
+#              Useful for creating a single tarfile of a git super-
+#              project that contains other submodules.
+#
+# Examples:    Use git-archive-all.sh to create archive distributions
+#              from git repositories. To use, simply do:
+#
+#                  cd $GIT_DIR; git-archive-all.sh
+#
+#              where $GIT_DIR is the root of your git superproject.
+#
+# License:     GPL3
+#
+###############################################################################
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+#
+###############################################################################
+
+# DEBUGGING
+set -e
+set -C # noclobber
+
+# TRAP SIGNALS
+trap 'cleanup' QUIT EXIT
+
+# For security reasons, explicitly set the internal field separator
+# to newline, space, tab
+OLD_IFS=$IFS
+IFS='
+       '
+
+function cleanup () {
+    rm -f $TMPFILE
+    rm -f $TOARCHIVE
+    IFS="$OLD_IFS"
+}
+
+function usage () {
+    echo "Usage is as follows:"
+    echo
+    echo "$PROGRAM <--version>"
+    echo "    Prints the program version number on a line by itself and exits."
+    echo
+    echo "$PROGRAM <--usage|--help|-?>"
+    echo "    Prints this usage output and exits."
+    echo
+    echo "$PROGRAM [--format <fmt>] [--prefix <path>] [--separate|-s] [output_file]"
+    echo "    Creates an archive for the entire git superproject, and its submodules"
+    echo "    using the passed parameters, described below."
+    echo
+    echo "    If '--format' is specified, the archive is created with the named"
+    echo "    git archiver backend. Obviously, this must be a backend that git-archive"
+    echo "    understands. The format defaults to 'tar' if not specified."
+    echo
+    echo "    If '--prefix' is specified, the archive's superproject and all submodules"
+    echo "    are created with the <path> prefix named. The default is to not use one."
+    echo
+    echo "    If '--separate' or '-s' is specified, individual archives will be created"
+    echo "    for each of the superproject itself and its submodules. The default is to"
+    echo "    concatenate individual archives into one larger archive."
+    echo
+    echo "    If 'output_file' is specified, the resulting archive is created as the"
+    echo "    file named. This parameter is essentially a path that must be writeable."
+    echo "    When combined with '--separate' ('-s') this path must refer to a directory."
+    echo "    Without this parameter or when combined with '--separate' the resulting"
+    echo "    archive(s) are named with a dot-separated path of the archived directory and"
+    echo "    a file extension equal to their format (e.g., 'superdir.submodule1dir.tar')."
+}
+
+function version () {
+    echo "$PROGRAM version $VERSION"
+}
+
+# Internal variables and initializations.
+readonly PROGRAM=`basename "$0"`
+readonly VERSION=0.2
+
+OLD_PWD="`pwd`"
+TMPDIR=${TMPDIR:-/tmp}
+TMPFILE=`mktemp "$TMPDIR/$PROGRAM.XXXXXX"` # Create a place to store our work's progress
+TOARCHIVE=`mktemp "$TMPDIR/$PROGRAM.toarchive.XXXXXX"`
+OUT_FILE=$OLD_PWD # assume "this directory" without a name change by default
+SEPARATE=0
+
+FORMAT=tar
+PREFIX=
+TREEISH=HEAD
+
+# RETURN VALUES/EXIT STATUS CODES
+readonly E_BAD_OPTION=254
+readonly E_UNKNOWN=255
+
+# Process command-line arguments.
+while test $# -gt 0; do
+    case $1 in
+        --format )
+            shift
+            FORMAT="$1"
+            shift
+            ;;
+
+        --prefix )
+            shift
+            PREFIX="$1"
+            shift
+            ;;
+
+        --separate | -s )
+            shift
+            SEPARATE=1
+            ;;
+
+        --version )
+            version
+            exit
+            ;;
+
+        -? | --usage | --help )
+            usage
+            exit
+            ;;
+
+        -* )
+            echo "Unrecognized option: $1" >&2
+            usage
+            exit $E_BAD_OPTION
+            ;;
+
+        * )
+            break
+            ;;
+    esac
+done
+
+if [ ! -z "$1" ]; then
+    OUT_FILE="$1"
+    shift
+fi
+
+# Validate parameters; error early, error often.
+if [ $SEPARATE -eq 1 -a ! -d $OUT_FILE ]; then
+    echo "When creating multiple archives, your destination must be a directory."
+    echo "If it's not, you risk being surprised when your files are overwritten."
+    exit
+elif [ `git config -l | grep -q '^core\.bare=false'; echo $?` -ne 0 ]; then
+    echo "$PROGRAM must be run from a git working copy (i.e., not a bare repository)."
+    exit
+fi
+
+# Create the superproject's git-archive
+git archive --format=$FORMAT --prefix="$PREFIX" $TREEISH > $TMPDIR/$(basename $(pwd)).$FORMAT
+echo $TMPDIR/$(basename $(pwd)).$FORMAT >| $TMPFILE # clobber on purpose
+superfile=`head -n 1 $TMPFILE`
+
+# find all '.git' dirs, these show us the remaining to-be-archived dirs
+find . -name '.git' -type d -print | sed -e 's/^\.\///' -e 's/\.git$//' | grep -v '^$' >> $TOARCHIVE
+
+while read path; do
+    TREEISH=$(git submodule | grep "^ .*${path%/} " | cut -d ' ' -f 2) # git-submodule does not list trailing slashes in $path
+    cd "$path"
+    git archive --format=$FORMAT --prefix="${PREFIX}$path" ${TREEISH:-HEAD} > "$TMPDIR"/"$(echo "$path" | sed -e 's/\//./g')"$FORMAT
+    if [ $FORMAT == 'zip' ]; then
+        # delete the empty directory entry; zipped submodules won't unzip if we don't do this
+        zip -d "$(tail -n 1 $TMPFILE)" "${PREFIX}${path%/}" >/dev/null # remove trailing '/'
+    fi
+    echo "$TMPDIR"/"$(echo "$path" | sed -e 's/\//./g')"$FORMAT >> $TMPFILE
+    cd "$OLD_PWD"
+done < $TOARCHIVE
+
+# Concatenate archives into a super-archive.
+if [ $SEPARATE -eq 0 ]; then
+    if [ $FORMAT == 'tar' ]; then
+        sed -e '1d' $TMPFILE | while read file; do
+            tar --concatenate -f "$superfile" "$file" && rm -f "$file"
+        done
+    elif [ $FORMAT == 'zip' ]; then
+        sed -e '1d' $TMPFILE | while read file; do
+            # zip incorrectly stores the full path, so cd and then grow
+            cd `dirname "$file"`
+            zip -g "$superfile" `basename "$file"` && rm -f "$file"
+        done
+        cd "$OLD_PWD"
+    fi
+
+    echo "$superfile" >| $TMPFILE # clobber on purpose
+fi
+
+while read file; do
+    mv "$file" "$OUT_FILE"
+done < $TMPFILE
index 671212d..0bc190e 100644 (file)
@@ -1,3 +1,8 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
 import sys
 sys.path.insert(0, '../apps')
 sys.path.insert(0, '../lib')
index 3ac4192..3268f45 100755 (executable)
@@ -1,5 +1,8 @@
 #!/usr/bin/env python
 # -*- coding: utf-8 -*-
+# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
 from django.core.management import setup_environ
 from wolnelektury import settings
 import sys
@@ -22,19 +25,19 @@ for file_name in os.listdir('mp3'):
     base_name, ext = splitext(file_name)
     if ext != '.mp3':
         continue
-    
+
     audio = easyid3.EasyID3(join('mp3', file_name))
     title = audio['title'][0]
     artist = title.split(',', 1)[0].strip()
     artist_slug = slughifi(artist)
     title_part = slughifi(title.rsplit(',', 1)[1].strip())
-    
+
     print "--------------------"
     print "File: %s" % file_name
     print "Title: %s" % title
     print
     print "Matching books:"
-    
+
     matching_books = [book for book in Book.tagged.with_all(artist_slug) if book.slug not in chosen_book_slugs]
     matching_books = [book for book in matching_books if title_part in book.slug]
 
@@ -48,11 +51,10 @@ for file_name in os.listdir('mp3'):
     else:
         print "Skipping %s: No matching book found" % file_name
         continue
-    
+
     print "You chose %d (%s)" % (i, matching_books[i].slug)
-    
+
     chosen_book_slugs.add(matching_books[i].slug)
     os.rename(join('mp3', file_name), join('new_mp3', matching_books[i].slug + '.mp3'))
     os.rename(join('oggvorbis', base_name + '.ogg'), join('new_ogg', matching_books[i].slug + '.ogg'))
-    
-    
\ No newline at end of file
+
index e72512b..bea5cda 100755 (executable)
@@ -1,4 +1,8 @@
 #!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
 import sys
 
 from django.core.management import setup_environ
index 245ed1d..3244243 100755 (executable)
@@ -1,5 +1,8 @@
 #!/usr/bin/env python
 # -*- coding: utf-8 -*-
+# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
 from django.core.management import setup_environ
 from wolnelektury import settings
 import sys
@@ -28,7 +31,7 @@ for tag in Tag.objects.all():
         tag.main_page = True
     else:
         tag.main_page = False
-    
+
     tag.save()
     sys.stderr.write('.')
 
index 41d3f3d..c53cfd3 100644 (file)
@@ -1,3 +1,8 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
 import httplib2
 from poster.encode import multipart_encode
 from poster.streaminghttp import register_openers
diff --git a/wolnelektury.vhost.tmpl b/wolnelektury.vhost.tmpl
new file mode 100644 (file)
index 0000000..6fac756
--- /dev/null
@@ -0,0 +1,23 @@
+<VirtualHost *:80>
+    ServerName $DOMAIN
+    ServerAdmin $ADMIN_EMAIL
+
+    WSGIDaemonProcess $PROJECT_NAME user=$WSGI_USER group=$WSGI_USER processes=$WSGI_PROCESSES threads=$WSGI_THREADS display-name=%{GROUP}
+    WSGIProcessGroup $PROJECT_NAME
+
+    WSGIScriptAlias / $WSGI_TARGET
+    <Directory $WSGI_DIR>
+        Order allow,deny
+        allow from all
+    </Directory>
+
+    Alias /media $MEDIA_ROOT
+    <Directory $MEDIA_ROOT >
+        Order allow,deny
+        Allow from all
+    </Directory>
+
+    LogLevel warn
+    ErrorLog /var/log/apache2/$PROJECT_NAME/error.log
+    CustomLog /var/log/apache2/$PROJECT_NAME/access.log combined
+</VirtualHost>
index 76e3903..5535819 100644 (file)
@@ -16,6 +16,7 @@ sys.path = [
        '%(path)s/releases/current',
        '%(path)s/releases/current/apps',
        '%(path)s/releases/current/lib',
+    '%(path)s/releases/current/lib/librarian',
 ] + sys.path
 
 # Run Django
diff --git a/wolnelektury.wsgi.tmpl b/wolnelektury.wsgi.tmpl
new file mode 100644 (file)
index 0000000..a27cbb4
--- /dev/null
@@ -0,0 +1,25 @@
+#!$PYTHON
+import site
+site.addsitedir('$PYTHON_SITE')
+
+import os
+from os.path import abspath, dirname, join
+import sys
+
+# Redirect sys.stdout to sys.stderr for bad libraries like geopy that use
+# print statements for optional import exceptions.
+sys.stdout = sys.stderr
+
+# Add apps and lib directories to PYTHONPATH
+sys.path = [
+    '$PROJECT_ROOT',
+       '$PROJECT_ROOT/lib',
+    '$PROJECT_ROOT/lib/librarian',
+       '$PROJECT_ROOT/apps',
+] + sys.path
+
+# Run Django
+os.environ['DJANGO_SETTINGS_MODULE'] = '$PROJECT_NAME.settings'
+
+from django.core.handlers.wsgi import WSGIHandler
+application = WSGIHandler()
diff --git a/wolnelektury/context_processors.py b/wolnelektury/context_processors.py
new file mode 100644 (file)
index 0000000..0cbf605
--- /dev/null
@@ -0,0 +1,6 @@
+
+def extra_settings(request):
+    from django.conf import settings
+    return {
+        'STATIC_URL': settings.STATIC_URL,
+    }
diff --git a/wolnelektury/locale/de/LC_MESSAGES/django.mo b/wolnelektury/locale/de/LC_MESSAGES/django.mo
new file mode 100644 (file)
index 0000000..147a86e
Binary files /dev/null and b/wolnelektury/locale/de/LC_MESSAGES/django.mo differ
diff --git a/wolnelektury/locale/de/LC_MESSAGES/django.po b/wolnelektury/locale/de/LC_MESSAGES/django.po
new file mode 100644 (file)
index 0000000..ea4e223
--- /dev/null
@@ -0,0 +1,797 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+# 
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-08-25 10:23+0000\n"
+"PO-Revision-Date: 2010-08-25 10:43\n"
+"Last-Translator: <radek.czajka@gmail.com>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Translated-Using: django-rosetta 0.5.6\n"
+
+#: templates/404.html:6 templates/404.html.py:15
+msgid "Page does not exist"
+msgstr "Die angeforderte Webseite existiert nicht"
+
+#: templates/404.html:17
+msgid "We are sorry, but this page does not exist. Please check if you entered correct address or go to "
+msgstr "Die gesuchte Seite existiert leider nicht mehr. Überprüfen Sie bitte, ob Sie sich bei der Eingabe der URL in die Adresszeile des Browsers vertippt haben oder gehen Sie zur Startseite"
+
+#: templates/404.html:17
+msgid "main page"
+msgstr "Startseite"
+
+#: templates/500.html:6 templates/500.html.py:54
+msgid "Server error"
+msgstr "Serverfehler"
+
+#: templates/500.html:55
+msgid "<p>The Wolnelektury.pl site is currently unavailable. Meanwhile, visit our <a href='http://nowoczesnapolska.org.pl'>blog</a>.</p> <p>Inform our <a href='mailto:fundacja@nowoczesnapolska.org.pl'>administrators</a> about the error.</p>"
+msgstr "<p> Wolnelektury.pl ist zurzeit nicht verfügbar. Besuchen Sie unsere Homepage <a href='http://nowoczesnapolska.org.pl'> Blog </ a>. </ P> Informieren Sie uns <a href = \"mailto: fundacja@nowoczesnapolska.org.pl\" > Administratoren </ a> über den Fehler. </ p>"
+
+#: templates/503.html:6 templates/503.html.py:54
+msgid "Service unavailable"
+msgstr "Service nicht verfügbar"
+
+#: templates/503.html:56
+msgid "The Wolnelektury.pl site is currently unavailable due to maintainance."
+msgstr "Wolnelektury.pl wegen Wartungsarbeiten momentan nicht verfügbar."
+
+#: templates/base.html:19
+msgid "Internet Explorer cannot display this site properly. Click here to read more..."
+msgstr "Diese Seite kann nicht richtig im Internet Explorer angezeigt werden. Klicken Sie hier, um mehr zu lesen..."
+
+#: templates/base.html:32
+msgid "Welcome"
+msgstr "Willkommen"
+
+#: templates/base.html:33
+msgid "Your shelves"
+msgstr "Deine Bücherregale"
+
+#: templates/base.html:35
+msgid "Administration"
+msgstr "Administration"
+
+#: templates/base.html:37 templates/base.html.py:41
+msgid "Report a bug"
+msgstr ""
+
+#: templates/base.html:38
+msgid "Logout"
+msgstr "Abmelden"
+
+#: templates/base.html:42 templates/base.html.py:88 templates/base.html:92
+#: templates/base.html.py:96 templates/auth/login.html:4
+#: templates/auth/login.html.py:7 templates/auth/login.html:12
+#: templates/auth/login.html.py:15
+msgid "Sign in"
+msgstr "Anmelden"
+
+#: templates/base.html:42 templates/base.html.py:88 templates/base.html:96
+#: templates/base.html.py:100 templates/auth/login.html:7
+#: templates/auth/login.html.py:21 templates/auth/login.html:23
+msgid "Register"
+msgstr "Registrieren"
+
+#: templates/base.html:69
+msgid ""
+"\n"
+"\t\t\t\tWolne Lektury is a project lead by <a href=\"http://nowoczesnapolska.org.pl/\">Modern Poland Foundation</a>.\n"
+"\t\t\t\tDigital reproductions are made by <a href=\"http://www.bn.org.pl/\">The National Library</a>, based on TNL resources.\n"
+"\t\t\t\tHosting <a href=\"http://eo.pl/\">EO Networks</a>.\n"
+"\t\t\t\t"
+msgstr ""
+"\n"
+"\t\t\t\tWolne Lektury ist ein Projekt, dass von <a href=\"http://nowoczesnapolska.org.pl/\">Stiftung Modernes Polen </a>.\n"
+"\t\t\t\tDigitale Reproduktion entwickelt von der <a href=\"http://www.bn.org.pl/\">Natonalbibliothek</a>, Exemplare aus dem Bücherbestand NB. \n"
+"\t\t\t\tHosting <a href=\"http://eo.pl/\">EO Networks</a>.\n"
+"\t\t\t\t"
+
+#: templates/base.html:76
+msgid ""
+"\n"
+"\t\t\t\tModern Poland Foundation, 00-514 Warsaw, ul. Marszałkowska 84/92 lok. 125, tel/fax: (22) 621-30-17\n"
+"                e-mail: <a href=\"mailto:fundacja@nowoczesnapolska.org.pl\">fundacja@nowoczesnapolska.org.pl</a>\n"
+"\t\t\t\t"
+msgstr ""
+"\n"
+"\t\t\t\t Stiftung Modernes Polen, 00-514 Warsaw, ul. Marszałkowska 84/92 lok. 125, tel/fax: (22) 621-30-17\n"
+"                e-mail: <a href=\"mailto:fundacja@nowoczesnapolska.org.pl\">fundacja@nowoczesnapolska.org.pl</a>\n"
+"\t\t\t\t"
+
+#: templates/base.html:85 templates/base.html.py:106 templates/base.html:112
+#: templates/catalogue/book_detail.html:146
+#: templates/catalogue/book_fragments.html:33
+#: templates/catalogue/book_stub_detail.html:31
+#: templates/catalogue/differentiate_tags.html:23
+#: templates/catalogue/search_multiple_hits.html:29
+#: templates/catalogue/search_no_hits.html:22
+#: templates/catalogue/search_too_short.html:19
+#: templates/catalogue/tagged_object_list.html:155
+msgid "Close"
+msgstr "Schliessen"
+
+#: templates/base.html:108 templates/base.html.py:114
+#: templates/catalogue/book_detail.html:148
+#: templates/catalogue/book_fragments.html:35
+#: templates/catalogue/book_stub_detail.html:33
+#: templates/catalogue/differentiate_tags.html:25
+#: templates/catalogue/search_multiple_hits.html:31
+#: templates/catalogue/search_no_hits.html:24
+#: templates/catalogue/search_too_short.html:21
+#: templates/catalogue/tagged_object_list.html:157
+msgid "Loading"
+msgstr "Herunterladen"
+
+#: templates/admin/base_site.html:4 templates/admin/base_site.html.py:7
+msgid "Site administration"
+msgstr "Webseite-Administration"
+
+#: templates/admin/base_site.html:8
+msgid "Translations"
+msgstr "Übersetzungen"
+
+#: templates/admin/catalogue/book/change_list.html:6
+msgid "Import book"
+msgstr "Buch importieren"
+
+#: templates/auth/login.html:4
+msgid "Register on"
+msgstr "Registrieren"
+
+#: templates/auth/login.html:9 templates/catalogue/book_detail.html:12
+#: templates/catalogue/book_fragments.html:12
+#: templates/catalogue/book_list.html:12
+#: templates/catalogue/book_stub_detail.html:12
+#: templates/catalogue/breadcrumbs.html:21
+#: templates/catalogue/main_page.html:13 templates/info/base.html:10
+#: templates/lessons/document_detail.html:9
+#: templates/lessons/document_list.html:51
+msgid "Search"
+msgstr "Suchen"
+
+#: templates/auth/login.html:9 templates/catalogue/book_detail.html:12
+#: templates/catalogue/book_fragments.html:12
+#: templates/catalogue/book_list.html:12
+#: templates/catalogue/book_stub_detail.html:12
+#: templates/catalogue/main_page.html:13
+#: templates/catalogue/tagged_object_list.html:43 templates/info/base.html:10
+#: templates/lessons/document_detail.html:9
+#: templates/lessons/document_list.html:51
+msgid "or"
+msgstr "oder"
+
+#: templates/auth/login.html:9 templates/catalogue/book_detail.html:12
+#: templates/catalogue/book_list.html:12
+#: templates/catalogue/book_stub_detail.html:12
+#: templates/lessons/document_list.html:51
+msgid "return to main page"
+msgstr "Zur Startseite wechseln"
+
+#: templates/catalogue/book_detail.html:5
+msgid "on WolneLektury.pl"
+msgstr "auf  WolneLektury.pl"
+
+#: templates/catalogue/book_detail.html:29
+msgid "Work is licensed under "
+msgstr "Das Werk ist unter der Lizenz zugänglich"
+
+#: templates/catalogue/book_detail.html:31
+msgid "Based on"
+msgstr "Basierend auf"
+
+#: templates/catalogue/book_detail.html:40
+msgid "Put a book"
+msgstr "Buch ablegen"
+
+#: templates/catalogue/book_detail.html:40
+msgid "on the shelf!"
+msgstr "aufs Regal!"
+
+#: templates/catalogue/book_detail.html:44
+msgid "Read online"
+msgstr "Online lesen"
+
+#: templates/catalogue/book_detail.html:47
+msgid "Download PDF"
+msgstr "PDF-Datei herunterladen"
+
+#: templates/catalogue/book_detail.html:50
+msgid "Download EPUB"
+msgstr "EPUB-Datei herunterladen"
+
+#: templates/catalogue/book_detail.html:53
+msgid "Download ODT"
+msgstr "ODT-Datei herunterladen"
+
+#: templates/catalogue/book_detail.html:56
+msgid "Download TXT"
+msgstr "TXT-Datei herunterladen"
+
+#: templates/catalogue/book_detail.html:61
+msgid "Artist"
+msgstr "Liest"
+
+#: templates/catalogue/book_detail.html:63
+msgid "Director"
+msgstr "Führt Regie"
+
+#: templates/catalogue/book_detail.html:67
+msgid "Download MP3"
+msgstr "MP3-Datei herunterladen"
+
+#: templates/catalogue/book_detail.html:68
+msgid "Download Ogg Vorbis"
+msgstr "Ogg Vorbis-Datei herunterladen"
+
+#: templates/catalogue/book_detail.html:95
+msgid "Details"
+msgstr "Details"
+
+#: templates/catalogue/book_detail.html:99
+msgid "Author"
+msgstr "Autor"
+
+#: templates/catalogue/book_detail.html:105
+msgid "Epoch"
+msgstr "Epoche"
+
+#: templates/catalogue/book_detail.html:111
+msgid "Kind"
+msgstr "Art"
+
+#: templates/catalogue/book_detail.html:117
+msgid "Genre"
+msgstr "Gattung"
+
+#: templates/catalogue/book_detail.html:123
+msgid "Other resources"
+msgstr "Andere Ressourcen"
+
+#: templates/catalogue/book_detail.html:125
+msgid "Book on project's wiki"
+msgstr "Schullektüre auf  WikiProjekt"
+
+#: templates/catalogue/book_detail.html:126
+msgid "Source of the book"
+msgstr "Buchquelle"
+
+#: templates/catalogue/book_detail.html:128
+msgid "Book description on Lektury.Gazeta.pl"
+msgstr "Buchbeschreibung unter Lektury.Gazeta.pl"
+
+#: templates/catalogue/book_detail.html:131
+msgid "Book description on Wikipedia"
+msgstr "Buchbeschreibung auf Wikipedia"
+
+#: templates/catalogue/book_detail.html:136
+msgid "Work's themes "
+msgstr "Werkmotive"
+
+#: templates/catalogue/book_fragments.html:5
+#: templates/catalogue/book_fragments.html:10
+msgid "Theme"
+msgstr "Motiv"
+
+#: templates/catalogue/book_fragments.html:5
+#: templates/catalogue/book_fragments.html:10
+msgid "in work "
+msgstr "im Werk"
+
+#: templates/catalogue/book_fragments.html:5
+msgid "on"
+msgstr "auf"
+
+#: templates/catalogue/book_fragments.html:12
+msgid "return to book's page"
+msgstr "Gehe auf die Buchseite zurück"
+
+#: templates/catalogue/book_fragments.html:26
+msgid "See description"
+msgstr "Beschreibung ansehen"
+
+#: templates/catalogue/book_fragments.html:26
+msgid "of the book "
+msgstr ""
+
+#: templates/catalogue/book_list.html:7
+msgid "Listing of all works on WolneLektury.pl"
+msgstr "Werkverzeichnis unter WolneLektury.pl"
+
+#: templates/catalogue/book_list.html:10
+msgid "Listing of all works"
+msgstr "Werkverzeichnis"
+
+#: templates/catalogue/book_sets.html:2
+msgid "Put a book on the shelf!"
+msgstr "Leg das Buch aufs Regal ab!"
+
+#: templates/catalogue/book_sets.html:3 templates/catalogue/book_sets.html:6
+#: templates/catalogue/fragment_sets.html:16
+msgid "Create new shelf"
+msgstr "Neues Bücherregal erstellen"
+
+#: templates/catalogue/book_sets.html:10
+msgid "You do not have any shelves. You can create one below, if you want to."
+msgstr "Keine neue Bücherregale vorhanden. Wenn du willst, kannst du ein neues Bücherregal erstellen."
+
+#: templates/catalogue/book_sets.html:15 templates/catalogue/book_short.html:4
+msgid "Put on the shelf!"
+msgstr "Leg aufs Regal ab!"
+
+#: templates/catalogue/book_short.html:14
+msgid "Jump to"
+msgstr "Überspringen"
+
+#: templates/catalogue/book_short.html:16
+msgid "Categories"
+msgstr "Kategorien"
+
+#: templates/catalogue/book_stub_detail.html:17
+msgid "This work is in public domain and will be published on Internet school library of Wolne Lektury soon."
+msgstr "Dieses Werk ist zur öffentlichen Nutzung vorgesehen und wird bald in der Internetbibliothek Wolne Lektury veröffentlicht sein."
+
+#: templates/catalogue/book_stub_detail.html:20
+msgid "This work will become part of public domain and will be allowed to be published without restrictions in"
+msgstr "Dieses Werk wird bald zur öffentlichen Nutzung freigestellt und kann in der Zukunft ohne weitere Einschränkungen veröffentlicht werden"
+
+#: templates/catalogue/book_stub_detail.html:22
+msgid "Find out why Internet libraries can't publish this work."
+msgstr "Finde heraus, warum Internet-Bibliotheken die Werke dieses Autors nicht veröffentlichen dürfen."
+
+#: templates/catalogue/book_stub_detail.html:24
+msgid "This work is copyrighted."
+msgstr "Dieses Werk ist urheberrechtlich geschützt."
+
+#: templates/catalogue/book_text.html:17
+msgid "Table of contents"
+msgstr "Inhalt"
+
+#: templates/catalogue/book_text.html:18
+#: templates/catalogue/tagged_object_list.html:146
+msgid "Themes"
+msgstr "Motive"
+
+#: templates/catalogue/differentiate_tags.html:13
+msgid "The criteria are ambiguous. Please select one of the following options:"
+msgstr ""
+
+#: templates/catalogue/folded_tag_list.html:4
+msgid "Show full category"
+msgstr "Alle Kategorien anzeigen"
+
+#: templates/catalogue/folded_tag_list.html:13
+#: templates/catalogue/main_page.html:43 templates/catalogue/main_page.html:48
+#: templates/catalogue/main_page.html:87
+#: templates/catalogue/main_page.html:270
+#: templates/catalogue/main_page.html:279
+msgid "See more"
+msgstr "mehr"
+
+#: templates/catalogue/folded_tag_list.html:22
+#: templates/catalogue/main_page.html:250
+msgid "Hide"
+msgstr "weniger"
+
+#: templates/catalogue/fragment_sets.html:2
+msgid "Shelves containing fragment"
+msgstr "Regale mit Buchauszügen"
+
+#: templates/catalogue/fragment_sets.html:4
+#: templates/catalogue/main_page.html:28
+msgid "You do not own any shelves. You can create one below, if you want to."
+msgstr "Keine neue Bücherregale vorhanden. Wenn du willst, kannst du ein neues Bücherregal erstellen."
+
+#: templates/catalogue/fragment_sets.html:9
+msgid "Save all shelves"
+msgstr "Alle Bücherregale speichern"
+
+#: templates/catalogue/fragment_short.html:7
+msgid "Expand fragment"
+msgstr "Buchauszug aufklappen"
+
+#: templates/catalogue/fragment_short.html:13
+msgid "Hide fragment"
+msgstr "Buchauszug zuklappen"
+
+#: templates/catalogue/fragment_short.html:18
+msgid "See in a book"
+msgstr "Werk ansehen"
+
+#: templates/catalogue/main_page.html:13
+msgid "check list of books"
+msgstr "Siehe Bücherliste"
+
+#: templates/catalogue/main_page.html:13
+msgid "in our repository"
+msgstr "in unserer Sammlung"
+
+#: templates/catalogue/main_page.html:17
+msgid "Browse books by categories"
+msgstr "Bücher nach ausgewählten Kategorien ansehen"
+
+#: templates/catalogue/main_page.html:19
+#: templates/catalogue/user_shelves.html:2
+msgid "Your shelves with books"
+msgstr "Deine Bücherregale"
+
+#: templates/catalogue/main_page.html:24
+msgid "delete"
+msgstr "löschen"
+
+#: templates/catalogue/main_page.html:33
+#: templates/catalogue/user_shelves.html:15
+msgid "Create shelf"
+msgstr "Bücherregal erstellen"
+
+#: templates/catalogue/main_page.html:37
+msgid "Create your own book set. You can share it with friends by sending them link to your shelf."
+msgstr "Erstelle dein eigenes Bücherregal. Du kannst es später mal mit deinen Freunden teilen, indem du den Link an sie verschickst."
+
+#: templates/catalogue/main_page.html:38
+msgid "You need to "
+msgstr "Um deine Bücherregale zu verwalten "
+
+#: templates/catalogue/main_page.html:38
+msgid "sign in"
+msgstr "musst du angemeldet  sein"
+
+#: templates/catalogue/main_page.html:38
+msgid "to manage your shelves."
+msgstr "Bücherregale verwalten"
+
+#: templates/catalogue/main_page.html:41
+#: templates/lessons/document_list.html:49
+msgid "Hand-outs for teachers"
+msgstr "Lehrmaterialien"
+
+#: templates/catalogue/main_page.html:42
+msgid "Lessons' prospects and other ideas for using Wolnelektury.pl for teaching."
+msgstr "Unterrichtsszenarien und andere Ideen für die Verwendung von Wolnelektury.pl für das Unterricht"
+
+#: templates/catalogue/main_page.html:47
+msgid "are professional recordings of literary texts from our repository, available on free license in MP3 and Ogg Vorbis formats as well as in DAISY system."
+msgstr "sind professionelle Aufnahmen literarischer Texte aus unserer Sammlung, die unter freier Lizenz in folgenden Formaten verfügbar sind: MP3-und Ogg-Vorbis-Formate sowie im DAISY-System."
+
+#: templates/catalogue/main_page.html:54
+#: templates/catalogue/tagged_object_list.html:128
+msgid "Authors"
+msgstr "Autoren"
+
+#: templates/catalogue/main_page.html:58
+#: templates/catalogue/tagged_object_list.html:132
+msgid "Kinds"
+msgstr "Arten"
+
+#: templates/catalogue/main_page.html:62
+#: templates/catalogue/tagged_object_list.html:136
+msgid "Genres"
+msgstr "Gattungen"
+
+#: templates/catalogue/main_page.html:66
+#: templates/catalogue/tagged_object_list.html:140
+msgid "Epochs"
+msgstr "Epochen"
+
+#: templates/catalogue/main_page.html:72
+msgid "Themes and topics"
+msgstr "Motive und Themen"
+
+#: templates/catalogue/main_page.html:75
+msgid "Themes groups"
+msgstr "Motivketten"
+
+#: templates/catalogue/main_page.html:260
+msgid "News"
+msgstr "News"
+
+#: templates/catalogue/main_page.html:264
+msgid "See our blog"
+msgstr "Siehe unseren Blog"
+
+#: templates/catalogue/main_page.html:267
+msgid "You can help us!"
+msgstr "Du kannst uns helfen!"
+
+#: templates/catalogue/main_page.html:268
+msgid "We try our best to elaborate works appended to our library. It is possible only due to support of our volunteers."
+msgstr "Wir sind stets bemüht, unseren Bibliothekbestand ständig um neue Werke zu erweitern. Dies ist nur dank der Hilfe unserer Volontäre möglich."
+
+#: templates/catalogue/main_page.html:269
+msgid "We invite people who want to take part in developing Internet school library Wolne Lektury."
+msgstr "Wir laden herzlich alle Personen ein, die sich an der Mitgestaltung unserer Internet-Schulbibliothek beteiligen wollen."
+
+#: templates/catalogue/main_page.html:273
+msgid "About us"
+msgstr "Über das Projekt"
+
+#: templates/catalogue/main_page.html:275
+msgid ""
+"\n"
+"\t\t\tInternet library with school readings “Wolne Lektury” (<a href=\"http://wolnelektury.pl\">www.wolnelektury.pl</a>) is a project made by Modern Poland Foundation. It started in 2007 and shares school readings, which are recommended by Ministry of National Education and are in public domain.\n"
+"\t\t\t"
+msgstr ""
+"\n"
+"\t\t\tSchulbücher “Wolne Lektury”  in der Internetbibliothek(<a href=\"http://wolnelektury.pl\">www.wolnelektury.pl</a>) ist ein Projekt, das von der Stiftung Modernes Polen gefördert wird. Die Stiftung ist seit 2007 tätig und hat bisher viele Schulbücher aus dem Bibliothekbestand zur öffentlichen Nutzung freigestellt. Die Schulbücher werden ausdrücklich vom Bildungsministerium empfohlen.\n"
+"\t\t\t"
+
+#: templates/catalogue/search_multiple_hits.html:5
+#: templates/catalogue/search_too_short.html:5
+msgid "Searching in"
+msgstr "Suchen in"
+
+#: templates/catalogue/search_multiple_hits.html:14
+msgid "More than one result matching the criteria found."
+msgstr "Es wurden mehrere Treffer in dieser Kategorie gefunden."
+
+#: templates/catalogue/search_no_hits.html:5
+msgid "Search in WolneLektury.pl"
+msgstr "Suche unter WolneLektury.pl"
+
+#: templates/catalogue/search_no_hits.html:14
+#: templates/catalogue/tagged_object_list.html:116
+msgid "Sorry! Search cirteria did not match any resources."
+msgstr "Sorry! Die Suche ergab leider keine Treffer."
+
+#: templates/catalogue/search_no_hits.html:16
+msgid ""
+"Search engine supports following criteria: title, author, theme/topic, epoch, kind and genre.\n"
+"\t\tAs for now we do not support full text search."
+msgstr ""
+"Die Suche kann nach folgenden Kriterien eingegrenzt werden: Titel, Autor, Motiv/Thema, Epoche, Literaturgattung und Gattungsart. \n"
+"\t\tDie Suche nach Text-Phrasen wird momentan nicht unterstützt."
+
+#: templates/catalogue/search_too_short.html:14
+msgid "Sorry! Search query must have at least two characters."
+msgstr "Ihre Suchanfrage muss mindestens 2 Zeichen enthalten."
+
+#: templates/catalogue/tag_list.html:4
+msgid "See full category"
+msgstr "Alle Kategorien ansehen"
+
+#: templates/catalogue/tagged_object_list.html:15
+msgid "Your shelf is empty"
+msgstr "Dein Bücherregal ist leer"
+
+#: templates/catalogue/tagged_object_list.html:16
+msgid "You can put a book on a shelf by entering page of the reading and clicking 'Put on the shelf'."
+msgstr "Du kannst das Buch aufs Regal ablegen, indem du \" aufs Regal!\" - Button anklickst."
+
+#: templates/catalogue/tagged_object_list.html:32
+msgid "Download all books from this shelf"
+msgstr "Alle Bücher aus diesem Regal herunterladen"
+
+#: templates/catalogue/tagged_object_list.html:36
+msgid "Choose books' formats which you want to download:"
+msgstr "Wähle Buchformate aus, die du herunterladen möchtest:"
+
+#: templates/catalogue/tagged_object_list.html:37
+#: templates/catalogue/tagged_object_list.html:39
+#: templates/catalogue/tagged_object_list.html:40
+msgid "for reading"
+msgstr "zum Lesen"
+
+#: templates/catalogue/tagged_object_list.html:37
+msgid "and printing using"
+msgstr "drucken mit"
+
+#: templates/catalogue/tagged_object_list.html:39
+msgid "and editing using"
+msgstr "bearbeiten mit"
+
+#: templates/catalogue/tagged_object_list.html:40
+msgid "on small displays, for example mobile phones"
+msgstr "auf kleines Display, z. B. Handy"
+
+#: templates/catalogue/tagged_object_list.html:41
+#: templates/catalogue/tagged_object_list.html:42
+msgid "for listening"
+msgstr "zum Hören"
+
+#: templates/catalogue/tagged_object_list.html:41
+msgid "on favourite MP3 player"
+msgstr "auf Lieblings-MP3-Player"
+
+#: templates/catalogue/tagged_object_list.html:42
+msgid "open format"
+msgstr "Format öffnen"
+
+#: templates/catalogue/tagged_object_list.html:42
+msgid "Xiph.org Foundation"
+msgstr "Xiph.org Stiftung"
+
+#: templates/catalogue/tagged_object_list.html:43
+#: templates/lessons/ajax_document_detail.html:3
+#: templates/lessons/document_detail.html:13
+msgid "Download"
+msgstr "Herunterladen"
+
+#: templates/catalogue/tagged_object_list.html:43
+msgid "Updating list of books' formats on the shelf"
+msgstr "Liste der Buchformate auf dem Regal aktualisieren"
+
+#: templates/catalogue/tagged_object_list.html:43
+msgid "cancel"
+msgstr "löschen"
+
+#: templates/catalogue/tagged_object_list.html:48
+msgid "Share this shelf"
+msgstr "Teile dieses Bücherregal"
+
+#: templates/catalogue/tagged_object_list.html:50
+msgid "Copy this link and share it with other people to let them see your shelf."
+msgstr "Kopiere diesen Link und verschicke an Personen, mit denen du dein Bücherregal teilen willst."
+
+#: templates/catalogue/tagged_object_list.html:60
+msgid "Read work's study of this author on Lektury.Gazeta.pl"
+msgstr "Lies Werkanalyse dieses Autors unter Lektury.Gazeta.pl"
+
+#: templates/catalogue/tagged_object_list.html:62
+#, fuzzy, python-format
+msgid "Read study of epoch %(last_tag)s on Lektury.Gazeta.pl"
+msgstr "Lies Werkanalyse dieses Autors unter Lektury.Gazeta.pl"
+
+#: templates/catalogue/tagged_object_list.html:64
+#, fuzzy, python-format
+msgid "Read study of kind %(last_tag)s on Lektury.Gazeta.pl"
+msgstr "Lies Werkanalyse dieses Autors unter Lektury.Gazeta.pl"
+
+#: templates/catalogue/tagged_object_list.html:66
+#, fuzzy, python-format
+msgid "Read study of genre %(last_tag)s on Lektury.Gazeta.pl"
+msgstr "Lies Werkanalyse dieses Autors unter Lektury.Gazeta.pl"
+
+#: templates/catalogue/tagged_object_list.html:68
+#, fuzzy
+msgid "Read related study on Lektury.Gazeta.pl"
+msgstr "Lies Werkanalyse dieses Autors unter Lektury.Gazeta.pl"
+
+#: templates/catalogue/tagged_object_list.html:76
+msgid "Read article about this author on Wikipedia"
+msgstr "Lies den Beitrag über diesen Autor auf Wikipedia"
+
+#: templates/catalogue/tagged_object_list.html:78
+#, fuzzy, python-format
+msgid "Read article about epoch %(last_tag)s on Wikipedia"
+msgstr "Lies den Beitrag über diesen Autor auf Wikipedia"
+
+#: templates/catalogue/tagged_object_list.html:80
+#, fuzzy, python-format
+msgid "Read article about kind %(last_tag)s on Wikipedia"
+msgstr "Lies den Beitrag über diesen Autor auf Wikipedia"
+
+#: templates/catalogue/tagged_object_list.html:82
+#, fuzzy, python-format
+msgid "Read article about genre %(last_tag)s on Wikipedia"
+msgstr "Lies den Beitrag über diesen Autor auf Wikipedia"
+
+#: templates/catalogue/tagged_object_list.html:84
+#, fuzzy
+msgid "Read related article on Wikipedia"
+msgstr "Lies den Beitrag über diesen Autor auf Wikipedia"
+
+#: templates/catalogue/tagged_object_list.html:94
+msgid "Delete"
+msgstr "Löschen"
+
+#: templates/catalogue/tagged_object_list.html:102
+msgid "This author's works are copyrighted."
+msgstr "Die Werke dieses Autors sind urheberrechtlich geschützt."
+
+#: templates/catalogue/tagged_object_list.html:105
+msgid "This author's works are in public domain and will be published on Internet school library of Wolne Lektury soon."
+msgstr "Dieses Werk ist zur öffentlichen Nutzung vorgesehen und wird bald in der Internetbibliothek Wolne Lektury veröffentlicht sein."
+
+#: templates/catalogue/tagged_object_list.html:109
+msgid "This author's works will become part of public domain and will be allowed to be published without restrictions in"
+msgstr "Die Werke dieses Autors werden bald zur öffentlichen Nutzung freigestellt und können in der Zukunft ohne weitere Einschränkungen veröffentlicht werden."
+
+#: templates/catalogue/tagged_object_list.html:111
+msgid "Find out why Internet libraries can't publish this author's works."
+msgstr "Finde heraus, warum Internet-Bibliotheken zu den Werken dieses Autors den Zugang verwähren."
+
+#: templates/catalogue/user_shelves.html:6
+msgid "remove"
+msgstr "löschen"
+
+#: templates/catalogue/user_shelves.html:10
+msgid "You do not own any shelves. You can create one below if you want to"
+msgstr "Keine neue Bücherregale vorhanden. Wenn du willst, kannst du ein neues Bücherregal erstellen."
+
+#: templates/info/base.html:10
+msgid "return to the main page"
+msgstr "zur Startseite wechseln"
+
+#: templates/info/join_us.html:2
+msgid ""
+"We have over 1000 works published in Wolne Lektury!\n"
+"Help us expand the library and set new readings free by\n"
+"making a donation or transferring 1% of your income tax."
+msgstr "Auf unserer Hompage Wolne Lektury wurden bereits etwa 1000 Werke veröffentlicht! Helfe uns bei der Mitgestaltung und Veröffentlichung neuer Schullektüren, indem du uns eine Spende in Höhe von 1% deiner Steuerabgaben übergibst."
+
+#: templates/info/join_us.html:5 templates/info/join_us.html.py:10
+msgid "More..."
+msgstr "Mehr..."
+
+#: templates/info/join_us.html:7
+msgid ""
+"Become an editor of Wolne Lektury! Find out if\n"
+"we're currently working on a reading you're looking for and prepare\n"
+"a publication by yourself by logging into the Editorial Platform."
+msgstr "Werde Redakteur/in bei  Wolne Lektury! Schau, ob wir gerade an der Veröffentlichung der Schullektüre arbeiten, die du ausgesucht hast. Um eigene Texte zu veröffentlichen, musst du vorher auf unserer redaktionellen Online-Plattform eingeloggt sein. "
+
+#: templates/lessons/ajax_document_detail.html:3
+#: templates/lessons/document_detail.html:13
+msgid "author"
+msgstr "Autor"
+
+#: templates/lessons/document_detail.html:9
+msgid "return to list of materials"
+msgstr "zurück zur Materialienliste"
+
+#: templates/lessons/document_list.html:7
+msgid "Hand-outs for teachers on "
+msgstr "Lehrmaterialien"
+
+#: templates/pagination/pagination.html:5
+#: templates/pagination/pagination.html:7
+msgid "previous"
+msgstr "zurück"
+
+#: templates/pagination/pagination.html:21
+#: templates/pagination/pagination.html:23
+msgid "next"
+msgstr "vor"
+
+#~ msgid "Polish"
+#~ msgstr "Polnisch"
+
+#~ msgid "German"
+#~ msgstr "Deutsch"
+
+#~ msgid "English"
+#~ msgstr "Englisch"
+
+#~ msgid "Lithuanian"
+#~ msgstr "Litauisch"
+
+#~ msgid "French"
+#~ msgstr "Französisch"
+
+#~ msgid "Russian"
+#~ msgstr "Russisch"
+
+#~ msgid "Spanish"
+#~ msgstr "Spanisch"
+
+#~ msgid "Ukrainian"
+#~ msgstr "Ukrainisch"
+
+#~ msgid "Choose your interface language: "
+#~ msgstr "Wählen Sie Ihre Sprache:"
+
+#~ msgid "Choose language"
+#~ msgstr "Sprache wählen"
+
+#~ msgid "Hide description"
+#~ msgstr "Beschreibung ausblenden"
+
+#~ msgid "Read study of epoch"
+#~ msgstr "Lies Epochenanalyse"
+
+#~ msgid "on Lektury.Gazeta.pl"
+#~ msgstr "unter Lektury.Gazeta.pl"
+
+#~ msgid "Read article about epoch"
+#~ msgstr "Lies den Beitrag aus dieser Epoche"
+
+#~ msgid "on Wikipedia"
+#~ msgstr "auf Wikipedia"
diff --git a/wolnelektury/locale/en/LC_MESSAGES/django.mo b/wolnelektury/locale/en/LC_MESSAGES/django.mo
new file mode 100644 (file)
index 0000000..bc4aa78
Binary files /dev/null and b/wolnelektury/locale/en/LC_MESSAGES/django.mo differ
diff --git a/wolnelektury/locale/en/LC_MESSAGES/django.po b/wolnelektury/locale/en/LC_MESSAGES/django.po
new file mode 100644 (file)
index 0000000..ac311e4
--- /dev/null
@@ -0,0 +1,774 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-08-25 10:23+0000\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: templates/404.html:6 templates/404.html.py:15
+msgid "Page does not exist"
+msgstr ""
+
+#: templates/404.html:17
+msgid ""
+"We are sorry, but this page does not exist. Please check if you entered "
+"correct address or go to "
+msgstr ""
+
+#: templates/404.html:17
+msgid "main page"
+msgstr ""
+
+#: templates/500.html:6 templates/500.html.py:54
+msgid "Server error"
+msgstr ""
+
+#: templates/500.html:55
+msgid ""
+"<p>The Wolnelektury.pl site is currently unavailable. Meanwhile, visit our "
+"<a href='http://nowoczesnapolska.org.pl'>blog</a>.</p> <p>Inform our <a "
+"href='mailto:fundacja@nowoczesnapolska.org.pl'>administrators</a> about the "
+"error.</p>"
+msgstr ""
+
+#: templates/503.html:6 templates/503.html.py:54
+msgid "Service unavailable"
+msgstr ""
+
+#: templates/503.html:56
+msgid "The Wolnelektury.pl site is currently unavailable due to maintainance."
+msgstr ""
+
+#: templates/base.html:19
+msgid ""
+"Internet Explorer cannot display this site properly. Click here to read "
+"more..."
+msgstr ""
+
+#: templates/base.html:32
+msgid "Welcome"
+msgstr ""
+
+#: templates/base.html:33
+msgid "Your shelves"
+msgstr ""
+
+#: templates/base.html:35
+msgid "Administration"
+msgstr ""
+
+#: templates/base.html:37 templates/base.html.py:41
+msgid "Report a bug"
+msgstr ""
+
+#: templates/base.html:38
+msgid "Logout"
+msgstr ""
+
+#: templates/base.html:42 templates/base.html.py:88 templates/base.html:92
+#: templates/base.html.py:96 templates/auth/login.html:4
+#: templates/auth/login.html.py:7 templates/auth/login.html:12
+#: templates/auth/login.html.py:15
+msgid "Sign in"
+msgstr ""
+
+#: templates/base.html:42 templates/base.html.py:88 templates/base.html:96
+#: templates/base.html.py:100 templates/auth/login.html:7
+#: templates/auth/login.html.py:21 templates/auth/login.html:23
+msgid "Register"
+msgstr ""
+
+#: templates/base.html:69
+msgid ""
+"\n"
+"\t\t\t\tWolne Lektury is a project lead by <a href=\"http://nowoczesnapolska."
+"org.pl/\">Modern Poland Foundation</a>.\n"
+"\t\t\t\tDigital reproductions are made by <a href=\"http://www.bn.org.pl/"
+"\">The National Library</a>, based on TNL resources.\n"
+"\t\t\t\tHosting <a href=\"http://eo.pl/\">EO Networks</a>.\n"
+"\t\t\t\t"
+msgstr ""
+
+#: templates/base.html:76
+msgid ""
+"\n"
+"\t\t\t\tModern Poland Foundation, 00-514 Warsaw, ul. Marszałkowska 84/92 "
+"lok. 125, tel/fax: (22) 621-30-17\n"
+"                e-mail: <a href=\"mailto:fundacja@nowoczesnapolska.org.pl"
+"\">fundacja@nowoczesnapolska.org.pl</a>\n"
+"\t\t\t\t"
+msgstr ""
+
+#: templates/base.html:85 templates/base.html.py:106 templates/base.html:112
+#: templates/catalogue/book_detail.html:146
+#: templates/catalogue/book_fragments.html:33
+#: templates/catalogue/book_stub_detail.html:31
+#: templates/catalogue/differentiate_tags.html:23
+#: templates/catalogue/search_multiple_hits.html:29
+#: templates/catalogue/search_no_hits.html:22
+#: templates/catalogue/search_too_short.html:19
+#: templates/catalogue/tagged_object_list.html:155
+msgid "Close"
+msgstr ""
+
+#: templates/base.html:108 templates/base.html.py:114
+#: templates/catalogue/book_detail.html:148
+#: templates/catalogue/book_fragments.html:35
+#: templates/catalogue/book_stub_detail.html:33
+#: templates/catalogue/differentiate_tags.html:25
+#: templates/catalogue/search_multiple_hits.html:31
+#: templates/catalogue/search_no_hits.html:24
+#: templates/catalogue/search_too_short.html:21
+#: templates/catalogue/tagged_object_list.html:157
+msgid "Loading"
+msgstr ""
+
+#: templates/admin/base_site.html:4 templates/admin/base_site.html.py:7
+msgid "Site administration"
+msgstr ""
+
+#: templates/admin/base_site.html:8
+msgid "Translations"
+msgstr ""
+
+#: templates/admin/catalogue/book/change_list.html:6
+msgid "Import book"
+msgstr ""
+
+#: templates/auth/login.html:4
+msgid "Register on"
+msgstr ""
+
+#: templates/auth/login.html:9 templates/catalogue/book_detail.html:12
+#: templates/catalogue/book_fragments.html:12
+#: templates/catalogue/book_list.html:12
+#: templates/catalogue/book_stub_detail.html:12
+#: templates/catalogue/breadcrumbs.html:21
+#: templates/catalogue/main_page.html:13 templates/info/base.html:10
+#: templates/lessons/document_detail.html:9
+#: templates/lessons/document_list.html:51
+msgid "Search"
+msgstr ""
+
+#: templates/auth/login.html:9 templates/catalogue/book_detail.html:12
+#: templates/catalogue/book_fragments.html:12
+#: templates/catalogue/book_list.html:12
+#: templates/catalogue/book_stub_detail.html:12
+#: templates/catalogue/main_page.html:13
+#: templates/catalogue/tagged_object_list.html:43 templates/info/base.html:10
+#: templates/lessons/document_detail.html:9
+#: templates/lessons/document_list.html:51
+msgid "or"
+msgstr ""
+
+#: templates/auth/login.html:9 templates/catalogue/book_detail.html:12
+#: templates/catalogue/book_list.html:12
+#: templates/catalogue/book_stub_detail.html:12
+#: templates/lessons/document_list.html:51
+msgid "return to main page"
+msgstr ""
+
+#: templates/catalogue/book_detail.html:5
+msgid "on WolneLektury.pl"
+msgstr ""
+
+#: templates/catalogue/book_detail.html:29
+msgid "Work is licensed under "
+msgstr ""
+
+#: templates/catalogue/book_detail.html:31
+msgid "Based on"
+msgstr ""
+
+#: templates/catalogue/book_detail.html:40
+msgid "Put a book"
+msgstr ""
+
+#: templates/catalogue/book_detail.html:40
+msgid "on the shelf!"
+msgstr ""
+
+#: templates/catalogue/book_detail.html:44
+msgid "Read online"
+msgstr ""
+
+#: templates/catalogue/book_detail.html:47
+msgid "Download PDF"
+msgstr ""
+
+#: templates/catalogue/book_detail.html:50
+msgid "Download EPUB"
+msgstr ""
+
+#: templates/catalogue/book_detail.html:53
+msgid "Download ODT"
+msgstr ""
+
+#: templates/catalogue/book_detail.html:56
+msgid "Download TXT"
+msgstr ""
+
+#: templates/catalogue/book_detail.html:61
+msgid "Artist"
+msgstr ""
+
+#: templates/catalogue/book_detail.html:63
+msgid "Director"
+msgstr ""
+
+#: templates/catalogue/book_detail.html:67
+msgid "Download MP3"
+msgstr ""
+
+#: templates/catalogue/book_detail.html:68
+msgid "Download Ogg Vorbis"
+msgstr ""
+
+#: templates/catalogue/book_detail.html:95
+msgid "Details"
+msgstr ""
+
+#: templates/catalogue/book_detail.html:99
+msgid "Author"
+msgstr ""
+
+#: templates/catalogue/book_detail.html:105
+msgid "Epoch"
+msgstr ""
+
+#: templates/catalogue/book_detail.html:111
+msgid "Kind"
+msgstr ""
+
+#: templates/catalogue/book_detail.html:117
+msgid "Genre"
+msgstr ""
+
+#: templates/catalogue/book_detail.html:123
+msgid "Other resources"
+msgstr ""
+
+#: templates/catalogue/book_detail.html:125
+msgid "Book on project's wiki"
+msgstr ""
+
+#: templates/catalogue/book_detail.html:126
+msgid "Source of the book"
+msgstr ""
+
+#: templates/catalogue/book_detail.html:128
+msgid "Book description on Lektury.Gazeta.pl"
+msgstr ""
+
+#: templates/catalogue/book_detail.html:131
+msgid "Book description on Wikipedia"
+msgstr ""
+
+#: templates/catalogue/book_detail.html:136
+msgid "Work's themes "
+msgstr ""
+
+#: templates/catalogue/book_fragments.html:5
+#: templates/catalogue/book_fragments.html:10
+msgid "Theme"
+msgstr ""
+
+#: templates/catalogue/book_fragments.html:5
+#: templates/catalogue/book_fragments.html:10
+msgid "in work "
+msgstr ""
+
+#: templates/catalogue/book_fragments.html:5
+msgid "on"
+msgstr ""
+
+#: templates/catalogue/book_fragments.html:12
+msgid "return to book's page"
+msgstr ""
+
+#: templates/catalogue/book_fragments.html:26
+msgid "See description"
+msgstr ""
+
+#: templates/catalogue/book_fragments.html:26
+msgid "of the book "
+msgstr ""
+
+#: templates/catalogue/book_list.html:7
+msgid "Listing of all works on WolneLektury.pl"
+msgstr ""
+
+#: templates/catalogue/book_list.html:10
+msgid "Listing of all works"
+msgstr ""
+
+#: templates/catalogue/book_sets.html:2
+msgid "Put a book on the shelf!"
+msgstr ""
+
+#: templates/catalogue/book_sets.html:3 templates/catalogue/book_sets.html:6
+#: templates/catalogue/fragment_sets.html:16
+msgid "Create new shelf"
+msgstr ""
+
+#: templates/catalogue/book_sets.html:10
+msgid "You do not have any shelves. You can create one below, if you want to."
+msgstr ""
+
+#: templates/catalogue/book_sets.html:15 templates/catalogue/book_short.html:4
+msgid "Put on the shelf!"
+msgstr ""
+
+#: templates/catalogue/book_short.html:14
+msgid "Jump to"
+msgstr ""
+
+#: templates/catalogue/book_short.html:16
+msgid "Categories"
+msgstr ""
+
+#: templates/catalogue/book_stub_detail.html:17
+msgid ""
+"This work is in public domain and will be published on Internet school "
+"library of Wolne Lektury soon."
+msgstr ""
+
+#: templates/catalogue/book_stub_detail.html:20
+msgid ""
+"This work will become part of public domain and will be allowed to be "
+"published without restrictions in"
+msgstr ""
+
+#: templates/catalogue/book_stub_detail.html:22
+msgid "Find out why Internet libraries can't publish this work."
+msgstr ""
+
+#: templates/catalogue/book_stub_detail.html:24
+msgid "This work is copyrighted."
+msgstr ""
+
+#: templates/catalogue/book_text.html:17
+msgid "Table of contents"
+msgstr ""
+
+#: templates/catalogue/book_text.html:18
+#: templates/catalogue/tagged_object_list.html:146
+msgid "Themes"
+msgstr ""
+
+#: templates/catalogue/differentiate_tags.html:13
+msgid "The criteria are ambiguous. Please select one of the following options:"
+msgstr ""
+
+#: templates/catalogue/folded_tag_list.html:4
+msgid "Show full category"
+msgstr ""
+
+#: templates/catalogue/folded_tag_list.html:13
+#: templates/catalogue/main_page.html:43 templates/catalogue/main_page.html:48
+#: templates/catalogue/main_page.html:87
+#: templates/catalogue/main_page.html:270
+#: templates/catalogue/main_page.html:279
+msgid "See more"
+msgstr ""
+
+#: templates/catalogue/folded_tag_list.html:22
+#: templates/catalogue/main_page.html:250
+msgid "Hide"
+msgstr ""
+
+#: templates/catalogue/fragment_sets.html:2
+msgid "Shelves containing fragment"
+msgstr ""
+
+#: templates/catalogue/fragment_sets.html:4
+#: templates/catalogue/main_page.html:28
+msgid "You do not own any shelves. You can create one below, if you want to."
+msgstr ""
+
+#: templates/catalogue/fragment_sets.html:9
+msgid "Save all shelves"
+msgstr ""
+
+#: templates/catalogue/fragment_short.html:7
+msgid "Expand fragment"
+msgstr ""
+
+#: templates/catalogue/fragment_short.html:13
+msgid "Hide fragment"
+msgstr ""
+
+#: templates/catalogue/fragment_short.html:18
+msgid "See in a book"
+msgstr ""
+
+#: templates/catalogue/main_page.html:13
+msgid "check list of books"
+msgstr ""
+
+#: templates/catalogue/main_page.html:13
+msgid "in our repository"
+msgstr ""
+
+#: templates/catalogue/main_page.html:17
+msgid "Browse books by categories"
+msgstr ""
+
+#: templates/catalogue/main_page.html:19
+#: templates/catalogue/user_shelves.html:2
+msgid "Your shelves with books"
+msgstr ""
+
+#: templates/catalogue/main_page.html:24
+msgid "delete"
+msgstr ""
+
+#: templates/catalogue/main_page.html:33
+#: templates/catalogue/user_shelves.html:15
+msgid "Create shelf"
+msgstr ""
+
+#: templates/catalogue/main_page.html:37
+msgid ""
+"Create your own book set. You can share it with friends by sending them link "
+"to your shelf."
+msgstr ""
+
+#: templates/catalogue/main_page.html:38
+msgid "You need to "
+msgstr ""
+
+#: templates/catalogue/main_page.html:38
+msgid "sign in"
+msgstr ""
+
+#: templates/catalogue/main_page.html:38
+msgid "to manage your shelves."
+msgstr ""
+
+#: templates/catalogue/main_page.html:41
+#: templates/lessons/document_list.html:49
+msgid "Hand-outs for teachers"
+msgstr ""
+
+#: templates/catalogue/main_page.html:42
+msgid ""
+"Lessons' prospects and other ideas for using Wolnelektury.pl for teaching."
+msgstr ""
+
+#: templates/catalogue/main_page.html:47
+msgid ""
+"are professional recordings of literary texts from our repository, available "
+"on free license in MP3 and Ogg Vorbis formats as well as in DAISY system."
+msgstr ""
+
+#: templates/catalogue/main_page.html:54
+#: templates/catalogue/tagged_object_list.html:128
+msgid "Authors"
+msgstr ""
+
+#: templates/catalogue/main_page.html:58
+#: templates/catalogue/tagged_object_list.html:132
+msgid "Kinds"
+msgstr ""
+
+#: templates/catalogue/main_page.html:62
+#: templates/catalogue/tagged_object_list.html:136
+msgid "Genres"
+msgstr ""
+
+#: templates/catalogue/main_page.html:66
+#: templates/catalogue/tagged_object_list.html:140
+msgid "Epochs"
+msgstr ""
+
+#: templates/catalogue/main_page.html:72
+msgid "Themes and topics"
+msgstr ""
+
+#: templates/catalogue/main_page.html:75
+msgid "Themes groups"
+msgstr ""
+
+#: templates/catalogue/main_page.html:260
+msgid "News"
+msgstr ""
+
+#: templates/catalogue/main_page.html:264
+msgid "See our blog"
+msgstr ""
+
+#: templates/catalogue/main_page.html:267
+msgid "You can help us!"
+msgstr ""
+
+#: templates/catalogue/main_page.html:268
+msgid ""
+"We try our best to elaborate works appended to our library. It is possible "
+"only due to support of our volunteers."
+msgstr ""
+
+#: templates/catalogue/main_page.html:269
+msgid ""
+"We invite people who want to take part in developing Internet school library "
+"Wolne Lektury."
+msgstr ""
+
+#: templates/catalogue/main_page.html:273
+msgid "About us"
+msgstr ""
+
+#: templates/catalogue/main_page.html:275
+msgid ""
+"\n"
+"\t\t\tInternet library with school readings “Wolne Lektury” (<a href="
+"\"http://wolnelektury.pl\">www.wolnelektury.pl</a>) is a project made by "
+"Modern Poland Foundation. It started in 2007 and shares school readings, "
+"which are recommended by Ministry of National Education and are in public "
+"domain.\n"
+"\t\t\t"
+msgstr ""
+
+#: templates/catalogue/search_multiple_hits.html:5
+#: templates/catalogue/search_too_short.html:5
+msgid "Searching in"
+msgstr ""
+
+#: templates/catalogue/search_multiple_hits.html:14
+msgid "More than one result matching the criteria found."
+msgstr ""
+
+#: templates/catalogue/search_no_hits.html:5
+msgid "Search in WolneLektury.pl"
+msgstr ""
+
+#: templates/catalogue/search_no_hits.html:14
+#: templates/catalogue/tagged_object_list.html:116
+msgid "Sorry! Search cirteria did not match any resources."
+msgstr ""
+
+#: templates/catalogue/search_no_hits.html:16
+msgid ""
+"Search engine supports following criteria: title, author, theme/topic, "
+"epoch, kind and genre.\n"
+"\t\tAs for now we do not support full text search."
+msgstr ""
+
+#: templates/catalogue/search_too_short.html:14
+msgid "Sorry! Search query must have at least two characters."
+msgstr ""
+
+#: templates/catalogue/tag_list.html:4
+msgid "See full category"
+msgstr ""
+
+#: templates/catalogue/tagged_object_list.html:15
+msgid "Your shelf is empty"
+msgstr ""
+
+#: templates/catalogue/tagged_object_list.html:16
+msgid ""
+"You can put a book on a shelf by entering page of the reading and clicking "
+"'Put on the shelf'."
+msgstr ""
+
+#: templates/catalogue/tagged_object_list.html:32
+msgid "Download all books from this shelf"
+msgstr ""
+
+#: templates/catalogue/tagged_object_list.html:36
+msgid "Choose books' formats which you want to download:"
+msgstr ""
+
+#: templates/catalogue/tagged_object_list.html:37
+#: templates/catalogue/tagged_object_list.html:39
+#: templates/catalogue/tagged_object_list.html:40
+msgid "for reading"
+msgstr ""
+
+#: templates/catalogue/tagged_object_list.html:37
+msgid "and printing using"
+msgstr ""
+
+#: templates/catalogue/tagged_object_list.html:39
+msgid "and editing using"
+msgstr ""
+
+#: templates/catalogue/tagged_object_list.html:40
+msgid "on small displays, for example mobile phones"
+msgstr ""
+
+#: templates/catalogue/tagged_object_list.html:41
+#: templates/catalogue/tagged_object_list.html:42
+msgid "for listening"
+msgstr ""
+
+#: templates/catalogue/tagged_object_list.html:41
+msgid "on favourite MP3 player"
+msgstr ""
+
+#: templates/catalogue/tagged_object_list.html:42
+msgid "open format"
+msgstr ""
+
+#: templates/catalogue/tagged_object_list.html:42
+msgid "Xiph.org Foundation"
+msgstr ""
+
+#: templates/catalogue/tagged_object_list.html:43
+#: templates/lessons/ajax_document_detail.html:3
+#: templates/lessons/document_detail.html:13
+msgid "Download"
+msgstr ""
+
+#: templates/catalogue/tagged_object_list.html:43
+msgid "Updating list of books' formats on the shelf"
+msgstr ""
+
+#: templates/catalogue/tagged_object_list.html:43
+msgid "cancel"
+msgstr ""
+
+#: templates/catalogue/tagged_object_list.html:48
+msgid "Share this shelf"
+msgstr ""
+
+#: templates/catalogue/tagged_object_list.html:50
+msgid ""
+"Copy this link and share it with other people to let them see your shelf."
+msgstr ""
+
+#: templates/catalogue/tagged_object_list.html:60
+msgid "Read work's study of this author on Lektury.Gazeta.pl"
+msgstr ""
+
+#: templates/catalogue/tagged_object_list.html:62
+#, python-format
+msgid "Read study of epoch %(last_tag)s on Lektury.Gazeta.pl"
+msgstr ""
+
+#: templates/catalogue/tagged_object_list.html:64
+#, python-format
+msgid "Read study of kind %(last_tag)s on Lektury.Gazeta.pl"
+msgstr ""
+
+#: templates/catalogue/tagged_object_list.html:66
+#, python-format
+msgid "Read study of genre %(last_tag)s on Lektury.Gazeta.pl"
+msgstr ""
+
+#: templates/catalogue/tagged_object_list.html:68
+msgid "Read related study on Lektury.Gazeta.pl"
+msgstr ""
+
+#: templates/catalogue/tagged_object_list.html:76
+msgid "Read article about this author on Wikipedia"
+msgstr ""
+
+#: templates/catalogue/tagged_object_list.html:78
+#, python-format
+msgid "Read article about epoch %(last_tag)s on Wikipedia"
+msgstr ""
+
+#: templates/catalogue/tagged_object_list.html:80
+#, python-format
+msgid "Read article about kind %(last_tag)s on Wikipedia"
+msgstr ""
+
+#: templates/catalogue/tagged_object_list.html:82
+#, python-format
+msgid "Read article about genre %(last_tag)s on Wikipedia"
+msgstr ""
+
+#: templates/catalogue/tagged_object_list.html:84
+msgid "Read related article on Wikipedia"
+msgstr ""
+
+#: templates/catalogue/tagged_object_list.html:94
+msgid "Delete"
+msgstr ""
+
+#: templates/catalogue/tagged_object_list.html:102
+msgid "This author's works are copyrighted."
+msgstr ""
+
+#: templates/catalogue/tagged_object_list.html:105
+msgid ""
+"This author's works are in public domain and will be published on Internet "
+"school library of Wolne Lektury soon."
+msgstr ""
+
+#: templates/catalogue/tagged_object_list.html:109
+msgid ""
+"This author's works will become part of public domain and will be allowed to "
+"be published without restrictions in"
+msgstr ""
+
+#: templates/catalogue/tagged_object_list.html:111
+msgid "Find out why Internet libraries can't publish this author's works."
+msgstr ""
+
+#: templates/catalogue/user_shelves.html:6
+msgid "remove"
+msgstr ""
+
+#: templates/catalogue/user_shelves.html:10
+msgid "You do not own any shelves. You can create one below if you want to"
+msgstr ""
+
+#: templates/info/base.html:10
+msgid "return to the main page"
+msgstr ""
+
+#: templates/info/join_us.html:2
+#, python-format
+msgid ""
+"We have over 1000 works published in Wolne Lektury!\n"
+"Help us expand the library and set new readings free by\n"
+"making a donation or transferring 1% of your income tax."
+msgstr ""
+
+#: templates/info/join_us.html:5 templates/info/join_us.html.py:10
+msgid "More..."
+msgstr ""
+
+#: templates/info/join_us.html:7
+msgid ""
+"Become an editor of Wolne Lektury! Find out if\n"
+"we're currently working on a reading you're looking for and prepare\n"
+"a publication by yourself by logging into the Editorial Platform."
+msgstr ""
+
+#: templates/lessons/ajax_document_detail.html:3
+#: templates/lessons/document_detail.html:13
+msgid "author"
+msgstr ""
+
+#: templates/lessons/document_detail.html:9
+msgid "return to list of materials"
+msgstr ""
+
+#: templates/lessons/document_list.html:7
+msgid "Hand-outs for teachers on "
+msgstr ""
+
+#: templates/pagination/pagination.html:5
+#: templates/pagination/pagination.html:7
+msgid "previous"
+msgstr ""
+
+#: templates/pagination/pagination.html:21
+#: templates/pagination/pagination.html:23
+msgid "next"
+msgstr ""
diff --git a/wolnelektury/locale/es/LC_MESSAGES/django.mo b/wolnelektury/locale/es/LC_MESSAGES/django.mo
new file mode 100644 (file)
index 0000000..be4d3ec
Binary files /dev/null and b/wolnelektury/locale/es/LC_MESSAGES/django.mo differ
diff --git a/wolnelektury/locale/es/LC_MESSAGES/django.po b/wolnelektury/locale/es/LC_MESSAGES/django.po
new file mode 100644 (file)
index 0000000..4b8669b
--- /dev/null
@@ -0,0 +1,803 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+# 
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-08-25 10:24+0000\n"
+"PO-Revision-Date: 2010-08-25 10:49\n"
+"Last-Translator: <radek.czajka@gmail.com>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Translated-Using: django-rosetta 0.5.6\n"
+
+#: templates/404.html:6 templates/404.html.py:15
+msgid "Page does not exist"
+msgstr "Página no existe"
+
+#: templates/404.html:17
+msgid "We are sorry, but this page does not exist. Please check if you entered correct address or go to "
+msgstr "Lo sentimos, esta página no existe. Comprueba si la dirección es correcta o ve a la"
+
+#: templates/404.html:17
+msgid "main page"
+msgstr "página principal"
+
+#: templates/500.html:6 templates/500.html.py:54
+msgid "Server error"
+msgstr "Error del servidor"
+
+#: templates/500.html:55
+msgid "<p>The Wolnelektury.pl site is currently unavailable. Meanwhile, visit our <a href='http://nowoczesnapolska.org.pl'>blog</a>.</p> <p>Inform our <a href='mailto:fundacja@nowoczesnapolska.org.pl'>administrators</a> about the error.</p>"
+msgstr "<p>La página Wolnelektury.pl actualmente no está disponible. Mientras tanto visita nuestro <a href='http://nowoczesnapolska.org.pl'>blog</a>.</p> <p>Informa a nuestros <a href='mailto:fundacja@nowoczesnapolska.org.pl'>administradores</a> sobre el error.</p>"
+
+#: templates/503.html:6 templates/503.html.py:54
+msgid "Service unavailable"
+msgstr "Servicio no está disponible"
+
+#: templates/503.html:56
+msgid "The Wolnelektury.pl site is currently unavailable due to maintainance."
+msgstr "La página Wolnelektury.pl no está disponible debido al mantenimiento."
+
+#: templates/base.html:19
+msgid "Internet Explorer cannot display this site properly. Click here to read more..."
+msgstr "Internet Explorer no puede mostrar esta página correctamente. Haz clic aquí para saber más..."
+
+#: templates/base.html:32
+msgid "Welcome"
+msgstr "Bienvenido(a)"
+
+#: templates/base.html:33
+msgid "Your shelves"
+msgstr "Tus estantes"
+
+#: templates/base.html:35
+msgid "Administration"
+msgstr "Administración"
+
+#: templates/base.html:37 templates/base.html.py:41
+msgid "Report a bug"
+msgstr ""
+
+#: templates/base.html:38
+msgid "Logout"
+msgstr "Cerrar sesión"
+
+#: templates/base.html:42 templates/base.html.py:88 templates/base.html:92
+#: templates/base.html.py:96 templates/auth/login.html:4
+#: templates/auth/login.html.py:7 templates/auth/login.html:12
+#: templates/auth/login.html.py:15
+msgid "Sign in"
+msgstr "Iniciar sesión"
+
+#: templates/base.html:42 templates/base.html.py:88 templates/base.html:96
+#: templates/base.html.py:100 templates/auth/login.html:7
+#: templates/auth/login.html.py:21 templates/auth/login.html:23
+msgid "Register"
+msgstr "Registrarse"
+
+#: templates/base.html:69
+msgid ""
+"\n"
+"\t\t\t\tWolne Lektury is a project lead by <a href=\"http://nowoczesnapolska.org.pl/\">Modern Poland Foundation</a>.\n"
+"\t\t\t\tDigital reproductions are made by <a href=\"http://www.bn.org.pl/\">The National Library</a>, based on TNL resources.\n"
+"\t\t\t\tHosting <a href=\"http://eo.pl/\">EO Networks</a>.\n"
+"\t\t\t\t"
+msgstr ""
+"\n"
+"\t\t\t\tWolne Lektury es un proyecto dirigido por <a href=\"http://nowoczesnapolska.org.pl/\"> la Fundación Polonia Moderna</a>.\n"
+"\t\t\t\tReproducciones digitales están preparadas por <a href=\"http://www.bn.org.pl/\">La Biblioteca Nacional</a>, en base de los recursos de la BN. \n"
+"\t\t\t\tHosting <a href=\"http://eo.pl/\">EO Networks</a>.\n"
+"\t\t\t\t "
+
+#: templates/base.html:76
+msgid ""
+"\n"
+"\t\t\t\tModern Poland Foundation, 00-514 Warsaw, ul. Marszałkowska 84/92 lok. 125, tel/fax: (22) 621-30-17\n"
+"                e-mail: <a href=\"mailto:fundacja@nowoczesnapolska.org.pl\">fundacja@nowoczesnapolska.org.pl</a>\n"
+"\t\t\t\t"
+msgstr ""
+"\n"
+"\t\t\t\tFundación Polonia Moderna, c/ Marszałkowska 84/92, lok. 125, 00-514 Varsovia, tel/fax: +48 (22) 621-30-17\n"
+"                e-mail: <a href=\"mailto:fundacja@nowoczesnapolska.org.pl\">fundacja@nowoczesnapolska.org.pl</a>\n"
+"\t\t\t\t"
+
+#: templates/base.html:85 templates/base.html.py:106 templates/base.html:112
+#: templates/catalogue/book_detail.html:146
+#: templates/catalogue/book_fragments.html:33
+#: templates/catalogue/book_stub_detail.html:31
+#: templates/catalogue/differentiate_tags.html:23
+#: templates/catalogue/search_multiple_hits.html:29
+#: templates/catalogue/search_no_hits.html:22
+#: templates/catalogue/search_too_short.html:19
+#: templates/catalogue/tagged_object_list.html:155
+msgid "Close"
+msgstr "Cerrar"
+
+#: templates/base.html:108 templates/base.html.py:114
+#: templates/catalogue/book_detail.html:148
+#: templates/catalogue/book_fragments.html:35
+#: templates/catalogue/book_stub_detail.html:33
+#: templates/catalogue/differentiate_tags.html:25
+#: templates/catalogue/search_multiple_hits.html:31
+#: templates/catalogue/search_no_hits.html:24
+#: templates/catalogue/search_too_short.html:21
+#: templates/catalogue/tagged_object_list.html:157
+msgid "Loading"
+msgstr "Cargando"
+
+#: templates/admin/base_site.html:4 templates/admin/base_site.html.py:7
+msgid "Site administration"
+msgstr "Administración de la página"
+
+#: templates/admin/base_site.html:8
+msgid "Translations"
+msgstr "Traducciones"
+
+#: templates/admin/catalogue/book/change_list.html:6
+msgid "Import book"
+msgstr "Importar el libro"
+
+#: templates/auth/login.html:4
+msgid "Register on"
+msgstr "Registrarse en"
+
+#: templates/auth/login.html:9 templates/catalogue/book_detail.html:12
+#: templates/catalogue/book_fragments.html:12
+#: templates/catalogue/book_list.html:12
+#: templates/catalogue/book_stub_detail.html:12
+#: templates/catalogue/breadcrumbs.html:21
+#: templates/catalogue/main_page.html:13 templates/info/base.html:10
+#: templates/lessons/document_detail.html:9
+#: templates/lessons/document_list.html:51
+msgid "Search"
+msgstr "Buscar"
+
+#: templates/auth/login.html:9 templates/catalogue/book_detail.html:12
+#: templates/catalogue/book_fragments.html:12
+#: templates/catalogue/book_list.html:12
+#: templates/catalogue/book_stub_detail.html:12
+#: templates/catalogue/main_page.html:13
+#: templates/catalogue/tagged_object_list.html:43 templates/info/base.html:10
+#: templates/lessons/document_detail.html:9
+#: templates/lessons/document_list.html:51
+msgid "or"
+msgstr "o"
+
+#: templates/auth/login.html:9 templates/catalogue/book_detail.html:12
+#: templates/catalogue/book_list.html:12
+#: templates/catalogue/book_stub_detail.html:12
+#: templates/lessons/document_list.html:51
+msgid "return to main page"
+msgstr "volver a la página principal"
+
+#: templates/catalogue/book_detail.html:5
+msgid "on WolneLektury.pl"
+msgstr "en WolneLektury.pl"
+
+#: templates/catalogue/book_detail.html:29
+msgid "Work is licensed under "
+msgstr "Las obras se distribuyen bajo licencia"
+
+#: templates/catalogue/book_detail.html:31
+msgid "Based on"
+msgstr "Basado en"
+
+#: templates/catalogue/book_detail.html:40
+msgid "Put a book"
+msgstr "¡Poner un libro"
+
+#: templates/catalogue/book_detail.html:40
+msgid "on the shelf!"
+msgstr "en el estante!"
+
+#: templates/catalogue/book_detail.html:44
+msgid "Read online"
+msgstr "Leer online"
+
+#: templates/catalogue/book_detail.html:47
+msgid "Download PDF"
+msgstr "Descargar PDF"
+
+#: templates/catalogue/book_detail.html:50
+msgid "Download EPUB"
+msgstr "Descargar EPUB"
+
+#: templates/catalogue/book_detail.html:53
+msgid "Download ODT"
+msgstr "Descargar ODT"
+
+#: templates/catalogue/book_detail.html:56
+msgid "Download TXT"
+msgstr "Descargar TXT"
+
+#: templates/catalogue/book_detail.html:61
+msgid "Artist"
+msgstr "Artista"
+
+#: templates/catalogue/book_detail.html:63
+msgid "Director"
+msgstr "Director"
+
+#: templates/catalogue/book_detail.html:67
+msgid "Download MP3"
+msgstr "Descargar MP3"
+
+#: templates/catalogue/book_detail.html:68
+msgid "Download Ogg Vorbis"
+msgstr "Descargar Ogg Vorbis"
+
+#: templates/catalogue/book_detail.html:95
+msgid "Details"
+msgstr "Detalles"
+
+#: templates/catalogue/book_detail.html:99
+msgid "Author"
+msgstr "Autor"
+
+#: templates/catalogue/book_detail.html:105
+msgid "Epoch"
+msgstr "Época"
+
+#: templates/catalogue/book_detail.html:111
+msgid "Kind"
+msgstr "Género"
+
+#: templates/catalogue/book_detail.html:117
+msgid "Genre"
+msgstr "Subgénero"
+
+#: templates/catalogue/book_detail.html:123
+msgid "Other resources"
+msgstr "Otros recursos"
+
+#: templates/catalogue/book_detail.html:125
+msgid "Book on project's wiki"
+msgstr "Libro en wiki del proyecto"
+
+#: templates/catalogue/book_detail.html:126
+msgid "Source of the book"
+msgstr "Fuente del libro"
+
+#: templates/catalogue/book_detail.html:128
+msgid "Book description on Lektury.Gazeta.pl"
+msgstr "Descripción del libro en Lektury.Gazeta.pl"
+
+#: templates/catalogue/book_detail.html:131
+msgid "Book description on Wikipedia"
+msgstr "Descripción del libro en Wikipedia"
+
+#: templates/catalogue/book_detail.html:136
+msgid "Work's themes "
+msgstr "Temas de la obra"
+
+#: templates/catalogue/book_fragments.html:5
+#: templates/catalogue/book_fragments.html:10
+msgid "Theme"
+msgstr "Tema"
+
+#: templates/catalogue/book_fragments.html:5
+#: templates/catalogue/book_fragments.html:10
+msgid "in work "
+msgstr "de la obra"
+
+#: templates/catalogue/book_fragments.html:5
+msgid "on"
+msgstr "en"
+
+#: templates/catalogue/book_fragments.html:12
+msgid "return to book's page"
+msgstr "volver a la página del libro"
+
+#: templates/catalogue/book_fragments.html:26
+msgid "See description"
+msgstr "Ver la descripción"
+
+#: templates/catalogue/book_fragments.html:26
+msgid "of the book "
+msgstr "del libro"
+
+#: templates/catalogue/book_list.html:7
+msgid "Listing of all works on WolneLektury.pl"
+msgstr "Lista de las obras en WolneLektury.pl"
+
+#: templates/catalogue/book_list.html:10
+msgid "Listing of all works"
+msgstr "Lista de las obras"
+
+#: templates/catalogue/book_sets.html:2
+msgid "Put a book on the shelf!"
+msgstr "¡Poner un libro en el estante!"
+
+#: templates/catalogue/book_sets.html:3 templates/catalogue/book_sets.html:6
+#: templates/catalogue/fragment_sets.html:16
+msgid "Create new shelf"
+msgstr "Crear un estante nuevo"
+
+#: templates/catalogue/book_sets.html:10
+msgid "You do not have any shelves. You can create one below, if you want to."
+msgstr "No tienes ningún estante. Puedes crear uno abajo si quieres."
+
+#: templates/catalogue/book_sets.html:15 templates/catalogue/book_short.html:4
+msgid "Put on the shelf!"
+msgstr "¡Poner en el estante!"
+
+#: templates/catalogue/book_short.html:14
+msgid "Jump to"
+msgstr "Saltar a"
+
+#: templates/catalogue/book_short.html:16
+msgid "Categories"
+msgstr "Categorías"
+
+#: templates/catalogue/book_stub_detail.html:17
+msgid "This work is in public domain and will be published on Internet school library of Wolne Lektury soon."
+msgstr "Esta obra se encuentra en el dominio público y pronto será publicada en la biblioteca electrónica de Wolne Lektury."
+
+#: templates/catalogue/book_stub_detail.html:20
+msgid "This work will become part of public domain and will be allowed to be published without restrictions in"
+msgstr "Esta obra entrará en los recursos del dominio público y podrá ser publicada sin restricciones en"
+
+#: templates/catalogue/book_stub_detail.html:22
+msgid "Find out why Internet libraries can't publish this work."
+msgstr "Entérate por qué las bibliotecas  virtuales no pueden publicar esta obra."
+
+#: templates/catalogue/book_stub_detail.html:24
+msgid "This work is copyrighted."
+msgstr "Esta obra está protegida por los derechos de autor."
+
+#: templates/catalogue/book_text.html:17
+msgid "Table of contents"
+msgstr "Índice"
+
+#: templates/catalogue/book_text.html:18
+#: templates/catalogue/tagged_object_list.html:146
+msgid "Themes"
+msgstr "Temas"
+
+#: templates/catalogue/differentiate_tags.html:13
+msgid "The criteria are ambiguous. Please select one of the following options:"
+msgstr ""
+
+#: templates/catalogue/folded_tag_list.html:4
+msgid "Show full category"
+msgstr "Mostrar toda la categoría"
+
+#: templates/catalogue/folded_tag_list.html:13
+#: templates/catalogue/main_page.html:43 templates/catalogue/main_page.html:48
+#: templates/catalogue/main_page.html:87
+#: templates/catalogue/main_page.html:270
+#: templates/catalogue/main_page.html:279
+msgid "See more"
+msgstr "Ver más"
+
+#: templates/catalogue/folded_tag_list.html:22
+#: templates/catalogue/main_page.html:250
+msgid "Hide"
+msgstr "Esconder"
+
+#: templates/catalogue/fragment_sets.html:2
+msgid "Shelves containing fragment"
+msgstr "Estentes que contienen este fragmento"
+
+#: templates/catalogue/fragment_sets.html:4
+#: templates/catalogue/main_page.html:28
+msgid "You do not own any shelves. You can create one below, if you want to."
+msgstr "No tienes ningún estante. Puedes crear uno abajo si quieres."
+
+#: templates/catalogue/fragment_sets.html:9
+msgid "Save all shelves"
+msgstr "Guardar todos los estantes"
+
+#: templates/catalogue/fragment_short.html:7
+msgid "Expand fragment"
+msgstr "Ampliar este fragmento"
+
+#: templates/catalogue/fragment_short.html:13
+msgid "Hide fragment"
+msgstr "Esconder este fragmento"
+
+#: templates/catalogue/fragment_short.html:18
+msgid "See in a book"
+msgstr "Ver en el libro"
+
+#: templates/catalogue/main_page.html:13
+msgid "check list of books"
+msgstr "Verificar la lista de libros"
+
+#: templates/catalogue/main_page.html:13
+msgid "in our repository"
+msgstr "en nuestra colección"
+
+#: templates/catalogue/main_page.html:17
+msgid "Browse books by categories"
+msgstr "Mirar los libros según categoría"
+
+#: templates/catalogue/main_page.html:19
+#: templates/catalogue/user_shelves.html:2
+msgid "Your shelves with books"
+msgstr "Tus estantes con libros"
+
+#: templates/catalogue/main_page.html:24
+msgid "delete"
+msgstr "borrar"
+
+#: templates/catalogue/main_page.html:33
+#: templates/catalogue/user_shelves.html:15
+msgid "Create shelf"
+msgstr "Crear un estante"
+
+#: templates/catalogue/main_page.html:37
+msgid "Create your own book set. You can share it with friends by sending them link to your shelf."
+msgstr "Crea tu propia colección de libros. Puedes compartirla con tus amigos enviándoles el enlace a tu estante."
+
+#: templates/catalogue/main_page.html:38
+msgid "You need to "
+msgstr "Tienes que"
+
+#: templates/catalogue/main_page.html:38
+msgid "sign in"
+msgstr "iniciar la sesión"
+
+#: templates/catalogue/main_page.html:38
+msgid "to manage your shelves."
+msgstr "para organizar tus estantes."
+
+#: templates/catalogue/main_page.html:41
+#: templates/lessons/document_list.html:49
+msgid "Hand-outs for teachers"
+msgstr "Materiales para los profesores"
+
+#: templates/catalogue/main_page.html:42
+msgid "Lessons' prospects and other ideas for using Wolnelektury.pl for teaching."
+msgstr "Esquemas de clases y otras ideas para usar WolneLektury.pl en la enseñanza."
+
+#: templates/catalogue/main_page.html:47
+msgid "are professional recordings of literary texts from our repository, available on free license in MP3 and Ogg Vorbis formats as well as in DAISY system."
+msgstr "son grabaciones profesionales de textos literarios de nuestro depósito. Están disponibles gratis en formatos MP3, Ogg Vorbis y en el sistema DAISY. "
+
+#: templates/catalogue/main_page.html:54
+#: templates/catalogue/tagged_object_list.html:128
+msgid "Authors"
+msgstr "Autores"
+
+#: templates/catalogue/main_page.html:58
+#: templates/catalogue/tagged_object_list.html:132
+msgid "Kinds"
+msgstr "Géneros"
+
+#: templates/catalogue/main_page.html:62
+#: templates/catalogue/tagged_object_list.html:136
+msgid "Genres"
+msgstr "Subgéneros"
+
+#: templates/catalogue/main_page.html:66
+#: templates/catalogue/tagged_object_list.html:140
+msgid "Epochs"
+msgstr "Épocas"
+
+#: templates/catalogue/main_page.html:72
+msgid "Themes and topics"
+msgstr "Temas y motivos"
+
+#: templates/catalogue/main_page.html:75
+msgid "Themes groups"
+msgstr "Grupos de temas"
+
+#: templates/catalogue/main_page.html:260
+msgid "News"
+msgstr "Noticias"
+
+#: templates/catalogue/main_page.html:264
+msgid "See our blog"
+msgstr "Ver nuestro blog"
+
+#: templates/catalogue/main_page.html:267
+msgid "You can help us!"
+msgstr "¡Puedes ayudarnos!"
+
+#: templates/catalogue/main_page.html:268
+msgid "We try our best to elaborate works appended to our library. It is possible only due to support of our volunteers."
+msgstr "Hacemos todo lo posible para elaborar las obras de nuestra biblioteca con la mayor perfección. Esto es posible sólo gracias al apoyo de nuestros voluntarios."
+
+#: templates/catalogue/main_page.html:269
+msgid "We invite people who want to take part in developing Internet school library Wolne Lektury."
+msgstr "Invitamos a todos quienes quieren formar parte en el desarrollo de la biblioteca virtual de Wolne Lektury."
+
+#: templates/catalogue/main_page.html:273
+msgid "About us"
+msgstr "Sobre nosotros"
+
+#: templates/catalogue/main_page.html:275
+msgid ""
+"\n"
+"\t\t\tInternet library with school readings “Wolne Lektury” (<a href=\"http://wolnelektury.pl\">www.wolnelektury.pl</a>) is a project made by Modern Poland Foundation. It started in 2007 and shares school readings, which are recommended by Ministry of National Education and are in public domain.\n"
+"\t\t\t"
+msgstr ""
+"\n"
+"\t\t\tLa biblioteca virtual con lecturas “Wolne Lektury” (<a href=\"http://wolnelektury.pl\">www.wolnelektury.pl</a>)es un proyecto creado por la Fundación Polonia Moderna. Había comenzado su actividad en el año 2007 y está compartiendo las lecturas recomendadas por el Ministerio de la Educación Nacional y que son del dominio público.\n"
+"\t\t\t"
+
+#: templates/catalogue/search_multiple_hits.html:5
+#: templates/catalogue/search_too_short.html:5
+msgid "Searching in"
+msgstr "Buscando en"
+
+#: templates/catalogue/search_multiple_hits.html:14
+msgid "More than one result matching the criteria found."
+msgstr "Se ha encontrado más que un resultado que corresponde a tus criterios."
+
+#: templates/catalogue/search_no_hits.html:5
+msgid "Search in WolneLektury.pl"
+msgstr "Buscar en WolneLektury.pl"
+
+#: templates/catalogue/search_no_hits.html:14
+#: templates/catalogue/tagged_object_list.html:116
+msgid "Sorry! Search cirteria did not match any resources."
+msgstr "Lo sentimos, no hay resultados que corresponden con los criterios de la búsqueda."
+
+#: templates/catalogue/search_no_hits.html:16
+msgid ""
+"Search engine supports following criteria: title, author, theme/topic, epoch, kind and genre.\n"
+"\t\tAs for now we do not support full text search."
+msgstr ""
+"El buscador admite los criterios siguientes: título, autor, tema/motivo, época, género y subgénero.\n"
+"\t\tActualmente no admitimos la búsqueda de texto entero."
+
+#: templates/catalogue/search_too_short.html:14
+msgid "Sorry! Search query must have at least two characters."
+msgstr "¡Perdón! La pregunta debe tener por lo menos dos letras."
+
+#: templates/catalogue/tag_list.html:4
+msgid "See full category"
+msgstr "Ver toda la categoría"
+
+#: templates/catalogue/tagged_object_list.html:15
+msgid "Your shelf is empty"
+msgstr "Tu estante está vacío"
+
+#: templates/catalogue/tagged_object_list.html:16
+msgid "You can put a book on a shelf by entering page of the reading and clicking 'Put on the shelf'."
+msgstr "Puedes poner un libro en el estante entrando en la página de aquella lectura y haciendo clic en \"Poner en el estante\"."
+
+#: templates/catalogue/tagged_object_list.html:32
+msgid "Download all books from this shelf"
+msgstr "Descargar todos los libros de este estante"
+
+#: templates/catalogue/tagged_object_list.html:36
+msgid "Choose books' formats which you want to download:"
+msgstr "Elige formatos de los libros que quieres descargar:"
+
+#: templates/catalogue/tagged_object_list.html:37
+#: templates/catalogue/tagged_object_list.html:39
+#: templates/catalogue/tagged_object_list.html:40
+msgid "for reading"
+msgstr "para leer"
+
+#: templates/catalogue/tagged_object_list.html:37
+msgid "and printing using"
+msgstr "e imprimir"
+
+#: templates/catalogue/tagged_object_list.html:39
+msgid "and editing using"
+msgstr "y editar"
+
+#: templates/catalogue/tagged_object_list.html:40
+msgid "on small displays, for example mobile phones"
+msgstr "en pantallas pequeñas como las de teléfonos móviles"
+
+#: templates/catalogue/tagged_object_list.html:41
+#: templates/catalogue/tagged_object_list.html:42
+msgid "for listening"
+msgstr "para escuchar"
+
+#: templates/catalogue/tagged_object_list.html:41
+msgid "on favourite MP3 player"
+msgstr "en tu reproductor de MP3 favorito."
+
+#: templates/catalogue/tagged_object_list.html:42
+msgid "open format"
+msgstr "formato abierto"
+
+#: templates/catalogue/tagged_object_list.html:42
+msgid "Xiph.org Foundation"
+msgstr "Fundación Xiph.org"
+
+#: templates/catalogue/tagged_object_list.html:43
+#: templates/lessons/ajax_document_detail.html:3
+#: templates/lessons/document_detail.html:13
+msgid "Download"
+msgstr "Descargar"
+
+#: templates/catalogue/tagged_object_list.html:43
+msgid "Updating list of books' formats on the shelf"
+msgstr "Actualizando la lista de formatos de los libros en el estante"
+
+#: templates/catalogue/tagged_object_list.html:43
+msgid "cancel"
+msgstr "cancelar"
+
+#: templates/catalogue/tagged_object_list.html:48
+msgid "Share this shelf"
+msgstr "Compartir este estante"
+
+#: templates/catalogue/tagged_object_list.html:50
+msgid "Copy this link and share it with other people to let them see your shelf."
+msgstr "Copia este enlace y compártelo con otros para que puedan ver tu estante. "
+
+#: templates/catalogue/tagged_object_list.html:60
+msgid "Read work's study of this author on Lektury.Gazeta.pl"
+msgstr "Leer el estudio sobre las obras de este autor en Lektury.Gazeta.pl"
+
+#: templates/catalogue/tagged_object_list.html:62
+#, fuzzy, python-format
+msgid "Read study of epoch %(last_tag)s on Lektury.Gazeta.pl"
+msgstr "Leer el estudio sobre las obras de este autor en Lektury.Gazeta.pl"
+
+#: templates/catalogue/tagged_object_list.html:64
+#, fuzzy, python-format
+msgid "Read study of kind %(last_tag)s on Lektury.Gazeta.pl"
+msgstr "Leer el estudio sobre las obras de este autor en Lektury.Gazeta.pl"
+
+#: templates/catalogue/tagged_object_list.html:66
+#, fuzzy, python-format
+msgid "Read study of genre %(last_tag)s on Lektury.Gazeta.pl"
+msgstr "Leer el estudio sobre las obras de este autor en Lektury.Gazeta.pl"
+
+#: templates/catalogue/tagged_object_list.html:68
+#, fuzzy
+msgid "Read related study on Lektury.Gazeta.pl"
+msgstr "Leer el estudio sobre las obras de este autor en Lektury.Gazeta.pl"
+
+#: templates/catalogue/tagged_object_list.html:76
+msgid "Read article about this author on Wikipedia"
+msgstr "Leer el artículo sobre este autor en Wikipedia"
+
+#: templates/catalogue/tagged_object_list.html:78
+#, fuzzy, python-format
+msgid "Read article about epoch %(last_tag)s on Wikipedia"
+msgstr "Leer el artículo sobre este autor en Wikipedia"
+
+#: templates/catalogue/tagged_object_list.html:80
+#, fuzzy, python-format
+msgid "Read article about kind %(last_tag)s on Wikipedia"
+msgstr "Leer el artículo sobre este autor en Wikipedia"
+
+#: templates/catalogue/tagged_object_list.html:82
+#, fuzzy, python-format
+msgid "Read article about genre %(last_tag)s on Wikipedia"
+msgstr "Leer el artículo sobre este autor en Wikipedia"
+
+#: templates/catalogue/tagged_object_list.html:84
+#, fuzzy
+msgid "Read related article on Wikipedia"
+msgstr "Leer el artículo sobre este autor en Wikipedia"
+
+#: templates/catalogue/tagged_object_list.html:94
+msgid "Delete"
+msgstr "Borrar"
+
+#: templates/catalogue/tagged_object_list.html:102
+msgid "This author's works are copyrighted."
+msgstr "Las obras de este autor están protegidas por los derechos de autor."
+
+#: templates/catalogue/tagged_object_list.html:105
+msgid "This author's works are in public domain and will be published on Internet school library of Wolne Lektury soon."
+msgstr "Las obras de este autor se encuentran en el dominio público y pronto serán publicadas en la biblioteca virtual de Wolne Lektury."
+
+#: templates/catalogue/tagged_object_list.html:109
+msgid "This author's works will become part of public domain and will be allowed to be published without restrictions in"
+msgstr "Las obras de este autor entrarán en los recursos del dominio público y podrán ser publicadas sin restricciones en "
+
+#: templates/catalogue/tagged_object_list.html:111
+msgid "Find out why Internet libraries can't publish this author's works."
+msgstr "Entérate por qué las bibliotecas virtuales no pueden publicar las obras de este autor."
+
+#: templates/catalogue/user_shelves.html:6
+msgid "remove"
+msgstr "borrar"
+
+#: templates/catalogue/user_shelves.html:10
+msgid "You do not own any shelves. You can create one below if you want to"
+msgstr "No tienes ningún estante. Puedes crear uno abajo si quieres."
+
+#: templates/info/base.html:10
+msgid "return to the main page"
+msgstr "volver a la página principal"
+
+#: templates/info/join_us.html:2
+msgid ""
+"We have over 1000 works published in Wolne Lektury!\n"
+"Help us expand the library and set new readings free by\n"
+"making a donation or transferring 1% of your income tax."
+msgstr ""
+"¡Hay más que 1000 obras publicadas en Wolne Lektury!\n"
+"Ayúdanos a desarrollar la biblioteca y publicar nuevas lecturas gratis\n"
+"haciendo una donación o transfiriendo 1% de tus impuestos."
+
+#: templates/info/join_us.html:5 templates/info/join_us.html.py:10
+msgid "More..."
+msgstr "Más..."
+
+#: templates/info/join_us.html:7
+msgid ""
+"Become an editor of Wolne Lektury! Find out if\n"
+"we're currently working on a reading you're looking for and prepare\n"
+"a publication by yourself by logging into the Editorial Platform."
+msgstr ""
+"Hazte el editor de Wolne Lektury! Averigua si\n"
+"actualmente estamos preparando la lectura que te interesa y prepara\n"
+"una publicación por ti mismo/a inscribiéndote en la Plataforma Editorial."
+
+#: templates/lessons/ajax_document_detail.html:3
+#: templates/lessons/document_detail.html:13
+msgid "author"
+msgstr "autor"
+
+#: templates/lessons/document_detail.html:9
+msgid "return to list of materials"
+msgstr "volver a la lista de los materiales"
+
+#: templates/lessons/document_list.html:7
+msgid "Hand-outs for teachers on "
+msgstr "Materiales para los profesores en"
+
+#: templates/pagination/pagination.html:5
+#: templates/pagination/pagination.html:7
+msgid "previous"
+msgstr "anterior"
+
+#: templates/pagination/pagination.html:21
+#: templates/pagination/pagination.html:23
+msgid "next"
+msgstr "siguiente"
+
+#~ msgid "Polish"
+#~ msgstr "polaco"
+
+#~ msgid "German"
+#~ msgstr "alemán"
+
+#~ msgid "English"
+#~ msgstr "inglés"
+
+#~ msgid "Lithuanian"
+#~ msgstr "lituano"
+
+#~ msgid "French"
+#~ msgstr "francés"
+
+#~ msgid "Russian"
+#~ msgstr "ruso"
+
+#~ msgid "Spanish"
+#~ msgstr "español"
+
+#~ msgid "Ukrainian"
+#~ msgstr "ucraniano"
+
+#~ msgid "Choose your interface language: "
+#~ msgstr "Elige el idioma de la interfaz:"
+
+#~ msgid "Choose language"
+#~ msgstr "Elige el idioma"
+
+#~ msgid "Hide description"
+#~ msgstr "Esconder la descripción"
+
+#~ msgid "Read study of epoch"
+#~ msgstr "Leer el estudio sobre esta época"
+
+#~ msgid "on Lektury.Gazeta.pl"
+#~ msgstr "en Lektury.Gazeta.pl"
+
+#~ msgid "Read article about epoch"
+#~ msgstr "Leer el artículo sobre esta época"
+
+#~ msgid "on Wikipedia"
+#~ msgstr "en Wikipedia"
diff --git a/wolnelektury/locale/fr/LC_MESSAGES/django.mo b/wolnelektury/locale/fr/LC_MESSAGES/django.mo
new file mode 100644 (file)
index 0000000..775809c
Binary files /dev/null and b/wolnelektury/locale/fr/LC_MESSAGES/django.mo differ
diff --git a/wolnelektury/locale/fr/LC_MESSAGES/django.po b/wolnelektury/locale/fr/LC_MESSAGES/django.po
new file mode 100644 (file)
index 0000000..007bb7c
--- /dev/null
@@ -0,0 +1,786 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-05-25 14:29+0200\n"
+"PO-Revision-Date: 2010-08-07 20:23+0100\n"
+"Last-Translator: Natalia Kertyczak <natalczyk@o2.pl>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: settings.py:37
+msgid "Polish"
+msgstr "polonais"
+
+#: settings.py:38
+msgid "German"
+msgstr "allemand"
+
+#: settings.py:39
+msgid "English"
+msgstr "anglais"
+
+#: settings.py:40
+msgid "Lithuanian"
+msgstr "lituanien"
+
+#: settings.py:41
+msgid "French"
+msgstr "français"
+
+#: settings.py:42
+msgid "Russian"
+msgstr "russe"
+
+#: settings.py:43
+msgid "Spanish"
+msgstr "espagnol"
+
+#: settings.py:44
+msgid "Ukrainian"
+msgstr "ukrainien"
+
+#: templates/404.html:6
+#: templates/404.html.py:15
+msgid "Page does not exist"
+msgstr "La page n'existe pas"
+
+#: templates/404.html:17
+msgid "We are sorry, but this page does not exist. Please check if you entered correct address or go to "
+msgstr "Désolé, cette page n'existe pas. Vérifiez si vous avez introduit l'adresse correcte ou allez à"
+
+#: templates/404.html:17
+msgid "main page"
+msgstr "l'accueil"
+
+#: templates/500.html:6
+#: templates/500.html.py:54
+msgid "Server error"
+msgstr "Erreur du serveur"
+
+#: templates/500.html:55
+msgid "<p>The Wolnelektury.pl site is currently unavailable. Meanwhile, visit our <a href='http://nowoczesnapolska.org.pl'>blog</a>.</p> <p>Inform our <a href='mailto:fundacja@nowoczesnapolska.org.pl'>administrators</a> about the error.</p>"
+msgstr "<p> Le site Wolnelektury.pl est temporairement inaccessible. En attendant, visitez notre <a href='http://nowoczesnapolska.org.pl'>blog</a>.</p> <p> Informez nos  <a href='mailto:fundacja@nowoczesnapolska.org.pl'> administrateurs </a> de l'erreur.</p>"
+
+#: templates/503.html:6
+#: templates/503.html.py:54
+msgid "Service unavailable"
+msgstr "Service inaccessible"
+
+#: templates/503.html:56
+msgid "The Wolnelektury.pl site is currently unavailable due to maintainance."
+msgstr "Le site Wolnelektury.pl est temporairement inaccessible en raison d'opérations de maintenance."
+
+#: templates/base.html:20
+msgid "Internet Explorer cannot display this site properly. Click here to read more..."
+msgstr "Internet Explorer ne peut pas afficher ce site correctement. Cliquer ici pour en savoir plus..."
+
+#: templates/base.html:33
+msgid "Welcome"
+msgstr "Bienvenue"
+
+#: templates/base.html:34
+msgid "Your shelves"
+msgstr "Vos étagères"
+
+#: templates/base.html:36
+msgid "Administration"
+msgstr "Administration"
+
+#: templates/base.html:38
+msgid "Logout"
+msgstr "Déconnexion"
+
+#: templates/base.html:41
+#: templates/base.html.py:87
+#: templates/base.html:91
+#: templates/base.html.py:95
+#: templates/auth/login.html:4
+#: templates/auth/login.html.py:7
+#: templates/auth/login.html:12
+#: templates/auth/login.html.py:15
+msgid "Sign in"
+msgstr "Connexion"
+
+#: templates/base.html:41
+#: templates/base.html.py:87
+#: templates/base.html:95
+#: templates/base.html.py:99
+#: templates/auth/login.html:7
+#: templates/auth/login.html.py:21
+#: templates/auth/login.html:23
+msgid "Register"
+msgstr "Créer un compte"
+
+#: templates/base.html:51
+msgid "Choose your interface language: "
+msgstr "Choisir la langue de l'interface"
+
+#: templates/base.html:56
+msgid "Choose language"
+msgstr "Choisir la langue"
+
+#: templates/base.html:68
+msgid ""
+"\n"
+"\t\t\t\tWolne Lektury is a project lead by <a href=\"http://nowoczesnapolska.org.pl/\">Modern Poland Foundation</a>.\n"
+"\t\t\t\tDigital reproductions are made by <a href=\"http://www.bn.org.pl/\">The National Library</a>, based on TNL resources. \n"
+"\t\t\t\tHosting <a href=\"http://eo.pl/\">EO Networks</a>.\n"
+"\t\t\t\t"
+msgstr ""
+"\n"
+"\t\t\t\tLectures libres et un projet réalisé par la <a href=\"http://nowoczesnapolska.org.pl/\">Fondation Pologne Moderne </a>.\n"
+"\t\t\t\tReproductions numériques faites par <a href=\"http://www.bn.org.pl/\">la Bibliothèque nationale</a>, basées sur ressources TNL. \n"
+"\t\t\t\tHosting <a href=\"http://eo.pl/\">EO Networks</a>.\n"
+"\t\t\t\t"
+
+#: templates/base.html:75
+msgid ""
+"\n"
+"\t\t\t\tModern Poland Foundation, 00-514 Warsaw, ul. Marszałkowska 84/92 lok. 125, tel/fax: (22) 621-30-17\n"
+"                e-mail: <a href=\"mailto:fundacja@nowoczesnapolska.org.pl\">fundacja@nowoczesnapolska.org.pl</a>\n"
+"\t\t\t\t"
+msgstr ""
+"\n"
+"\t\t\t\t Fondation Pologne Moderne, 00-514 Warszawa, ul. Marszałkowska 84/92 lok. 125, tel/fax: (22) 621-30-17\n"
+"                e-mail: <a href=\"mailto:fundacja@nowoczesnapolska.org.pl\">fundacja@nowoczesnapolska.org.pl</a>\n"
+"\t\t\t\t"
+
+#: templates/base.html:84
+#: templates/base.html.py:105
+#: templates/catalogue/book_detail.html:129
+#: templates/catalogue/book_fragments.html:33
+#: templates/catalogue/book_stub_detail.html:31
+#: templates/catalogue/search_multiple_hits.html:23
+#: templates/catalogue/search_no_hits.html:22
+#: templates/catalogue/search_too_short.html:19
+#: templates/catalogue/tagged_object_list.html:141
+msgid "Close"
+msgstr "Fermer"
+
+#: templates/base.html:107
+#: templates/catalogue/book_detail.html:131
+#: templates/catalogue/book_fragments.html:35
+#: templates/catalogue/book_stub_detail.html:33
+#: templates/catalogue/search_multiple_hits.html:25
+#: templates/catalogue/search_no_hits.html:24
+#: templates/catalogue/search_too_short.html:21
+#: templates/catalogue/tagged_object_list.html:143
+msgid "Loading"
+msgstr "Chargement en cours"
+
+#: templates/admin/base_site.html:4
+#: templates/admin/base_site.html.py:7
+msgid "Site administration"
+msgstr "Site de l'administrateur"
+
+#: templates/admin/base_site.html:8
+msgid "Translations"
+msgstr "Traductions"
+
+#: templates/admin/catalogue/book/change_list.html:6
+msgid "Import book"
+msgstr "Importer le livre"
+
+#: templates/auth/login.html:4
+msgid "Register on"
+msgstr "Régistrer sur"
+
+#: templates/auth/login.html:9
+#: templates/catalogue/book_detail.html:12
+#: templates/catalogue/book_fragments.html:12
+#: templates/catalogue/book_list.html:12
+#: templates/catalogue/book_stub_detail.html:12
+#: templates/catalogue/breadcrumbs.html:9
+#: templates/catalogue/main_page.html:13
+#: templates/info/base.html:10
+#: templates/lessons/document_detail.html:9
+#: templates/lessons/document_list.html:51
+msgid "Search"
+msgstr "Chercher"
+
+#: templates/auth/login.html:9
+#: templates/catalogue/book_detail.html:12
+#: templates/catalogue/book_fragments.html:12
+#: templates/catalogue/book_list.html:12
+#: templates/catalogue/book_stub_detail.html:12
+#: templates/catalogue/main_page.html:13
+#: templates/catalogue/tagged_object_list.html:41
+#: templates/info/base.html:10
+#: templates/lessons/document_detail.html:9
+#: templates/lessons/document_list.html:51
+msgid "or"
+msgstr "ou"
+
+#: templates/auth/login.html:9
+#: templates/catalogue/book_detail.html:12
+#: templates/catalogue/book_list.html:12
+#: templates/catalogue/book_stub_detail.html:12
+#: templates/lessons/document_list.html:51
+msgid "return to main page"
+msgstr "retour à l'accueil"
+
+#: templates/catalogue/book_detail.html:5
+msgid "on WolneLektury.pl"
+msgstr "sur WolneLektury.pl"
+
+#: templates/catalogue/book_detail.html:17
+msgid "Work is licensed under "
+msgstr "Oeuvre sous licence "
+
+#: templates/catalogue/book_detail.html:19
+msgid "Based on"
+msgstr "Basé sur"
+
+#: templates/catalogue/book_detail.html:24
+#: templates/catalogue/tagged_object_list.html:27
+msgid "Hide description"
+msgstr "Cacher la description"
+
+#: templates/catalogue/book_detail.html:27
+msgid "Put a book"
+msgstr "Mettre le livre"
+
+#: templates/catalogue/book_detail.html:27
+msgid "on the shelf!"
+msgstr "sur l'étagère"
+
+#: templates/catalogue/book_detail.html:31
+msgid "Read online"
+msgstr "Lire en ligne"
+
+#: templates/catalogue/book_detail.html:34
+msgid "Download PDF"
+msgstr "Télécharger un fichier PDF"
+
+#: templates/catalogue/book_detail.html:37
+msgid "Download ODT"
+msgstr "Télécharger un fichier ODT"
+
+#: templates/catalogue/book_detail.html:40
+msgid "Download TXT"
+msgstr "Télécharger un fichier TXT"
+
+#: templates/catalogue/book_detail.html:45
+msgid "Artist"
+msgstr "Artiste"
+
+#: templates/catalogue/book_detail.html:47
+msgid "Director"
+msgstr "Metteur en scène"
+
+#: templates/catalogue/book_detail.html:51
+msgid "Download MP3"
+msgstr "Télécharger un fichier MP3"
+
+#: templates/catalogue/book_detail.html:52
+msgid "Download Ogg Vorbis"
+msgstr "Télécharger un fichier Ogg Vorbis"
+
+#: templates/catalogue/book_detail.html:79
+msgid "Details"
+msgstr "Détails"
+
+#: templates/catalogue/book_detail.html:82
+msgid "Author"
+msgstr "Auteur"
+
+#: templates/catalogue/book_detail.html:88
+msgid "Epoch"
+msgstr "Epoque"
+
+#: templates/catalogue/book_detail.html:94
+msgid "Kind"
+msgstr "Type"
+
+#: templates/catalogue/book_detail.html:100
+msgid "Genre"
+msgstr "Genre"
+
+#: templates/catalogue/book_detail.html:106
+msgid "Other resources"
+msgstr "Autres ressources"
+
+#: templates/catalogue/book_detail.html:108
+msgid "Book on project's wiki"
+msgstr "Le livre sur le wiki du projet"
+
+#: templates/catalogue/book_detail.html:109
+msgid "Source of the book"
+msgstr "Source du livre"
+
+#: templates/catalogue/book_detail.html:111
+msgid "Book description on Lektury.Gazeta.pl"
+msgstr "Description du livre sur Lektury.Gazeta.pl"
+
+#: templates/catalogue/book_detail.html:114
+msgid "Book description on Wikipedia"
+msgstr "Description du livre sur Wikipédia"
+
+#: templates/catalogue/book_detail.html:119
+msgid "Work's themes "
+msgstr "Les thèmes de l'oeuvre"
+
+#: templates/catalogue/book_fragments.html:5
+#: templates/catalogue/book_fragments.html:10
+msgid "Theme"
+msgstr "Thème"
+
+#: templates/catalogue/book_fragments.html:5
+#: templates/catalogue/book_fragments.html:10
+msgid "in work "
+msgstr "dans l'oeuvre"
+
+#: templates/catalogue/book_fragments.html:5
+msgid "on"
+msgstr "sur"
+
+#: templates/catalogue/book_fragments.html:12
+msgid "return to book's page"
+msgstr "retour à la page du livre"
+
+#: templates/catalogue/book_fragments.html:26
+msgid "See description"
+msgstr "Voir description"
+
+#: templates/catalogue/book_fragments.html:26
+msgid "of the book "
+msgstr "du livre"
+
+#: templates/catalogue/book_list.html:7
+msgid "Alphabetical listing of works on WolneLektury.pl"
+msgstr "Liste alphabétique des oeuvres sur WolneLektury.pl"
+
+#: templates/catalogue/book_list.html:10
+msgid "Alphabetical listing of works"
+msgstr "Liste alphabétique des oeuvres"
+
+#: templates/catalogue/book_sets.html:2
+msgid "Put a book on the shelf!"
+msgstr "Mettre le livre sur l'étagère!"
+
+#: templates/catalogue/book_sets.html:4
+msgid "You do not have any shelves. You can create one below, if you want to."
+msgstr "Vous ne possédez aucune étagère. Vous pouvez en créer une au-dessous, si vous voulez."
+
+#: templates/catalogue/book_sets.html:9
+#: templates/catalogue/book_short.html:4
+msgid "Put on the shelf!"
+msgstr "Mettre sur l'étagère!"
+
+#: templates/catalogue/book_sets.html:16
+#: templates/catalogue/fragment_sets.html:16
+msgid "Create new shelf"
+msgstr "Créer une étagère nouvelle"
+
+#: templates/catalogue/book_short.html:14
+msgid "Jump to"
+msgstr "Aller à"
+
+#: templates/catalogue/book_short.html:16
+msgid "Categories"
+msgstr "Catégories"
+
+#: templates/catalogue/book_stub_detail.html:17
+msgid "This work is in public domain and will be published on Internet school library of Wolne Lektury soon."
+msgstr "Cette oeuvre est dans le domaine public et va être prochainement publiée dans la bibliothèque en ligne Wolne Lektury"
+
+#: templates/catalogue/book_stub_detail.html:20
+msgid "This work will become part of public domain and will be allowed to be published without restrictions in"
+msgstr "Cette oeuvre sera dans le domaine public et il sera possible de la publier sans restrictions en "
+
+#: templates/catalogue/book_stub_detail.html:22
+msgid "Find out why Internet libraries can't publish this work."
+msgstr "Apprendre pourquoi les bibliothéques en ligne ne peuvent pas publier cette oeuvre."
+
+#: templates/catalogue/book_stub_detail.html:24
+msgid "This work is copyrighted."
+msgstr "Cette oeuvre est protégée par le droit d'auteur"
+
+#: templates/catalogue/book_text.html:17
+msgid "Table of contents"
+msgstr "Tables des matières"
+
+#: templates/catalogue/book_text.html:18
+#: templates/catalogue/tagged_object_list.html:132
+msgid "Themes"
+msgstr "Thèmes"
+
+#: templates/catalogue/folded_tag_list.html:4
+msgid "Show full category"
+msgstr "Montrer la catégorie entière"
+
+#: templates/catalogue/folded_tag_list.html:13
+#: templates/catalogue/main_page.html:43
+#: templates/catalogue/main_page.html:48
+#: templates/catalogue/main_page.html:87
+#: templates/catalogue/main_page.html:270
+#: templates/catalogue/main_page.html:279
+msgid "See more"
+msgstr "Voir plus"
+
+#: templates/catalogue/folded_tag_list.html:22
+#: templates/catalogue/main_page.html:250
+msgid "Hide"
+msgstr "Cacher"
+
+#: templates/catalogue/fragment_sets.html:2
+msgid "Shelves containing fragment"
+msgstr "Etagères qui contiennent l'extrait"
+
+#: templates/catalogue/fragment_sets.html:4
+#: templates/catalogue/main_page.html:28
+msgid "You do not own any shelves. You can create one below, if you want to."
+msgstr "Vous ne possédez aucune étagère. Vous pouvez en créer une au-dessous, si vous voulez."
+
+#: templates/catalogue/fragment_sets.html:9
+msgid "Save all shelves"
+msgstr "Enregistrer toutes les étagères"
+
+#: templates/catalogue/fragment_short.html:6
+msgid "Expand fragment"
+msgstr "Montrer l'extrait"
+
+#: templates/catalogue/fragment_short.html:12
+msgid "Hide fragment"
+msgstr "Cacher l'extrait"
+
+#: templates/catalogue/fragment_short.html:17
+msgid "See in a book"
+msgstr "Voir dans le livre"
+
+#: templates/catalogue/main_page.html:13
+msgid "check list of books"
+msgstr "consultation de la liste des livres"
+
+#: templates/catalogue/main_page.html:13
+msgid "in our repository"
+msgstr "dans notre répertoire"
+
+#: templates/catalogue/main_page.html:17
+msgid "Browse books by categories"
+msgstr "Regarder les livres selon catégories"
+
+#: templates/catalogue/main_page.html:19
+#: templates/catalogue/user_shelves.html:2
+msgid "Your shelves with books"
+msgstr "Vos étagères avec les livres"
+
+#: templates/catalogue/main_page.html:24
+msgid "delete"
+msgstr "supprimer"
+
+#: templates/catalogue/main_page.html:33
+#: templates/catalogue/user_shelves.html:15
+msgid "Create shelf"
+msgstr "Créer une étagère"
+
+#: templates/catalogue/main_page.html:37
+msgid "Create your own book set. You can share it with friends by sending them link to your shelf."
+msgstr "Créer votre propre choix des livres. Vous pouvez les partager avec les amis en leur envoyant le lien à votre étagère."
+
+#: templates/catalogue/main_page.html:38
+msgid "You need to "
+msgstr "Vous devez "
+
+#: templates/catalogue/main_page.html:38
+msgid "sign in"
+msgstr "vous connecter"
+
+#: templates/catalogue/main_page.html:38
+msgid "to manage your shelves."
+msgstr "pour gérer vos étagères."
+
+#: templates/catalogue/main_page.html:41
+#: templates/lessons/document_list.html:49
+msgid "Hand-outs for teachers"
+msgstr "Fiches pour les enseignants"
+
+#: templates/catalogue/main_page.html:42
+msgid "Lessons' prospects and other ideas for using Wolnelektury.pl for teaching."
+msgstr "Plans des leçons et autres idées pour utiliser Wolnelektury.pl à enseigner."
+
+#: templates/catalogue/main_page.html:47
+msgid "are professional recordings of literary texts from our repository, available on free license in MP3 and Ogg Vorbis formats as well as in DAISY system."
+msgstr "sont des enregistrements professionnels des textes littéraires de notre répertoire, accessibles gratuitment au format MP3 et Ogg Vorbis ainsi que dans le système DAISY."
+
+#: templates/catalogue/main_page.html:54
+#: templates/catalogue/tagged_object_list.html:114
+msgid "Authors"
+msgstr "Auteurs"
+
+#: templates/catalogue/main_page.html:58
+#: templates/catalogue/tagged_object_list.html:118
+msgid "Kinds"
+msgstr "Types"
+
+#: templates/catalogue/main_page.html:62
+#: templates/catalogue/tagged_object_list.html:122
+msgid "Genres"
+msgstr "Genres"
+
+#: templates/catalogue/main_page.html:66
+#: templates/catalogue/tagged_object_list.html:126
+msgid "Epochs"
+msgstr "Epoques"
+
+#: templates/catalogue/main_page.html:72
+msgid "Themes and topics"
+msgstr "Thèmes et sujets"
+
+#: templates/catalogue/main_page.html:75
+msgid "Themes groups"
+msgstr "Groupes des thèmes"
+
+#: templates/catalogue/main_page.html:260
+msgid "News"
+msgstr "Actualités"
+
+#: templates/catalogue/main_page.html:264
+msgid "See our blog"
+msgstr "Voir notre blog"
+
+#: templates/catalogue/main_page.html:267
+msgid "You can help us!"
+msgstr "Vous pouvez nous aider"
+
+#: templates/catalogue/main_page.html:268
+msgid "We try our best to elaborate works appended to our library. It is possible only due to support of our volunteers."
+msgstr "Nous essayons de rédiger les oeuvres ajoutées à notre bibliothèque le mieux possible. C'est possible grâce à l'aide des nos bénévoles."
+
+#: templates/catalogue/main_page.html:269
+msgid "We invite people who want to take part in developing Internet school library Wolne Lektury."
+msgstr "Nous invitons ceux qui veulent participer au développement du bibliothèque en ligne Lectures Libres."
+
+#: templates/catalogue/main_page.html:273
+msgid "About us"
+msgstr "Qui sommes-nous?"
+
+#: templates/catalogue/main_page.html:275
+msgid ""
+"\n"
+"\t\t\tInternet library with school readings “Wolne Lektury” (<a href=\"http://wolnelektury.pl\">www.wolnelektury.pl</a>) is a project made by Modern Poland Foundation. It started in 2007 and shares school readings, which are recommended by Ministry of National Education and are in public domain.\n"
+"\t\t\t"
+msgstr ""
+"\n"
+"\t\t\tBibliothèque en ligne avec lectures scolaires “Wolne Lektury” (Lectures Libres) (<a href=\"http://wolnelektury.pl\">www.wolnelektury.pl</a>) est un projet de la Fondation Pologne Moderne. Il a été lancé en 2007 et il comprend des lectures scolaires recommendées par le Ministère de l'éducation nationale qui sont dans le domaine public.\n"
+"\t\t\t"
+
+#: templates/catalogue/search_multiple_hits.html:5
+#: templates/catalogue/search_too_short.html:5
+msgid "Searching in"
+msgstr "Recherche dans"
+
+#: templates/catalogue/search_multiple_hits.html:14
+msgid "More than one result matching the criteria found."
+msgstr "Plus qu'un résultat répondant aux critères."
+
+#: templates/catalogue/search_no_hits.html:5
+msgid "Search in WolneLektury.pl"
+msgstr "Recherche dans WolneLektury.pl"
+
+#: templates/catalogue/search_no_hits.html:14
+#: templates/catalogue/tagged_object_list.html:102
+msgid "Sorry! Search cirteria did not match any resources."
+msgstr "Nous sommes désolés, aucune ressource ne répond au critères de recherche."
+
+#: templates/catalogue/search_no_hits.html:16
+msgid ""
+"Search engine supports following criteria: title, author, theme/topic, epoch, kind and genre.\n"
+"\t\tAs for now we do not support full text search."
+msgstr ""
+"Le moteur de recherche permet de chercher selon le titre, auteur, sujet/thème, époque, type et genre.\n"
+"\t\tPour le moment nous n'assuront pas la recherche dans le texte entière."
+
+#: templates/catalogue/search_too_short.html:14
+msgid "Sorry! Search query must have at least two characters."
+msgstr "Nous sommes désolés, pour effectuer la recherche il faut entrer au moins deux caractères."
+
+#: templates/catalogue/tag_list.html:4
+msgid "See full category"
+msgstr "Voir catégorie entière"
+
+#: templates/catalogue/tagged_object_list.html:15
+msgid "Your shelf is empty"
+msgstr "Votre étagère est vide"
+
+#: templates/catalogue/tagged_object_list.html:16
+msgid "You can put a book on a shelf by entering page of the reading and clicking 'Put on the shelf'."
+msgstr "Vous pouvez mettre un livre sur l'étagère en entrant sur sa page et cliquant \"Mettre sur l'étagère\"."
+
+#: templates/catalogue/tagged_object_list.html:31
+msgid "Download all books from this shelf"
+msgstr "Télécharger tous les livres de cette étagère"
+
+#: templates/catalogue/tagged_object_list.html:35
+msgid "Choose books' formats which you want to download:"
+msgstr "Choisir le format du livre à télécharger:"
+
+#: templates/catalogue/tagged_object_list.html:36
+#: templates/catalogue/tagged_object_list.html:37
+#: templates/catalogue/tagged_object_list.html:38
+msgid "for reading"
+msgstr "pour lire"
+
+#: templates/catalogue/tagged_object_list.html:36
+msgid "and printing using"
+msgstr "et imprimer avec"
+
+#: templates/catalogue/tagged_object_list.html:37
+msgid "and editing using"
+msgstr "et rédiger avec"
+
+#: templates/catalogue/tagged_object_list.html:38
+msgid "on small displays, for example mobile phones"
+msgstr "sur petits écrans, par exemple téléphones portables"
+
+#: templates/catalogue/tagged_object_list.html:39
+#: templates/catalogue/tagged_object_list.html:40
+msgid "for listening"
+msgstr "pour écouter"
+
+#: templates/catalogue/tagged_object_list.html:39
+msgid "on favourite MP3 player"
+msgstr "sur baladeur MP3 préféré"
+
+#: templates/catalogue/tagged_object_list.html:40
+msgid "open format"
+msgstr "format ouvert"
+
+#: templates/catalogue/tagged_object_list.html:40
+msgid "Xiph.org Foundation"
+msgstr "Fondation Xiph.org "
+
+#: templates/catalogue/tagged_object_list.html:41
+#: templates/lessons/ajax_document_detail.html:3
+#: templates/lessons/document_detail.html:13
+msgid "Download"
+msgstr "Télécharger"
+
+#: templates/catalogue/tagged_object_list.html:41
+msgid "Updating list of books' formats on the shelf"
+msgstr "Mettre à jour la liste des formats des livres sur l'étagère"
+
+#: templates/catalogue/tagged_object_list.html:41
+msgid "cancel"
+msgstr "annuler"
+
+#: templates/catalogue/tagged_object_list.html:46
+msgid "Share this shelf"
+msgstr "Partager l'étagère"
+
+#: templates/catalogue/tagged_object_list.html:48
+msgid "Copy this link and share it with other people to let them see your shelf."
+msgstr "Copier le lien et partager avec les autres pour qu'ils puissent voir votre étagère"
+
+#: templates/catalogue/tagged_object_list.html:57
+msgid "Read work's study of this author on Lektury.Gazeta.pl"
+msgstr "Lire l'étude sur cet auteur sur Lektury.Gazeta.pl"
+
+#: templates/catalogue/tagged_object_list.html:60
+msgid "Read study of epoch"
+msgstr "Lire l'étude de l'époque"
+
+#: templates/catalogue/tagged_object_list.html:60
+msgid "on Lektury.Gazeta.pl"
+msgstr "sur Lektury.Gazeta.pl"
+
+#: templates/catalogue/tagged_object_list.html:67
+msgid "Read article about this author on Wikipedia"
+msgstr "Lire l'article sur cet auteur sur Wikipédia"
+
+#: templates/catalogue/tagged_object_list.html:70
+msgid "Read article about epoch"
+msgstr "Lire l'article sur cette époque"
+
+#: templates/catalogue/tagged_object_list.html:70
+msgid "on Wikipedia"
+msgstr "sur Wikipédia"
+
+#: templates/catalogue/tagged_object_list.html:80
+msgid "Delete"
+msgstr "Supprimer"
+
+#: templates/catalogue/tagged_object_list.html:88
+msgid "This author's works are copyrighted."
+msgstr "Les oeuvres de cet auteurs sont protégées par le droit d'auteur"
+
+#: templates/catalogue/tagged_object_list.html:91
+msgid "This author's works are in public domain and will be published on Internet school library of Wolne Lektury soon."
+msgstr "Les oeuvres de cet auteur sont dans le domaine public et vont être prochainement publiées dans la bibliothèque en ligne Wolne Lektury."
+
+#: templates/catalogue/tagged_object_list.html:95
+msgid "This author's works will become part of public domain and will be allowed to be published without restrictions in"
+msgstr "Les oeuvres de cet auteur seront dans le domaine public et il sera possible de les publier sans restrictions en"
+
+#: templates/catalogue/tagged_object_list.html:97
+msgid "Find out why Internet libraries can't publish this author's works."
+msgstr "Lire  pourquoi les bibliothèques en ligne ne peuvent pas publier les oeuvres de cet auteur."
+
+#: templates/catalogue/user_shelves.html:6
+msgid "remove"
+msgstr "supprimer"
+
+#: templates/catalogue/user_shelves.html:10
+msgid "You do not own any shelves. You can create one below if you want to"
+msgstr "Vous ne possédez aucune étagère. Vous pouvez en créer une en-dessus, si vous voulez."
+
+#: templates/info/base.html:10
+msgid "return to the main page"
+msgstr "retour à l'accueil"
+
+#: templates/info/join_us.html:2
+msgid ""
+"We have over 1000 works published in Wolne Lektury!\n"
+"Help us expand the library and set new readings free by\n"
+"making a donation or transferring 1% of your income tax."
+msgstr ""
+"Il y a plus de 1000 oeuvres publiées sur Lectures libres!\n"
+"Aidez-nous à développer la bibliothèque et mettre de textes nouveaux à disposition gratuite en\n"
+"faisant une donation ou en nous transmettant 1% de votre impôt sur le revenu."
+
+#: templates/info/join_us.html:5
+#: templates/info/join_us.html.py:10
+msgid "More..."
+msgstr "Plus..."
+
+#: templates/info/join_us.html:7
+msgid ""
+"Become an editor of Wolne Lektury! Find out if\n"
+"we're currently working on a reading you're looking for and prepare\n"
+"a publication by yourself by logging into the Editorial Platform."
+msgstr ""
+"Devenez un éditeur de Lectures libres! Lisez si\n"
+"nous sommes en train de préparer un texte que vous cherchez et rédigez\n"
+"une publication vous-mêmes en se connectant sur la Platforme des éditeurs."
+
+#: templates/lessons/ajax_document_detail.html:3
+#: templates/lessons/document_detail.html:13
+msgid "author"
+msgstr "auteur"
+
+#: templates/lessons/document_detail.html:9
+msgid "return to list of materials"
+msgstr "retour à la liste des matériaux"
+
+#: templates/lessons/document_list.html:7
+msgid "Hand-outs for teachers on "
+msgstr "Fiches pour les enseignants sur"
+
+#: templates/pagination/pagination.html:5
+#: templates/pagination/pagination.html:7
+msgid "previous"
+msgstr "précédent"
+
+#: templates/pagination/pagination.html:21
+#: templates/pagination/pagination.html:23
+msgid "next"
+msgstr "suivant"
+
diff --git a/wolnelektury/locale/lt/LC_MESSAGES/django.mo b/wolnelektury/locale/lt/LC_MESSAGES/django.mo
new file mode 100644 (file)
index 0000000..301573f
Binary files /dev/null and b/wolnelektury/locale/lt/LC_MESSAGES/django.mo differ
diff --git a/wolnelektury/locale/lt/LC_MESSAGES/django.po b/wolnelektury/locale/lt/LC_MESSAGES/django.po
new file mode 100644 (file)
index 0000000..42e20f1
--- /dev/null
@@ -0,0 +1,794 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+# 
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-08-25 10:23+0000\n"
+"PO-Revision-Date: 2010-08-25 10:54\n"
+"Last-Translator: <radek.czajka@gmail.com>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Translated-Using: django-rosetta 0.5.6\n"
+
+#: templates/404.html:6 templates/404.html.py:15
+msgid "Page does not exist"
+msgstr "Tinklapis neegzistuoja"
+
+#: templates/404.html:17
+msgid "We are sorry, but this page does not exist. Please check if you entered correct address or go to "
+msgstr "Atsiprašom, bet svetainė neveike"
+
+#: templates/404.html:17
+msgid "main page"
+msgstr "pagrindinis puslapis"
+
+#: templates/500.html:6 templates/500.html.py:54
+msgid "Server error"
+msgstr "serverio klaida"
+
+#: templates/500.html:55
+msgid "<p>The Wolnelektury.pl site is currently unavailable. Meanwhile, visit our <a href='http://nowoczesnapolska.org.pl'>blog</a>.</p> <p>Inform our <a href='mailto:fundacja@nowoczesnapolska.org.pl'>administrators</a> about the error.</p>"
+msgstr ""
+"<p>Servisas Laisvojiliteratura.lt yra laikinai neprieinamas. Aplankyk mūsų <a href='http://nowoczesnapolska.org.pl'>blogą</a></p>\n"
+"<p>Powiadom <a href='mailto:fundacja@nowoczesnapolska.org.pl'>administratorów</a> o błędzie.</p>"
+
+#: templates/503.html:6 templates/503.html.py:54
+msgid "Service unavailable"
+msgstr "Servisas neprieinamas"
+
+#: templates/503.html:56
+msgid "The Wolnelektury.pl site is currently unavailable due to maintainance."
+msgstr "Servisas Laisvojiliteratura.lt pastaruoju metu yra neprieinamas del konservavimo darbų"
+
+#: templates/base.html:19
+msgid "Internet Explorer cannot display this site properly. Click here to read more..."
+msgstr "Internet Explorer nie sugeba teisingai parodyti šio tinklapio. Paspausti čia, kad sužinoti daugiau..."
+
+#: templates/base.html:32
+msgid "Welcome"
+msgstr "Sveikiname"
+
+#: templates/base.html:33
+msgid "Your shelves"
+msgstr "Tavo lentynos"
+
+#: templates/base.html:35
+msgid "Administration"
+msgstr "Administracija "
+
+#: templates/base.html:37 templates/base.html.py:41
+msgid "Report a bug"
+msgstr ""
+
+#: templates/base.html:38
+msgid "Logout"
+msgstr "Atsijungti"
+
+#: templates/base.html:42 templates/base.html.py:88 templates/base.html:92
+#: templates/base.html.py:96 templates/auth/login.html:4
+#: templates/auth/login.html.py:7 templates/auth/login.html:12
+#: templates/auth/login.html.py:15
+msgid "Sign in"
+msgstr "Prisijungti  "
+
+#: templates/base.html:42 templates/base.html.py:88 templates/base.html:96
+#: templates/base.html.py:100 templates/auth/login.html:7
+#: templates/auth/login.html.py:21 templates/auth/login.html:23
+msgid "Register"
+msgstr "Registruotis "
+
+#: templates/base.html:69
+msgid ""
+"\n"
+"\t\t\t\tWolne Lektury is a project lead by <a href=\"http://nowoczesnapolska.org.pl/\">Modern Poland Foundation</a>.\n"
+"\t\t\t\tDigital reproductions are made by <a href=\"http://www.bn.org.pl/\">The National Library</a>, based on TNL resources.\n"
+"\t\t\t\tHosting <a href=\"http://eo.pl/\">EO Networks</a>.\n"
+"\t\t\t\t"
+msgstr ""
+"\n"
+"Projektą Laisvoji Literatura veda <a href=\"http://nowoczesnapolska.org.pl/\"> Šiuolaikines Lenkijos Fondas</a>. \n"
+"Skaitmenines reprodukcijas paruoše <a href=\"http://www.bn.org.pl/\">Lenkijos Tautinė Biblioteka</a> egzemplioriai paskolinti iš Lenkijos Tautinės Bibliotekos.\n"
+"Hosting <a href=\"http://eo.pl/\">EO Networks</a>."
+
+#: templates/base.html:76
+msgid ""
+"\n"
+"\t\t\t\tModern Poland Foundation, 00-514 Warsaw, ul. Marszałkowska 84/92 lok. 125, tel/fax: (22) 621-30-17\n"
+"                e-mail: <a href=\"mailto:fundacja@nowoczesnapolska.org.pl\">fundacja@nowoczesnapolska.org.pl</a>\n"
+"\t\t\t\t"
+msgstr ""
+"\n"
+"Šiuolaikines Lenkijos Fondas, 00-514 Varšuva, ul. Marszałkowska 84/92 butas 125, tel/fax: (22) 621-30-17, e-mail: <a href=\"mailto:fundacja@nowoczesnapolska.org.pl\">fundacja@nowoczesnapolska.org.pl</a>Fundacja Nowoczesna Polska, 00-514 Warszawa, ul. Marszałkowska 84/92 lok. 125, tel/fax: (22) 621-30-17, e-mail: <a href=\"mailto:fundacja@nowoczesnapolska.org.pl\">fundacja@nowoczesnapolska.org.pl</a>"
+
+#: templates/base.html:85 templates/base.html.py:106 templates/base.html:112
+#: templates/catalogue/book_detail.html:146
+#: templates/catalogue/book_fragments.html:33
+#: templates/catalogue/book_stub_detail.html:31
+#: templates/catalogue/differentiate_tags.html:23
+#: templates/catalogue/search_multiple_hits.html:29
+#: templates/catalogue/search_no_hits.html:22
+#: templates/catalogue/search_too_short.html:19
+#: templates/catalogue/tagged_object_list.html:155
+msgid "Close"
+msgstr "Uždaryk "
+
+#: templates/base.html:108 templates/base.html.py:114
+#: templates/catalogue/book_detail.html:148
+#: templates/catalogue/book_fragments.html:35
+#: templates/catalogue/book_stub_detail.html:33
+#: templates/catalogue/differentiate_tags.html:25
+#: templates/catalogue/search_multiple_hits.html:31
+#: templates/catalogue/search_no_hits.html:24
+#: templates/catalogue/search_too_short.html:21
+#: templates/catalogue/tagged_object_list.html:157
+msgid "Loading"
+msgstr "Krovimas"
+
+#: templates/admin/base_site.html:4 templates/admin/base_site.html.py:7
+msgid "Site administration"
+msgstr "Tinklapio administracija"
+
+#: templates/admin/base_site.html:8
+msgid "Translations"
+msgstr "Vertimai"
+
+#: templates/admin/catalogue/book/change_list.html:6
+msgid "Import book"
+msgstr "Importuok knygą"
+
+#: templates/auth/login.html:4
+msgid "Register on"
+msgstr "Registruotis į"
+
+#: templates/auth/login.html:9 templates/catalogue/book_detail.html:12
+#: templates/catalogue/book_fragments.html:12
+#: templates/catalogue/book_list.html:12
+#: templates/catalogue/book_stub_detail.html:12
+#: templates/catalogue/breadcrumbs.html:21
+#: templates/catalogue/main_page.html:13 templates/info/base.html:10
+#: templates/lessons/document_detail.html:9
+#: templates/lessons/document_list.html:51
+msgid "Search"
+msgstr "ieškojimas"
+
+#: templates/auth/login.html:9 templates/catalogue/book_detail.html:12
+#: templates/catalogue/book_fragments.html:12
+#: templates/catalogue/book_list.html:12
+#: templates/catalogue/book_stub_detail.html:12
+#: templates/catalogue/main_page.html:13
+#: templates/catalogue/tagged_object_list.html:43 templates/info/base.html:10
+#: templates/lessons/document_detail.html:9
+#: templates/lessons/document_list.html:51
+msgid "or"
+msgstr "arba"
+
+#: templates/auth/login.html:9 templates/catalogue/book_detail.html:12
+#: templates/catalogue/book_list.html:12
+#: templates/catalogue/book_stub_detail.html:12
+#: templates/lessons/document_list.html:51
+msgid "return to main page"
+msgstr "gryžk į pagrindinį puslapį"
+
+#: templates/catalogue/book_detail.html:5
+msgid "on WolneLektury.pl"
+msgstr "LaisvojiLiteratura.lt"
+
+#: templates/catalogue/book_detail.html:29
+msgid "Work is licensed under "
+msgstr "Kūrinys yra prieinamas su licencija "
+
+#: templates/catalogue/book_detail.html:31
+msgid "Based on"
+msgstr "Pagal motyvus"
+
+#: templates/catalogue/book_detail.html:40
+msgid "Put a book"
+msgstr "Prijung literatūrą"
+
+#: templates/catalogue/book_detail.html:40
+msgid "on the shelf!"
+msgstr "į lentyną!"
+
+#: templates/catalogue/book_detail.html:44
+msgid "Read online"
+msgstr "Skaityk online"
+
+#: templates/catalogue/book_detail.html:47
+msgid "Download PDF"
+msgstr "atsisiųsk PDF failą"
+
+#: templates/catalogue/book_detail.html:50
+msgid "Download EPUB"
+msgstr "atsisiųsk EPUB failą"
+
+#: templates/catalogue/book_detail.html:53
+msgid "Download ODT"
+msgstr "atsisiųsk ODT failą"
+
+#: templates/catalogue/book_detail.html:56
+msgid "Download TXT"
+msgstr "atsisiųsk TXT failą"
+
+#: templates/catalogue/book_detail.html:61
+msgid "Artist"
+msgstr "artistas"
+
+#: templates/catalogue/book_detail.html:63
+msgid "Director"
+msgstr "vadovas"
+
+#: templates/catalogue/book_detail.html:67
+msgid "Download MP3"
+msgstr "atsisiųsk MP3 failą"
+
+#: templates/catalogue/book_detail.html:68
+msgid "Download Ogg Vorbis"
+msgstr "atsisiųsk Ogg Vorbis failą"
+
+#: templates/catalogue/book_detail.html:95
+msgid "Details"
+msgstr "detalės "
+
+#: templates/catalogue/book_detail.html:99
+msgid "Author"
+msgstr "Autorius"
+
+#: templates/catalogue/book_detail.html:105
+msgid "Epoch"
+msgstr "Gadynė"
+
+#: templates/catalogue/book_detail.html:111
+msgid "Kind"
+msgstr "Rūšis  "
+
+#: templates/catalogue/book_detail.html:117
+msgid "Genre"
+msgstr "Padermė "
+
+#: templates/catalogue/book_detail.html:123
+msgid "Other resources"
+msgstr "Kitose vietose"
+
+#: templates/catalogue/book_detail.html:125
+msgid "Book on project's wiki"
+msgstr "Sukurk straipsnį apie knygą vikiprojekte"
+
+#: templates/catalogue/book_detail.html:126
+msgid "Source of the book"
+msgstr "Literaturos šaltinis"
+
+#: templates/catalogue/book_detail.html:128
+msgid "Book description on Lektury.Gazeta.pl"
+msgstr "Literaturos aprašymas Lektury.Gazeta.pl"
+
+#: templates/catalogue/book_detail.html:131
+msgid "Book description on Wikipedia"
+msgstr "Literaturos aprašymas Vikipedijoje"
+
+#: templates/catalogue/book_detail.html:136
+msgid "Work's themes "
+msgstr "Kūrinio motyvai"
+
+#: templates/catalogue/book_fragments.html:5
+#: templates/catalogue/book_fragments.html:10
+msgid "Theme"
+msgstr "Motyvas"
+
+#: templates/catalogue/book_fragments.html:5
+#: templates/catalogue/book_fragments.html:10
+msgid "in work "
+msgstr "kurinyje"
+
+#: templates/catalogue/book_fragments.html:5
+msgid "on"
+msgstr "ant"
+
+#: templates/catalogue/book_fragments.html:12
+msgid "return to book's page"
+msgstr "Sugryžk į pagrindinį puslapį "
+
+#: templates/catalogue/book_fragments.html:26
+msgid "See description"
+msgstr "Aprašymas"
+
+#: templates/catalogue/book_fragments.html:26
+msgid "of the book "
+msgstr "kūrinio"
+
+#: templates/catalogue/book_list.html:7
+msgid "Listing of all works on WolneLektury.pl"
+msgstr "Kūriniu sąrašas WolneLektury.pl"
+
+#: templates/catalogue/book_list.html:10
+msgid "Listing of all works"
+msgstr "Kūriniu sąrašas"
+
+#: templates/catalogue/book_sets.html:2
+msgid "Put a book on the shelf!"
+msgstr "Įmesk knyga į lentyną!  "
+
+#: templates/catalogue/book_sets.html:3 templates/catalogue/book_sets.html:6
+#: templates/catalogue/fragment_sets.html:16
+msgid "Create new shelf"
+msgstr "Sukurk naują lentyną"
+
+#: templates/catalogue/book_sets.html:10
+msgid "You do not have any shelves. You can create one below, if you want to."
+msgstr "Neturi nei vienos lentynos. Jeigu nori gali žemiau sukurti naują lentyną."
+
+#: templates/catalogue/book_sets.html:15 templates/catalogue/book_short.html:4
+msgid "Put on the shelf!"
+msgstr "Įmesk į lentyną! "
+
+#: templates/catalogue/book_short.html:14
+msgid "Jump to"
+msgstr "Santrumpa"
+
+#: templates/catalogue/book_short.html:16
+msgid "Categories"
+msgstr "Kūrinio kategorija  "
+
+#: templates/catalogue/book_stub_detail.html:17
+msgid "This work is in public domain and will be published on Internet school library of Wolne Lektury soon."
+msgstr "Šis kūrinys randasi viešojoje srityje bet  ne už ilgo bys paviešintas Laisvosios Literaturos internetinėje bibliotekoje. "
+
+#: templates/catalogue/book_stub_detail.html:20
+msgid "This work will become part of public domain and will be allowed to be published without restrictions in"
+msgstr "Šis kūrinys atsiras viešiojoje sryty ir gales buti viešintas be jokiu apriboimu už"
+
+#: templates/catalogue/book_stub_detail.html:22
+msgid "Find out why Internet libraries can't publish this work."
+msgstr "Sužinok kodėl internetines bibliotekos neprileidzia šio autoraus kūriniu."
+
+#: templates/catalogue/book_stub_detail.html:24
+msgid "This work is copyrighted."
+msgstr "Šis kūrinis apimtas autoriaus teisę."
+
+#: templates/catalogue/book_text.html:17
+msgid "Table of contents"
+msgstr "Turinys"
+
+#: templates/catalogue/book_text.html:18
+#: templates/catalogue/tagged_object_list.html:146
+msgid "Themes"
+msgstr "Motyai"
+
+#: templates/catalogue/differentiate_tags.html:13
+msgid "The criteria are ambiguous. Please select one of the following options:"
+msgstr ""
+
+#: templates/catalogue/folded_tag_list.html:4
+msgid "Show full category"
+msgstr "Apžiūrek visą kategoriją"
+
+#: templates/catalogue/folded_tag_list.html:13
+#: templates/catalogue/main_page.html:43 templates/catalogue/main_page.html:48
+#: templates/catalogue/main_page.html:87
+#: templates/catalogue/main_page.html:270
+#: templates/catalogue/main_page.html:279
+msgid "See more"
+msgstr "Apžiūrėk daugiau"
+
+#: templates/catalogue/folded_tag_list.html:22
+#: templates/catalogue/main_page.html:250
+msgid "Hide"
+msgstr "Suvyniok"
+
+#: templates/catalogue/fragment_sets.html:2
+msgid "Shelves containing fragment"
+msgstr "Lentynos turinčios fragmentus "
+
+#: templates/catalogue/fragment_sets.html:4
+#: templates/catalogue/main_page.html:28
+msgid "You do not own any shelves. You can create one below, if you want to."
+msgstr "Neturi nei vienos lentynos. Jeigu nori gali žemiau sukurti naują lentyną."
+
+#: templates/catalogue/fragment_sets.html:9
+msgid "Save all shelves"
+msgstr "Užsirašyk lentyną "
+
+#: templates/catalogue/fragment_short.html:7
+msgid "Expand fragment"
+msgstr "Išplėsk fragmentą"
+
+#: templates/catalogue/fragment_short.html:13
+msgid "Hide fragment"
+msgstr "Suvyniok fragmentą"
+
+#: templates/catalogue/fragment_short.html:18
+msgid "See in a book"
+msgstr "Surask knygoje"
+
+#: templates/catalogue/main_page.html:13
+msgid "check list of books"
+msgstr "patikrink knygų sąrašą"
+
+#: templates/catalogue/main_page.html:13
+msgid "in our repository"
+msgstr "mūsų knygų rinkiny"
+
+#: templates/catalogue/main_page.html:17
+msgid "Browse books by categories"
+msgstr "Peržiurinek literaturą pagal išrinktą kategoriją"
+
+#: templates/catalogue/main_page.html:19
+#: templates/catalogue/user_shelves.html:2
+msgid "Your shelves with books"
+msgstr "Tavo lentynos su literatura"
+
+#: templates/catalogue/main_page.html:24
+msgid "delete"
+msgstr "pašalink"
+
+#: templates/catalogue/main_page.html:33
+#: templates/catalogue/user_shelves.html:15
+msgid "Create shelf"
+msgstr "Sukurk lentyną"
+
+#: templates/catalogue/main_page.html:37
+msgid "Create your own book set. You can share it with friends by sending them link to your shelf."
+msgstr "Sukurk savo knygų rinkiny. Gali juo veliau pasidalinti su kitais, persiūsk jiems nuorodą i tavo lentyną."
+
+#: templates/catalogue/main_page.html:38
+msgid "You need to "
+msgstr "Gali"
+
+#: templates/catalogue/main_page.html:38
+msgid "sign in"
+msgstr "Prisijungti  "
+
+#: templates/catalogue/main_page.html:38
+msgid "to manage your shelves."
+msgstr "Kad valdti savo lentynom."
+
+#: templates/catalogue/main_page.html:41
+#: templates/lessons/document_list.html:49
+msgid "Hand-outs for teachers"
+msgstr "Pagalbinės medžiagos mokytojams"
+
+#: templates/catalogue/main_page.html:42
+msgid "Lessons' prospects and other ideas for using Wolnelektury.pl for teaching."
+msgstr "Pamokų scenarijai ir kiti sumanymai kaip panaudoti servisą LaisvojiLiteratura.lt mokslui."
+
+#: templates/catalogue/main_page.html:47
+msgid "are professional recordings of literary texts from our repository, available on free license in MP3 and Ogg Vorbis formats as well as in DAISY system."
+msgstr "Tai profesjonalus literaturinių tekstų garso įrašai, mūsų rinkinių laisvai prieinami šiuose įrašymo formatouse: MP3, Ogg Vorbis ir sistema DAISY."
+
+#: templates/catalogue/main_page.html:54
+#: templates/catalogue/tagged_object_list.html:128
+msgid "Authors"
+msgstr "Autoriai"
+
+#: templates/catalogue/main_page.html:58
+#: templates/catalogue/tagged_object_list.html:132
+msgid "Kinds"
+msgstr "Rušys"
+
+#: templates/catalogue/main_page.html:62
+#: templates/catalogue/tagged_object_list.html:136
+msgid "Genres"
+msgstr "Padermės "
+
+#: templates/catalogue/main_page.html:66
+#: templates/catalogue/tagged_object_list.html:140
+msgid "Epochs"
+msgstr "Gadynės"
+
+#: templates/catalogue/main_page.html:72
+msgid "Themes and topics"
+msgstr "Motyvai ir temos"
+
+#: templates/catalogue/main_page.html:75
+msgid "Themes groups"
+msgstr "Motyvų grupė"
+
+#: templates/catalogue/main_page.html:260
+msgid "News"
+msgstr "žinios"
+
+#: templates/catalogue/main_page.html:264
+msgid "See our blog"
+msgstr "Aplankyk mūsų blogą"
+
+#: templates/catalogue/main_page.html:267
+msgid "You can help us!"
+msgstr "Gali mums padėti!"
+
+#: templates/catalogue/main_page.html:268
+msgid "We try our best to elaborate works appended to our library. It is possible only due to support of our volunteers."
+msgstr "Dėka savanorių apršymai kūriniu, kurie yra prijungemi i mūsų biblioteką yra kiekvieną kartą kruopščiai paruošti"
+
+#: templates/catalogue/main_page.html:269
+msgid "We invite people who want to take part in developing Internet school library Wolne Lektury."
+msgstr "Kviečiame visus, kurie nori kartu su mumi kurti mokykline internetine biblioteką Laisvoji Literatura."
+
+#: templates/catalogue/main_page.html:273
+msgid "About us"
+msgstr "Apie projektą"
+
+#: templates/catalogue/main_page.html:275
+msgid ""
+"\n"
+"\t\t\tInternet library with school readings “Wolne Lektury” (<a href=\"http://wolnelektury.pl\">www.wolnelektury.pl</a>) is a project made by Modern Poland Foundation. It started in 2007 and shares school readings, which are recommended by Ministry of National Education and are in public domain.\n"
+"\t\t\t"
+msgstr ""
+"\n"
+"\t\t\tInternetine biblioteka \"Laisvoji Literatura\" (www.laisvojiliteratura.lt) siūlanti mokyklinę literaturą -          tai Šiuolaikines Lenkijos Fondasto projektas. Fondas veike nou 2007 metų ir savo rinkinuose turi mokyklinę literaturą,          kuri yra rekomenduojama per Švietimo ir Mokslo Ministeriją ir kuri jau\tpateko į viešią Interneto svetainę.\n"
+"\t\t\t"
+
+#: templates/catalogue/search_multiple_hits.html:5
+#: templates/catalogue/search_too_short.html:5
+msgid "Searching in"
+msgstr "Ieškoimas"
+
+#: templates/catalogue/search_multiple_hits.html:14
+msgid "More than one result matching the criteria found."
+msgstr "Surasta daugiau nei vienas paješku rezultatas"
+
+#: templates/catalogue/search_no_hits.html:5
+msgid "Search in WolneLektury.pl"
+msgstr "Ieškok šiame tinklapyje LasvojiLiteratura.lt "
+
+#: templates/catalogue/search_no_hits.html:14
+#: templates/catalogue/tagged_object_list.html:116
+msgid "Sorry! Search cirteria did not match any resources."
+msgstr "Atsiprašom! Trūksta rezultatų atitinkančių užklausimui. "
+
+#: templates/catalogue/search_no_hits.html:16
+msgid ""
+"Search engine supports following criteria: title, author, theme/topic, epoch, kind and genre.\n"
+"\t\tAs for now we do not support full text search."
+msgstr "Paieškos programa aptarnauja šiuos  kriterijusi: kūrinio pavadinimas, autorius,  motyvas/tema, gadynė, rušys ir padermė. Dabartiniu metu neaptarnaujame paieškos frazių kūrinio tekste. "
+
+#: templates/catalogue/search_too_short.html:14
+msgid "Sorry! Search query must have at least two characters."
+msgstr "Atsiprašom! Užklausimas turi susideti iš ne mažiau nei dviejų  ženklų."
+
+#: templates/catalogue/tag_list.html:4
+msgid "See full category"
+msgstr "Apžiurek visą kategoriją"
+
+#: templates/catalogue/tagged_object_list.html:15
+msgid "Your shelf is empty"
+msgstr "Tavo lentyna yra tušia"
+
+#: templates/catalogue/tagged_object_list.html:16
+msgid "You can put a book on a shelf by entering page of the reading and clicking 'Put on the shelf'."
+msgstr "Gali įmesti knygą į lentyną,  įeik į knygos tinklapį ir išrink \"Į lentyną\".    "
+
+#: templates/catalogue/tagged_object_list.html:32
+msgid "Download all books from this shelf"
+msgstr "Persisiųsk visas knygas iš šios lentynos"
+
+#: templates/catalogue/tagged_object_list.html:36
+msgid "Choose books' formats which you want to download:"
+msgstr "Pasirink knygos persiuntimo formatą:"
+
+#: templates/catalogue/tagged_object_list.html:37
+#: templates/catalogue/tagged_object_list.html:39
+#: templates/catalogue/tagged_object_list.html:40
+msgid "for reading"
+msgstr "į skaitimą"
+
+#: templates/catalogue/tagged_object_list.html:37
+msgid "and printing using"
+msgstr "ir spausdinti su pagalbą"
+
+#: templates/catalogue/tagged_object_list.html:39
+msgid "and editing using"
+msgstr "ir edituoti su pagalbą "
+
+#: templates/catalogue/tagged_object_list.html:40
+msgid "on small displays, for example mobile phones"
+msgstr "ant displėjaus, pvz. mobilaus telefono "
+
+#: templates/catalogue/tagged_object_list.html:41
+#: templates/catalogue/tagged_object_list.html:42
+msgid "for listening"
+msgstr "klausyti"
+
+#: templates/catalogue/tagged_object_list.html:41
+msgid "on favourite MP3 player"
+msgstr "numylėtam MP3 grotuve"
+
+#: templates/catalogue/tagged_object_list.html:42
+msgid "open format"
+msgstr "atviras formatas"
+
+#: templates/catalogue/tagged_object_list.html:42
+msgid "Xiph.org Foundation"
+msgstr "Fondo Xiph.Org"
+
+#: templates/catalogue/tagged_object_list.html:43
+#: templates/lessons/ajax_document_detail.html:3
+#: templates/lessons/document_detail.html:13
+msgid "Download"
+msgstr "Atsisiųsti"
+
+#: templates/catalogue/tagged_object_list.html:43
+msgid "Updating list of books' formats on the shelf"
+msgstr "Atnaujinti knygų formatų sąrašą lentynose. "
+
+#: templates/catalogue/tagged_object_list.html:43
+msgid "cancel"
+msgstr "anuliuoti"
+
+#: templates/catalogue/tagged_object_list.html:48
+msgid "Share this shelf"
+msgstr "Pasidalink šia lentyną."
+
+#: templates/catalogue/tagged_object_list.html:50
+msgid "Copy this link and share it with other people to let them see your shelf."
+msgstr "Sukopijuok šią nuorodą ir persiusk ją tiems, su kuriais noru pasidalinti savo lentyną."
+
+#: templates/catalogue/tagged_object_list.html:60
+msgid "Read work's study of this author on Lektury.Gazeta.pl"
+msgstr "Perskaityk šio autoriaus aprašymą tinklapį Lektury.Gazeta.pl"
+
+#: templates/catalogue/tagged_object_list.html:62
+#, fuzzy, python-format
+msgid "Read study of epoch %(last_tag)s on Lektury.Gazeta.pl"
+msgstr "Perskaityk šio autoriaus aprašymą tinklapį Lektury.Gazeta.pl"
+
+#: templates/catalogue/tagged_object_list.html:64
+#, fuzzy, python-format
+msgid "Read study of kind %(last_tag)s on Lektury.Gazeta.pl"
+msgstr "Perskaityk šio autoriaus aprašymą tinklapį Lektury.Gazeta.pl"
+
+#: templates/catalogue/tagged_object_list.html:66
+#, fuzzy, python-format
+msgid "Read study of genre %(last_tag)s on Lektury.Gazeta.pl"
+msgstr "Perskaityk šio autoriaus aprašymą tinklapį Lektury.Gazeta.pl"
+
+#: templates/catalogue/tagged_object_list.html:68
+#, fuzzy
+msgid "Read related study on Lektury.Gazeta.pl"
+msgstr "Perskaityk šio autoriaus aprašymą tinklapį Lektury.Gazeta.pl"
+
+#: templates/catalogue/tagged_object_list.html:76
+msgid "Read article about this author on Wikipedia"
+msgstr "Perskaityk straipsny apie autoriu Wikipedijoje"
+
+#: templates/catalogue/tagged_object_list.html:78
+#, fuzzy, python-format
+msgid "Read article about epoch %(last_tag)s on Wikipedia"
+msgstr "Perskaityk straipsny apie autoriu Wikipedijoje"
+
+#: templates/catalogue/tagged_object_list.html:80
+#, fuzzy, python-format
+msgid "Read article about kind %(last_tag)s on Wikipedia"
+msgstr "Perskaityk straipsny apie autoriu Wikipedijoje"
+
+#: templates/catalogue/tagged_object_list.html:82
+#, fuzzy, python-format
+msgid "Read article about genre %(last_tag)s on Wikipedia"
+msgstr "Perskaityk straipsny apie autoriu Wikipedijoje"
+
+#: templates/catalogue/tagged_object_list.html:84
+#, fuzzy
+msgid "Read related article on Wikipedia"
+msgstr "Perskaityk straipsny apie autoriu Wikipedijoje"
+
+#: templates/catalogue/tagged_object_list.html:94
+msgid "Delete"
+msgstr "pašalinti "
+
+#: templates/catalogue/tagged_object_list.html:102
+msgid "This author's works are copyrighted."
+msgstr "Šio autoriaus  kūriniai yra saugomi nepažeidžiant autorių teisės"
+
+#: templates/catalogue/tagged_object_list.html:105
+msgid "This author's works are in public domain and will be published on Internet school library of Wolne Lektury soon."
+msgstr "Šio autoriaus kūrinys jau yra viešoje Interneto svetaineję ir neužilgo bus paplatintas internetine bibliotekoje  Laisvoji Literatura"
+
+#: templates/catalogue/tagged_object_list.html:109
+msgid "This author's works will become part of public domain and will be allowed to be published without restrictions in"
+msgstr "Šio autoriaus kūrinys  neužilgo atsiras viešoje Interneto svetaineję ir gales but paplatinti be jokiu ribų"
+
+#: templates/catalogue/tagged_object_list.html:111
+msgid "Find out why Internet libraries can't publish this author's works."
+msgstr "Sužinok kodel šio autoriaus kūriniai negali būti platinti internetineje bibliotekoje"
+
+#: templates/catalogue/user_shelves.html:6
+msgid "remove"
+msgstr "panaikinti"
+
+#: templates/catalogue/user_shelves.html:10
+msgid "You do not own any shelves. You can create one below if you want to"
+msgstr "Neturi nei vienos lentynos. Jeigu nori gali žemiau sukurti naują lentyną."
+
+#: templates/info/base.html:10
+msgid "return to the main page"
+msgstr "sugryžk į pagrindinį puslapį "
+
+#: templates/info/join_us.html:2
+msgid ""
+"We have over 1000 works published in Wolne Lektury!\n"
+"Help us expand the library and set new readings free by\n"
+"making a donation or transferring 1% of your income tax."
+msgstr "Tinklapyje Laisvoji Literatura rasi virš 1000 kūrinių! Padek mums vystytis ir plesti literatura paskirk 1% pajamų mokesčio bibliotekai"
+
+#: templates/info/join_us.html:5 templates/info/join_us.html.py:10
+msgid "More..."
+msgstr "Daugiau..."
+
+#: templates/info/join_us.html:7
+msgid ""
+"Become an editor of Wolne Lektury! Find out if\n"
+"we're currently working on a reading you're looking for and prepare\n"
+"a publication by yourself by logging into the Editorial Platform."
+msgstr "Gali likti redaktoriumi Laisvojos Literaturos! Patikrink, ar pastaruoju metu ruošama yra publikacija jūsų  ieškamos knygos ir savarankiškai  paruošk publikacija – prisijung prie Redakcines Platformos."
+
+#: templates/lessons/ajax_document_detail.html:3
+#: templates/lessons/document_detail.html:13
+msgid "author"
+msgstr "autorius"
+
+#: templates/lessons/document_detail.html:9
+msgid "return to list of materials"
+msgstr "gryžk i medžiagų srašą"
+
+#: templates/lessons/document_list.html:7
+msgid "Hand-outs for teachers on "
+msgstr "Pagalbines medžiagos mokytojams"
+
+#: templates/pagination/pagination.html:5
+#: templates/pagination/pagination.html:7
+msgid "previous"
+msgstr "ankstesnis"
+
+#: templates/pagination/pagination.html:21
+#: templates/pagination/pagination.html:23
+msgid "next"
+msgstr "sekantis "
+
+#~ msgid "Polish"
+#~ msgstr "Lenkų"
+
+#~ msgid "German"
+#~ msgstr "Vokiečių"
+
+#~ msgid "English"
+#~ msgstr "Anglų "
+
+#~ msgid "Lithuanian"
+#~ msgstr "Lietuvių"
+
+#~ msgid "French"
+#~ msgstr "Prancūzų"
+
+#~ msgid "Russian"
+#~ msgstr "Rusų"
+
+#~ msgid "Spanish"
+#~ msgstr "Ispanų"
+
+#~ msgid "Ukrainian"
+#~ msgstr "Ukrainiečių"
+
+#~ msgid "Choose your interface language: "
+#~ msgstr "Pasirink sąsajos kalbą:"
+
+#~ msgid "Choose language"
+#~ msgstr "Pasirink kalbą"
+
+#~ msgid "Hide description"
+#~ msgstr "Suvyniok aprašymą "
+
+#~ msgid "Read study of epoch"
+#~ msgstr "Perskaityk gadynės aprašymą"
+
+#~ msgid "on Lektury.Gazeta.pl"
+#~ msgstr "tinklapyje Lektury.Gazeta.pl"
+
+#~ msgid "Read article about epoch"
+#~ msgstr "Perskaityk straipsnį apie gadynę "
+
+#~ msgid "on Wikipedia"
+#~ msgstr "Vikipedijoje"
index d0ea820..5d4b75d 100644 (file)
Binary files a/wolnelektury/locale/pl/LC_MESSAGES/django.mo and b/wolnelektury/locale/pl/LC_MESSAGES/django.mo differ
index 4934745..72a3e74 100644 (file)
@@ -7,148 +7,899 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2008-09-04 06:17-0500\n"
-"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
-"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"POT-Creation-Date: 2010-08-25 10:23+0000\n"
+"PO-Revision-Date: 2010-08-25 10:59\n"
+"Last-Translator: <radek.czajka@gmail.com>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
+"X-Translated-Using: django-rosetta 0.5.6\n"
 
-#: catalogue/models.py:15
-msgid "author"
-msgstr "autor"
+#: localsettings.py:37
+msgid "Polish"
+msgstr "polski"
+
+#: localsettings.py:38
+msgid "German"
+msgstr "niemiecki"
+
+#: localsettings.py:39
+msgid "English"
+msgstr "angielski"
+
+#: localsettings.py:40
+msgid "Lithuanian"
+msgstr "litewski"
+
+#: localsettings.py:41
+msgid "French"
+msgstr "francuski"
+
+#: localsettings.py:42
+msgid "Russian"
+msgstr "rosyjski"
+
+#: localsettings.py:43
+msgid "Spanish"
+msgstr "hiszpański"
+
+#: localsettings.py:44
+msgid "Ukrainian"
+msgstr "ukraiński"
+
+#: templates/404.html:6 templates/404.html.py:15
+msgid "Page does not exist"
+msgstr "Podana strona nie istnieje"
+
+#: templates/404.html:17
+msgid ""
+"We are sorry, but this page does not exist. Please check if you entered "
+"correct address or go to "
+msgstr ""
+"Przepraszamy, ale ta strona nie istnieje. Sprawdź czy podałeś dobry adres, "
+"lub przejdź do"
 
-#: catalogue/models.py:16
-msgid "epoch"
-msgstr "epoka"
+#: templates/404.html:17
+msgid "main page"
+msgstr "strony głównej"
+
+#: templates/500.html:6 templates/500.html.py:54
+msgid "Server error"
+msgstr "Błąd serwera"
+
+#: templates/500.html:55
+msgid ""
+"<p>The Wolnelektury.pl site is currently unavailable. Meanwhile, visit our "
+"<a href='http://nowoczesnapolska.org.pl'>blog</a>.</p> <p>Inform our <a "
+"href='mailto:fundacja@nowoczesnapolska.org.pl'>administrators</a> about the "
+"error.</p>"
+msgstr ""
+"<p>Serwis Wolnelektury.pl jest chwilowo niedostępny. Odwiedź naszego <a "
+"href='http://nowoczesnapolska.org.pl'>bloga</a></p>\n"
+"<p>Powiadom <a href='mailto:fundacja@nowoczesnapolska.org."
+"pl'>administratorów</a> o błędzie.</p>"
+
+#: templates/503.html:6 templates/503.html.py:54
+msgid "Service unavailable"
+msgstr "Serwis niedostępny"
+
+#: templates/503.html:56
+msgid "The Wolnelektury.pl site is currently unavailable due to maintainance."
+msgstr ""
+"Serwis Wolnelektury.pl jest obecnie niedostępny z powodu prac "
+"konserwacyjnych."
+
+#: templates/base.html:19
+msgid ""
+"Internet Explorer cannot display this site properly. Click here to read "
+"more..."
+msgstr ""
+"Internet Explorer nie potrafi poprawnie wyświetlić tej strony. Kliknij "
+"tutaj, aby dowiedzieć się więcej..."
+
+#: templates/base.html:32
+msgid "Welcome"
+msgstr "Witaj"
+
+#: templates/base.html:33
+msgid "Your shelves"
+msgstr "Twoje półki"
+
+#: templates/base.html:35
+msgid "Administration"
+msgstr "Administracja"
+
+#: templates/base.html:37 templates/base.html.py:41
+msgid "Report a bug"
+msgstr "Zgłoś błąd"
+
+#: templates/base.html:38
+msgid "Logout"
+msgstr "Wyloguj"
+
+#: templates/base.html:42 templates/base.html.py:88 templates/base.html:92
+#: templates/base.html.py:96 templates/auth/login.html:4
+#: templates/auth/login.html.py:7 templates/auth/login.html:12
+#: templates/auth/login.html.py:15
+msgid "Sign in"
+msgstr "Zaloguj się"
+
+#: templates/base.html:42 templates/base.html.py:88 templates/base.html:96
+#: templates/base.html.py:100 templates/auth/login.html:7
+#: templates/auth/login.html.py:21 templates/auth/login.html:23
+msgid "Register"
+msgstr "Załóż konto"
+
+#: templates/base.html:69
+msgid ""
+"\n"
+"\t\t\t\tWolne Lektury is a project lead by <a href=\"http://nowoczesnapolska."
+"org.pl/\">Modern Poland Foundation</a>.\n"
+"\t\t\t\tDigital reproductions are made by <a href=\"http://www.bn.org.pl/"
+"\">The National Library</a>, based on TNL resources.\n"
+"\t\t\t\tHosting <a href=\"http://eo.pl/\">EO Networks</a>.\n"
+"\t\t\t\t"
+msgstr ""
+"\n"
+"Wolne Lektury to projekt prowadzony przez <a href=\"http://nowoczesnapolska."
+"org.pl/\">Fundację Nowoczesna Polska</a>. \n"
+"Reprodukcje cyfrowe wykonane przez <a href=\"http://www.bn.org.pl/"
+"\">Bibliotekę Narodową</a> z egzemplarzy pochodzących ze zbiorów BN.\n"
+"Hosting <a href=\"http://eo.pl/\">EO Networks</a>. "
+
+#: templates/base.html:76
+msgid ""
+"\n"
+"\t\t\t\tModern Poland Foundation, 00-514 Warsaw, ul. Marszałkowska 84/92 "
+"lok. 125, tel/fax: (22) 621-30-17\n"
+"                e-mail: <a href=\"mailto:fundacja@nowoczesnapolska.org.pl"
+"\">fundacja@nowoczesnapolska.org.pl</a>\n"
+"\t\t\t\t"
+msgstr ""
+"\n"
+"Fundacja Nowoczesna Polska, 00-514 Warszawa, ul. Marszałkowska 84/92 lok. "
+"125, tel/fax: (22) 621-30-17, e-mail: <a href=\"mailto:"
+"fundacja@nowoczesnapolska.org.pl\">fundacja@nowoczesnapolska.org.pl</a>"
+
+#: templates/base.html:85 templates/base.html.py:106 templates/base.html:112
+#: templates/catalogue/book_detail.html:146
+#: templates/catalogue/book_fragments.html:33
+#: templates/catalogue/book_stub_detail.html:31
+#: templates/catalogue/differentiate_tags.html:23
+#: templates/catalogue/search_multiple_hits.html:29
+#: templates/catalogue/search_no_hits.html:22
+#: templates/catalogue/search_too_short.html:19
+#: templates/catalogue/tagged_object_list.html:155
+msgid "Close"
+msgstr "Zamknij"
+
+#: templates/base.html:108 templates/base.html.py:114
+#: templates/catalogue/book_detail.html:148
+#: templates/catalogue/book_fragments.html:35
+#: templates/catalogue/book_stub_detail.html:33
+#: templates/catalogue/differentiate_tags.html:25
+#: templates/catalogue/search_multiple_hits.html:31
+#: templates/catalogue/search_no_hits.html:24
+#: templates/catalogue/search_too_short.html:21
+#: templates/catalogue/tagged_object_list.html:157
+msgid "Loading"
+msgstr "Ładowanie"
+
+#: templates/admin/base_site.html:4 templates/admin/base_site.html.py:7
+msgid "Site administration"
+msgstr "Administracja stroną"
+
+#: templates/admin/base_site.html:8
+msgid "Translations"
+msgstr "Tłumaczenia"
+
+#: templates/admin/catalogue/book/change_list.html:6
+msgid "Import book"
+msgstr "Importuj książkę"
+
+#: templates/auth/login.html:4
+msgid "Register on"
+msgstr "Zarejestruj się w"
+
+#: templates/auth/login.html:9 templates/catalogue/book_detail.html:12
+#: templates/catalogue/book_fragments.html:12
+#: templates/catalogue/book_list.html:12
+#: templates/catalogue/book_stub_detail.html:12
+#: templates/catalogue/breadcrumbs.html:21
+#: templates/catalogue/main_page.html:13 templates/info/base.html:10
+#: templates/lessons/document_detail.html:9
+#: templates/lessons/document_list.html:51
+msgid "Search"
+msgstr "Szukaj"
+
+#: templates/auth/login.html:9 templates/catalogue/book_detail.html:12
+#: templates/catalogue/book_fragments.html:12
+#: templates/catalogue/book_list.html:12
+#: templates/catalogue/book_stub_detail.html:12
+#: templates/catalogue/main_page.html:13
+#: templates/catalogue/tagged_object_list.html:43 templates/info/base.html:10
+#: templates/lessons/document_detail.html:9
+#: templates/lessons/document_list.html:51
+msgid "or"
+msgstr "lub"
+
+#: templates/auth/login.html:9 templates/catalogue/book_detail.html:12
+#: templates/catalogue/book_list.html:12
+#: templates/catalogue/book_stub_detail.html:12
+#: templates/lessons/document_list.html:51
+msgid "return to main page"
+msgstr "wróć do strony głównej"
+
+#: templates/catalogue/book_detail.html:5
+msgid "on WolneLektury.pl"
+msgstr "w WolneLektury.pl"
+
+#: templates/catalogue/book_detail.html:29
+msgid "Work is licensed under "
+msgstr "Utwór jest udostępniony na licencji"
+
+#: templates/catalogue/book_detail.html:31
+msgid "Based on"
+msgstr "Na podstawie"
+
+#: templates/catalogue/book_detail.html:40
+msgid "Put a book"
+msgstr "Wrzuć lekturę"
+
+#: templates/catalogue/book_detail.html:40
+msgid "on the shelf!"
+msgstr "na półkę!"
+
+#: templates/catalogue/book_detail.html:44
+msgid "Read online"
+msgstr "Czytaj online"
+
+#: templates/catalogue/book_detail.html:47
+msgid "Download PDF"
+msgstr "Pobierz plik PDF"
+
+#: templates/catalogue/book_detail.html:50
+msgid "Download EPUB"
+msgstr "Pobierz plik EPUB"
+
+#: templates/catalogue/book_detail.html:53
+msgid "Download ODT"
+msgstr "Pobierz plik ODT"
+
+#: templates/catalogue/book_detail.html:56
+msgid "Download TXT"
+msgstr "Pobierz plik TXT"
+
+#: templates/catalogue/book_detail.html:61
+msgid "Artist"
+msgstr "Czyta"
+
+#: templates/catalogue/book_detail.html:63
+msgid "Director"
+msgstr "Reżyseruje"
+
+#: templates/catalogue/book_detail.html:67
+msgid "Download MP3"
+msgstr "Pobierz plik MP3"
+
+#: templates/catalogue/book_detail.html:68
+msgid "Download Ogg Vorbis"
+msgstr "Pobierz plik Ogg Vorbis"
+
+#: templates/catalogue/book_detail.html:95
+msgid "Details"
+msgstr "O utworze"
+
+#: templates/catalogue/book_detail.html:99
+msgid "Author"
+msgstr "Autor"
+
+#: templates/catalogue/book_detail.html:105
+msgid "Epoch"
+msgstr "Epoka"
+
+#: templates/catalogue/book_detail.html:111
+msgid "Kind"
+msgstr "Rodzaj"
+
+#: templates/catalogue/book_detail.html:117
+msgid "Genre"
+msgstr "Gatunek"
+
+#: templates/catalogue/book_detail.html:123
+msgid "Other resources"
+msgstr "W innych miejscach"
+
+#: templates/catalogue/book_detail.html:125
+msgid "Book on project's wiki"
+msgstr "Lektura na wiki projektu"
+
+#: templates/catalogue/book_detail.html:126
+msgid "Source of the book"
+msgstr "Źródło lektury"
+
+#: templates/catalogue/book_detail.html:128
+msgid "Book description on Lektury.Gazeta.pl"
+msgstr "Opis lektury w Lektury.Gazeta.pl"
+
+#: templates/catalogue/book_detail.html:131
+msgid "Book description on Wikipedia"
+msgstr "Opis lektury w Wikipedii"
+
+#: templates/catalogue/book_detail.html:136
+msgid "Work's themes "
+msgstr "Motywy w utworze"
 
-#: catalogue/models.py:17
-msgid "kind"
-msgstr "rodzaj"
+#: templates/catalogue/book_fragments.html:5
+#: templates/catalogue/book_fragments.html:10
+msgid "Theme"
+msgstr "Motyw"
+
+#: templates/catalogue/book_fragments.html:5
+#: templates/catalogue/book_fragments.html:10
+msgid "in work "
+msgstr "w utworze"
+
+#: templates/catalogue/book_fragments.html:5
+msgid "on"
+msgstr "w"
+
+#: templates/catalogue/book_fragments.html:12
+msgid "return to book's page"
+msgstr "wróć do strony utworu"
+
+#: templates/catalogue/book_fragments.html:26
+msgid "See description"
+msgstr "Zobacz opis"
+
+#: templates/catalogue/book_fragments.html:26
+msgid "of the book "
+msgstr "utworu"
+
+#: templates/catalogue/book_list.html:7
+msgid "Listing of all works on WolneLektury.pl"
+msgstr "Spis wszystkich utworów w WolneLektury.pl"
+
+#: templates/catalogue/book_list.html:10
+msgid "Listing of all works"
+msgstr "Spis wszystkich utworów"
+
+#: templates/catalogue/book_sets.html:2
+msgid "Put a book on the shelf!"
+msgstr "Wrzuć lekturę na półkę!"
+
+#: templates/catalogue/book_sets.html:3 templates/catalogue/book_sets.html:6
+#: templates/catalogue/fragment_sets.html:16
+msgid "Create new shelf"
+msgstr "Utwórz nową półkę"
 
-#: catalogue/models.py:18
-msgid "genre"
-msgstr "gatunek"
+#: templates/catalogue/book_sets.html:10
+msgid "You do not have any shelves. You can create one below, if you want to."
+msgstr ""
+"Nie posiadasz żadnych półek. Jeśli chcesz, możesz utworzyć nową półkę "
+"poniżej."
 
-#: catalogue/models.py:19
-msgid "theme"
-msgstr "motyw"
+#: templates/catalogue/book_sets.html:15 templates/catalogue/book_short.html:4
+msgid "Put on the shelf!"
+msgstr "Wrzuć na półkę"
 
-#: catalogue/models.py:20
-msgid "set"
-msgstr "zestaw"
+#: templates/catalogue/book_short.html:14
+msgid "Jump to"
+msgstr "Na skróty"
 
-#: catalogue/models.py:34
-msgid "name"
-msgstr "nazwa"
+#: templates/catalogue/book_short.html:16
+msgid "Categories"
+msgstr "Utwór w kategoriach"
 
-#: catalogue/models.py:35 catalogue/models.py:71
-msgid "slug"
-msgstr "slug"
+#: templates/catalogue/book_stub_detail.html:17
+msgid ""
+"This work is in public domain and will be published on Internet school "
+"library of Wolne Lektury soon."
+msgstr ""
+"To dzieło znajduje się w domenie publicznej i niedługo zostanie opublikowane "
+"w szkolnej bibliotece internetowej Wolne Lektury."
 
-#: catalogue/models.py:36
-msgid "sort key"
-msgstr "klucz sortowania"
+#: templates/catalogue/book_stub_detail.html:20
+msgid ""
+"This work will become part of public domain and will be allowed to be "
+"published without restrictions in"
+msgstr ""
+"To dzieło przejdzie do zasobów domeny publicznej i będzie mogło być "
+"publikowane bez żadnych ograniczeń za"
 
-#: catalogue/models.py:37
-msgid "category"
-msgstr "kategoria"
+#: templates/catalogue/book_stub_detail.html:22
+msgid "Find out why Internet libraries can't publish this work."
+msgstr ""
+"Dowiedz się, dlaczego biblioteki internetowe nie mogą udostępniać dzieł tego "
+"autora."
+
+#: templates/catalogue/book_stub_detail.html:24
+msgid "This work is copyrighted."
+msgstr "To dzieło objęte jest prawem autorskim."
+
+#: templates/catalogue/book_text.html:17
+msgid "Table of contents"
+msgstr "Spis treści"
+
+#: templates/catalogue/book_text.html:18
+#: templates/catalogue/tagged_object_list.html:146
+msgid "Themes"
+msgstr "Motywy"
+
+#: templates/catalogue/differentiate_tags.html:13
+msgid "The criteria are ambiguous. Please select one of the following options:"
+msgstr "Podane kryteria są niejednoznaczne. Proszę wybrać jedną z następujących możliwości:"
+
+#: templates/catalogue/folded_tag_list.html:4
+msgid "Show full category"
+msgstr "Zobacz całą kategorię"
+
+#: templates/catalogue/folded_tag_list.html:13
+#: templates/catalogue/main_page.html:27 templates/catalogue/main_page.html:52
+#: templates/catalogue/main_page.html:57 templates/catalogue/main_page.html:96
+#: templates/catalogue/main_page.html:279
+#: templates/catalogue/main_page.html:288
+msgid "See more"
+msgstr "Zobacz więcej"
+
+#: templates/catalogue/folded_tag_list.html:22
+#: templates/catalogue/main_page.html:259
+msgid "Hide"
+msgstr "Zwiń"
+
+#: templates/catalogue/fragment_sets.html:2
+msgid "Shelves containing fragment"
+msgstr "Półki zawierające fragment"
+
+#: templates/catalogue/fragment_sets.html:4
+#: templates/catalogue/main_page.html:37
+msgid "You do not own any shelves. You can create one below, if you want to."
+msgstr ""
+"Nie posiadasz żadnych półek. Jeśli chcesz, możesz utworzyć nową półkę "
+"poniżej."
 
-#: catalogue/models.py:45 catalogue/models.py:72 catalogue/models.py:86
-#: chunks/models.py:11
-msgid "description"
-msgstr "opis"
+#: templates/catalogue/fragment_sets.html:9
+msgid "Save all shelves"
+msgstr "Zapisz półki"
 
-#: catalogue/models.py:54 newtagging/models.py:470
-msgid "tag"
-msgstr "tag"
+#: templates/catalogue/fragment_short.html:7
+msgid "Expand fragment"
+msgstr "Rozwiń fragment"
 
-#: catalogue/models.py:55 newtagging/admin.py:38
-msgid "tags"
-msgstr "tagi"
+#: templates/catalogue/fragment_short.html:13
+msgid "Hide fragment"
+msgstr "Zwiń fragment"
 
-#: catalogue/models.py:70
-msgid "title"
-msgstr "tytuł"
+#: templates/catalogue/fragment_short.html:18
+msgid "See in a book"
+msgstr "Zobacz w utworze"
 
-#: catalogue/models.py:73
-msgid "creation date"
-msgstr "data utworzenia"
+#: templates/catalogue/main_page.html:13
+msgid "check list of books"
+msgstr "zobacz spis utworów"
 
-#: catalogue/models.py:76
-msgid "XML file"
-msgstr "plik XML"
+#: templates/catalogue/main_page.html:13
+msgid "in our repository"
+msgstr "w naszym zbiorze"
 
-#: catalogue/models.py:77
-msgid "PDF file"
-msgstr "plik PDF"
+#: templates/catalogue/main_page.html:17
+msgid "Browse books by categories"
+msgstr "Przeglądaj lektury według wybranych kategorii"
 
-#: catalogue/models.py:78
-msgid "ODT file"
-msgstr "plik ODT"
+#: templates/catalogue/main_page.html:19
+msgid "Wolne Lektury Widget"
+msgstr "Widżet Wolne Lektury"
 
-#: catalogue/models.py:79
-msgid "HTML file"
-msgstr "plik HTML"
+#: templates/catalogue/main_page.html:20
+msgid ""
+"Place our widget - search engine for Wolne Lektury which gives access to "
+"free books and audiobooks - on your homepage! Just copy the HTML code below "
+"onto your page:"
+msgstr ""
+"Umieść widżet – wyszukiwarkę Wolnych Lektur umożliwiającą dostęp do "
+"darmowych lektur i audiobooków – na swojej stronie WWW! Po prostu skopiuj poniższy kod HTML "
+"na swoją stronę:"
 
-#: catalogue/models.py:162
-msgid "book"
-msgstr "książka"
+#: templates/catalogue/main_page.html:21
+msgid "Insert this element in place where you want display the widget"
+msgstr "Umieść ten element w miejscu gdzie chcesz wyświetlić widżet"
 
-#: catalogue/models.py:163
-msgid "books"
-msgstr "książki"
+#: templates/catalogue/main_page.html:24
+msgid "Place this element just before closing body tag: </body>"
+msgstr "Umieść ten element tuż przed zamknięciem taga body: </body>"
 
-#: catalogue/models.py:180
-msgid "fragment"
-msgstr "fragment"
+#: templates/catalogue/main_page.html:28
+#: templates/catalogue/user_shelves.html:2
+msgid "Your shelves with books"
+msgstr "Twoje półki z lekturami"
 
-#: catalogue/models.py:181
-msgid "fragments"
-msgstr "fragmenty"
+#: templates/catalogue/main_page.html:33
+msgid "delete"
+msgstr "usuń"
 
-#: chunks/models.py:10
-msgid "key"
-msgstr "klucz"
+#: templates/catalogue/main_page.html:42
+#: templates/catalogue/user_shelves.html:15
+msgid "Create shelf"
+msgstr "Utwórz półkę"
 
-#: chunks/models.py:10
-msgid "A unique name for this chunk of content"
-msgstr "Unikalna nazwa dla tego kawałka treści"
+#: templates/catalogue/main_page.html:46
+msgid ""
+"Create your own book set. You can share it with friends by sending them link "
+"to your shelf."
+msgstr ""
+"Stwórz własny zestaw lektur. Możesz się nim później podzielić z innymi, "
+"przesyłając im link do Twojej półki."
 
-#: chunks/models.py:12
-msgid "content"
-msgstr "zawartość"
+#: templates/catalogue/main_page.html:47
+msgid "You need to "
+msgstr "Aby zarządzać swoimi półkami, musisz się"
 
-#: chunks/models.py:16
-msgid "chunk"
-msgstr "kawałek"
+#: templates/catalogue/main_page.html:47
+msgid "sign in"
+msgstr "zalogować"
 
-#: chunks/models.py:17
-msgid "chunks"
-msgstr "kawałki"
+#: templates/catalogue/main_page.html:47
+msgid "to manage your shelves."
+msgstr "."
 
-#: newtagging/models.py:471
-msgid "content type"
-msgstr "typ zawartości"
+#: templates/catalogue/main_page.html:50
+#: templates/lessons/document_list.html:49
+msgid "Hand-outs for teachers"
+msgstr "Materiały pomocnicze dla nauczycieli"
 
-#: newtagging/models.py:472
-msgid "object id"
-msgstr "id obiektu"
+#: templates/catalogue/main_page.html:51
+msgid ""
+"Lessons' prospects and other ideas for using Wolnelektury.pl for teaching."
+msgstr ""
+"Scenariusze lekcji i inne pomysły na wykorzytanie serwisu WolneLektury.pl "
+"podczas nauczania."
 
-#: newtagging/views.py:29
-msgid "tagged_object_list must be called with a queryset or a model."
+#: templates/catalogue/main_page.html:56
+msgid ""
+"are professional recordings of literary texts from our repository, available "
+"on free license in MP3 and Ogg Vorbis formats as well as in DAISY system."
+msgstr ""
+"to profesjonalne nagrania tekstów literackich z naszego zbioru dostępne na "
+"wolnej licencji w formatach MP3, Ogg Vorbis oraz w systemie DAISY."
+
+#: templates/catalogue/main_page.html:63
+#: templates/catalogue/tagged_object_list.html:128
+msgid "Authors"
+msgstr "Autorzy"
+
+#: templates/catalogue/main_page.html:67
+#: templates/catalogue/tagged_object_list.html:132
+msgid "Kinds"
+msgstr "Rodzaje"
+
+#: templates/catalogue/main_page.html:71
+#: templates/catalogue/tagged_object_list.html:136
+msgid "Genres"
+msgstr "Gatunki"
+
+#: templates/catalogue/main_page.html:75
+#: templates/catalogue/tagged_object_list.html:140
+msgid "Epochs"
+msgstr "Epoki"
+
+#: templates/catalogue/main_page.html:81
+msgid "Themes and topics"
+msgstr "Motywy i tematy"
+
+#: templates/catalogue/main_page.html:84
+msgid "Themes groups"
+msgstr "Rodziny motywów"
+
+#: templates/catalogue/main_page.html:269
+msgid "News"
+msgstr "Aktualności"
+
+#: templates/catalogue/main_page.html:273
+msgid "See our blog"
+msgstr "Zobacz nasz blog"
+
+#: templates/catalogue/main_page.html:276
+msgid "You can help us!"
+msgstr "Możesz nam pomóc!"
+
+#: templates/catalogue/main_page.html:277
+msgid ""
+"We try our best to elaborate works appended to our library. It is possible "
+"only due to support of our volunteers."
 msgstr ""
+"Utwory włączane sukcesywnie do naszej biblioteki staramy się opracowywać jak "
+"najdokładniej. Jest to możliwe tylko dzięki współpracującym z nami "
+"wolontariuszom."
 
-#: newtagging/views.py:31
-msgid "tagged_object_list must be called with a tag model."
+#: templates/catalogue/main_page.html:278
+msgid ""
+"We invite people who want to take part in developing Internet school library "
+"Wolne Lektury."
 msgstr ""
+"Zapraszamy wszystkie osoby, które chcą współtworzyć szkolną bibliotekę "
+"internetową Wolne Lektury."
+
+#: templates/catalogue/main_page.html:282
+msgid "About us"
+msgstr "O projekcie"
 
-#: newtagging/views.py:33
-msgid "tagged_object_list must be called with a tag."
+#: templates/catalogue/main_page.html:284
+msgid ""
+"\n"
+"\t\t\tInternet library with school readings “Wolne Lektury” (<a href="
+"\"http://wolnelektury.pl\">www.wolnelektury.pl</a>) is a project made by "
+"Modern Poland Foundation. It started in 2007 and shares school readings, "
+"which are recommended by Ministry of National Education and are in public "
+"domain.\n"
+"\t\t\t"
 msgstr ""
+"\n"
+"Biblioteka internetowa z lekturami szkolnymi „Wolne Lektury” (<a href="
+"\"http://wolnelektury.pl\">www.wolnelektury.pl</a>) to projekt realizowany "
+"przez Fundację Nowoczesna Polska. Działa od 2007 roku i udostępnia w swoich "
+"zbiorach lektury szkolne, które są zalecane do użytku przez Ministerstwo "
+"Edukacji Narodowej i które trafiły już do domeny publicznej."
+
+#: templates/catalogue/search_multiple_hits.html:5
+#: templates/catalogue/search_too_short.html:5
+msgid "Searching in"
+msgstr "Wyszukiwanie w"
+
+#: templates/catalogue/search_multiple_hits.html:14
+msgid "More than one result matching the criteria found."
+msgstr "Znaleziono więcej niż jeden wynik wyszukiwania."
+
+#: templates/catalogue/search_no_hits.html:5
+msgid "Search in WolneLektury.pl"
+msgstr "Wyszukiwanie w WolneLektury.pl"
+
+#: templates/catalogue/search_no_hits.html:14
+#: templates/catalogue/tagged_object_list.html:116
+msgid "Sorry! Search cirteria did not match any resources."
+msgstr "Przepraszamy! Brak wyników spełniających kryteria podane w zapytaniu."
+
+#: templates/catalogue/search_no_hits.html:16
+msgid ""
+"Search engine supports following criteria: title, author, theme/topic, "
+"epoch, kind and genre.\n"
+"\t\tAs for now we do not support full text search."
+msgstr ""
+"Wyszukiwarka obsługuje takie kryteria jak tytuł, autor, motyw/temat, epoka, "
+"rodzaj i gatunek utworu. Obecnie nie obsługujemy wyszukiwania fraz w "
+"tekstach utworów."
+
+#: templates/catalogue/search_too_short.html:14
+msgid "Sorry! Search query must have at least two characters."
+msgstr "Przepraszamy! Zapytanie musi zawierać co najmniej dwa znaki."
 
-#: newtagging/views.py:37
+#: templates/catalogue/tag_list.html:4
+msgid "See full category"
+msgstr "Zobacz całą kategorię"
+
+#: templates/catalogue/tagged_object_list.html:15
+msgid "Your shelf is empty"
+msgstr "Twoja półka jest pusta"
+
+#: templates/catalogue/tagged_object_list.html:16
+msgid ""
+"You can put a book on a shelf by entering page of the reading and clicking "
+"'Put on the shelf'."
+msgstr ""
+"Możesz wrzucić książkę na półkę, wchodząc na stronę danej lektury i klikając "
+"na przycisk „Na półkę!”."
+
+#: templates/catalogue/tagged_object_list.html:32
+msgid "Download all books from this shelf"
+msgstr "Pobierz wszystkie książki z tej półki"
+
+#: templates/catalogue/tagged_object_list.html:36
+msgid "Choose books' formats which you want to download:"
+msgstr "Wybierz formaty książek, które chcesz pobrać:"
+
+#: templates/catalogue/tagged_object_list.html:37
+#: templates/catalogue/tagged_object_list.html:39
+#: templates/catalogue/tagged_object_list.html:40
+msgid "for reading"
+msgstr "do czytania"
+
+#: templates/catalogue/tagged_object_list.html:37
+msgid "and printing using"
+msgstr "i drukowania przy pomocy"
+
+#: templates/catalogue/tagged_object_list.html:39
+msgid "and editing using"
+msgstr "i edytowania przy pomocy"
+
+#: templates/catalogue/tagged_object_list.html:40
+msgid "on small displays, for example mobile phones"
+msgstr "na małych ekranach, np. na komórce"
+
+#: templates/catalogue/tagged_object_list.html:41
+#: templates/catalogue/tagged_object_list.html:42
+msgid "for listening"
+msgstr "do słuchania"
+
+#: templates/catalogue/tagged_object_list.html:41
+msgid "on favourite MP3 player"
+msgstr "w ulubionym odtwarzaczu MP3"
+
+#: templates/catalogue/tagged_object_list.html:42
+msgid "open format"
+msgstr "otwarty format"
+
+#: templates/catalogue/tagged_object_list.html:42
+msgid "Xiph.org Foundation"
+msgstr "Fundacji Xiph.Org"
+
+#: templates/catalogue/tagged_object_list.html:43
+#: templates/lessons/ajax_document_detail.html:3
+#: templates/lessons/document_detail.html:13
+msgid "Download"
+msgstr "Pobierz"
+
+#: templates/catalogue/tagged_object_list.html:43
+msgid "Updating list of books' formats on the shelf"
+msgstr "Uaktualnianie listy formatów książek na półce."
+
+#: templates/catalogue/tagged_object_list.html:43
+msgid "cancel"
+msgstr "anuluj"
+
+#: templates/catalogue/tagged_object_list.html:48
+msgid "Share this shelf"
+msgstr "Podziel się tą półką"
+
+#: templates/catalogue/tagged_object_list.html:50
+msgid ""
+"Copy this link and share it with other people to let them see your shelf."
+msgstr ""
+"Skopiuj ten link i przekaż go osobom, z którymi chcesz się podzielić tą "
+"półką."
+
+#: templates/catalogue/tagged_object_list.html:60
+msgid "Read work's study of this author on Lektury.Gazeta.pl"
+msgstr "Przeczytaj omówienia utworów autora w serwisie Lektury.Gazeta.pl"
+
+#: templates/catalogue/tagged_object_list.html:62
+#, python-format
+msgid "Read study of epoch %(last_tag)s on Lektury.Gazeta.pl"
+msgstr "Przeczytaj omówienia z epoki %(last_tag)s w serwisie Lektury.Gazeta.pl"
+
+#: templates/catalogue/tagged_object_list.html:64
+#, python-format
+msgid "Read study of kind %(last_tag)s on Lektury.Gazeta.pl"
+msgstr ""
+"Przeczytaj omówienia z rodzaju %(last_tag)s w serwisie Lektury.Gazeta.pl"
+
+#: templates/catalogue/tagged_object_list.html:66
+#, python-format
+msgid "Read study of genre %(last_tag)s on Lektury.Gazeta.pl"
+msgstr ""
+"Przeczytaj omówienia z gatunku %(last_tag)s w serwisie Lektury.Gazeta.pl"
+
+#: templates/catalogue/tagged_object_list.html:68
+msgid "Read related study on Lektury.Gazeta.pl"
+msgstr "Przeczytaj powiązane omówienia w serwisie Lektury.Gazeta.pl"
+
+#: templates/catalogue/tagged_object_list.html:76
+msgid "Read article about this author on Wikipedia"
+msgstr "Przeczytaj artykuł o autorze w Wikipedii"
+
+#: templates/catalogue/tagged_object_list.html:78
+#, python-format
+msgid "Read article about epoch %(last_tag)s on Wikipedia"
+msgstr "Przeczytaj artykuł o epoce %(last_tag)s w Wikipedii"
+
+#: templates/catalogue/tagged_object_list.html:80
 #, python-format
-msgid "No tags found matching \"%s\"."
-msgstr "Nie znaleziono tagów zgodnych z \"%s\"."
+msgid "Read article about kind %(last_tag)s on Wikipedia"
+msgstr "Przeczytaj artykuł o rodzaju %(last_tag)s w Wikipedii"
+
+#: templates/catalogue/tagged_object_list.html:82
+#, python-format
+msgid "Read article about genre %(last_tag)s on Wikipedia"
+msgstr "Przeczytaj artykuł o gatunku %(last_tag)s w Wikipedii"
+
+#: templates/catalogue/tagged_object_list.html:84
+msgid "Read related article on Wikipedia"
+msgstr "Przeczytaj powiązany artykuł w Wikipedii"
+
+#: templates/catalogue/tagged_object_list.html:94
+msgid "Delete"
+msgstr "Usuń"
+
+#: templates/catalogue/tagged_object_list.html:102
+msgid "This author's works are copyrighted."
+msgstr "Dzieła tego autora objęte są prawem autorskim."
+
+#: templates/catalogue/tagged_object_list.html:105
+msgid ""
+"This author's works are in public domain and will be published on Internet "
+"school library of Wolne Lektury soon."
+msgstr ""
+"Dzieła tego autora znajdują się w domenie publicznej i niedługo zostaną "
+"opublikowane w szkolnej bibliotece internetowej Wolne Lektury."
+
+#: templates/catalogue/tagged_object_list.html:109
+msgid ""
+"This author's works will become part of public domain and will be allowed to "
+"be published without restrictions in"
+msgstr ""
+"Dzieła tego autora przejdą do zasobów domeny publicznej i będą mogły być "
+"publikowane bez żadnych ograniczeń za"
+
+#: templates/catalogue/tagged_object_list.html:111
+msgid "Find out why Internet libraries can't publish this author's works."
+msgstr ""
+"Dowiedz się, dlaczego biblioteki internetowe nie mogą udostępniać dzieł tego "
+"autora."
+
+#: templates/catalogue/user_shelves.html:6
+msgid "remove"
+msgstr "usuń"
+
+#: templates/catalogue/user_shelves.html:10
+msgid "You do not own any shelves. You can create one below if you want to"
+msgstr ""
+"Nie posiadasz żadnych półek. Jeśli chcesz, możesz utworzyć półkę poniżej."
+
+#: templates/info/base.html:10
+msgid "return to the main page"
+msgstr "wróć do strony głównej"
+
+#: templates/info/join_us.html:2
+msgid ""
+"We have over 1000 works published in Wolne Lektury!\n"
+"Help us expand the library and set new readings free by\n"
+"making a donation or transferring 1% of your income tax."
+msgstr ""
+"W serwisie Wolne Lektury już teraz opublikowanych jest ponad 1000 utworów! "
+"Pomóż w rozwijaniu biblioteki i uwalnianiu nowych lektur przekazując nam "
+"darowiznę lub 1% podatku."
+
+#: templates/info/join_us.html:5 templates/info/join_us.html.py:10
+msgid "More..."
+msgstr "Więcej..."
+
+#: templates/info/join_us.html:7
+msgid ""
+"Become an editor of Wolne Lektury! Find out if\n"
+"we're currently working on a reading you're looking for and prepare\n"
+"a publication by yourself by logging into the Editorial Platform."
+msgstr ""
+"Zostań redaktorem lub redaktorką Wolnych Lektur! Sprawdź, czy obecnie "
+"pracujemy nad publikacją wyszukiwanej przez ciebie lektury i samodzielnie "
+"przygotuj publikację logując się na Platformie Redakcyjnej."
+
+#: templates/lessons/ajax_document_detail.html:3
+#: templates/lessons/document_detail.html:13
+msgid "author"
+msgstr "autor"
+
+#: templates/lessons/document_detail.html:9
+msgid "return to list of materials"
+msgstr "wróć do listy materiałów"
+
+#: templates/lessons/document_list.html:7
+msgid "Hand-outs for teachers on "
+msgstr "Materiały pomocnicze dla nauczycieli w "
+
+#: templates/pagination/pagination.html:5
+#: templates/pagination/pagination.html:7
+msgid "previous"
+msgstr "poprzedni"
+
+#: templates/pagination/pagination.html:21
+#: templates/pagination/pagination.html:23
+msgid "next"
+msgstr "następny"
+
+#~ msgid "Choose your interface language: "
+#~ msgstr "Wybierz język interfejsu:"
+
+#~ msgid "Choose language"
+#~ msgstr "Wybierz język"
+
+#~ msgid "Hide description"
+#~ msgstr "Zwiń opis"
diff --git a/wolnelektury/locale/ru/LC_MESSAGES/django.mo b/wolnelektury/locale/ru/LC_MESSAGES/django.mo
new file mode 100644 (file)
index 0000000..d79768d
Binary files /dev/null and b/wolnelektury/locale/ru/LC_MESSAGES/django.mo differ
diff --git a/wolnelektury/locale/ru/LC_MESSAGES/django.po b/wolnelektury/locale/ru/LC_MESSAGES/django.po
new file mode 100644 (file)
index 0000000..c94d638
--- /dev/null
@@ -0,0 +1,803 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+# 
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-08-25 10:23+0000\n"
+"PO-Revision-Date: 2010-08-25 11:05\n"
+"Last-Translator: <radek.czajka@gmail.com>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Translated-Using: django-rosetta 0.5.6\n"
+
+#: templates/404.html:6 templates/404.html.py:15
+msgid "Page does not exist"
+msgstr "Сайт не существует"
+
+#: templates/404.html:17
+msgid "We are sorry, but this page does not exist. Please check if you entered correct address or go to "
+msgstr "Извините! Этот сайт не существует. Проверьте, пожалуйста, набрали ли вы хороший адрес или зайдите на"
+
+#: templates/404.html:17
+msgid "main page"
+msgstr "главную страницу"
+
+#: templates/500.html:6 templates/500.html.py:54
+msgid "Server error"
+msgstr "Ошибка сервера"
+
+#: templates/500.html:55
+msgid "<p>The Wolnelektury.pl site is currently unavailable. Meanwhile, visit our <a href='http://nowoczesnapolska.org.pl'>blog</a>.</p> <p>Inform our <a href='mailto:fundacja@nowoczesnapolska.org.pl'>administrators</a> about the error.</p>"
+msgstr "<p> The Wolnelektury.pl временно не работает. Тем времнем зайдите на <a href='http://nowoczesnapolska.org.pl'>blog</a>.</p> <p>Inform our <a href='mailto:fundacja@nowoczesnapolska.org.pl'>administrators</a> about the error.</p>"
+
+#: templates/503.html:6 templates/503.html.py:54
+msgid "Service unavailable"
+msgstr "Сервис недоступен"
+
+#: templates/503.html:56
+msgid "The Wolnelektury.pl site is currently unavailable due to maintainance."
+msgstr "По поводу технической поддрежки сайт The Wolnelektury.pl временно не работает."
+
+#: templates/base.html:19
+msgid "Internet Explorer cannot display this site properly. Click here to read more..."
+msgstr "Internet Explorer не может хорошо показать сайта. Щелкните здесь, чтобы прочитать больше..."
+
+#: templates/base.html:32
+msgid "Welcome"
+msgstr "Добро пожаловать"
+
+#: templates/base.html:33
+msgid "Your shelves"
+msgstr "Ваши полки"
+
+#: templates/base.html:35
+msgid "Administration"
+msgstr "Администрация"
+
+#: templates/base.html:37 templates/base.html.py:41
+msgid "Report a bug"
+msgstr ""
+
+#: templates/base.html:38
+msgid "Logout"
+msgstr "Выход"
+
+#: templates/base.html:42 templates/base.html.py:88 templates/base.html:92
+#: templates/base.html.py:96 templates/auth/login.html:4
+#: templates/auth/login.html.py:7 templates/auth/login.html:12
+#: templates/auth/login.html.py:15
+msgid "Sign in"
+msgstr "Вход"
+
+#: templates/base.html:42 templates/base.html.py:88 templates/base.html:96
+#: templates/base.html.py:100 templates/auth/login.html:7
+#: templates/auth/login.html.py:21 templates/auth/login.html:23
+msgid "Register"
+msgstr "Зарегистроваться"
+
+#: templates/base.html:69
+msgid ""
+"\n"
+"\t\t\t\tWolne Lektury is a project lead by <a href=\"http://nowoczesnapolska.org.pl/\">Modern Poland Foundation</a>.\n"
+"\t\t\t\tDigital reproductions are made by <a href=\"http://www.bn.org.pl/\">The National Library</a>, based on TNL resources.\n"
+"\t\t\t\tHosting <a href=\"http://eo.pl/\">EO Networks</a>.\n"
+"\t\t\t\t"
+msgstr ""
+"\n"
+"\t\t\t\tWolne Lektury - это проект под управлением <a href=\"http://nowoczesnapolska.org.pl/\"> Фонда Молодой Польши </a>.\n"
+"\t\t\t\t Цифровые копии создаются <a href=\"http://www.bn.org.pl/\"> Народной бибиотеки </a>, основанной на ресурсах TNL. \n"
+"\t\t\t\tHosting <a href=\"http://eo.pl/\">EO Networks</a>.\n"
+"\t\t\t\t"
+
+#: templates/base.html:76
+msgid ""
+"\n"
+"\t\t\t\tModern Poland Foundation, 00-514 Warsaw, ul. Marszałkowska 84/92 lok. 125, tel/fax: (22) 621-30-17\n"
+"                e-mail: <a href=\"mailto:fundacja@nowoczesnapolska.org.pl\">fundacja@nowoczesnapolska.org.pl</a>\n"
+"\t\t\t\t"
+msgstr ""
+"\n"
+"\t\t\t\tФонд Молодой Польши, 00-514 Варшава, ul. Marszałkowska 84/92 lok. 125, tel/fax: (22) 621-30-17\n"
+"                e-mail: <a href=\"mailto:fundacja@nowoczesnapolska.org.pl\">fundacja@nowoczesnapolska.org.pl</a>\n"
+"\t\t\t\t"
+
+#: templates/base.html:85 templates/base.html.py:106 templates/base.html:112
+#: templates/catalogue/book_detail.html:146
+#: templates/catalogue/book_fragments.html:33
+#: templates/catalogue/book_stub_detail.html:31
+#: templates/catalogue/differentiate_tags.html:23
+#: templates/catalogue/search_multiple_hits.html:29
+#: templates/catalogue/search_no_hits.html:22
+#: templates/catalogue/search_too_short.html:19
+#: templates/catalogue/tagged_object_list.html:155
+msgid "Close"
+msgstr "Закройте"
+
+#: templates/base.html:108 templates/base.html.py:114
+#: templates/catalogue/book_detail.html:148
+#: templates/catalogue/book_fragments.html:35
+#: templates/catalogue/book_stub_detail.html:33
+#: templates/catalogue/differentiate_tags.html:25
+#: templates/catalogue/search_multiple_hits.html:31
+#: templates/catalogue/search_no_hits.html:24
+#: templates/catalogue/search_too_short.html:21
+#: templates/catalogue/tagged_object_list.html:157
+msgid "Loading"
+msgstr "Погрузка"
+
+#: templates/admin/base_site.html:4 templates/admin/base_site.html.py:7
+msgid "Site administration"
+msgstr "Сайт администрации"
+
+#: templates/admin/base_site.html:8
+msgid "Translations"
+msgstr "Перевод"
+
+#: templates/admin/catalogue/book/change_list.html:6
+msgid "Import book"
+msgstr "Импорт книги"
+
+#: templates/auth/login.html:4
+msgid "Register on"
+msgstr "Регистрация на"
+
+#: templates/auth/login.html:9 templates/catalogue/book_detail.html:12
+#: templates/catalogue/book_fragments.html:12
+#: templates/catalogue/book_list.html:12
+#: templates/catalogue/book_stub_detail.html:12
+#: templates/catalogue/breadcrumbs.html:21
+#: templates/catalogue/main_page.html:13 templates/info/base.html:10
+#: templates/lessons/document_detail.html:9
+#: templates/lessons/document_list.html:51
+msgid "Search"
+msgstr "Поиск"
+
+#: templates/auth/login.html:9 templates/catalogue/book_detail.html:12
+#: templates/catalogue/book_fragments.html:12
+#: templates/catalogue/book_list.html:12
+#: templates/catalogue/book_stub_detail.html:12
+#: templates/catalogue/main_page.html:13
+#: templates/catalogue/tagged_object_list.html:43 templates/info/base.html:10
+#: templates/lessons/document_detail.html:9
+#: templates/lessons/document_list.html:51
+msgid "or"
+msgstr "или"
+
+#: templates/auth/login.html:9 templates/catalogue/book_detail.html:12
+#: templates/catalogue/book_list.html:12
+#: templates/catalogue/book_stub_detail.html:12
+#: templates/lessons/document_list.html:51
+msgid "return to main page"
+msgstr "возврат на главную страницу"
+
+#: templates/catalogue/book_detail.html:5
+msgid "on WolneLektury.pl"
+msgstr "на WolneLektury.pl"
+
+#: templates/catalogue/book_detail.html:29
+msgid "Work is licensed under "
+msgstr "Разрешение на работу со стороны"
+
+#: templates/catalogue/book_detail.html:31
+msgid "Based on"
+msgstr "Основанный на"
+
+#: templates/catalogue/book_detail.html:40
+msgid "Put a book"
+msgstr "Поставьте книгу"
+
+#: templates/catalogue/book_detail.html:40
+msgid "on the shelf!"
+msgstr "на полку"
+
+#: templates/catalogue/book_detail.html:44
+msgid "Read online"
+msgstr "Читать онлайн"
+
+#: templates/catalogue/book_detail.html:47
+msgid "Download PDF"
+msgstr "Скачать PDF"
+
+#: templates/catalogue/book_detail.html:50
+msgid "Download EPUB"
+msgstr "Скачать EPUB"
+
+#: templates/catalogue/book_detail.html:53
+msgid "Download ODT"
+msgstr "Скачать ODT"
+
+#: templates/catalogue/book_detail.html:56
+msgid "Download TXT"
+msgstr "Скачать TXT"
+
+#: templates/catalogue/book_detail.html:61
+msgid "Artist"
+msgstr "Артист"
+
+#: templates/catalogue/book_detail.html:63
+msgid "Director"
+msgstr "режиссер"
+
+#: templates/catalogue/book_detail.html:67
+msgid "Download MP3"
+msgstr "скачать MP3"
+
+#: templates/catalogue/book_detail.html:68
+msgid "Download Ogg Vorbis"
+msgstr "Скачать Ogg Vorbis"
+
+#: templates/catalogue/book_detail.html:95
+msgid "Details"
+msgstr "Подробнее"
+
+#: templates/catalogue/book_detail.html:99
+msgid "Author"
+msgstr "Автор"
+
+#: templates/catalogue/book_detail.html:105
+msgid "Epoch"
+msgstr "эпоха"
+
+#: templates/catalogue/book_detail.html:111
+msgid "Kind"
+msgstr "форма"
+
+#: templates/catalogue/book_detail.html:117
+msgid "Genre"
+msgstr "жанр"
+
+#: templates/catalogue/book_detail.html:123
+msgid "Other resources"
+msgstr "другие ресурсы"
+
+#: templates/catalogue/book_detail.html:125
+msgid "Book on project's wiki"
+msgstr "Книга по проекту вики"
+
+#: templates/catalogue/book_detail.html:126
+msgid "Source of the book"
+msgstr "Источник книги"
+
+#: templates/catalogue/book_detail.html:128
+msgid "Book description on Lektury.Gazeta.pl"
+msgstr "Описание книги на Lektury.Gazeta.pl"
+
+#: templates/catalogue/book_detail.html:131
+msgid "Book description on Wikipedia"
+msgstr "Описание книги на Wikipedia"
+
+#: templates/catalogue/book_detail.html:136
+msgid "Work's themes "
+msgstr "Темы труда"
+
+#: templates/catalogue/book_fragments.html:5
+#: templates/catalogue/book_fragments.html:10
+msgid "Theme"
+msgstr "Мотив"
+
+#: templates/catalogue/book_fragments.html:5
+#: templates/catalogue/book_fragments.html:10
+msgid "in work "
+msgstr "в труде"
+
+#: templates/catalogue/book_fragments.html:5
+msgid "on"
+msgstr "на"
+
+#: templates/catalogue/book_fragments.html:12
+msgid "return to book's page"
+msgstr "Возратитесь на сайт книги"
+
+#: templates/catalogue/book_fragments.html:26
+msgid "See description"
+msgstr "Посмотрите описание"
+
+#: templates/catalogue/book_fragments.html:26
+msgid "of the book "
+msgstr "данной книги"
+
+#: templates/catalogue/book_list.html:7
+msgid "Listing of all works on WolneLektury.pl"
+msgstr "Список работ на WolneLektury.pl"
+
+#: templates/catalogue/book_list.html:10
+msgid "Listing of all works"
+msgstr "Список работ"
+
+#: templates/catalogue/book_sets.html:2
+msgid "Put a book on the shelf!"
+msgstr "Поставьте книгу на полку!"
+
+#: templates/catalogue/book_sets.html:3 templates/catalogue/book_sets.html:6
+#: templates/catalogue/fragment_sets.html:16
+msgid "Create new shelf"
+msgstr "Создать новую полку"
+
+#: templates/catalogue/book_sets.html:10
+msgid "You do not have any shelves. You can create one below, if you want to."
+msgstr "У вас нет никаких полок. Если вы хотите, вы можете создать одну ниже."
+
+#: templates/catalogue/book_sets.html:15 templates/catalogue/book_short.html:4
+msgid "Put on the shelf!"
+msgstr "Поставьте на полку!"
+
+#: templates/catalogue/book_short.html:14
+msgid "Jump to"
+msgstr "Перейдите на"
+
+#: templates/catalogue/book_short.html:16
+msgid "Categories"
+msgstr "Категории"
+
+#: templates/catalogue/book_stub_detail.html:17
+msgid "This work is in public domain and will be published on Internet school library of Wolne Lektury soon."
+msgstr "Этот труд находится в публичной области. Мыпоместим ее в школьной библиотеке Wolne Lektury скоро. ?"
+
+#: templates/catalogue/book_stub_detail.html:20
+msgid "This work will become part of public domain and will be allowed to be published without restrictions in"
+msgstr "Этот труд будет частью публичной сферы. Ее издание будет разрешено без ограничения ... ?"
+
+#: templates/catalogue/book_stub_detail.html:22
+msgid "Find out why Internet libraries can't publish this work."
+msgstr "Узнайте, почему интернет-библиотеки не могут издать этого труда."
+
+#: templates/catalogue/book_stub_detail.html:24
+msgid "This work is copyrighted."
+msgstr "На эту работу распространяется авторское право."
+
+#: templates/catalogue/book_text.html:17
+msgid "Table of contents"
+msgstr "Оглавление"
+
+#: templates/catalogue/book_text.html:18
+#: templates/catalogue/tagged_object_list.html:146
+msgid "Themes"
+msgstr "Мотивы"
+
+#: templates/catalogue/differentiate_tags.html:13
+msgid "The criteria are ambiguous. Please select one of the following options:"
+msgstr ""
+
+#: templates/catalogue/folded_tag_list.html:4
+msgid "Show full category"
+msgstr "Показать всю категорию"
+
+#: templates/catalogue/folded_tag_list.html:13
+#: templates/catalogue/main_page.html:43 templates/catalogue/main_page.html:48
+#: templates/catalogue/main_page.html:87
+#: templates/catalogue/main_page.html:270
+#: templates/catalogue/main_page.html:279
+msgid "See more"
+msgstr "Подробнее"
+
+#: templates/catalogue/folded_tag_list.html:22
+#: templates/catalogue/main_page.html:250
+msgid "Hide"
+msgstr "Скрыть"
+
+#: templates/catalogue/fragment_sets.html:2
+msgid "Shelves containing fragment"
+msgstr "Полки с фрагментом"
+
+#: templates/catalogue/fragment_sets.html:4
+#: templates/catalogue/main_page.html:28
+msgid "You do not own any shelves. You can create one below, if you want to."
+msgstr "У вас нет никакой полки. Если вы хотите, вы можете создать одну ниже."
+
+#: templates/catalogue/fragment_sets.html:9
+msgid "Save all shelves"
+msgstr "Сохранить все полки"
+
+#: templates/catalogue/fragment_short.html:7
+msgid "Expand fragment"
+msgstr "Растянуть фрагмент"
+
+#: templates/catalogue/fragment_short.html:13
+msgid "Hide fragment"
+msgstr "Скрыть фрагмент"
+
+#: templates/catalogue/fragment_short.html:18
+msgid "See in a book"
+msgstr "Посмотрите в книге"
+
+#: templates/catalogue/main_page.html:13
+msgid "check list of books"
+msgstr "проверить список книг"
+
+#: templates/catalogue/main_page.html:13
+msgid "in our repository"
+msgstr "в нашем хранилище"
+
+#: templates/catalogue/main_page.html:17
+msgid "Browse books by categories"
+msgstr "Просматривать книги по категориям"
+
+#: templates/catalogue/main_page.html:19
+#: templates/catalogue/user_shelves.html:2
+msgid "Your shelves with books"
+msgstr "Ваши книжные полки"
+
+#: templates/catalogue/main_page.html:24
+msgid "delete"
+msgstr "удалить"
+
+#: templates/catalogue/main_page.html:33
+#: templates/catalogue/user_shelves.html:15
+msgid "Create shelf"
+msgstr "Создать полку"
+
+#: templates/catalogue/main_page.html:37
+msgid "Create your own book set. You can share it with friends by sending them link to your shelf."
+msgstr "Создать собственный набор книг. Вы можете делиться ими со своими друзьями, посылая ссылку на свою полку."
+
+#: templates/catalogue/main_page.html:38
+msgid "You need to "
+msgstr "Вам необходимо"
+
+#: templates/catalogue/main_page.html:38
+msgid "sign in"
+msgstr "Войти в систему,"
+
+#: templates/catalogue/main_page.html:38
+msgid "to manage your shelves."
+msgstr "чтобы управлять своими полками"
+
+#: templates/catalogue/main_page.html:41
+#: templates/lessons/document_list.html:49
+msgid "Hand-outs for teachers"
+msgstr "Хендауты для учителей"
+
+#: templates/catalogue/main_page.html:42
+msgid "Lessons' prospects and other ideas for using Wolnelektury.pl for teaching."
+msgstr "Конспекты уроков и другие идеи использования Wolnelektury.pl учителями."
+
+#: templates/catalogue/main_page.html:47
+msgid "are professional recordings of literary texts from our repository, available on free license in MP3 and Ogg Vorbis formats as well as in DAISY system."
+msgstr "- это профессиональные записи литературных текстов из нашего хранилища. Они доступны по бесплатному разрешению ? в форматах MP3 и Ogg Vorbis, а также в системе DAISY."
+
+#: templates/catalogue/main_page.html:54
+#: templates/catalogue/tagged_object_list.html:128
+msgid "Authors"
+msgstr "Авторы"
+
+#: templates/catalogue/main_page.html:58
+#: templates/catalogue/tagged_object_list.html:132
+msgid "Kinds"
+msgstr "Формы"
+
+#: templates/catalogue/main_page.html:62
+#: templates/catalogue/tagged_object_list.html:136
+msgid "Genres"
+msgstr "Жанры"
+
+#: templates/catalogue/main_page.html:66
+#: templates/catalogue/tagged_object_list.html:140
+msgid "Epochs"
+msgstr "Эпохи"
+
+#: templates/catalogue/main_page.html:72
+msgid "Themes and topics"
+msgstr "Мотивы и темы"
+
+#: templates/catalogue/main_page.html:75
+msgid "Themes groups"
+msgstr "Тематические группы"
+
+#: templates/catalogue/main_page.html:260
+msgid "News"
+msgstr "Новости"
+
+#: templates/catalogue/main_page.html:264
+msgid "See our blog"
+msgstr "Посмотрите наш блог"
+
+#: templates/catalogue/main_page.html:267
+msgid "You can help us!"
+msgstr "Вы можете нам помочь!"
+
+#: templates/catalogue/main_page.html:268
+msgid "We try our best to elaborate works appended to our library. It is possible only due to support of our volunteers."
+msgstr "Мы стремимся тщательно разрабатывать труды, прибавляемые в нашу библиотеку. Это является возможным только благодаря помощи наших волонтеров."
+
+#: templates/catalogue/main_page.html:269
+msgid "We invite people who want to take part in developing Internet school library Wolne Lektury."
+msgstr "Мы приглашаем людей, которые хотят принять участие в развитии школьной библиотеки Интернета Wolne Lektury."
+
+#: templates/catalogue/main_page.html:273
+msgid "About us"
+msgstr "О нас"
+
+#: templates/catalogue/main_page.html:275
+msgid ""
+"\n"
+"\t\t\tInternet library with school readings “Wolne Lektury” (<a href=\"http://wolnelektury.pl\">www.wolnelektury.pl</a>) is a project made by Modern Poland Foundation. It started in 2007 and shares school readings, which are recommended by Ministry of National Education and are in public domain.\n"
+"\t\t\t"
+msgstr ""
+"\n"
+"\t\t\tИнтернет-библиотека со школьными чтениями “Wolne Lektury” (<a href=\"http://wolnelektury.pl\">www.wolnelektury.pl</a>) является проектом, созданным фондом Современной Польши. Действуя с 2007 г., библиотека делает доступными школьные чтения публичного домена, предлагаемые министром народного образования. \n"
+"\t\t\t"
+
+#: templates/catalogue/search_multiple_hits.html:5
+#: templates/catalogue/search_too_short.html:5
+msgid "Searching in"
+msgstr "Искать в"
+
+#: templates/catalogue/search_multiple_hits.html:14
+msgid "More than one result matching the criteria found."
+msgstr "Больше чем один критерий соответствует найденным критериям."
+
+#: templates/catalogue/search_no_hits.html:5
+msgid "Search in WolneLektury.pl"
+msgstr "Искать в WolneLektury.pl"
+
+#: templates/catalogue/search_no_hits.html:14
+#: templates/catalogue/tagged_object_list.html:116
+msgid "Sorry! Search cirteria did not match any resources."
+msgstr "Извините! Критерий поиска не соответствует никаким ресурсам."
+
+#: templates/catalogue/search_no_hits.html:16
+msgid ""
+"Search engine supports following criteria: title, author, theme/topic, epoch, kind and genre.\n"
+"\t\tAs for now we do not support full text search."
+msgstr ""
+"Искать поддержку двигателя используя критерии: заглавие, автор, тема/сюжет, эпоха, форма и жанр.\n"
+"\t\tПока мы не поддерживаем поиска всего текста."
+
+#: templates/catalogue/search_too_short.html:14
+msgid "Sorry! Search query must have at least two characters."
+msgstr "Извините! У искаемого вопроса должны быть по крайней мере два свойства."
+
+#: templates/catalogue/tag_list.html:4
+msgid "See full category"
+msgstr "Вся категория"
+
+#: templates/catalogue/tagged_object_list.html:15
+msgid "Your shelf is empty"
+msgstr "У тебя пустая полка"
+
+#: templates/catalogue/tagged_object_list.html:16
+msgid "You can put a book on a shelf by entering page of the reading and clicking 'Put on the shelf'."
+msgstr "Вы можете поставить книгу на полку, заходя на сайт произведения или щелкнув 'Поставить на полку'."
+
+#: templates/catalogue/tagged_object_list.html:32
+msgid "Download all books from this shelf"
+msgstr "Скачать все книги с этой полки"
+
+#: templates/catalogue/tagged_object_list.html:36
+msgid "Choose books' formats which you want to download:"
+msgstr "Выбрать формат книг, которые вы хотите скачать:"
+
+#: templates/catalogue/tagged_object_list.html:37
+#: templates/catalogue/tagged_object_list.html:39
+#: templates/catalogue/tagged_object_list.html:40
+msgid "for reading"
+msgstr "для чтения"
+
+#: templates/catalogue/tagged_object_list.html:37
+msgid "and printing using"
+msgstr "и для печатки"
+
+#: templates/catalogue/tagged_object_list.html:39
+msgid "and editing using"
+msgstr "и для редактирования"
+
+#: templates/catalogue/tagged_object_list.html:40
+msgid "on small displays, for example mobile phones"
+msgstr "на маленьких дисплеях, напр. мобильных телефонов"
+
+#: templates/catalogue/tagged_object_list.html:41
+#: templates/catalogue/tagged_object_list.html:42
+msgid "for listening"
+msgstr "для слушания"
+
+#: templates/catalogue/tagged_object_list.html:41
+msgid "on favourite MP3 player"
+msgstr "на любимом MP3-плейере"
+
+#: templates/catalogue/tagged_object_list.html:42
+msgid "open format"
+msgstr "открытый формат"
+
+#: templates/catalogue/tagged_object_list.html:42
+msgid "Xiph.org Foundation"
+msgstr "Фонд Xiph.org"
+
+#: templates/catalogue/tagged_object_list.html:43
+#: templates/lessons/ajax_document_detail.html:3
+#: templates/lessons/document_detail.html:13
+msgid "Download"
+msgstr "Скачать"
+
+#: templates/catalogue/tagged_object_list.html:43
+msgid "Updating list of books' formats on the shelf"
+msgstr "Обновить список форматов книг на полке"
+
+#: templates/catalogue/tagged_object_list.html:43
+msgid "cancel"
+msgstr "Отменить"
+
+#: templates/catalogue/tagged_object_list.html:48
+msgid "Share this shelf"
+msgstr "Делить эту полку"
+
+#: templates/catalogue/tagged_object_list.html:50
+msgid "Copy this link and share it with other people to let them see your shelf."
+msgstr "Копировать эту ссылку и делить с другими пользователями, чтобы они могли увидеть вашу полку."
+
+#: templates/catalogue/tagged_object_list.html:60
+msgid "Read work's study of this author on Lektury.Gazeta.pl"
+msgstr "Читать очерк произведения данного автора на Lektury.Gazeta.pl"
+
+#: templates/catalogue/tagged_object_list.html:62
+#, fuzzy, python-format
+msgid "Read study of epoch %(last_tag)s on Lektury.Gazeta.pl"
+msgstr "Читать очерк произведения данного автора на Lektury.Gazeta.pl"
+
+#: templates/catalogue/tagged_object_list.html:64
+#, fuzzy, python-format
+msgid "Read study of kind %(last_tag)s on Lektury.Gazeta.pl"
+msgstr "Читать очерк произведения данного автора на Lektury.Gazeta.pl"
+
+#: templates/catalogue/tagged_object_list.html:66
+#, fuzzy, python-format
+msgid "Read study of genre %(last_tag)s on Lektury.Gazeta.pl"
+msgstr "Читать очерк произведения данного автора на Lektury.Gazeta.pl"
+
+#: templates/catalogue/tagged_object_list.html:68
+#, fuzzy
+msgid "Read related study on Lektury.Gazeta.pl"
+msgstr "Читать очерк произведения данного автора на Lektury.Gazeta.pl"
+
+#: templates/catalogue/tagged_object_list.html:76
+msgid "Read article about this author on Wikipedia"
+msgstr "Прочитайте статью об авторе в Википедии"
+
+#: templates/catalogue/tagged_object_list.html:78
+#, fuzzy, python-format
+msgid "Read article about epoch %(last_tag)s on Wikipedia"
+msgstr "Прочитайте статью об авторе в Википедии"
+
+#: templates/catalogue/tagged_object_list.html:80
+#, fuzzy, python-format
+msgid "Read article about kind %(last_tag)s on Wikipedia"
+msgstr "Прочитайте статью об авторе в Википедии"
+
+#: templates/catalogue/tagged_object_list.html:82
+#, fuzzy, python-format
+msgid "Read article about genre %(last_tag)s on Wikipedia"
+msgstr "Прочитайте статью об авторе в Википедии"
+
+#: templates/catalogue/tagged_object_list.html:84
+#, fuzzy
+msgid "Read related article on Wikipedia"
+msgstr "Прочитайте статью об авторе в Википедии"
+
+#: templates/catalogue/tagged_object_list.html:94
+msgid "Delete"
+msgstr "Удалить"
+
+#: templates/catalogue/tagged_object_list.html:102
+msgid "This author's works are copyrighted."
+msgstr "На работы этого автора распространяется авторское право."
+
+#: templates/catalogue/tagged_object_list.html:105
+msgid "This author's works are in public domain and will be published on Internet school library of Wolne Lektury soon."
+msgstr "Работы данного автора находятся в публичной области и будут изданы в школьной библиотеке Интернета скоро."
+
+#: templates/catalogue/tagged_object_list.html:109
+msgid "This author's works will become part of public domain and will be allowed to be published without restrictions in"
+msgstr "Труды данного автора будут частью публичной области и возможным будет их издание без ограничений на"
+
+#: templates/catalogue/tagged_object_list.html:111
+msgid "Find out why Internet libraries can't publish this author's works."
+msgstr "Узнайте, почему интернет-библиотеки не могут издать работ этого автора."
+
+#: templates/catalogue/user_shelves.html:6
+msgid "remove"
+msgstr "убрать"
+
+#: templates/catalogue/user_shelves.html:10
+msgid "You do not own any shelves. You can create one below if you want to"
+msgstr "У вас нет никаких полок. Если хотите, вы можете создать одну ниже."
+
+#: templates/info/base.html:10
+msgid "return to the main page"
+msgstr "возвратитесь на главную страницу"
+
+#: templates/info/join_us.html:2
+msgid ""
+"We have over 1000 works published in Wolne Lektury!\n"
+"Help us expand the library and set new readings free by\n"
+"making a donation or transferring 1% of your income tax."
+msgstr ""
+"У нас больше 1000 трудов в Wolne Lektury!\n"
+"Помогите нам распространить библиотеку и поместить новые бесплатные чтения\n"
+"при помощи денежного пожертвования или перевода 1% вашего подоходного налога."
+
+#: templates/info/join_us.html:5 templates/info/join_us.html.py:10
+msgid "More..."
+msgstr "Подробнее..."
+
+#: templates/info/join_us.html:7
+msgid ""
+"Become an editor of Wolne Lektury! Find out if\n"
+"we're currently working on a reading you're looking for and prepare\n"
+"a publication by yourself by logging into the Editorial Platform."
+msgstr ""
+"Станьте редактором Wolne Lektury! Узанйте работаем ли\n"
+"мы сейчас над чтением, которе вы ищите и сами подготовьте\n"
+"публикацию, входя в платформу редактировки."
+
+#: templates/lessons/ajax_document_detail.html:3
+#: templates/lessons/document_detail.html:13
+msgid "author"
+msgstr "автор"
+
+#: templates/lessons/document_detail.html:9
+msgid "return to list of materials"
+msgstr "возвратитесь к списку материалов"
+
+#: templates/lessons/document_list.html:7
+msgid "Hand-outs for teachers on "
+msgstr "хендауты для учителей на"
+
+#: templates/pagination/pagination.html:5
+#: templates/pagination/pagination.html:7
+msgid "previous"
+msgstr "предыдущая"
+
+#: templates/pagination/pagination.html:21
+#: templates/pagination/pagination.html:23
+msgid "next"
+msgstr "следующая"
+
+#~ msgid "Polish"
+#~ msgstr "польский"
+
+#~ msgid "German"
+#~ msgstr "немецкий"
+
+#~ msgid "English"
+#~ msgstr "английский"
+
+#~ msgid "Lithuanian"
+#~ msgstr "литовский"
+
+#~ msgid "French"
+#~ msgstr "французский"
+
+#~ msgid "Russian"
+#~ msgstr "русский"
+
+#~ msgid "Spanish"
+#~ msgstr "испанский"
+
+#~ msgid "Ukrainian"
+#~ msgstr "украинский"
+
+#~ msgid "Choose your interface language: "
+#~ msgstr "Выберите язык интерфейса"
+
+#~ msgid "Choose language"
+#~ msgstr "Выберите язык"
+
+#~ msgid "Hide description"
+#~ msgstr "Скрыть описание"
+
+#~ msgid "Read study of epoch"
+#~ msgstr "Прочитайте очерк эпохи"
+
+#~ msgid "on Lektury.Gazeta.pl"
+#~ msgstr "на Lektury.Gazeta.pl"
+
+#~ msgid "Read article about epoch"
+#~ msgstr "Прочитайте статью об эпохе"
+
+#~ msgid "on Wikipedia"
+#~ msgstr "в Википедии"
diff --git a/wolnelektury/locale/uk/LC_MESSAGES/django.mo b/wolnelektury/locale/uk/LC_MESSAGES/django.mo
new file mode 100644 (file)
index 0000000..c3cc069
Binary files /dev/null and b/wolnelektury/locale/uk/LC_MESSAGES/django.mo differ
diff --git a/wolnelektury/locale/uk/LC_MESSAGES/django.po b/wolnelektury/locale/uk/LC_MESSAGES/django.po
new file mode 100644 (file)
index 0000000..97db73e
--- /dev/null
@@ -0,0 +1,782 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-08-25 10:23+0000\n"
+"PO-Revision-Date: 2010-08-26 14:09+0100\n"
+"Last-Translator: Natalia Kertyczak <natalczyk@o2.pl>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: templates/404.html:6
+#: templates/404.html.py:15
+#: templates/404.html:6 templates/404.html.py:15
+msgid "Page does not exist"
+msgstr "Сторінка не існує"
+
+#: templates/404.html:17
+msgid "We are sorry, but this page does not exist. Please check if you entered correct address or go to "
+msgstr "На жаль, ця сторінка не існує. Будь ласка, перевірте, чи ви ввели правильну адресу або перейдіть на"
+
+#: templates/404.html:17
+msgid "main page"
+msgstr "головна сторінка"
+
+#: templates/500.html:6
+#: templates/500.html.py:54
+msgid "Server error"
+msgstr "Помилка сервера"
+
+#: templates/500.html:55
+msgid "<p>The Wolnelektury.pl site is currently unavailable. Meanwhile, visit our <a href='http://nowoczesnapolska.org.pl'>blog</a>.</p> <p>Inform our <a href='mailto:fundacja@nowoczesnapolska.org.pl'>administrators</a> about the error.</p>"
+msgstr "<p>Сторінка Wolnelektury.pl тимчасово недоступна. В міжчасі, увійдіть на наш <a href='http://nowoczesnapolska.org.pl'>блог</a>.</p> <p>Повідомте наших <a href='mailto:fundacja@nowoczesnapolska.org.pl'>адміністраторів</a> про помилку.</p>"
+
+#: templates/503.html:6
+#: templates/503.html.py:54
+msgid "Service unavailable"
+msgstr "Послуга недоступна"
+
+#: templates/503.html:56
+msgid "The Wolnelektury.pl site is currently unavailable due to maintainance."
+msgstr "В зв'язку з технічними роботами сервіс Wolnelektury.pl тимчасово недоступний."
+
+#: templates/base.html:20
+msgid "Internet Explorer cannot display this site properly. Click here to read more..."
+msgstr "Інтернет Експолорер не може правильно відобразити цієї сторінки. Натисніть, щоб дізнатися більше..."
+
+#: templates/base.html:32
+msgid "Welcome"
+msgstr "Ласкаво просимо"
+
+#: templates/base.html:33
+msgid "Your shelves"
+msgstr "Ваші полиці"
+
+#: templates/base.html:35
+msgid "Administration"
+msgstr "Адміністрація"
+
+#: templates/base.html:37 templates/base.html.py:41
+msgid "Report a bug"
+msgstr ""
+
+#: templates/base.html:38
+msgid "Logout"
+msgstr "Вийти "
+
+#: templates/base.html:41
+#: templates/base.html.py:87
+#: templates/base.html:91
+#: templates/base.html.py:95
+#: templates/auth/login.html:4
+#: templates/auth/login.html.py:7
+#: templates/auth/login.html:12
+#: templates/auth/login.html.py:15
+msgid "Sign in"
+msgstr "Увійти"
+
+#: templates/base.html:42 templates/base.html.py:88 templates/base.html:96
+#: templates/base.html.py:100 templates/auth/login.html:7
+#: templates/auth/login.html.py:21 templates/auth/login.html:23
+msgid "Register"
+msgstr "Зареєструватися"
+
+#: templates/base.html:51
+msgid "Choose your interface language: "
+msgstr "Вибрати мову інтерфейсу"
+
+#: templates/base.html:56
+msgid "Choose language"
+msgstr "Вибрати мову"
+
+#: templates/base.html:68
+msgid ""
+"\n"
+"\t\t\t\tWolne Lektury is a project lead by <a href=\"http://nowoczesnapolska."
+"org.pl/\">Modern Poland Foundation</a>.\n"
+"\t\t\t\tDigital reproductions are made by <a href=\"http://www.bn.org.pl/"
+"\">The National Library</a>, based on TNL resources.\n"
+"\t\t\t\tHosting <a href=\"http://eo.pl/\">EO Networks</a>.\n"
+"\t\t\t\t"
+msgstr ""
+"\n"
+"\t\t\t\tWolne Lektury це проект реалізований <a href=\"http://nowoczesnapolska.org.pl/\">Фондом Модерна Польща</a>.\n"
+"\t\t\t\tЦифрові репродукції виконані <a href=\"http://www.bn.org.pl/\">Національною Бібліотекою</a>, на основі її засобів. \n"
+"\t\t\t\tГостинг <a href=\"http://eo.pl/\">EO Networks</a>.\n"
+"\t\t\t\t"
+
+#: templates/base.html:76
+msgid ""
+"\n"
+"\t\t\t\tModern Poland Foundation, 00-514 Warsaw, ul. Marszałkowska 84/92 lok. 125, tel/fax: (22) 621-30-17\n"
+"                e-mail: <a href=\"mailto:fundacja@nowoczesnapolska.org.pl\">fundacja@nowoczesnapolska.org.pl</a>\n"
+"\t\t\t\t"
+msgstr ""
+"\n"
+"\t\t\t\tФонд Модерна Польща, 00-514 Warszawa, ul. Marszałkowska 84/92 lok. 125, тел/факс: (22) 621-30-17\n"
+"                eлектронна пошта: <a href=\"mailto:fundacja@nowoczesnapolska.org.pl\">fundacja@nowoczesnapolska.org.pl</a>\n"
+"\t\t\t\t"
+
+#: templates/base.html:85 templates/base.html.py:106 templates/base.html:112
+#: templates/catalogue/book_detail.html:146
+#: templates/catalogue/book_fragments.html:33
+#: templates/catalogue/book_stub_detail.html:31
+#: templates/catalogue/differentiate_tags.html:23
+#: templates/catalogue/search_multiple_hits.html:29
+#: templates/catalogue/search_no_hits.html:22
+#: templates/catalogue/search_too_short.html:19
+#: templates/catalogue/tagged_object_list.html:155
+msgid "Close"
+msgstr "Зачинити"
+
+#: templates/base.html:108 templates/base.html.py:114
+#: templates/catalogue/book_detail.html:148
+#: templates/catalogue/book_fragments.html:35
+#: templates/catalogue/book_stub_detail.html:33
+#: templates/catalogue/differentiate_tags.html:25
+#: templates/catalogue/search_multiple_hits.html:31
+#: templates/catalogue/search_no_hits.html:24
+#: templates/catalogue/search_too_short.html:21
+#: templates/catalogue/tagged_object_list.html:157
+msgid "Loading"
+msgstr "Завантажується"
+
+#: templates/admin/base_site.html:4
+#: templates/admin/base_site.html.py:7
+msgid "Site administration"
+msgstr "Сайт адміністрації"
+
+#: templates/admin/base_site.html:8
+msgid "Translations"
+msgstr "Переклади"
+
+#: templates/admin/catalogue/book/change_list.html:6
+msgid "Import book"
+msgstr "Імпортувати книжку"
+
+#: templates/auth/login.html:4
+msgid "Register on"
+msgstr "Реєстрація на"
+
+#: templates/auth/login.html:9
+#: templates/catalogue/book_detail.html:12
+#: templates/catalogue/book_fragments.html:12
+#: templates/catalogue/book_list.html:12
+#: templates/catalogue/book_stub_detail.html:12
+
+#: templates/catalogue/breadcrumbs.html:21
+#: templates/catalogue/main_page.html:13 templates/info/base.html:10
+#: templates/lessons/document_detail.html:9
+#: templates/lessons/document_list.html:51
+msgid "Search"
+msgstr "Пошук"
+
+#: templates/auth/login.html:9
+#: templates/catalogue/book_detail.html:12
+#: templates/catalogue/book_fragments.html:12
+#: templates/catalogue/book_list.html:12
+#: templates/catalogue/book_stub_detail.html:12
+#: templates/catalogue/main_page.html:13
+#: templates/lessons/document_detail.html:9
+#: templates/lessons/document_list.html:51
+msgid "or"
+msgstr "або"
+
+#: templates/auth/login.html:9
+#: templates/catalogue/book_detail.html:12
+#: templates/catalogue/book_list.html:12
+#: templates/catalogue/book_stub_detail.html:12
+#: templates/lessons/document_list.html:51
+msgid "return to main page"
+msgstr "повернення на головну сторінку"
+
+#: templates/catalogue/book_detail.html:5
+msgid "on WolneLektury.pl"
+msgstr "на WolneLektury.pl"
+
+#: templates/catalogue/book_detail.html:29
+msgid "Work is licensed under "
+msgstr "Твір на ліцензії"
+
+#: templates/catalogue/book_detail.html:31
+msgid "Based on"
+msgstr "На основі"
+
+#: templates/catalogue/book_detail.html:24
+#: templates/catalogue/tagged_object_list.html:27
+msgid "Hide description"
+msgstr "Сховати опис"
+#: templates/catalogue/book_detail.html:40
+msgid "Put a book"
+msgstr "Покласти книжку"
+
+#: templates/catalogue/book_detail.html:40
+msgid "on the shelf!"
+msgstr "на полицю!"
+
+#: templates/catalogue/book_detail.html:44
+msgid "Read online"
+msgstr "Читати онлайн"
+
+#: templates/catalogue/book_detail.html:47
+msgid "Download PDF"
+msgstr "Завантажити PDF"
+
+#: templates/catalogue/book_detail.html:37
+#: templates/catalogue/book_detail.html:50
+msgid "Download EPUB"
+msgstr "Завантажити EPUB"
+
+#: templates/catalogue/book_detail.html:53
+msgid "Download ODT"
+msgstr "Завантажити ODT"
+
+#: templates/catalogue/book_detail.html:40
+#: templates/catalogue/book_detail.html:56
+msgid "Download TXT"
+msgstr "Завантажити TXT"
+
+#: templates/catalogue/book_detail.html:45
+msgid "Artist"
+msgstr "Артист"
+
+#: templates/catalogue/book_detail.html:63
+msgid "Director"
+msgstr "Режисер"
+
+#: templates/catalogue/book_detail.html:51
+msgid "Download MP3"
+msgstr "Завантажити MP3"
+
+#: templates/catalogue/book_detail.html:52
+msgid "Download Ogg Vorbis"
+msgstr "Завантажити Ogg Vorbis"
+
+#: templates/catalogue/book_detail.html:95
+msgid "Details"
+msgstr "Подробиці"
+
+
+#: templates/catalogue/book_detail.html:82
+msgid "Author"
+msgstr "Автор"
+
+#: templates/catalogue/book_detail.html:88
+msgid "Epoch"
+msgstr "Епоха"
+
+#: templates/catalogue/book_detail.html:94
+msgid "Kind"
+msgstr "Рід"
+
+#: templates/catalogue/book_detail.html:100
+#: templates/catalogue/book_detail.html:117
+msgid "Genre"
+msgstr "Жанр"
+
+#: templates/catalogue/book_detail.html:106
+
+msgid "Other resources"
+msgstr "Інші засоби"
+
+#: templates/catalogue/book_detail.html:125
+msgid "Book on project's wiki"
+msgstr "Книжка на вікі проекту"
+
+
+#: templates/catalogue/book_detail.html:109
+
+#: templates/catalogue/book_detail.html:126
+msgid "Source of the book"
+msgstr "Джерело книжки"
+
+#: templates/catalogue/book_detail.html:128
+msgid "Book description on Lektury.Gazeta.pl"
+msgstr "Опис книжки на Lektury.Gazeta.pl"
+
+#: templates/catalogue/book_detail.html:114
+msgid "Book description on Wikipedia"
+msgstr "Опис книжки на Вікіпедії"
+
+#: templates/catalogue/book_detail.html:119
+msgid "Work's themes "
+msgstr "Теми твору"
+
+#: templates/catalogue/book_fragments.html:5
+#: templates/catalogue/book_fragments.html:10
+msgid "Theme"
+msgstr "Тема"
+
+#: templates/catalogue/book_fragments.html:5
+#: templates/catalogue/book_fragments.html:10
+msgid "in work "
+msgstr "в творі"
+
+#: templates/catalogue/book_fragments.html:5
+msgid "on"
+msgstr "на"
+
+#: templates/catalogue/book_fragments.html:12
+msgid "return to book's page"
+msgstr "повернення на головну"
+
+#: templates/catalogue/book_fragments.html:26
+msgid "See description"
+msgstr "Дивитись опис"
+
+#: templates/catalogue/book_fragments.html:26
+msgid "of the book "
+msgstr "книжки"
+
+#: templates/catalogue/book_list.html:7
+msgid "Alphabetical listing of works on WolneLektury.pl"
+msgstr "Алфавітний список творів на WolneLektury.pl"
+
+#: templates/catalogue/book_list.html:10
+msgid "Alphabetical listing of works"
+msgstr "Алфавітний список творів"
+msgid "Listing of all works on WolneLektury.pl"
+msgstr ""
+
+#: templates/catalogue/book_list.html:10
+msgid "Listing of all works"
+msgstr ""
+
+#: templates/catalogue/book_sets.html:2
+msgid "Put a book on the shelf!"
+msgstr "Покласти книжку на полицю!"
+
+#: templates/catalogue/book_sets.html:4
+msgid "You do not have any shelves. You can create one below, if you want to."
+msgstr "В вас немає жодних полиць. Ви можете створити полицю нижче, якщо бажаєте."
+
+#: templates/catalogue/book_sets.html:9
+#: templates/catalogue/book_short.html:4
+msgid "Put on the shelf!"
+msgstr "Покласти на полицю!"
+
+#: templates/catalogue/book_sets.html:16
+#: templates/catalogue/fragment_sets.html:16
+msgid "Create new shelf"
+msgstr "Створити нову полицю"
+
+#: templates/catalogue/book_short.html:14
+msgid "Jump to"
+msgstr "Перейти до"
+
+#: templates/catalogue/book_short.html:16
+msgid "Categories"
+msgstr "Категорії"
+
+#: templates/catalogue/book_stub_detail.html:17
+msgid "This work is in public domain and will be published on Internet school library of Wolne Lektury soon."
+msgstr "Цей твір є частиною суспільного надбання і скоро буде опублікований на Wolne Lektury"
+
+#: templates/catalogue/book_stub_detail.html:20
+msgid "This work will become part of public domain and will be allowed to be published without restrictions in"
+msgstr "Цей твір стане частиною суспільного надбання і можна буде його публікувати без обмежень у"
+
+#: templates/catalogue/book_stub_detail.html:22
+msgid "Find out why Internet libraries can't publish this work."
+msgstr "Дізнатися, чому інтернет-бібліотеки не можуть опублікувати цього твору"
+
+#: templates/catalogue/book_stub_detail.html:24
+msgid "This work is copyrighted."
+msgstr "Цей твір охороняється авторстким правом"
+
+#: templates/catalogue/book_text.html:17
+msgid "Table of contents"
+msgstr "Зміст"
+
+#: templates/catalogue/book_text.html:18
+#: templates/catalogue/tagged_object_list.html:146
+msgid "Themes"
+msgstr "Теми"
+
+#: templates/catalogue/differentiate_tags.html:13
+msgid "The criteria are ambiguous. Please select one of the following options:"
+msgstr ""
+
+#: templates/catalogue/folded_tag_list.html:4
+msgid "Show full category"
+msgstr "Показати всю категорію"
+
+#: templates/catalogue/folded_tag_list.html:13
+#: templates/catalogue/main_page.html:43
+#: templates/catalogue/main_page.html:48
+#: templates/catalogue/main_page.html:87
+#: templates/catalogue/main_page.html:270
+#: templates/catalogue/main_page.html:279
+msgid "See more"
+msgstr "Більше"
+
+#: templates/catalogue/folded_tag_list.html:22
+#: templates/catalogue/main_page.html:250
+msgid "Hide"
+msgstr "Сховати"
+
+#: templates/catalogue/fragment_sets.html:2
+msgid "Shelves containing fragment"
+msgstr "Полиці, які містять фрагмент"
+
+#: templates/catalogue/fragment_sets.html:4
+#: templates/catalogue/main_page.html:28
+msgid "You do not own any shelves. You can create one below, if you want to."
+msgstr "В вас немає жодних полиць. В можете створити полицю нижче, якщо бажаєте."
+
+#: templates/catalogue/fragment_sets.html:9
+msgid "Save all shelves"
+msgstr "Зберегти всі полиці"
+
+#: templates/catalogue/fragment_short.html:7
+msgid "Expand fragment"
+msgstr "Показати фрагмент"
+
+#: templates/catalogue/fragment_short.html:13
+msgid "Hide fragment"
+msgstr "Сховати фрагмент"
+
+#: templates/catalogue/fragment_short.html:18
+msgid "See in a book"
+msgstr "Дивитись у книжці"
+
+#: templates/catalogue/main_page.html:13
+msgid "check list of books"
+msgstr "перевірити список книжок"
+
+#: templates/catalogue/main_page.html:13
+msgid "in our repository"
+msgstr "в нашій базі"
+
+#: templates/catalogue/main_page.html:17
+msgid "Browse books by categories"
+msgstr "Переглядати книжки за категоріями"
+
+#: templates/catalogue/main_page.html:19
+#: templates/catalogue/user_shelves.html:2
+msgid "Your shelves with books"
+msgstr "Ваші полиці з книжками"
+
+#: templates/catalogue/main_page.html:24
+msgid "delete"
+msgstr "видалити"
+
+#: templates/catalogue/main_page.html:33
+#: templates/catalogue/user_shelves.html:15
+msgid "Create shelf"
+msgstr "Створити подицю"
+
+#: templates/catalogue/main_page.html:37
+msgid "Create your own book set. You can share it with friends by sending them link to your shelf."
+msgstr "Створити свій вибір книжок. Ви можете поділитися ним з друзями висилаючи їм посилання на вашу подицю."
+
+#: templates/catalogue/main_page.html:38
+msgid "You need to "
+msgstr "Вам треба"
+
+#: templates/catalogue/main_page.html:38
+msgid "sign in"
+msgstr "увійти в акаунт"
+
+#: templates/catalogue/main_page.html:38
+msgid "to manage your shelves."
+msgstr "щоб управляти своїми полицями"
+
+#: templates/catalogue/main_page.html:41
+#: templates/lessons/document_list.html:49
+msgid "Hand-outs for teachers"
+msgstr "Матеріали для вчителів"
+
+#: templates/catalogue/main_page.html:42
+msgid "Lessons' prospects and other ideas for using Wolnelektury.pl for teaching."
+msgstr "Плани уроків та інші ідеї як користуватися Wolnelektury.pl в навчанні"
+
+#: templates/catalogue/main_page.html:47
+msgid "are professional recordings of literary texts from our repository, available on free license in MP3 and Ogg Vorbis formats as well as in DAISY system."
+msgstr "це професійні записи текстів літератури з нашої бази, доступні на вільній ліцензії у форматах MP3 та Ogg Vorbis, а також в системі DAISY."
+
+#: templates/catalogue/main_page.html:54
+
+#: templates/catalogue/tagged_object_list.html:128
+
+msgid "Authors"
+msgstr "Автори"
+
+#: templates/catalogue/main_page.html:58
+#: templates/catalogue/tagged_object_list.html:132
+
+msgid "Kinds"
+msgstr "Роди"
+
+#: templates/catalogue/main_page.html:62
+#: templates/catalogue/tagged_object_list.html:136
+
+msgid "Genres"
+msgstr "Жанри"
+
+#: templates/catalogue/main_page.html:66
+#: templates/catalogue/tagged_object_list.html:140
+msgid "Epochs"
+msgstr "Епохи"
+
+#: templates/catalogue/main_page.html:72
+msgid "Themes and topics"
+msgstr "Теми та мотиви"
+
+#: templates/catalogue/main_page.html:75
+msgid "Themes groups"
+msgstr "Групи мотивів"
+
+#: templates/catalogue/main_page.html:260
+msgid "News"
+msgstr "Новості"
+
+#: templates/catalogue/main_page.html:264
+msgid "See our blog"
+msgstr "Дивитись наш блог"
+
+#: templates/catalogue/main_page.html:267
+msgid "You can help us!"
+msgstr "Можете нам допомогти!"
+
+#: templates/catalogue/main_page.html:268
+msgid "We try our best to elaborate works appended to our library. It is possible only due to support of our volunteers."
+msgstr "Ми намагаємося якомога краще підготувати твори, які додаються до нашої бібліотеки. Це можливо тільки завдяки нашим волонтерам."
+
+#: templates/catalogue/main_page.html:269
+msgid "We invite people who want to take part in developing Internet school library Wolne Lektury."
+msgstr "Запрошуємо всіх, хто хоче брати участь у творенні шкільної  інтернет-бібліотеки Wolne Lektury."
+
+#: templates/catalogue/main_page.html:273
+msgid "About us"
+msgstr "Про нас"
+
+#: templates/catalogue/main_page.html:275
+msgid ""
+"\n"
+"\t\t\tInternet library with school readings “Wolne Lektury” (<a href=\"http://wolnelektury.pl\">www.wolnelektury.pl</a>) is a project made by Modern Poland Foundation. It started in 2007 and shares school readings, which are recommended by Ministry of National Education and are in public domain.\n"
+"\t\t\t"
+msgstr ""
+"\n"
+"\t\t\tІнтернет-бібліотека шкільної літератури “Wolne Lektury” (<a href=\"http://wolnelektury.pl\">www.wolnelektury.pl</a>) це проект реалізований Фондом Модерна Польща. Діє він з 2007 року та надає доступ до літератури, рекомендованої Міністерством національної освіти, яка є частиною суспільного надбання.\n"
+"\t\t\t"
+
+#: templates/catalogue/search_multiple_hits.html:5
+#: templates/catalogue/search_too_short.html:5
+msgid "Searching in"
+msgstr "Пошук в"
+
+#: templates/catalogue/search_multiple_hits.html:14
+msgid "More than one result matching the criteria found."
+msgstr "Більше ніж один результат відповідає критеріям."
+
+#: templates/catalogue/search_no_hits.html:5
+msgid "Search in WolneLektury.pl"
+msgstr "Пошук в WolneLektury.pl"
+
+#: templates/catalogue/search_no_hits.html:14
+#: templates/catalogue/tagged_object_list.html:102
+msgid "Sorry! Search cirteria did not match any resources."
+msgstr "На жаль, критеріям пошуку не відповідає жоден результат."
+
+#: templates/catalogue/search_no_hits.html:16
+msgid ""
+"Search engine supports following criteria: title, author, theme/topic, epoch, kind and genre.\n"
+"\t\tAs for now we do not support full text search."
+msgstr ""
+"В пошуковій системі можливий пошук за критеріями: автор, тема/мотив, епоха, рід та жанр.\n"
+"\t\tНаразі неможливий пошук в цілому тексті."
+
+#: templates/catalogue/search_too_short.html:14
+msgid "Sorry! Search query must have at least two characters."
+msgstr "На жаль, для пошуку потрібно ввести щонайменше два знаки."
+
+#: templates/catalogue/tag_list.html:4
+msgid "See full category"
+msgstr "Дивитись всю категорію"
+
+#: templates/catalogue/tagged_object_list.html:15
+msgid "Your shelf is empty"
+msgstr "Ваша полиця порожня"
+
+#: templates/catalogue/tagged_object_list.html:16
+msgid "You can put a book on a shelf by entering page of the reading and clicking 'Put on the shelf'."
+msgstr "Щоб покласти книжку на полицю, увійдіть на сторінку книжки та натисніть \"Покласти на полицю\"."
+
+#: templates/catalogue/tagged_object_list.html:32
+msgid "Download all books from this shelf"
+msgstr "Завантажити всі книжки з цієї полиці"
+
+#: templates/catalogue/tagged_object_list.html:36
+msgid "Choose books' formats which you want to download:"
+msgstr "Вибрати формат, в якому хочете завантажити книжку:"
+
+#: templates/catalogue/tagged_object_list.html:37
+#: templates/catalogue/tagged_object_list.html:39
+#: templates/catalogue/tagged_object_list.html:40
+msgid "for reading"
+msgstr "для читання"
+
+#: templates/catalogue/tagged_object_list.html:37
+msgid "and printing using"
+msgstr "та друку з використанням"
+
+#: templates/catalogue/tagged_object_list.html:39
+msgid "and editing using"
+msgstr "та едиції з використанням"
+
+#: templates/catalogue/tagged_object_list.html:40
+msgid "on small displays, for example mobile phones"
+msgstr "на невеликих екранах, на приклад на мобільному телефоні"
+
+#: templates/catalogue/tagged_object_list.html:41
+#: templates/catalogue/tagged_object_list.html:42
+msgid "for listening"
+msgstr "для слухання"
+
+#: templates/catalogue/tagged_object_list.html:41
+msgid "on favourite MP3 player"
+msgstr "на улюбленому плеєрі MP3"
+
+#: templates/catalogue/tagged_object_list.html:42
+msgid "open format"
+msgstr "відкритий формат"
+
+#: templates/catalogue/tagged_object_list.html:42
+msgid "Xiph.org Foundation"
+msgstr "Фонд Xiph.org"
+
+#: templates/catalogue/tagged_object_list.html:43
+#: templates/lessons/ajax_document_detail.html:3
+#: templates/lessons/document_detail.html:13
+msgid "Download"
+msgstr "Завантажити"
+
+#: templates/catalogue/tagged_object_list.html:43
+msgid "Updating list of books' formats on the shelf"
+msgstr "Оновити список форматів книжок, які на полиці"
+
+#: templates/catalogue/tagged_object_list.html:43
+msgid "cancel"
+msgstr "відхилити"
+
+#: templates/catalogue/tagged_object_list.html:48
+msgid "Share this shelf"
+msgstr "Поділитися цією полицею"
+
+#: templates/catalogue/tagged_object_list.html:48
+msgid "Copy this link and share it with other people to let them see your shelf."
+msgstr "Копіювати це посилання, щоб вислати іншим, та поділитися полицею."
+
+#: templates/catalogue/tagged_object_list.html:57
+msgid "Read work's study of this author on Lektury.Gazeta.pl"
+msgstr "Прочитати обговорення цього автора на Lektury.Gazeta.pl"
+
+#: templates/catalogue/tagged_object_list.html:60
+msgid "Read study of epoch"
+msgstr "Прочитати обговорення епохи"
+
+#: templates/catalogue/tagged_object_list.html:60
+msgid "on Lektury.Gazeta.pl"
+msgstr "на Lektury.Gazeta.pl"
+
+#: templates/catalogue/tagged_object_list.html:67
+msgid "Read article about this author on Wikipedia"
+msgstr "Прочитати статтю про цього автора на Вікіпедії"
+
+#: templates/catalogue/tagged_object_list.html:70
+msgid "Read article about epoch"
+msgstr "Прочитати статтю про цю епоху"
+
+#: templates/catalogue/tagged_object_list.html:70
+msgid "on Wikipedia"
+msgstr "на Вікіпедії"
+
+#: templates/catalogue/tagged_object_list.html:80
+
+msgid "Delete"
+msgstr "Видалити"
+
+#: templates/catalogue/tagged_object_list.html:102
+msgid "This author's works are copyrighted."
+msgstr "Твори цього автора охороняються авторським правом"
+
+#: templates/catalogue/tagged_object_list.html:91
+msgid "This author's works are in public domain and will be published on Internet school library of Wolne Lektury soon."
+msgstr "Твори цього автора є частиною суспільного надбання і скоро будуть опубліковані на  Wolne Lektury."
+
+#: templates/catalogue/tagged_object_list.html:95
+msgid "This author's works will become part of public domain and will be allowed to be published without restrictions in"
+msgstr "Твори цього автора стануть частиною суспільного надбання і можна буде їх публікувати без обмежень в"
+
+#: templates/catalogue/tagged_object_list.html:111
+msgid "Find out why Internet libraries can't publish this author's works."
+msgstr "Дізнатися чому інтернет-бібліотеки не можуть опубілкувати творів цього автора."
+
+#: templates/catalogue/user_shelves.html:6
+msgid "remove"
+msgstr "Видалити"
+
+#: templates/catalogue/user_shelves.html:10
+msgid "You do not own any shelves. You can create one below if you want to"
+msgstr "В вас немає жодних полиць. Можете створити полицю нижче, якщо бажаєте"
+
+#: templates/info/base.html:10
+msgid "return to the main page"
+msgstr "повернення на головну"
+
+#: templates/info/join_us.html:2
+msgid ""
+"We have over 1000 works published in Wolne Lektury!\n"
+"Help us expand the library and set new readings free by\n"
+"making a donation or transferring 1% of your income tax."
+msgstr ""
+"На сайті Wolne Lektury опубліковано більше 1000 творів!\n"
+"Допоможіть нам розвивати бібліотеку і надавати доступ до нових творів - \n"
+"передайте нам внесок або 1 відсоток вашого податку на прибуток."
+
+#: templates/info/join_us.html:5
+#: templates/info/join_us.html.py:10
+msgid "More..."
+msgstr "Більше..."
+
+#: templates/info/join_us.html:7
+msgid ""
+"Become an editor of Wolne Lektury! Find out if\n"
+"we're currently working on a reading you're looking for and prepare\n"
+"a publication by yourself by logging into the Editorial Platform."
+msgstr ""
+"Станьте редакторами  Wolne Lektury! Дізнайтеся чи\n"
+"працюємо зараз над текстом, якого шукаєте та самі підготуйте\n"
+"публікацію, реєструючись на Редакторській платформі."
+
+#: templates/lessons/ajax_document_detail.html:3
+#: templates/lessons/document_detail.html:13
+msgid "author"
+msgstr "автор"
+
+#: templates/lessons/document_detail.html:9
+msgid "return to list of materials"
+msgstr "повернення до списку матеріалів"
+
+#: templates/lessons/document_list.html:7
+msgid "Hand-outs for teachers on "
+msgstr "Матеріали для вчителів у"
+
+#: templates/pagination/pagination.html:5
+#: templates/pagination/pagination.html:7
+msgid "previous"
+msgstr "попередня"
+
+#: templates/pagination/pagination.html:21
+#: templates/pagination/pagination.html:23
+msgid "next"
+msgstr "наступна"
+
index a9acc04..309a56e 100755 (executable)
@@ -1,12 +1,18 @@
 #!/usr/bin/env python
-from os.path import abspath, dirname, join
+import os.path
 import sys
 
+ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+
 # Add apps and lib directories to PYTHONPATH
-sys.path.insert(0, abspath(join(dirname(__file__), '../apps')))
-sys.path.insert(0, abspath(join(dirname(__file__), '../lib')))
+sys.path = [
+    os.path.join(ROOT, 'apps'),
+    os.path.join(ROOT, 'lib'),
+    os.path.join(ROOT, 'lib/librarian'),
+] + sys.path
 
 from django.core.management import execute_manager
+
 try:
     import settings # Assumed to be in the same directory.
 except ImportError:
index c9a17dc..60b382c 100644 (file)
@@ -118,7 +118,7 @@ class ProfileMiddleware(object):
             response.content += self.summary_for_files(stats_str)
 
             os.unlink(self.tmpfile)
-            
+
             response.content += '\n%d SQL Queries:\n' % len(connection.queries)
             response.content += pprint.pformat(connection.queries)
 
index 6b7d333..9396a1d 100644 (file)
@@ -1,3 +1,4 @@
+# -*- coding: utf-8 -*-
 # Django settings for wolnelektury project.
 from os import path
 
@@ -5,6 +6,7 @@ PROJECT_DIR = path.abspath(path.dirname(__file__))
 
 DEBUG = False
 TEMPLATE_DEBUG = DEBUG
+MAINTENANCE_MODE = False
 
 ADMINS = [
     # ('Your Name', 'your_email@domain.com'),
@@ -30,6 +32,20 @@ TIME_ZONE = 'Europe/Warsaw Poland'
 # http://www.i18nguy.com/unicode/language-identifiers.html
 LANGUAGE_CODE = 'pl'
 
+gettext = lambda s: s
+
+LANGUAGES = tuple(sorted([
+    ('pl', u'polski'),
+    ('de', u'Deutsch'),
+    ('en', u'English'),
+    ('lt', u'lietuvių'),
+    ('fr', u'français'),
+    ('ru', u'русский'),
+    ('es', u'español'),
+    ('uk', u'українська'),
+], key=lambda x: x[0]))
+
+
 SITE_ID = 1
 
 # If you set this to False, Django will make some optimizations so as not
@@ -67,6 +83,7 @@ TEMPLATE_CONTEXT_PROCESSORS = [
     'django.core.context_processors.i18n',
     'django.core.context_processors.media',
     'django.core.context_processors.request',
+    'wolnelektury.context_processors.extra_settings',
 ]
 
 MIDDLEWARE_CLASSES = [
@@ -75,6 +92,9 @@ MIDDLEWARE_CLASSES = [
     'django.contrib.auth.middleware.AuthenticationMiddleware',
     'django.middleware.doc.XViewMiddleware',
     'pagination.middleware.PaginationMiddleware',
+    'django.middleware.locale.LocaleMiddleware',
+
+    'maintenancemode.middleware.MaintenanceModeMiddleware',
 ]
 
 ROOT_URLCONF = 'wolnelektury.urls'
@@ -95,7 +115,7 @@ INSTALLED_APPS = [
     'django.contrib.sites',
     'django.contrib.admin',
     'django.contrib.admindocs',
-    
+
     # external
     'south',
     'sorl.thumbnail',
@@ -104,10 +124,14 @@ INSTALLED_APPS = [
     'pagination',
     'chunks',
     'compress',
+    'modeltranslation',
     'catalogue',
     'lessons',
     'piston',
     'api',
+    'rosetta',
+    'infopages',
+    'suggest',
 ]
 
 CACHE_BACKEND = 'locmem:///?max_entries=3000'
@@ -115,7 +139,7 @@ CACHE_BACKEND = 'locmem:///?max_entries=3000'
 # CSS and JavaScript file groups
 COMPRESS_CSS = {
     'all': {
-        'source_filenames': ('css/master.css', 'css/jquery.autocomplete.css', 'css/master.plain.css', 'css/sponsors.css',),
+        'source_filenames': ('css/master.css', 'css/jquery.autocomplete.css', 'css/jquery.countdown.css', 'css/master.plain.css', 'css/sponsors.css', 'css/facelist_2-0.css',),
         'output_filename': 'css/all.min?.css',
     },
     'book': {
@@ -130,9 +154,14 @@ COMPRESS_JS = {
         'output_filename': 'js/jquery.min.js',
     },
     'all': {
-        'source_filenames': ('js/jquery.autocomplete.js', 'js/jquery.form.js', 
+        'source_filenames': ('js/jquery.autocomplete.js', 'js/jquery.form.js',
+            'js/jquery.countdown.js', 'js/jquery.countdown-pl.js',
+            'js/jquery.countdown-de.js', 'js/jquery.countdown-uk.js',
+            'js/jquery.countdown-es.js', 'js/jquery.countdown-lt.js',
+            'js/jquery.countdown-ru.js', 'js/jquery.countdown-fr.js',
+            'js/jquery.marquee.js',
             'js/jquery.jqmodal.js', 'js/jquery.labelify.js', 'js/catalogue.js',
-            'js/jquery.cookie.js',),
+            ),
         'output_filename': 'js/all?.min.js',
     },
     'book': {
@@ -157,6 +186,11 @@ THUMBNAIL_PROCESSORS = (
     'sponsors.processors.add_padding',
 )
 
+TRANSLATION_REGISTRY = "wolnelektury.translation"
+
+# limit number of filtering tags
+MAX_TAG_LIST = 6
+
 # Load localsettings, if they exist
 try:
     from localsettings import *
diff --git a/wolnelektury/static/css/facelist_2-0.css b/wolnelektury/static/css/facelist_2-0.css
new file mode 100644 (file)
index 0000000..bd6d35e
--- /dev/null
@@ -0,0 +1,182 @@
+.facelist-selections a {
+       color: black;
+       text-decoration: none;
+}
+.facelist-selections a:hover {
+       color: black;
+       text-decoration: none;
+}
+ul.facelist-selections {
+       list-style-type: none;
+       border-top: 1px solid #888;
+       border-bottom: 1px solid #b6b6b6;
+       border-left: 1px solid #aaa;
+       border-right: 1px solid #aaa;
+       padding: 4px 0 4px 4px;
+       overflow: auto;
+       background-color: #fff;
+       box-shadow:inset 0 1px 2px #888;
+       -webkit-box-shadow:inset 0 1px 2px #888;
+       -moz-box-shadow:inset 0 1px 2px #888;
+       width: 90%;
+}
+
+ul.facelist-selections.loading {
+       background-color: #eee;
+}
+
+ul.facelist-selections li {
+       float: left;
+       margin: 1px 4px 1px 0;
+       padding-top: 20px;
+       margin-left: 10px;
+}
+
+ul.facelist-selections li.facelist-selection-item {
+       color:white;
+       position: relative;
+       background-color: #fbc11d;
+       -moz-border-radius: 3px;
+       -webkit-border-radius: 3px;
+       border-radius: 3px;
+       -webkit-transition: background-color .2s ease-in;
+       cursor: pointer;
+       padding:2px 5px 2px 5px;
+       font-size: 13px;
+       font-family: "Lucida Grande", arial, sans-serif;
+}
+
+ul.facelist-selections li.facelist-selection-item:last-child {
+       margin-left: 30px;
+}
+
+ul.facelist-selections li.facelist-selection-item a.facelist-close {
+       float: right;
+       margin: 1px 0 0 7px;
+       padding: 0 2px;
+       cursor: pointer;
+       color: #black;
+       font-family: "Helvetica", helvetica, arial, sans-serif;
+       font-size: 14px;
+       font-weight: bold;
+       -webkit-transition: color .1s ease-in;
+}
+
+ul.facelist-selections li.facelist-selection-item.blur a.facelist-close {
+       color: #999;
+}
+
+ul.facelist-selections li:hover.facelist-selection-item {
+       background-color: #d8dfea;
+}
+
+ul.facelist-selections li.facelist-selection-item.selected {
+       background-color: #5670a6;
+       color: #fff; 
+}
+
+ul.facelist-selections li.facelist-original {
+       margin-left: 0;
+}
+
+ul.facelist-selections li.facelist-original input {
+       border: none;
+       outline: none;
+       font-size: 13px;
+       width: 120px;
+       height: 18px;
+       padding-top: 3px;
+}
+
+ul.facelist-list {
+       position: absolute;
+       list-style-type: none;
+       margin: 2px 0 0 0;
+       padding: 0;
+       font-size: 14px;
+       color: #000;
+       font-family: "Lucida Grande", arial, sans-serif;
+       background-color: #fff;
+       z-index: 2;
+       border: solid #ccd5e4 1px;
+}
+
+li.facelist-result-item, li.facelist-message {
+       margin: 0 0 0 0;
+       padding: 5px 12px;
+       background-color: transparent;
+       border: 1px solid #fff;
+       border-bottom: 1px solid #ddd;
+       cursor: pointer;
+}
+
+li:first-child.facelist-result-item {
+       margin: 0;
+}
+
+li.facelist-message {
+       margin: 0;
+       cursor: default;
+}
+
+li.facelist-result-item.active {
+       background-color: #3b5998;
+       border-color: #3342e8;
+       color: #fff;
+}
+
+li.facelist-result-item em { 
+       font-style: normal; 
+       background: #dbe1ec;  
+       padding: 0 2px;
+}
+
+li.facelist-result-item.active em { 
+       background: #5670a6;  
+       color: #fff;
+}
+
+/* Firefox 3.0 Hacks */
+ul.facelist-list,  x:-moz-any-link, x:default { 
+       border: 1px solid #888;
+}
+BODY:first-of-type ul.facelist-list, x:-moz-any-link, x:default { /* Target FF 3.5+ */
+       border: none;
+}
+
+/* Webkit Hacks  */
+@media screen and (-webkit-min-device-pixel-ratio:0) { 
+       ul.facelist-selections {
+               border-top-width: 2px;
+       }
+       ul.facelist-selections li.facelist-selection-item {
+               padding-top: 3px;
+               padding-bottom: 3px;
+       }
+       ul.facelist-selections li.facelist-selection-item a.facelist-close {
+               margin-top: -1px;
+       }
+       ul.facelist-selections li.facelist-original input {
+               height: 19px;
+       }
+}
+
+/* Opera Hacks  */
+@media all and (-webkit-min-device-pixel-ratio:10000), not all and (-webkit-min-device-pixel-ratio:0) {
+       ul.facelist-list {
+               border: 1px solid #888;
+       }
+       ul.facelist-selections li.facelist-selection-item a.facelist-close {
+               margin-left: 4px;
+               margin-top: 0;
+       }
+}
+
+/* IE Hacks  */
+ul.facelist-list {
+       border: 1px solid #888\9;
+}
+ul.facelist-selections li.facelist-selection-item a.facelist-close {
+       margin-left: 4px\9;
+       margin-top: 0\9;
+}
diff --git a/wolnelektury/static/css/jquery.countdown.css b/wolnelektury/static/css/jquery.countdown.css
new file mode 100644 (file)
index 0000000..da40686
--- /dev/null
@@ -0,0 +1,52 @@
+/* jQuery Countdown styles 1.5.7. */
+.hasCountdown {
+       /*border: 1px solid #ccc;
+       background-color: #eee;*/
+       margin: 20px 0 50px 0;
+}
+.countdown_rtl {
+       direction: rtl;
+}
+.countdown_holding span {
+       background-color: #ccc;
+}
+.countdown_row {
+       clear: both;
+       width: 100%;
+       padding: 0px 2px;
+       text-align: center;
+}
+.countdown_show1 .countdown_section {
+       width: 98%;
+}
+.countdown_show2 .countdown_section {
+       width: 48%;
+}
+.countdown_show3 .countdown_section {
+       width: 32.5%;
+}
+.countdown_show4 .countdown_section {
+       width: 24.5%;
+}
+.countdown_show5 .countdown_section {
+       width: 19.5%;
+}
+.countdown_show6 .countdown_section {
+       width: 16.25%;
+}
+.countdown_show7 .countdown_section {
+       width: 14%;
+}
+.countdown_section {
+       display: block;
+       float: left;
+       font-size: 100%;
+       text-align: center;
+}
+.countdown_amount {
+       font-size: 350%;
+}
+.countdown_descr {
+       display: block;
+       width: 100%;
+}
index b0d3542..5e31549 100644 (file)
@@ -78,6 +78,7 @@ img {
     overflow-x: hidden;
     overflow-y: auto;
     opacity: 0.9;
+    z-index: 99;
 }
 
 #toc ol, #themes ol {
@@ -154,11 +155,18 @@ p {
     color: #777;
     padding: 0 0.5em;
     width: 7.5em;
+
     font-style: normal;
     font-weight: normal;
+    font-variant: normal;
+    letter-spacing: 0;
+    text-transform: none;
+    text-decoration: none;
+
     font-size: 16px;
     float: right;
     margin-right: -9.5em;
+    margin-bottom: 0.5em;
     clear: both;
     left: 40em;
     line-height: 1.5em;
@@ -169,6 +177,9 @@ p {
     font-style: normal;
     font-weight: normal;
     font-size: 12px;
+    padding-left: 2px;
+    position: relative;
+    top: -4px;
 }
 
 #footnotes .annotation {
@@ -194,10 +205,13 @@ blockquote {
 /* ============= */
 /* = Numbering = */
 /* ============= */
+.verse, .paragraph {
+       position:relative;
+}
 .anchor {
     position: absolute;
     margin: -0.25em -0.5em;
-    left: 1em;
+    left: -3em;
     color: #777;
     font-size: 12px;
     width: 2em;
@@ -317,3 +331,11 @@ em.person {
     font-variant: small-caps;
 }
 
+
+/* =================================== */
+/* = Hide some elements for printing = */
+/* =================================== */
+
+@media print {
+    #menu {display: none;}
+}
index ba6e0aa..cfa644f 100644 (file)
@@ -88,6 +88,36 @@ em {
     color: #777;
 }
 
+.lang-menu {
+       margin-right: 0.7em;
+       line-height: 24px;
+} 
+
+.lang-menu button {
+       color: blue;
+       border: none;
+       border-right: 1px solid gray;
+       -moz-border-radius: 2px;
+       background: inherit;    
+       cursor: pointer;
+       padding: 0.2em 0.5em;   
+       font-size: 10px;
+}
+
+.lang-menu button:hover {
+       color: blue;
+       text-decoration: underline;     
+}
+
+.lang-menu button.active {
+       color: black;
+       text-decoration: none;
+}
+
+.lang-menu button.last {
+       border-right: none;
+}
+
 /* ======================== */
 /* = Footer with sponsors = */
 /* ======================== */
@@ -116,6 +146,13 @@ em {
     margin: 0.5em 0;
     padding: 0.5em;
     background-color: rgb(132, 191, 42);
+}
+
+#searchContainer {
+    width: 100%;
+    min-height: 65px;
+    background-color: rgb(132, 191, 42);
+    padding: 0px 5px;
     -moz-border-radius: 4px;
     -webkit-border-radius: 4px;
     border-radius: 4px;
@@ -123,6 +160,11 @@ em {
     border-right: 0.15em solid #7B9C2D;
 }
 
+#searchContainer #search-form {
+    padding: 0;
+    margin: 0;
+}
+
 #search-form p {
     margin: 0em 0 0 0;
 }
@@ -133,11 +175,12 @@ em {
 }
 
 #search-form li {
-    margin: 0;
+    margin: 2px 0 0 5px;
     padding: 0;
     list-style: none;
     display: block;
     float: left;
+    /*margin-left: 5px;*/
 }
 
 #search-form li.category, #search-form li.book-title {
@@ -164,13 +207,26 @@ em {
 }
 
 .ac_input {
-    width: 18em;
+    width: 300px;
+    border: 0;
 }
 
 p .ac_input {
     width: 28em;
 }
 
+#searchSubmit {
+    float: left; 
+    margin-top: 10px; 
+    height: 33px;
+}
+/* ================== */
+/* = Search matches = */
+/* ================== */
+
+.matches li:first-letter {
+    text-transform: uppercase;
+}
 
 /* ============= */
 /* = Tags list = */
@@ -351,6 +407,10 @@ div.shown-tags p, div.all-tags p {
 #description {
     margin-top: 0.5em;
     text-align: justify;
+    overflow: hidden;
+}
+#description-short {
+       display:none;
 }
 
 #description .meta {
@@ -459,6 +519,36 @@ div.shown-tags p, div.all-tags p {
     color: #900;    
 }
 
+#toggle-share-shelf {
+    display: block;
+    width: 100%;
+    height: 1.5em;
+    background-color: #EEE;
+    margin-top: 0.5em;
+    padding: 0.5em 0;
+    -moz-border-radius: 4px;
+    -webkit-border-radius: 4px;
+    border-radius: 4px;
+    text-align: center;   
+    outline: none; 
+}
+#toggle-share-shelf p {
+       margin:0;
+}
+
+#share-shelf {
+    -moz-border-radius: 4px;
+    -webkit-border-radius: 4px;
+    border-radius: 4px;
+    border: 3px solid #EEE;
+    padding: 5px;
+    margin-top: -5px;
+}
+#share-shelf input {
+       width: 100%;
+}
+
+
 /* ============================ */
 /* = Books and fragments list = */
 /* ============================ */
@@ -550,6 +640,7 @@ div.shown-tags p, div.all-tags p {
 
 .cuteform .error {
     color: #BF3024;
+       display: block;
 }
 
 /* ================ */
@@ -659,6 +750,37 @@ div.shown-tags p, div.all-tags p {
     text-decoration: none;
 }
 
+#suggest-window {
+    position: absolute;
+    display: none;
+    width: 35em;
+    background-color: transparent;
+    margin-top: -0.5em;
+    margin-left: 1em;
+}
+
+#suggest-window div.header {
+    background-color: #FFF;
+    border-right: 0.3em solid #DDD;
+    width: 4em;
+    right: 0;
+    left: auto;
+    padding: 0.5em 1em 0.5em 1em;
+    float: right;
+    text-align: center;
+}
+
+#suggest-window div.target {
+    clear: both;
+    background-color: #FFF;
+    border-right: 0.3em solid #DDD;
+    border-bottom: 0.3em solid #DDD;
+    padding: 1em;
+}
+#suggest-form textarea {
+       width: 30em;
+}
+
 /* ======================== */
 /* = Alphabetic book list = */
 /* ======================== */
@@ -669,11 +791,15 @@ div.shown-tags p, div.all-tags p {
 }
 
 #book-a-list #book-list ol {
-    padding: 0;
+    padding-left: 1em;
     margin: 0.3em 0 1.2em 0;
     list-style: none;
 }
 
+#book-a-list #book-list h2 a {
+    color: black;
+}
+
 #top-message {
     background-color: #2F4110;
     color: #FFF;
@@ -751,6 +877,14 @@ div.shown-tags p, div.all-tags p {
     display: block;
 }
 
+#document-list ul {
+  padding-left: 30px;
+  list-style: disc;
+}
+#document-list li li a {
+  width: 340px;
+}
+
 #document-list li a:hover, #document-list li a.active {
     text-decoration: none;
     background-color: #EEE;
@@ -810,4 +944,7 @@ div.shown-tags p, div.all-tags p {
     font-size: 12px;
     color: #FFF;
     text-decoration: none;
-}
\ No newline at end of file
+}
+#createNewShelf {
+display: none;
+}
index 9f6a9bb..4b847dc 100644 (file)
@@ -1,8 +1,14 @@
+.sponsors-sponsor-logo {
+  margin-left: 1em;
+  vertical-align: middle;
+}
+
 .sponsors-sponsor-column {
-    float: left;
-    overflow: hidden;
+  line-height: 120px;
+  padding-right: 5em;
 }
 
-.sponsors-sponsor-logo {
-    float: left;
-}c
\ No newline at end of file
+.sponsors-sponsor-column-name {
+  font-weight: bold;
+  font-size: 1.25em;
+}
diff --git a/wolnelektury/static/css/widget.css b/wolnelektury/static/css/widget.css
new file mode 100644 (file)
index 0000000..cd8e16b
--- /dev/null
@@ -0,0 +1,46 @@
+#wl {
+background-color: white;
+}
+#wl img {
+border: 0;
+}
+.ui-menu {
+width: 160px;
+font-size: small;
+list-style-type: none;
+padding: 0;
+margin:0;
+border-left:  1px solid #696969;
+border-right: 1px solid #696969;
+border-bottom: 1px solid #696969;
+}
+
+.ui-menu li {
+font-size: small;
+padding: 5px;
+width: 150px
+}
+
+.ui-menu li:nth-child(odd) {
+background-color: white;
+}
+
+.ui-menu li:nth-child(even){
+background-color: #EDF1F5;
+}
+
+.ui-menu li:hover{
+background-color: #053469;
+color:white;
+}
+
+.ui-menu a:hover {
+color:white;
+text-decoration: none;
+}
+
+.ui-corner-all {
+width: 160px;
+cursor: pointer;
+display:block;
+}
diff --git a/wolnelektury/static/img/search.png b/wolnelektury/static/img/search.png
new file mode 100644 (file)
index 0000000..6bfc84c
Binary files /dev/null and b/wolnelektury/static/img/search.png differ
index 41e3be2..9960bfa 100644 (file)
@@ -1,30 +1,34 @@
-$(function() {    
+$(function() {
     function scrollToAnchor(anchor) {
         if (anchor) {
-            var element = $('a[name="' + anchor.slice(1) + '"]');
+            var anchor_name = anchor.slice(1);
+            var element = $('a[name="' + anchor_name + '"]');
             if (element.length > 0) {
                 $.scrollTo(element, 500, {offset: {top: -50, left: 0}});
-                $(element).highlightFade('yellow');
+                foot_elem = $('#footnotes a[name="' + anchor_name + '"]');
+                if (foot_elem.length > 0) {
+                    $(element).parent().highlightFade('yellow');
+                }
                 window.location.hash = anchor;
             }
         }
     }
-    
+
     $.highlightFade.defaults.speed = 3000;
     $('#toc').hide();
     if ($('#toc li').length == 0) {
         $('#menu li a[href="#toc"]').remove();
     }
-    
+
     // On page load, scroll to anchor
     scrollToAnchor(window.location.hash)
-    
+
     $('#toc, #themes, #book-text').delegate('click', 'a', function(event) {
         event.preventDefault();
         $('#menu li a.selected').click();
         scrollToAnchor($(this).attr('href'));
     });
-    
+
     $('#menu li a').toggle(function() {
         $('#menu li a.selected').click();
         $(this).addClass('selected');
index 519280a..31bad6e 100644 (file)
@@ -1,3 +1,53 @@
+var LOCALE_TEXTS = {
+    "pl": {
+        "DELETE_SHELF": "Czy na pewno usunąć półkę",
+        "HIDE_DESCRIPTION": "Zwiń opis",
+        "EXPAND_DESCRIPTION": "Rozwiń opis",
+        "LOADING": "Ładowanie"
+    },
+    "de": {
+        "DELETE_SHELF": "Möchtest du wirklich dieses Bücherregal entfernen?",
+        "HIDE_DESCRIPTION": "Beschreibung zuklappen",
+        "EXPAND_DESCRIPTION": "Beschreibung aufklappen",
+        "LOADING": "Herunterladen"
+    },
+    "fr": {
+        "DELETE_SHELF": "Voulez-vous supprimer l'étagère  définitivement?",
+        "HIDE_DESCRIPTION": "Montrer la description",
+        "EXPAND_DESCRIPTION": "Cacher la description",
+        "LOADING": "Chargement"
+    },
+    "en": {
+        "DELETE_SHELF": "Are you sure you want to delete this shelf?",
+        "HIDE_DESCRIPTION": "Hide",
+        "EXPAND_DESCRIPTION": "Expand",
+        "LOADING": "Loading"
+    },
+    "ru": {
+        "DELETE_SHELF": "Уверены ли вы том, чтобы удалить полку?",
+        "HIDE_DESCRIPTION": "Свернуть описание",
+        "EXPAND_DESCRIPTION": "Раскрыть описание",
+        "LOADING": "Загрузка"
+    },
+    "es": {
+        "DELETE_SHELF": "¿Estás seguro que quieres borrar este estante?",
+        "HIDE_DESCRIPTION": "Esconder la descripción",
+        "EXPAND_DESCRIPTION": "Ampliar la descripción",
+        "LOADING": "Cargando"
+    },
+    "lt":{
+        "DELETE_SHELF": "Ar tikrai nori pašalinti lentną?",
+        "HIDE_DESCRIPTION": "Suvyniok aprašymą ",
+        "EXPAND_DESCRIPTION": "Išplėsk aprašymą",
+        "LOADING": "Krovimas"
+    },
+    "uk":{
+        "DELETE_SHELF": "Ви впевнені, що хочете видалити полицю?",
+        "HIDE_DESCRIPTION": "Сховати опис",
+        "EXPAND_DESCRIPTION": "Показати опис",
+        "LOADING": "Завантажується"
+    }
+}
 var BANNER_TEXTS = [
     'Przekaż 1% żeby ukryć ten baner.',
     'Jak dobrze wydać 1% swojego podatku? <strong>Poradnik dla opornych</strong>.',
@@ -35,63 +85,115 @@ function changeBannerText() {
             $(this).html(BANNER_TEXTS[index]);
             $(this).fadeIn('slow');
         });
-        
+
         setTimeout(changeBannerText, 30 * 1000);
     }
 }
 
+function autocomplete_result_handler(event, item) {
+    $(event.target).closest('form').submit();
+}
+function serverTime() {
+    var time = null;
+    $.ajax({url: '/katalog/zegar/',
+        async: false, dataType: 'text',
+        success: function(text) {
+            time = new Date(text);
+        }, error: function(http, message, exc) {
+            time = new Date();
+    }});
+    return time;
+}
 
 (function($) {
     $(function() {
+
+        $.fn.toggle_slide = function(p) {
+            cont = $(this);
+            short_el = p['short_el'] || $(':first-child', this);
+            long_el = p['long_el'] || short_el.next();
+            button = p['button'];
+            short_text = p['short_text'],
+            long_text = p['long_text'];
+
+            var toggle_fun = function(cont, short_el, long_el, button, short_text, long_text) {
+                var toggle = function() {
+                    if (cont.hasClass('short')) {
+                        cont.animate({"height": long_el.attr("cont_h")+'px'}, {duration: "fast" }).removeClass('short');
+                        short_el.hide();
+                        long_el.show();
+                        if (button && long_text) button.html(long_text);
+                    } else {
+                        cont.animate({"height": short_el.attr("cont_h")+'px'}, {duration: "fast" }).addClass('short');
+                        long_el.hide();
+                        short_el.show();
+                        if (button && short_text) button.html(short_text);
+                    }
+                    return false;
+                }
+                return toggle;
+            }
+            if (long_el.html().length <= short_el.html().length)
+                return;
+
+            // ensure long element shown first
+            long_el.show();short_el.hide();
+            long_el.attr("cont_h", $(this).height()).hide();
+            short_el.show().attr("cont_h", $(this).height());
+            $(this).addClass('short');
+
+            if (button && short_text) button.html(short_text);
+            if (button) button.hover(
+                function() { $(this).css({background: '#F3F3F3', cursor: 'pointer'}); },
+                function() { $(this).css({background: '#EEE'}); }
+            ).click(toggle_fun(cont, short_el, long_el, button, short_text, long_text));
+            short_el.hover(
+                function() { $(this).css({background: '#F3F3F3', cursor: 'pointer'}); },
+                function() { $(this).css({background: '#FFF'}); }
+            ).click(toggle_fun(cont, short_el, long_el, button, short_text, long_text));
+            long_el.hover(
+                function() { $(this).css({background: '#F3F3F3', cursor: 'pointer'}); },
+                function() { $(this).css({background: '#FFF'}); }
+            ).click(toggle_fun(cont, short_el, long_el, button, short_text, long_text));
+        };
+
         $('form input').labelify({labelledClass: 'blur'});
-        
+
         target = $('#login-register-window div.target');
-        
+
         $('#show-registration-form').click(function() {
             $('#login-form').hide();
             $('#registration-form').show();
         });
-        
+
         $('#show-login-form').click(function() {
             $('#registration-form').hide();
             $('#login-form').show();
         });
-        
+
         // Fragments
-        $('.fragment-text').each(function() {
-            if ($(this).prev().filter('.fragment-short-text').length) {
-                $(this).hover(
-                    function() { $(this).css({background: '#F3F3F3', cursor: 'pointer'}); },
-                    function() { $(this).css({background: '#FFF'}); }
-                ).click(function() {
-                    $(this).fadeOut(function() {
-                        $(this).prev().fadeIn()
-                    });
-                })
-            }
+        $('.fragment-short-text').each(function() {
+            var fragment = $(this).closest('.fragment');
+            fragment.toggle_slide({
+                short_el: $(this),
+                long_el: fragment.find('.fragment-text')
+            })
         });
-        
-        $('.fragment-short-text').click(function() {
-            $(this).fadeOut(function() { $(this).next().fadeIn() });
-        }).hover(
-            function() { $(this).css({background: '#F3F3F3', cursor: 'pointer'}); },
-            function() { $(this).css({background: '#FFF'}); }
-        );
-        
+
         $('.show-all-tags').click(function() {
-            $(this).parent().parent().fadeOut(function() { 
+            $(this).parent().parent().fadeOut(function() {
                 $(this).next().fadeIn();
             });
             return false;
         });
-        
+
         $('.hide-all-tags').click(function() {
            $(this).parent().parent().fadeOut(function() {
                $(this).prev().fadeIn();
            });
-           return false; 
+           return false;
         });
-        
+
         $('#registration-form').ajaxForm({
             dataType: 'json',
             beforeSubmit: function() {
@@ -112,7 +214,7 @@ function changeBannerText() {
                 }
             }
         });
-        
+
         $('#login-form').ajaxForm({
             dataType: 'json',
             beforeSubmit: function() {
@@ -133,7 +235,7 @@ function changeBannerText() {
                 }
             }
         });
-        
+
         $('#login-register-window').jqm({
             target: target[0],
             overlay: 60,
@@ -145,7 +247,7 @@ function changeBannerText() {
                 hash.w.show();
             }
         });
-        
+
         $('ul.shelf-list li').hover(function() {
             $(this).css({background: '#EEE', cursor: 'pointer'});
         }, function() {
@@ -153,18 +255,18 @@ function changeBannerText() {
         }).click(function() {
             location.href = $('a.visit-shelf', this).attr('href');
         });
-        
-        $('.delete-shelf').click(function() { 
+
+        $('.delete-shelf').click(function() {
             var link = $(this);
             var shelf_name = $('.visit-shelf', link.parent()).text();
-            if (confirm('Czy na pewno usunąć półkę ' + shelf_name + '?')) {
+            if (confirm(LOCALE_TEXTS[LANGUAGE_CODE]['DELETE_SHELF']+ ' '+ shelf_name + '?')) {
                 $.post(link.attr('href'), function(data, textStatus) {
                     link.parent().remove();
                 });
             }
             return false;
         });
-        
+
         $('#user-shelves-window').jqm({
             ajax: '@href',
             target: $('#user-shelves-window div.target')[0],
@@ -176,14 +278,14 @@ function changeBannerText() {
                 $('div.header', hash.w).css({width: $(hash.t).width()});
                 hash.w.show();
             },
-            onLoad: function(hash) { 
+            onLoad: function(hash) {
                 $('form', hash.w).ajaxForm({
                     target: $('#user-shelves-window div.target'),
                     success: function() { setTimeout(function() { $('#user-shelves-window').jqmHide() }, 1000) }
                 });
-                
+
                 $('input', hash.w).labelify({labelledClass: 'blur'});
-                
+
                 $('ul.shelf-list li', hash.w).hover(function() {
                     $(this).css({background: '#EEE', cursor: 'pointer'});
                 }, function() {
@@ -191,11 +293,11 @@ function changeBannerText() {
                 }).click(function() {
                     location.href = $('a.visit-shelf', this).attr('href');
                 });
-                
+
                 $('.delete-shelf').click(function() {
                     var link = $(this);
                     var shelf_name = $('.visit-shelf', link.parent()).text();
-                    if (confirm('Czy na pewno usunąć półkę ' + shelf_name + '?')) {
+                    if (confirm(LOCALE_TEXTS[LANGUAGE_CODE]['DELETE_SHELF'] + ' ' + shelf_name + '?')) {
                         $.post(link.attr('href'), function(data, textStatus) {
                             link.parent().remove();
                         });
@@ -204,48 +306,94 @@ function changeBannerText() {
                 });
             }
         });
-    
+
+        $('#suggest-window').jqm({
+            ajax: '@href',
+            target: $('#suggest-window div.target')[0],
+            overlay: 60,
+            trigger: '#suggest-link',
+            onShow: function(hash) {
+                var offset = $(hash.t).offset();
+                hash.w.css({position: 'absolute', left: offset.left - hash.w.width() + $(hash.t).width(), top: offset.top});
+                $('div.header', hash.w).css({width: $(hash.t).width()});
+                hash.w.show();
+            },
+            onLoad: function(hash) {
+                $('form', hash.w).ajaxForm({
+                    dataType: 'json',
+                    target: $('#suggest-window div.target'),
+                    success: function(response) {
+                        if (response.success) {
+                            $('#suggest-window div.target').text(response.message);
+                            setTimeout(function() { $('#suggest-window').jqmHide() }, 1000)
+                        }
+                        else {
+                            $('#suggest-form .error').remove();
+                            $.each(response.errors, function(id, errors) {
+                                $('#suggest-form #id_' + id).before('<span class="error">' + errors[0] + '</span>');
+                            });
+                            $('#suggest-form input[type=submit]').removeAttr('disabled');
+                            return false;
+                        }
+                    }
+                });
+            }
+        });
+
         $('#books-list .book').hover(
             function() { $(this).css({background: '#F3F3F3', cursor: 'pointer'}); },
             function() { $(this).css({background: '#FFF'}); }
         ).click(function() {
             location.href = $('h2 a', this).attr('href');
         });
-    
-        $('#toggle-description').hover(
+
+        $('#description').each(function(){$(this).toggle_slide({
+            long_el: $('#description-long', this),
+            short_el: $('#description-short', this),
+            button: $(this).nextAll('#toggle-description').first().find('p'),
+            long_text: LOCALE_TEXTS[LANGUAGE_CODE]['HIDE_DESCRIPTION'] + ' ▲',
+            short_text: LOCALE_TEXTS[LANGUAGE_CODE]['EXPAND_DESCRIPTION'] + ' ▼'
+        })});
+
+        $('#toggle-share-shelf').hover(
             function() { $(this).css({background: '#F3F3F3', cursor: 'pointer'}); },
             function() { $(this).css({background: '#EEE'}); }
         ).click(function() {
-            if ($('#description').hasClass('hidden')) {
-                $('#description').slideDown('fast').removeClass('hidden');
-                $.cookie('description-state', 'opened', {path: '/', expires: 30});
-                $('p', this).html('Zwiń opis ▲');
+            if ($('#share-shelf').hasClass('hidden')) {
+                $('#share-shelf').slideDown('fast').removeClass('hidden');
             } else {
-                $('#description').slideUp('fast').addClass('hidden');
-                $.cookie('description-state', 'closed', {path: '/', expires: 30});
-                $('p', this).html('Rozwiń opis ▼');
+                $('#share-shelf').slideUp('fast').addClass('hidden');
             }
         });
-    
+
         var target = $('#set-window div.target');
-    
+
         $('#set-window').jqm({
-            ajax: '@href', 
+            ajax: '@href',
             target: target[0],
             overlay: 60,
-            trigger: 'a.jqm-trigger', 
-            onShow: function(hash) { 
+            trigger: 'a.jqm-trigger',
+            onShow: function(hash) {
                 var offset = $(hash.t).offset();
-                target.html('<p><img src="/static/img/indicator.gif" /> Ładowanie</p>');
+                target.html('<p><img src="/static/img/indicator.gif" />'+LOCALE_TEXTS[LANGUAGE_CODE]['DELETE_SHELF']+'</p>');
                 hash.w.css({position: 'absolute', left: offset.left, top: offset.top}).show() },
-            onLoad: function(hash) { 
+            onLoad: function(hash) {
+        try {
+            $('#createShelfTrigger').click(function(){
+                $('#createNewShelf').show();
+            });
+        } catch (e){}
+
                 $('form', hash.w).ajaxForm({
                     target: target,
-                    success: function() { setTimeout(function() { $('#set-window').jqmHide() }, 1000) }
+                    success: function() {
+            setTimeout(function() {
+                    $('#set-window').jqmHide();
+                       }, 1000)}
                 });
             }
         });
-        
+
         $('a.remove-from-shelf').click(function(event) {
             event.preventDefault();
             link = $(this);
@@ -253,22 +401,20 @@ function changeBannerText() {
                 link.parent().remove();
             });
         });
-        
-        if ($.cookie('description-state') == 'closed') {
-            $('#description').hide().addClass('hidden');
-            $('#toggle-description p').html('Rozwiń opis ▼');
-        }
-                
+
+        $('#share-shelf').hide().addClass('hidden');
+        $('#share-shelf input').focus(function(){this.select();});
+
         $('#user-info').show();
         changeBannerText();
         $('#onepercent-banner').show();
-        
+
         var formatsDownloaded = false;
         $('#download-shelf').click(function() {
             $('#download-shelf-menu').slideDown('fast');
-            
+
             if (!formatsDownloaded) {
-                // Pobierz dane o formatach
+                // Get info about the formats
                 formatsDownloaded = true;
                 $.ajax({
                     url: $('#download-formats-form').attr('data-formats-feed'),
@@ -295,10 +441,26 @@ function changeBannerText() {
             }
             return false;
         });
-        
+
         $('#download-formats-form-cancel').click(function() {
             $('#download-shelf-menu').slideUp('fast');
             return false;
         });
+
+        $('marquee').marquee().mouseover(function () {
+            $(this).trigger('stop');
+        }).mouseout(function () {
+            $(this).trigger('start');
+             $(this).data('drag', false);
+        }).mousemove(function (event) {
+            if ($(this).data('drag') == true) {
+                this.scrollLeft = $(this).data('scrollX') + ($(this).data('x') - event.clientX);
+            }
+        }).mousedown(function (event) {
+            $(this).data('drag', true).data('x', event.clientX).data('scrollX', this.scrollLeft);
+        }).mouseup(function () {
+            $(this).data('drag', false);
+        });
+
     });
-})(jQuery)
\ No newline at end of file
+})(jQuery)
diff --git a/wolnelektury/static/js/jquery-ui-1.8.2.custom.min.js b/wolnelektury/static/js/jquery-ui-1.8.2.custom.min.js
new file mode 100644 (file)
index 0000000..57a95a5
--- /dev/null
@@ -0,0 +1,75 @@
+/*!
+ * jQuery UI 1.8.2
+ *
+ * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * http://docs.jquery.com/UI
+ */
+(function(c){c.ui=c.ui||{};if(!c.ui.version){c.extend(c.ui,{version:"1.8.2",plugin:{add:function(a,b,d){a=c.ui[a].prototype;for(var e in d){a.plugins[e]=a.plugins[e]||[];a.plugins[e].push([b,d[e]])}},call:function(a,b,d){if((b=a.plugins[b])&&a.element[0].parentNode)for(var e=0;e<b.length;e++)a.options[b[e][0]]&&b[e][1].apply(a.element,d)}},contains:function(a,b){return document.compareDocumentPosition?a.compareDocumentPosition(b)&16:a!==b&&a.contains(b)},hasScroll:function(a,b){if(c(a).css("overflow")==
+"hidden")return false;b=b&&b=="left"?"scrollLeft":"scrollTop";var d=false;if(a[b]>0)return true;a[b]=1;d=a[b]>0;a[b]=0;return d},isOverAxis:function(a,b,d){return a>b&&a<b+d},isOver:function(a,b,d,e,f,g){return c.ui.isOverAxis(a,d,f)&&c.ui.isOverAxis(b,e,g)},keyCode:{ALT:18,BACKSPACE:8,CAPS_LOCK:20,COMMA:188,COMMAND:91,COMMAND_LEFT:91,COMMAND_RIGHT:93,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,MENU:93,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,
+NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SHIFT:16,SPACE:32,TAB:9,UP:38,WINDOWS:91}});c.fn.extend({_focus:c.fn.focus,focus:function(a,b){return typeof a==="number"?this.each(function(){var d=this;setTimeout(function(){c(d).focus();b&&b.call(d)},a)}):this._focus.apply(this,arguments)},enableSelection:function(){return this.attr("unselectable","off").css("MozUserSelect","")},disableSelection:function(){return this.attr("unselectable","on").css("MozUserSelect",
+"none")},scrollParent:function(){var a;a=c.browser.msie&&/(static|relative)/.test(this.css("position"))||/absolute/.test(this.css("position"))?this.parents().filter(function(){return/(relative|absolute|fixed)/.test(c.curCSS(this,"position",1))&&/(auto|scroll)/.test(c.curCSS(this,"overflow",1)+c.curCSS(this,"overflow-y",1)+c.curCSS(this,"overflow-x",1))}).eq(0):this.parents().filter(function(){return/(auto|scroll)/.test(c.curCSS(this,"overflow",1)+c.curCSS(this,"overflow-y",1)+c.curCSS(this,"overflow-x",
+1))}).eq(0);return/fixed/.test(this.css("position"))||!a.length?c(document):a},zIndex:function(a){if(a!==undefined)return this.css("zIndex",a);if(this.length){a=c(this[0]);for(var b;a.length&&a[0]!==document;){b=a.css("position");if(b=="absolute"||b=="relative"||b=="fixed"){b=parseInt(a.css("zIndex"));if(!isNaN(b)&&b!=0)return b}a=a.parent()}}return 0}});c.extend(c.expr[":"],{data:function(a,b,d){return!!c.data(a,d[3])},focusable:function(a){var b=a.nodeName.toLowerCase(),d=c.attr(a,"tabindex");return(/input|select|textarea|button|object/.test(b)?
+!a.disabled:"a"==b||"area"==b?a.href||!isNaN(d):!isNaN(d))&&!c(a)["area"==b?"parents":"closest"](":hidden").length},tabbable:function(a){var b=c.attr(a,"tabindex");return(isNaN(b)||b>=0)&&c(a).is(":focusable")}})}})(jQuery);
+;/*!
+ * jQuery UI Widget 1.8.2
+ *
+ * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * http://docs.jquery.com/UI/Widget
+ */
+(function(b){var j=b.fn.remove;b.fn.remove=function(a,c){return this.each(function(){if(!c)if(!a||b.filter(a,[this]).length)b("*",this).add(this).each(function(){b(this).triggerHandler("remove")});return j.call(b(this),a,c)})};b.widget=function(a,c,d){var e=a.split(".")[0],f;a=a.split(".")[1];f=e+"-"+a;if(!d){d=c;c=b.Widget}b.expr[":"][f]=function(h){return!!b.data(h,a)};b[e]=b[e]||{};b[e][a]=function(h,g){arguments.length&&this._createWidget(h,g)};c=new c;c.options=b.extend({},c.options);b[e][a].prototype=
+b.extend(true,c,{namespace:e,widgetName:a,widgetEventPrefix:b[e][a].prototype.widgetEventPrefix||a,widgetBaseClass:f},d);b.widget.bridge(a,b[e][a])};b.widget.bridge=function(a,c){b.fn[a]=function(d){var e=typeof d==="string",f=Array.prototype.slice.call(arguments,1),h=this;d=!e&&f.length?b.extend.apply(null,[true,d].concat(f)):d;if(e&&d.substring(0,1)==="_")return h;e?this.each(function(){var g=b.data(this,a),i=g&&b.isFunction(g[d])?g[d].apply(g,f):g;if(i!==g&&i!==undefined){h=i;return false}}):this.each(function(){var g=
+b.data(this,a);if(g){d&&g.option(d);g._init()}else b.data(this,a,new c(d,this))});return h}};b.Widget=function(a,c){arguments.length&&this._createWidget(a,c)};b.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",options:{disabled:false},_createWidget:function(a,c){this.element=b(c).data(this.widgetName,this);this.options=b.extend(true,{},this.options,b.metadata&&b.metadata.get(c)[this.widgetName],a);var d=this;this.element.bind("remove."+this.widgetName,function(){d.destroy()});this._create();
+this._init()},_create:function(){},_init:function(){},destroy:function(){this.element.unbind("."+this.widgetName).removeData(this.widgetName);this.widget().unbind("."+this.widgetName).removeAttr("aria-disabled").removeClass(this.widgetBaseClass+"-disabled ui-state-disabled")},widget:function(){return this.element},option:function(a,c){var d=a,e=this;if(arguments.length===0)return b.extend({},e.options);if(typeof a==="string"){if(c===undefined)return this.options[a];d={};d[a]=c}b.each(d,function(f,
+h){e._setOption(f,h)});return e},_setOption:function(a,c){this.options[a]=c;if(a==="disabled")this.widget()[c?"addClass":"removeClass"](this.widgetBaseClass+"-disabled ui-state-disabled").attr("aria-disabled",c);return this},enable:function(){return this._setOption("disabled",false)},disable:function(){return this._setOption("disabled",true)},_trigger:function(a,c,d){var e=this.options[a];c=b.Event(c);c.type=(a===this.widgetEventPrefix?a:this.widgetEventPrefix+a).toLowerCase();d=d||{};if(c.originalEvent){a=
+b.event.props.length;for(var f;a;){f=b.event.props[--a];c[f]=c.originalEvent[f]}}this.element.trigger(c,d);return!(b.isFunction(e)&&e.call(this.element[0],c,d)===false||c.isDefaultPrevented())}}})(jQuery);
+;/*
+ * jQuery UI Position 1.8.2
+ *
+ * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * http://docs.jquery.com/UI/Position
+ */
+(function(c){c.ui=c.ui||{};var m=/left|center|right/,n=/top|center|bottom/,p=c.fn.position,q=c.fn.offset;c.fn.position=function(a){if(!a||!a.of)return p.apply(this,arguments);a=c.extend({},a);var b=c(a.of),d=(a.collision||"flip").split(" "),e=a.offset?a.offset.split(" "):[0,0],g,h,i;if(a.of.nodeType===9){g=b.width();h=b.height();i={top:0,left:0}}else if(a.of.scrollTo&&a.of.document){g=b.width();h=b.height();i={top:b.scrollTop(),left:b.scrollLeft()}}else if(a.of.preventDefault){a.at="left top";g=h=
+0;i={top:a.of.pageY,left:a.of.pageX}}else{g=b.outerWidth();h=b.outerHeight();i=b.offset()}c.each(["my","at"],function(){var f=(a[this]||"").split(" ");if(f.length===1)f=m.test(f[0])?f.concat(["center"]):n.test(f[0])?["center"].concat(f):["center","center"];f[0]=m.test(f[0])?f[0]:"center";f[1]=n.test(f[1])?f[1]:"center";a[this]=f});if(d.length===1)d[1]=d[0];e[0]=parseInt(e[0],10)||0;if(e.length===1)e[1]=e[0];e[1]=parseInt(e[1],10)||0;if(a.at[0]==="right")i.left+=g;else if(a.at[0]==="center")i.left+=
+g/2;if(a.at[1]==="bottom")i.top+=h;else if(a.at[1]==="center")i.top+=h/2;i.left+=e[0];i.top+=e[1];return this.each(function(){var f=c(this),k=f.outerWidth(),l=f.outerHeight(),j=c.extend({},i);if(a.my[0]==="right")j.left-=k;else if(a.my[0]==="center")j.left-=k/2;if(a.my[1]==="bottom")j.top-=l;else if(a.my[1]==="center")j.top-=l/2;j.left=parseInt(j.left);j.top=parseInt(j.top);c.each(["left","top"],function(o,r){c.ui.position[d[o]]&&c.ui.position[d[o]][r](j,{targetWidth:g,targetHeight:h,elemWidth:k,
+elemHeight:l,offset:e,my:a.my,at:a.at})});c.fn.bgiframe&&f.bgiframe();f.offset(c.extend(j,{using:a.using}))})};c.ui.position={fit:{left:function(a,b){var d=c(window);b=a.left+b.elemWidth-d.width()-d.scrollLeft();a.left=b>0?a.left-b:Math.max(0,a.left)},top:function(a,b){var d=c(window);b=a.top+b.elemHeight-d.height()-d.scrollTop();a.top=b>0?a.top-b:Math.max(0,a.top)}},flip:{left:function(a,b){if(b.at[0]!=="center"){var d=c(window);d=a.left+b.elemWidth-d.width()-d.scrollLeft();var e=b.my[0]==="left"?
+-b.elemWidth:b.my[0]==="right"?b.elemWidth:0,g=-2*b.offset[0];a.left+=a.left<0?e+b.targetWidth+g:d>0?e-b.targetWidth+g:0}},top:function(a,b){if(b.at[1]!=="center"){var d=c(window);d=a.top+b.elemHeight-d.height()-d.scrollTop();var e=b.my[1]==="top"?-b.elemHeight:b.my[1]==="bottom"?b.elemHeight:0,g=b.at[1]==="top"?b.targetHeight:-b.targetHeight,h=-2*b.offset[1];a.top+=a.top<0?e+b.targetHeight+h:d>0?e+g+h:0}}}};if(!c.offset.setOffset){c.offset.setOffset=function(a,b){if(/static/.test(c.curCSS(a,"position")))a.style.position=
+"relative";var d=c(a),e=d.offset(),g=parseInt(c.curCSS(a,"top",true),10)||0,h=parseInt(c.curCSS(a,"left",true),10)||0;e={top:b.top-e.top+g,left:b.left-e.left+h};"using"in b?b.using.call(a,e):d.css(e)};c.fn.offset=function(a){var b=this[0];if(!b||!b.ownerDocument)return null;if(a)return this.each(function(){c.offset.setOffset(this,a)});return q.call(this)}}})(jQuery);
+;/*
+ * jQuery UI Autocomplete 1.8.2
+ *
+ * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * http://docs.jquery.com/UI/Autocomplete
+ *
+ * Depends:
+ *     jquery.ui.core.js
+ *     jquery.ui.widget.js
+ *     jquery.ui.position.js
+ */
+(function(e){e.widget("ui.autocomplete",{options:{minLength:1,delay:300},_create:function(){var a=this,c=this.element[0].ownerDocument;this.element.addClass("ui-autocomplete-input").attr("autocomplete","off").attr({role:"textbox","aria-autocomplete":"list","aria-haspopup":"true"}).bind("keydown.autocomplete",function(d){var b=e.ui.keyCode;switch(d.keyCode){case b.PAGE_UP:a._move("previousPage",d);break;case b.PAGE_DOWN:a._move("nextPage",d);break;case b.UP:a._move("previous",d);d.preventDefault();
+break;case b.DOWN:a._move("next",d);d.preventDefault();break;case b.ENTER:case b.NUMPAD_ENTER:a.menu.active&&d.preventDefault();case b.TAB:if(!a.menu.active)return;a.menu.select(d);break;case b.ESCAPE:a.element.val(a.term);a.close(d);break;case b.LEFT:case b.RIGHT:case b.SHIFT:case b.CONTROL:case b.ALT:case b.COMMAND:case b.COMMAND_RIGHT:case b.INSERT:case b.CAPS_LOCK:case b.END:case b.HOME:break;default:clearTimeout(a.searching);a.searching=setTimeout(function(){a.search(null,d)},a.options.delay);
+break}}).bind("focus.autocomplete",function(){a.selectedItem=null;a.previous=a.element.val()}).bind("blur.autocomplete",function(d){clearTimeout(a.searching);a.closing=setTimeout(function(){a.close(d);a._change(d)},150)});this._initSource();this.response=function(){return a._response.apply(a,arguments)};this.menu=e("<ul></ul>").addClass("ui-autocomplete").appendTo("body",c).mousedown(function(){setTimeout(function(){clearTimeout(a.closing)},13)}).menu({focus:function(d,b){b=b.item.data("item.autocomplete");
+false!==a._trigger("focus",null,{item:b})&&/^key/.test(d.originalEvent.type)&&a.element.val(b.value)},selected:function(d,b){b=b.item.data("item.autocomplete");false!==a._trigger("select",d,{item:b})&&a.element.val(b.value);a.close(d);d=a.previous;if(a.element[0]!==c.activeElement){a.element.focus();a.previous=d}a.selectedItem=b},blur:function(){a.menu.element.is(":visible")&&a.element.val(a.term)}}).zIndex(this.element.zIndex()+1).css({top:0,left:0}).hide().data("menu");e.fn.bgiframe&&this.menu.element.bgiframe()},
+destroy:function(){this.element.removeClass("ui-autocomplete-input").removeAttr("autocomplete").removeAttr("role").removeAttr("aria-autocomplete").removeAttr("aria-haspopup");this.menu.element.remove();e.Widget.prototype.destroy.call(this)},_setOption:function(a){e.Widget.prototype._setOption.apply(this,arguments);a==="source"&&this._initSource()},_initSource:function(){var a,c;if(e.isArray(this.options.source)){a=this.options.source;this.source=function(d,b){b(e.ui.autocomplete.filter(a,d.term))}}else if(typeof this.options.source===
+"string"){c=this.options.source;this.source=function(d,b){e.getJSON(c,d,b)}}else this.source=this.options.source},search:function(a,c){a=a!=null?a:this.element.val();if(a.length<this.options.minLength)return this.close(c);clearTimeout(this.closing);if(this._trigger("search")!==false)return this._search(a)},_search:function(a){this.term=this.element.addClass("ui-autocomplete-loading").val();this.source({term:a},this.response)},_response:function(a){if(a.length){a=this._normalize(a);this._suggest(a);
+this._trigger("open")}else this.close();this.element.removeClass("ui-autocomplete-loading")},close:function(a){clearTimeout(this.closing);if(this.menu.element.is(":visible")){this._trigger("close",a);this.menu.element.hide();this.menu.deactivate()}},_change:function(a){this.previous!==this.element.val()&&this._trigger("change",a,{item:this.selectedItem})},_normalize:function(a){if(a.length&&a[0].label&&a[0].value)return a;return e.map(a,function(c){if(typeof c==="string")return{label:c,value:c};return e.extend({label:c.label||
+c.value,value:c.value||c.label},c)})},_suggest:function(a){var c=this.menu.element.empty().zIndex(this.element.zIndex()+1),d;this._renderMenu(c,a);this.menu.deactivate();this.menu.refresh();this.menu.element.show().position({my:"left top",at:"left bottom",of:this.element,collision:"none"});a=c.width("").width();d=this.element.width();c.width(Math.max(a,d))},_renderMenu:function(a,c){var d=this;e.each(c,function(b,f){d._renderItem(a,f)})},_renderItem:function(a,c){return e("<li></li>").data("item.autocomplete",
+c).append("<a>"+c.label+"</a>").appendTo(a)},_move:function(a,c){if(this.menu.element.is(":visible"))if(this.menu.first()&&/^previous/.test(a)||this.menu.last()&&/^next/.test(a)){this.element.val(this.term);this.menu.deactivate()}else this.menu[a](c);else this.search(null,c)},widget:function(){return this.menu.element}});e.extend(e.ui.autocomplete,{escapeRegex:function(a){return a.replace(/([\^\$\(\)\[\]\{\}\*\.\+\?\|\\])/gi,"\\$1")},filter:function(a,c){var d=new RegExp(e.ui.autocomplete.escapeRegex(c),
+"i");return e.grep(a,function(b){return d.test(b.label||b.value||b)})}})})(jQuery);
+(function(e){e.widget("ui.menu",{_create:function(){var a=this;this.element.addClass("ui-menu ui-widget ui-widget-content ui-corner-all").attr({role:"listbox","aria-activedescendant":"ui-active-menuitem"}).click(function(c){if(e(c.target).closest(".ui-menu-item a").length){c.preventDefault();a.select(c)}});this.refresh()},refresh:function(){var a=this;this.element.children("li:not(.ui-menu-item):has(a)").addClass("ui-menu-item").attr("role","menuitem").children("a").addClass("ui-corner-all").attr("tabindex",
+-1).mouseenter(function(c){a.activate(c,e(this).parent())}).mouseleave(function(){a.deactivate()})},activate:function(a,c){this.deactivate();if(this.hasScroll()){var d=c.offset().top-this.element.offset().top,b=this.element.attr("scrollTop"),f=this.element.height();if(d<0)this.element.attr("scrollTop",b+d);else d>f&&this.element.attr("scrollTop",b+d-f+c.height())}this.active=c.eq(0).children("a").addClass("ui-state-hover").attr("id","ui-active-menuitem").end();this._trigger("focus",a,{item:c})},deactivate:function(){if(this.active){this.active.children("a").removeClass("ui-state-hover").removeAttr("id");
+this._trigger("blur");this.active=null}},next:function(a){this.move("next",".ui-menu-item:first",a)},previous:function(a){this.move("prev",".ui-menu-item:last",a)},first:function(){return this.active&&!this.active.prev().length},last:function(){return this.active&&!this.active.next().length},move:function(a,c,d){if(this.active){a=this.active[a+"All"](".ui-menu-item").eq(0);a.length?this.activate(d,a):this.activate(d,this.element.children(c))}else this.activate(d,this.element.children(c))},nextPage:function(a){if(this.hasScroll())if(!this.active||
+this.last())this.activate(a,this.element.children(":first"));else{var c=this.active.offset().top,d=this.element.height(),b=this.element.children("li").filter(function(){var f=e(this).offset().top-c-d+e(this).height();return f<10&&f>-10});b.length||(b=this.element.children(":last"));this.activate(a,b)}else this.activate(a,this.element.children(!this.active||this.last()?":first":":last"))},previousPage:function(a){if(this.hasScroll())if(!this.active||this.first())this.activate(a,this.element.children(":last"));
+else{var c=this.active.offset().top,d=this.element.height();result=this.element.children("li").filter(function(){var b=e(this).offset().top-c+d-e(this).height();return b<10&&b>-10});result.length||(result=this.element.children(":first"));this.activate(a,result)}else this.activate(a,this.element.children(!this.active||this.first()?":last":":first"))},hasScroll:function(){return this.element.height()<this.element.attr("scrollHeight")},select:function(a){this._trigger("selected",a,{item:this.active})}})})(jQuery);
+;
\ No newline at end of file
index 5ad9178..6f46e1b 100644 (file)
@@ -1,18 +1,22 @@
 /*
- * Autocomplete - jQuery plugin 1.0.2
+ * jQuery Autocomplete plugin 1.1
  *
- * Copyright (c) 2007 Dylan Verheul, Dan G. Switzer, Anjesh Tuladhar, Jörn Zaefferer
+ * Copyright (c) 2009 Jörn Zaefferer
  *
  * Dual licensed under the MIT and GPL licenses:
  *   http://www.opensource.org/licenses/mit-license.php
  *   http://www.gnu.org/licenses/gpl.html
  *
- * Revision: $Id: jquery.autocomplete.js 5747 2008-06-25 18:30:55Z joern.zaefferer $
- *
+ * Revision: $Id: jquery.autocomplete.js 15 2009-08-22 10:30:27Z joern.zaefferer $
+ */
+
+/*
+ * Modified by Radek Czajka, Fundacja Nowoczesna Polska, 2010-05-10:
+ *   escape regex for word start checking in matchSubset
  */
 
 ;(function($) {
-       
+
 $.fn.extend({
        autocomplete: function(urlOrData, options) {
                var isUrl = typeof urlOrData == "string";
@@ -22,13 +26,13 @@ $.fn.extend({
                        delay: isUrl ? $.Autocompleter.defaults.delay : 10,
                        max: options && !options.scroll ? 10 : 150
                }, options);
-               
+
                // if highlight is set to false, replace it with a do-nothing function
                options.highlight = options.highlight || function(value) { return value; };
-               
+
                // if the formatMatch option is not specified, then use formatItem for backwards compatibility
                options.formatMatch = options.formatMatch || options.formatItem;
-               
+
                return this.each(function() {
                        new $.Autocompleter(this, options);
                });
@@ -77,9 +81,9 @@ $.Autocompleter = function(input, options) {
                mouseDownOnSelect: false
        };
        var select = $.Autocompleter.Select(options, input, selectCurrent, config);
-       
+
        var blockSubmit;
-       
+
        // prevent form submit in opera when selecting with return key
        $.browser.opera && $(input.form).bind("submit.autocomplete", function() {
                if (blockSubmit) {
@@ -87,13 +91,16 @@ $.Autocompleter = function(input, options) {
                        return false;
                }
        });
-       
+
        // only opera doesn't trigger keydown multiple times while pressed, others don't work with keypress at all
        $input.bind(($.browser.opera ? "keypress" : "keydown") + ".autocomplete", function(event) {
+               // a keypress means the input has focus
+               // avoids issue where input had focus before the autocomplete was applied
+               hasFocus = 1;
                // track last key pressed
                lastKeyPressCode = event.keyCode;
                switch(event.keyCode) {
-               
+
                        case KEY.UP:
                                event.preventDefault();
                                if ( select.visible() ) {
@@ -102,7 +109,7 @@ $.Autocompleter = function(input, options) {
                                        onChange(0, true);
                                }
                                break;
-                               
+
                        case KEY.DOWN:
                                event.preventDefault();
                                if ( select.visible() ) {
@@ -111,7 +118,7 @@ $.Autocompleter = function(input, options) {
                                        onChange(0, true);
                                }
                                break;
-                               
+
                        case KEY.PAGEUP:
                                event.preventDefault();
                                if ( select.visible() ) {
@@ -120,7 +127,7 @@ $.Autocompleter = function(input, options) {
                                        onChange(0, true);
                                }
                                break;
-                               
+
                        case KEY.PAGEDOWN:
                                event.preventDefault();
                                if ( select.visible() ) {
@@ -129,7 +136,7 @@ $.Autocompleter = function(input, options) {
                                        onChange(0, true);
                                }
                                break;
-                       
+
                        // matches also semicolon
                        case options.multiple && $.trim(options.multipleSeparator) == "," && KEY.COMMA:
                        case KEY.TAB:
@@ -141,11 +148,11 @@ $.Autocompleter = function(input, options) {
                                        return false;
                                }
                                break;
-                               
+
                        case KEY.ESC:
                                select.hide();
                                break;
-                               
+
                        default:
                                clearTimeout(timeout);
                                timeout = setTimeout(onChange, options.delay);
@@ -196,43 +203,57 @@ $.Autocompleter = function(input, options) {
                $input.unbind();
                $(input.form).unbind(".autocomplete");
        });
-       
-       
+
+
        function selectCurrent() {
                var selected = select.selected();
                if( !selected )
                        return false;
-               
+
                var v = selected.result;
                previousValue = v;
-               
+
                if ( options.multiple ) {
                        var words = trimWords($input.val());
                        if ( words.length > 1 ) {
-                               v = words.slice(0, words.length - 1).join( options.multipleSeparator ) + options.multipleSeparator + v;
+                               var seperator = options.multipleSeparator.length;
+                               var cursorAt = $(input).selection().start;
+                               var wordAt, progress = 0;
+                               $.each(words, function(i, word) {
+                                       progress += word.length;
+                                       if (cursorAt <= progress) {
+                                               wordAt = i;
+                                               return false;
+                                       }
+                                       progress += seperator;
+                               });
+                               words[wordAt] = v;
+                               // TODO this should set the cursor to the right position, but it gets overriden somewhere
+                               //$.Autocompleter.Selection(input, progress + seperator, progress + seperator);
+                               v = words.join( options.multipleSeparator );
                        }
                        v += options.multipleSeparator;
                }
-               
+
                $input.val(v);
                hideResultsNow();
                $input.trigger("result", [selected.data, selected.value]);
                return true;
        }
-       
+
        function onChange(crap, skipPrevCheck) {
                if( lastKeyPressCode == KEY.DEL ) {
                        select.hide();
                        return;
                }
-               
+
                var currentValue = $input.val();
-               
+
                if ( !skipPrevCheck && currentValue == previousValue )
                        return;
-               
+
                previousValue = currentValue;
-               
+
                currentValue = lastWord(currentValue);
                if ( currentValue.length >= options.minChars) {
                        $input.addClass(options.loadingClass);
@@ -244,27 +265,32 @@ $.Autocompleter = function(input, options) {
                        select.hide();
                }
        };
-       
+
        function trimWords(value) {
-               if ( !value ) {
+               if (!value)
                        return [""];
-               }
-               var words = value.split( options.multipleSeparator );
-               var result = [];
-               $.each(words, function(i, value) {
-                       if ( $.trim(value) )
-                               result[i] = $.trim(value);
+               if (!options.multiple)
+                       return [$.trim(value)];
+               return $.map(value.split(options.multipleSeparator), function(word) {
+                       return $.trim(value).length ? $.trim(word) : null;
                });
-               return result;
        }
-       
+
        function lastWord(value) {
                if ( !options.multiple )
                        return value;
                var words = trimWords(value);
+               if (words.length == 1)
+                       return words[0];
+               var cursorAt = $(input).selection().start;
+               if (cursorAt == value.length) {
+                       words = trimWords(value)
+               } else {
+                       words = trimWords(value.replace(value.substring(cursorAt), ""));
+               }
                return words[words.length - 1];
        }
-       
+
        // fills in the input box w/the first match (assumed to be the best match)
        // q: the term entered
        // sValue: the first matching result
@@ -275,7 +301,7 @@ $.Autocompleter = function(input, options) {
                        // fill in the value (keep the case the user has typed)
                        $input.val($input.val() + sValue.substring(lastWord(previousValue).length));
                        // select the portion of the value not typed by the user (so the next character will erase)
-                       $.Autocompleter.Selection(input, previousValue.length, previousValue.length + sValue.length);
+                       $(input).selection(previousValue.length, previousValue.length + sValue.length);
                }
        };
 
@@ -299,15 +325,14 @@ $.Autocompleter = function(input, options) {
                                                        var words = trimWords($input.val()).slice(0, -1);
                                                        $input.val( words.join(options.multipleSeparator) + (words.length ? options.multipleSeparator : "") );
                                                }
-                                               else
+                                               else {
                                                        $input.val( "" );
+                                                       $input.trigger("result", null);
+                                               }
                                        }
                                }
                        );
                }
-               if (wasVisible)
-                       // position cursor at end of input field
-                       $.Autocompleter.Selection(input, input.value.length, input.value.length);
        };
 
        function receiveData(q, data) {
@@ -330,14 +355,14 @@ $.Autocompleter = function(input, options) {
                        success(term, data);
                // if an AJAX url has been supplied, try loading the data now
                } else if( (typeof options.url == "string") && (options.url.length > 0) ){
-                       
+
                        var extraParams = {
                                timestamp: +new Date()
                        };
                        $.each(options.extraParams, function(key, param) {
                                extraParams[key] = typeof param == "function" ? param() : param;
                        });
-                       
+
                        $.ajax({
                                // try to leverage ajaxQueue plugin to abort previous requests
                                mode: "abort",
@@ -361,7 +386,7 @@ $.Autocompleter = function(input, options) {
                        failure(term);
                }
        };
-       
+
        function parse(data) {
                var parsed = [];
                var rows = data.split("\n");
@@ -405,8 +430,22 @@ $.Autocompleter.defaults = {
        width: 0,
        multiple: false,
        multipleSeparator: ", ",
+    regex_escape: function(term) {
+        term = term.replace(/([\^\$\(\)\[\]\{\}\*\.\+\?\|\\])/gi, "\\$1");
+        /* no polish diacritics; should be more locale-aware */
+        term = term.replace(/a/g, '[aą]')
+                .replace(/c/g, '[cć]')
+                .replace(/e/g, '[eę]')
+                .replace(/l/g, '[lł]')
+                .replace(/n/g, '[nń]')
+                .replace(/o/g, '[oó]')
+                .replace(/s/g, '[sś]')
+                .replace(/z/g, '[zźż]');
+        return term;
+    },
        highlight: function(value, term) {
-               return value.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + term.replace(/([\^\$\(\)\[\]\{\}\*\.\+\?\|\\])/gi, "\\$1") + ")(?![^<>]*>)(?![^&;]+;)", "gi"), "<strong>$1</strong>");
+               term = $.Autocompleter.defaults.regex_escape(term);
+               return value.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + term + ")(?![^<>]*>)(?![^&;]+;)", "gi"), "<strong>$1</strong>");
        },
     scroll: true,
     scrollHeight: 180
@@ -416,25 +455,29 @@ $.Autocompleter.Cache = function(options) {
 
        var data = {};
        var length = 0;
-       
+
        function matchSubset(s, sub) {
-               if (!options.matchCase) 
+               if (!options.matchCase)
                        s = s.toLowerCase();
                var i = s.indexOf(sub);
+               if (options.matchContains == "word"){
+                       query = $.Autocompleter.defaults.regex_escape(sub.toLowerCase());
+                       i = s.toLowerCase().search("\\b" + query);
+               }
                if (i == -1) return false;
                return i == 0 || options.matchContains;
        };
-       
+
        function add(q, value) {
                if (length > options.cacheLength){
                        flush();
                }
-               if (!data[q]){ 
+               if (!data[q]){
                        length++;
                }
                data[q] = value;
        }
-       
+
        function populate(){
                if( !options.data ) return false;
                // track the matches
@@ -443,23 +486,23 @@ $.Autocompleter.Cache = function(options) {
 
                // no url was specified, we need to adjust the cache length to make sure it fits the local data store
                if( !options.url ) options.cacheLength = 1;
-               
+
                // track all options for minChars = 0
                stMatchSets[""] = [];
-               
+
                // loop through the array and create a lookup structure
                for ( var i = 0, ol = options.data.length; i < ol; i++ ) {
                        var rawValue = options.data[i];
                        // if rawValue is a string, make an array otherwise just reference the array
                        rawValue = (typeof rawValue == "string") ? [rawValue] : rawValue;
-                       
+
                        var value = options.formatMatch(rawValue, i+1, options.data.length);
                        if ( value === false )
                                continue;
-                               
+
                        var firstChar = value.charAt(0).toLowerCase();
                        // if no lookup array for this character exists, look it up now
-                       if( !stMatchSets[firstChar] ) 
+                       if( !stMatchSets[firstChar] )
                                stMatchSets[firstChar] = [];
 
                        // if the match is a string
@@ -468,7 +511,7 @@ $.Autocompleter.Cache = function(options) {
                                data: rawValue,
                                result: options.formatResult && options.formatResult(rawValue) || value
                        };
-                       
+
                        // push the current match into the set list
                        stMatchSets[firstChar].push(row);
 
@@ -486,15 +529,15 @@ $.Autocompleter.Cache = function(options) {
                        add(i, value);
                });
        }
-       
+
        // populate any existing data
        setTimeout(populate, 25);
-       
+
        function flush(){
                data = {};
                length = 0;
        }
-       
+
        return {
                flush: flush,
                add: add,
@@ -502,7 +545,7 @@ $.Autocompleter.Cache = function(options) {
                load: function(q) {
                        if (!options.cacheLength || !length)
                                return null;
-                       /* 
+                       /*
                         * if dealing w/local data and matchContains than we must make sure
                         * to loop through all the data collections looking for matches
                         */
@@ -522,9 +565,9 @@ $.Autocompleter.Cache = function(options) {
                                                        }
                                                });
                                        }
-                               }                               
+                               }
                                return csub;
-                       } else 
+                       } else
                        // if the exact item exists, use it
                        if (data[q]){
                                return data[q];
@@ -552,7 +595,7 @@ $.Autocompleter.Select = function (options, input, select, config) {
        var CLASSES = {
                ACTIVE: "ac_over"
        };
-       
+
        var listItems,
                active = -1,
                data,
@@ -560,7 +603,7 @@ $.Autocompleter.Select = function (options, input, select, config) {
                needsInit = true,
                element,
                list;
-       
+
        // Create results
        function init() {
                if (!needsInit)
@@ -570,11 +613,11 @@ $.Autocompleter.Select = function (options, input, select, config) {
                .addClass(options.resultsClass)
                .css("position", "absolute")
                .appendTo(document.body);
-       
+
                list = $("<ul/>").appendTo(element).mouseover( function(event) {
                        if(target(event).nodeName && target(event).nodeName.toUpperCase() == 'LI') {
                    active = $("li", list).removeClass(CLASSES.ACTIVE).index(target(event));
-                           $(target(event)).addClass(CLASSES.ACTIVE);            
+                           $(target(event)).addClass(CLASSES.ACTIVE);
                }
                }).click(function(event) {
                        $(target(event)).addClass(CLASSES.ACTIVE);
@@ -587,13 +630,13 @@ $.Autocompleter.Select = function (options, input, select, config) {
                }).mouseup(function() {
                        config.mouseDownOnSelect = false;
                });
-               
+
                if( options.width > 0 )
                        element.css("width", options.width);
-                       
+
                needsInit = false;
-       } 
-       
+       }
+
        function target(event) {
                var element = event.target;
                while(element && element.tagName != "LI")
@@ -620,7 +663,7 @@ $.Autocompleter.Select = function (options, input, select, config) {
             }
         }
        };
-       
+
        function movePosition(step) {
                active += step;
                if (active < 0) {
@@ -629,13 +672,13 @@ $.Autocompleter.Select = function (options, input, select, config) {
                        active = 0;
                }
        }
-       
+
        function limitNumberOfItems(available) {
                return options.max && options.max < available
                        ? options.max
                        : available;
        }
-       
+
        function fillList() {
                list.empty();
                var max = limitNumberOfItems(data.length);
@@ -657,7 +700,7 @@ $.Autocompleter.Select = function (options, input, select, config) {
                if ( $.fn.bgiframe )
                        list.bgiframe();
        }
-       
+
        return {
                display: function(d, q) {
                        init();
@@ -709,7 +752,7 @@ $.Autocompleter.Select = function (options, input, select, config) {
                                        maxHeight: options.scrollHeight,
                                        overflow: 'auto'
                                });
-                               
+
                 if($.browser.msie && typeof document.body.style.maxHeight === "undefined") {
                                        var listHeight = 0;
                                        listItems.each(function() {
@@ -722,7 +765,7 @@ $.Autocompleter.Select = function (options, input, select, config) {
                                                listItems.width( list.width() - parseInt(listItems.css("padding-left")) - parseInt(listItems.css("padding-right")) );
                                        }
                 }
-                
+
             }
                },
                selected: function() {
@@ -738,22 +781,48 @@ $.Autocompleter.Select = function (options, input, select, config) {
        };
 };
 
-$.Autocompleter.Selection = function(field, start, end) {
-       if( field.createTextRange ){
-               var selRange = field.createTextRange();
-               selRange.collapse(true);
-               selRange.moveStart("character", start);
-               selRange.moveEnd("character", end);
-               selRange.select();
-       } else if( field.setSelectionRange ){
-               field.setSelectionRange(start, end);
-       } else {
-               if( field.selectionStart ){
-                       field.selectionStart = start;
-                       field.selectionEnd = end;
+$.fn.selection = function(start, end) {
+       if (start !== undefined) {
+               return this.each(function() {
+                       if( this.createTextRange ){
+                               var selRange = this.createTextRange();
+                               if (end === undefined || start == end) {
+                                       selRange.move("character", start);
+                                       selRange.select();
+                               } else {
+                                       selRange.collapse(true);
+                                       selRange.moveStart("character", start);
+                                       selRange.moveEnd("character", end);
+                                       selRange.select();
+                               }
+                       } else if( this.setSelectionRange ){
+                               this.setSelectionRange(start, end);
+                       } else if( this.selectionStart ){
+                               this.selectionStart = start;
+                               this.selectionEnd = end;
+                       }
+               });
+       }
+       var field = this[0];
+       if ( field.createTextRange ) {
+               var range = document.selection.createRange(),
+                       orig = field.value,
+                       teststring = "<->",
+                       textLength = range.text.length;
+               range.text = teststring;
+               var caretAt = field.value.indexOf(teststring);
+               field.value = orig;
+               this.selection(caretAt, caretAt + textLength);
+               return {
+                       start: caretAt,
+                       end: caretAt + textLength
+               }
+       } else if( field.selectionStart !== undefined ){
+               return {
+                       start: field.selectionStart,
+                       end: field.selectionEnd
                }
        }
-       field.focus();
 };
 
 })(jQuery);
\ No newline at end of file
diff --git a/wolnelektury/static/js/jquery.cookie.js b/wolnelektury/static/js/jquery.cookie.js
deleted file mode 100644 (file)
index 6df1fac..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-/**
- * Cookie plugin
- *
- * Copyright (c) 2006 Klaus Hartl (stilbuero.de)
- * Dual licensed under the MIT and GPL licenses:
- * http://www.opensource.org/licenses/mit-license.php
- * http://www.gnu.org/licenses/gpl.html
- *
- */
-
-/**
- * Create a cookie with the given name and value and other optional parameters.
- *
- * @example $.cookie('the_cookie', 'the_value');
- * @desc Set the value of a cookie.
- * @example $.cookie('the_cookie', 'the_value', { expires: 7, path: '/', domain: 'jquery.com', secure: true });
- * @desc Create a cookie with all available options.
- * @example $.cookie('the_cookie', 'the_value');
- * @desc Create a session cookie.
- * @example $.cookie('the_cookie', null);
- * @desc Delete a cookie by passing null as value. Keep in mind that you have to use the same path and domain
- *       used when the cookie was set.
- *
- * @param String name The name of the cookie.
- * @param String value The value of the cookie.
- * @param Object options An object literal containing key/value pairs to provide optional cookie attributes.
- * @option Number|Date expires Either an integer specifying the expiration date from now on in days or a Date object.
- *                             If a negative value is specified (e.g. a date in the past), the cookie will be deleted.
- *                             If set to null or omitted, the cookie will be a session cookie and will not be retained
- *                             when the the browser exits.
- * @option String path The value of the path atribute of the cookie (default: path of page that created the cookie).
- * @option String domain The value of the domain attribute of the cookie (default: domain of page that created the cookie).
- * @option Boolean secure If true, the secure attribute of the cookie will be set and the cookie transmission will
- *                        require a secure protocol (like HTTPS).
- * @type undefined
- *
- * @name $.cookie
- * @cat Plugins/Cookie
- * @author Klaus Hartl/klaus.hartl@stilbuero.de
- */
-
-/**
- * Get the value of a cookie with the given name.
- *
- * @example $.cookie('the_cookie');
- * @desc Get the value of a cookie.
- *
- * @param String name The name of the cookie.
- * @return The value of the cookie.
- * @type String
- *
- * @name $.cookie
- * @cat Plugins/Cookie
- * @author Klaus Hartl/klaus.hartl@stilbuero.de
- */
-jQuery.cookie = function(name, value, options) {
-    if (typeof value != 'undefined') { // name and value given, set cookie
-        options = options || {};
-        if (value === null) {
-            value = '';
-            options.expires = -1;
-        }
-        var expires = '';
-        if (options.expires && (typeof options.expires == 'number' || options.expires.toUTCString)) {
-            var date;
-            if (typeof options.expires == 'number') {
-                date = new Date();
-                date.setTime(date.getTime() + (options.expires * 24 * 60 * 60 * 1000));
-            } else {
-                date = options.expires;
-            }
-            expires = '; expires=' + date.toUTCString(); // use expires attribute, max-age is not supported by IE
-        }
-        // CAUTION: Needed to parenthesize options.path and options.domain
-        // in the following expressions, otherwise they evaluate to undefined
-        // in the packed version for some reason...
-        var path = options.path ? '; path=' + (options.path) : '';
-        var domain = options.domain ? '; domain=' + (options.domain) : '';
-        var secure = options.secure ? '; secure' : '';
-        document.cookie = [name, '=', encodeURIComponent(value), expires, path, domain, secure].join('');
-    } else { // only name given, get cookie
-        var cookieValue = null;
-        if (document.cookie && document.cookie != '') {
-            var cookies = document.cookie.split(';');
-            for (var i = 0; i < cookies.length; i++) {
-                var cookie = jQuery.trim(cookies[i]);
-                // Does this cookie string begin with the name we want?
-                if (cookie.substring(0, name.length + 1) == (name + '=')) {
-                    cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
-                    break;
-                }
-            }
-        }
-        return cookieValue;
-    }
-};
\ No newline at end of file
diff --git a/wolnelektury/static/js/jquery.countdown-de.js b/wolnelektury/static/js/jquery.countdown-de.js
new file mode 100644 (file)
index 0000000..5a3f43d
--- /dev/null
@@ -0,0 +1,12 @@
+/* http://keith-wood.name/countdown.html
+   German initialisation for the jQuery countdown extension
+   Written by Keith Wood (kbwood@virginbroadband.com.au) Jan 2008. */
+(function($) {
+       $.countdown.regional['de'] = {
+               labels: ['Jahren', 'Monate', 'Wochen', 'Tage', 'Stunden', 'Minuten', 'Sekunden'],
+               labels1: ['Jahre', 'Monat', 'Woche', 'Tag', 'Stunde', 'Minute', 'Sekunde'],
+               compactLabels: ['J', 'M', 'W', 'T'],
+               whichLabels: null,
+               timeSeparator: ':', isRTL: false};
+       $.countdown.setDefaults($.countdown.regional['de']);
+})(jQuery);
diff --git a/wolnelektury/static/js/jquery.countdown-es.js b/wolnelektury/static/js/jquery.countdown-es.js
new file mode 100644 (file)
index 0000000..362f58c
--- /dev/null
@@ -0,0 +1,12 @@
+/* http://keith-wood.name/countdown.html
+ * Spanish initialisation for the jQuery countdown extension
+ * Written by Sergio Carracedo Martinez webmaster@neodisenoweb.com (2008) */
+(function($) {
+       $.countdown.regional['es'] = {
+               labels: ['Años', 'Meses', 'Semanas', 'Dias', 'Horas', 'Minutos', 'Segundos'],
+               labels1: ['Años', 'Meses', 'Semanas', 'Dias', 'Horas', 'Minutos', 'Segundos'],
+               compactLabels: ['a', 'm', 's', 'g'],
+               whichLabels: null,
+               timeSeparator: ':', isRTL: false};
+       $.countdown.setDefaults($.countdown.regional['es']);
+})(jQuery);
diff --git a/wolnelektury/static/js/jquery.countdown-fr.js b/wolnelektury/static/js/jquery.countdown-fr.js
new file mode 100644 (file)
index 0000000..70e17de
--- /dev/null
@@ -0,0 +1,12 @@
+/* http://keith-wood.name/countdown.html
+   French initialisation for the jQuery countdown extension
+   Written by Keith Wood (kbwood{at}iinet.com.au) Jan 2008. */
+(function($) {
+       $.countdown.regional['fr'] = {
+               labels: ['Années', 'Mois', 'Semaines', 'Jours', 'Heures', 'Minutes', 'Secondes'],
+               labels1: ['Année', 'Mois', 'Semaine', 'Jour', 'Heure', 'Minute', 'Seconde'],
+               compactLabels: ['a', 'm', 's', 'j'],
+               whichLabels: null,
+               timeSeparator: ':', isRTL: false};
+       $.countdown.setDefaults($.countdown.regional['fr']);
+})(jQuery);
diff --git a/wolnelektury/static/js/jquery.countdown-lt.js b/wolnelektury/static/js/jquery.countdown-lt.js
new file mode 100644 (file)
index 0000000..ee11c71
--- /dev/null
@@ -0,0 +1,12 @@
+/* http://keith-wood.name/countdown.html
+ * Lithuanian localisation for the jQuery countdown extension
+ * Written by Moacir P. de Sá Pereira (moacir{at}gmail.com) (2009) */
+(function($) {
+       $.countdown.regional['lt'] = {
+               labels: ['Metų', 'Mėnesių', 'Savaičių', 'Dienų', 'Valandų', 'Minučių', 'Sekundžių'],
+               labels1: ['Metai', 'Mėnuo', 'Savaitė', 'Diena', 'Valanda', 'Minutė', 'Sekundė'],
+               compactLabels: ['m', 'm', 's', 'd'],
+               whichLabels: null,
+               timeSeparator: ':', isRTL: false};
+       $.countdown.setDefaults($.countdown.regional['lt']);
+})(jQuery);
diff --git a/wolnelektury/static/js/jquery.countdown-pl.js b/wolnelektury/static/js/jquery.countdown-pl.js
new file mode 100644 (file)
index 0000000..6860a4b
--- /dev/null
@@ -0,0 +1,17 @@
+/* http://keith-wood.name/countdown.html
+ * Polish initialisation for the jQuery countdown extension
+ * Written by Pawel Lewtak lewtak@gmail.com (2008) */
+(function($) {
+       $.countdown.regional['pl'] = {
+               labels: ['lat', 'miesięcy', 'tygodni', 'dni', 'godzin', 'minut', 'sekund'],
+               labels1: ['rok', 'miesiąc', 'tydzień', 'dzień', 'godzina', 'minuta', 'sekunda'],
+               labels2: ['lata', 'miesiące', 'tygodnie', 'dni', 'godziny', 'minuty', 'sekundy'],
+               compactLabels: ['l', 'm', 't', 'd'], compactLabels1: ['r', 'm', 't', 'd'],
+               whichLabels: function(amount) {
+                       var units = amount % 10;
+                       var tens = Math.floor((amount % 100) / 10);
+                       return (amount == 1 ? 1 : (units >= 2 && units <= 4 && tens != 1 ? 2 : 0));
+               },
+               timeSeparator: ':', isRTL: false};
+       $.countdown.setDefaults($.countdown.regional['pl']);
+})(jQuery);
diff --git a/wolnelektury/static/js/jquery.countdown-ru.js b/wolnelektury/static/js/jquery.countdown-ru.js
new file mode 100644 (file)
index 0000000..badd3eb
--- /dev/null
@@ -0,0 +1,12 @@
+/* http://keith-wood.name/countdown.html
+ * Russian initialisation for the jQuery countdown extension
+ * Written by Dominus i3rixon@gmail.com (2008) */
+(function($) {
+       $.countdown.regional['ru'] = {
+               labels: ['Лет', 'Месяцев', 'Недель', 'Дней', 'Часов', 'Минут', 'Секунд'],
+               labels1: ['Год', 'Месяц', 'Неделя', 'День', 'Час', 'Минута', 'Секунда'],
+               compactLabels: ['l', 'm', 'n', 'd'], compactLabels1: ['g', 'm', 'n', 'd'],
+               whichLabels: null,
+               timeSeparator: ':', isRTL: false};
+       $.countdown.setDefaults($.countdown.regional['ru']);
+})(jQuery);
diff --git a/wolnelektury/static/js/jquery.countdown-uk.js b/wolnelektury/static/js/jquery.countdown-uk.js
new file mode 100644 (file)
index 0000000..c98791e
--- /dev/null
@@ -0,0 +1,12 @@
+/* http://keith-wood.name/countdown.html
+ * Ukrainian initialisation for the jQuery countdown extension
+ * Written by Goloborodko M misha.gm@gmail.com (2009) */
+(function($) {
+       $.countdown.regional['uk'] = {
+               labels: ['Років', 'Місяців', 'Тижднів', 'Днів', 'Годин', 'Хвилин', 'Секунд'],
+               labels1: ['Рік', 'Місяць', 'Тиждень', 'День', 'Година', 'Хвилина', 'Секунда'],
+               compactLabels: ['r', 'm', 't', 'd'],
+               whichLabels: null,
+               timeSeparator: ':', isRTL: false};
+       $.countdown.setDefaults($.countdown.regional['uk']);
+})(jQuery);
diff --git a/wolnelektury/static/js/jquery.countdown.js b/wolnelektury/static/js/jquery.countdown.js
new file mode 100644 (file)
index 0000000..f9c58d3
--- /dev/null
@@ -0,0 +1,759 @@
+/* http://keith-wood.name/countdown.html
+   Countdown for jQuery v1.5.8.
+   Written by Keith Wood (kbwood{at}iinet.com.au) January 2008.
+   Dual licensed under the GPL (http://dev.jquery.com/browser/trunk/jquery/GPL-LICENSE.txt) and
+   MIT (http://dev.jquery.com/browser/trunk/jquery/MIT-LICENSE.txt) licenses.
+   Please attribute the author if you use it. */
+
+/* Display a countdown timer.
+   Attach it with options like:
+   $('div selector').countdown(
+       {until: new Date(2009, 1 - 1, 1, 0, 0, 0), onExpiry: happyNewYear}); */
+
+(function($) { // Hide scope, no $ conflict
+
+/* Countdown manager. */
+function Countdown() {
+       this.regional = []; // Available regional settings, indexed by language code
+       this.regional[''] = { // Default regional settings
+               // The display texts for the counters
+               labels: ['Years', 'Months', 'Weeks', 'Days', 'Hours', 'Minutes', 'Seconds'],
+               // The display texts for the counters if only one
+               labels1: ['Year', 'Month', 'Week', 'Day', 'Hour', 'Minute', 'Second'],
+               compactLabels: ['y', 'm', 'w', 'd'], // The compact texts for the counters
+               whichLabels: null, // Function to determine which labels to use
+               timeSeparator: ':', // Separator for time periods
+               isRTL: false // True for right-to-left languages, false for left-to-right
+       };
+       this._defaults = {
+               until: null, // new Date(year, mth - 1, day, hr, min, sec) - date/time to count down to
+                       // or numeric for seconds offset, or string for unit offset(s):
+                       // 'Y' years, 'O' months, 'W' weeks, 'D' days, 'H' hours, 'M' minutes, 'S' seconds
+               since: null, // new Date(year, mth - 1, day, hr, min, sec) - date/time to count up from
+                       // or numeric for seconds offset, or string for unit offset(s):
+                       // 'Y' years, 'O' months, 'W' weeks, 'D' days, 'H' hours, 'M' minutes, 'S' seconds
+               timezone: null, // The timezone (hours or minutes from GMT) for the target times,
+                       // or null for client local
+               serverSync: null, // A function to retrieve the current server time for synchronisation
+               format: 'dHMS', // Format for display - upper case for always, lower case only if non-zero,
+                       // 'Y' years, 'O' months, 'W' weeks, 'D' days, 'H' hours, 'M' minutes, 'S' seconds
+               layout: '', // Build your own layout for the countdown
+               compact: false, // True to display in a compact format, false for an expanded one
+               significant: 0, // The number of periods with values to show, zero for all
+               description: '', // The description displayed for the countdown
+               expiryUrl: '', // A URL to load upon expiry, replacing the current page
+               expiryText: '', // Text to display upon expiry, replacing the countdown
+               alwaysExpire: false, // True to trigger onExpiry even if never counted down
+               onExpiry: null, // Callback when the countdown expires -
+                       // receives no parameters and 'this' is the containing division
+               onTick: null, // Callback when the countdown is updated -
+                       // receives int[7] being the breakdown by period (based on format)
+                       // and 'this' is the containing division
+               tickInterval: 1 // Interval (seconds) between onTick callbacks
+       };
+       $.extend(this._defaults, this.regional['']);
+       this._serverSyncs = [];
+}
+
+var PROP_NAME = 'countdown';
+
+var Y = 0; // Years
+var O = 1; // Months
+var W = 2; // Weeks
+var D = 3; // Days
+var H = 4; // Hours
+var M = 5; // Minutes
+var S = 6; // Seconds
+
+$.extend(Countdown.prototype, {
+       /* Class name added to elements to indicate already configured with countdown. */
+       markerClassName: 'hasCountdown',
+
+       /* Shared timer for all countdowns. */
+       _timer: setInterval(function() { $.countdown._updateTargets(); }, 980),
+       /* List of currently active countdown targets. */
+       _timerTargets: [],
+
+       /* Override the default settings for all instances of the countdown widget.
+          @param  options  (object) the new settings to use as defaults */
+       setDefaults: function(options) {
+               this._resetExtraLabels(this._defaults, options);
+               extendRemove(this._defaults, options || {});
+       },
+
+       /* Convert a date/time to UTC.
+          @param  tz     (number) the hour or minute offset from GMT, e.g. +9, -360
+          @param  year   (Date) the date/time in that timezone or
+                         (number) the year in that timezone
+          @param  month  (number, optional) the month (0 - 11) (omit if year is a Date)
+          @param  day    (number, optional) the day (omit if year is a Date)
+          @param  hours  (number, optional) the hour (omit if year is a Date)
+          @param  mins   (number, optional) the minute (omit if year is a Date)
+          @param  secs   (number, optional) the second (omit if year is a Date)
+          @param  ms     (number, optional) the millisecond (omit if year is a Date)
+          @return  (Date) the equivalent UTC date/time */
+       UTCDate: function(tz, year, month, day, hours, mins, secs, ms) {
+               if (typeof year == 'object' && year.constructor == Date) {
+                       ms = year.getMilliseconds();
+                       secs = year.getSeconds();
+                       mins = year.getMinutes();
+                       hours = year.getHours();
+                       day = year.getDate();
+                       month = year.getMonth();
+                       year = year.getFullYear();
+               }
+               var d = new Date();
+               d.setUTCFullYear(year);
+               d.setUTCDate(1);
+               d.setUTCMonth(month || 0);
+               d.setUTCDate(day || 1);
+               d.setUTCHours(hours || 0);
+               d.setUTCMinutes((mins || 0) - (Math.abs(tz) < 30 ? tz * 60 : tz));
+               d.setUTCSeconds(secs || 0);
+               d.setUTCMilliseconds(ms || 0);
+               return d;
+       },
+
+       /* Convert a set of periods into seconds.
+          Averaged for months and years.
+          @param  periods  (number[7]) the periods per year/month/week/day/hour/minute/second
+          @return  (number) the corresponding number of seconds */
+       periodsToSeconds: function(periods) {
+               return periods[0] * 31557600 + periods[1] * 2629800 + periods[2] * 604800 +
+                       periods[3] * 86400 + periods[4] * 3600 + periods[5] * 60 + periods[6];
+       },
+
+       /* Retrieve one or more settings values.
+          @param  name  (string, optional) the name of the setting to retrieve
+                        or 'all' for all instance settings or omit for all default settings
+          @return  (any) the requested setting(s) */
+       _settingsCountdown: function(target, name) {
+               if (!name) {
+                       return $.countdown._defaults;
+               }
+               var inst = $.data(target, PROP_NAME);
+               return (name == 'all' ? inst.options : inst.options[name]);
+       },
+
+       /* Attach the countdown widget to a div.
+          @param  target   (element) the containing division
+          @param  options  (object) the initial settings for the countdown */
+       _attachCountdown: function(target, options) {
+               var $target = $(target);
+               if ($target.hasClass(this.markerClassName)) {
+                       return;
+               }
+               $target.addClass(this.markerClassName);
+               var inst = {options: $.extend({}, options),
+                       _periods: [0, 0, 0, 0, 0, 0, 0]};
+               $.data(target, PROP_NAME, inst);
+               this._changeCountdown(target);
+       },
+
+       /* Add a target to the list of active ones.
+          @param  target  (element) the countdown target */
+       _addTarget: function(target) {
+               if (!this._hasTarget(target)) {
+                       this._timerTargets.push(target);
+               }
+       },
+
+       /* See if a target is in the list of active ones.
+          @param  target  (element) the countdown target
+          @return  (boolean) true if present, false if not */
+       _hasTarget: function(target) {
+               return ($.inArray(target, this._timerTargets) > -1);
+       },
+
+       /* Remove a target from the list of active ones.
+          @param  target  (element) the countdown target */
+       _removeTarget: function(target) {
+               this._timerTargets = $.map(this._timerTargets,
+                       function(value) { return (value == target ? null : value); }); // delete entry
+       },
+
+       /* Update each active timer target. */
+       _updateTargets: function() {
+               for (var i = this._timerTargets.length - 1; i >= 0; i--) {
+                       this._updateCountdown(this._timerTargets[i]);
+               }
+       },
+
+       /* Redisplay the countdown with an updated display.
+          @param  target  (jQuery) the containing division
+          @param  inst    (object) the current settings for this instance */
+       _updateCountdown: function(target, inst) {
+               var $target = $(target);
+               inst = inst || $.data(target, PROP_NAME);
+               if (!inst) {
+                       return;
+               }
+               $target.html(this._generateHTML(inst));
+               $target[(this._get(inst, 'isRTL') ? 'add' : 'remove') + 'Class']('countdown_rtl');
+               var onTick = this._get(inst, 'onTick');
+               if (onTick) {
+                       var periods = inst._hold != 'lap' ? inst._periods :
+                               this._calculatePeriods(inst, inst._show, this._get(inst, 'significant'), new Date());
+                       var tickInterval = this._get(inst, 'tickInterval');
+                       if (tickInterval == 1 || this.periodsToSeconds(periods) % tickInterval == 0) {
+                               onTick.apply(target, [periods]);
+                       }
+               }
+               var expired = inst._hold != 'pause' &&
+                       (inst._since ? inst._now.getTime() < inst._since.getTime() :
+                       inst._now.getTime() >= inst._until.getTime());
+               if (expired && !inst._expiring) {
+                       inst._expiring = true;
+                       if (this._hasTarget(target) || this._get(inst, 'alwaysExpire')) {
+                               this._removeTarget(target);
+                               var onExpiry = this._get(inst, 'onExpiry');
+                               if (onExpiry) {
+                                       onExpiry.apply(target, []);
+                               }
+                               var expiryText = this._get(inst, 'expiryText');
+                               if (expiryText) {
+                                       var layout = this._get(inst, 'layout');
+                                       inst.options.layout = expiryText;
+                                       this._updateCountdown(target, inst);
+                                       inst.options.layout = layout;
+                               }
+                               var expiryUrl = this._get(inst, 'expiryUrl');
+                               if (expiryUrl) {
+                                       window.location = expiryUrl;
+                               }
+                       }
+                       inst._expiring = false;
+               }
+               else if (inst._hold == 'pause') {
+                       this._removeTarget(target);
+               }
+               $.data(target, PROP_NAME, inst);
+       },
+
+       /* Reconfigure the settings for a countdown div.
+          @param  target   (element) the containing division
+          @param  options  (object) the new settings for the countdown or
+                           (string) an individual property name
+          @param  value    (any) the individual property value
+                           (omit if options is an object) */
+       _changeCountdown: function(target, options, value) {
+               options = options || {};
+               if (typeof options == 'string') {
+                       var name = options;
+                       options = {};
+                       options[name] = value;
+               }
+               var inst = $.data(target, PROP_NAME);
+               if (inst) {
+                       this._resetExtraLabels(inst.options, options);
+                       extendRemove(inst.options, options);
+                       this._adjustSettings(target, inst);
+                       $.data(target, PROP_NAME, inst);
+                       var now = new Date();
+                       if ((inst._since && inst._since < now) ||
+                                       (inst._until && inst._until > now)) {
+                               this._addTarget(target);
+                       }
+                       this._updateCountdown(target, inst);
+               }
+       },
+
+       /* Reset any extra labelsn and compactLabelsn entries if changing labels.
+          @param  base     (object) the options to be updated
+          @param  options  (object) the new option values */
+       _resetExtraLabels: function(base, options) {
+               var changingLabels = false;
+               for (var n in options) {
+                       if (n != 'whichLabels' && n.match(/[Ll]abels/)) {
+                               changingLabels = true;
+                               break;
+                       }
+               }
+               if (changingLabels) {
+                       for (var n in base) { // Remove custom numbered labels
+                               if (n.match(/[Ll]abels[0-9]/)) {
+                                       base[n] = null;
+                               }
+                       }
+               }
+       },
+
+       /* Calculate interal settings for an instance.
+          @param  target  (element) the containing division
+          @param  inst    (object) the current settings for this instance */
+       _adjustSettings: function(target, inst) {
+               var now;
+               var serverSync = this._get(inst, 'serverSync');
+               var serverOffset = 0;
+               var serverEntry = null;
+               for (var i = 0; i < this._serverSyncs.length; i++) {
+                       if (this._serverSyncs[i][0] == serverSync) {
+                               serverEntry = this._serverSyncs[i][1];
+                               break;
+                       }
+               }
+               if (serverEntry != null) {
+                       serverOffset = (serverSync ? serverEntry : 0);
+                       now = new Date();
+               }
+               else {
+                       var serverResult = (serverSync ? serverSync.apply(target, []) : null);
+                       now = new Date();
+                       serverOffset = (serverResult ? now.getTime() - serverResult.getTime() : 0);
+                       this._serverSyncs.push([serverSync, serverOffset]);
+               }
+               var timezone = this._get(inst, 'timezone');
+               timezone = (timezone == null ? -now.getTimezoneOffset() : timezone);
+               inst._since = this._get(inst, 'since');
+               if (inst._since != null) {
+                       inst._since = this.UTCDate(timezone, this._determineTime(inst._since, null));
+                       if (inst._since && serverOffset) {
+                               inst._since.setMilliseconds(inst._since.getMilliseconds() + serverOffset);
+                       }
+               }
+               inst._until = this.UTCDate(timezone, this._determineTime(this._get(inst, 'until'), now));
+               if (serverOffset) {
+                       inst._until.setMilliseconds(inst._until.getMilliseconds() + serverOffset);
+               }
+               inst._show = this._determineShow(inst);
+       },
+
+       /* Remove the countdown widget from a div.
+          @param  target  (element) the containing division */
+       _destroyCountdown: function(target) {
+               var $target = $(target);
+               if (!$target.hasClass(this.markerClassName)) {
+                       return;
+               }
+               this._removeTarget(target);
+               $target.removeClass(this.markerClassName).empty();
+               $.removeData(target, PROP_NAME);
+       },
+
+       /* Pause a countdown widget at the current time.
+          Stop it running but remember and display the current time.
+          @param  target  (element) the containing division */
+       _pauseCountdown: function(target) {
+               this._hold(target, 'pause');
+       },
+
+       /* Pause a countdown widget at the current time.
+          Stop the display but keep the countdown running.
+          @param  target  (element) the containing division */
+       _lapCountdown: function(target) {
+               this._hold(target, 'lap');
+       },
+
+       /* Resume a paused countdown widget.
+          @param  target  (element) the containing division */
+       _resumeCountdown: function(target) {
+               this._hold(target, null);
+       },
+
+       /* Pause or resume a countdown widget.
+          @param  target  (element) the containing division
+          @param  hold    (string) the new hold setting */
+       _hold: function(target, hold) {
+               var inst = $.data(target, PROP_NAME);
+               if (inst) {
+                       if (inst._hold == 'pause' && !hold) {
+                               inst._periods = inst._savePeriods;
+                               var sign = (inst._since ? '-' : '+');
+                               inst[inst._since ? '_since' : '_until'] =
+                                       this._determineTime(sign + inst._periods[0] + 'y' +
+                                               sign + inst._periods[1] + 'o' + sign + inst._periods[2] + 'w' +
+                                               sign + inst._periods[3] + 'd' + sign + inst._periods[4] + 'h' +
+                                               sign + inst._periods[5] + 'm' + sign + inst._periods[6] + 's');
+                               this._addTarget(target);
+                       }
+                       inst._hold = hold;
+                       inst._savePeriods = (hold == 'pause' ? inst._periods : null);
+                       $.data(target, PROP_NAME, inst);
+                       this._updateCountdown(target, inst);
+               }
+       },
+
+       /* Return the current time periods.
+          @param  target  (element) the containing division
+          @return  (number[7]) the current periods for the countdown */
+       _getTimesCountdown: function(target) {
+               var inst = $.data(target, PROP_NAME);
+               return (!inst ? null : (!inst._hold ? inst._periods :
+                       this._calculatePeriods(inst, inst._show, this._get(inst, 'significant'), new Date())));
+       },
+
+       /* Get a setting value, defaulting if necessary.
+          @param  inst  (object) the current settings for this instance
+          @param  name  (string) the name of the required setting
+          @return  (any) the setting's value or a default if not overridden */
+       _get: function(inst, name) {
+               return (inst.options[name] != null ?
+                       inst.options[name] : $.countdown._defaults[name]);
+       },
+
+       /* A time may be specified as an exact value or a relative one.
+          @param  setting      (string or number or Date) - the date/time value
+                               as a relative or absolute value
+          @param  defaultTime  (Date) the date/time to use if no other is supplied
+          @return  (Date) the corresponding date/time */
+       _determineTime: function(setting, defaultTime) {
+               var offsetNumeric = function(offset) { // e.g. +300, -2
+                       var time = new Date();
+                       time.setTime(time.getTime() + offset * 1000);
+                       return time;
+               };
+               var offsetString = function(offset) { // e.g. '+2d', '-4w', '+3h +30m'
+                       offset = offset.toLowerCase();
+                       var time = new Date();
+                       var year = time.getFullYear();
+                       var month = time.getMonth();
+                       var day = time.getDate();
+                       var hour = time.getHours();
+                       var minute = time.getMinutes();
+                       var second = time.getSeconds();
+                       var pattern = /([+-]?[0-9]+)\s*(s|m|h|d|w|o|y)?/g;
+                       var matches = pattern.exec(offset);
+                       while (matches) {
+                               switch (matches[2] || 's') {
+                                       case 's': second += parseInt(matches[1], 10); break;
+                                       case 'm': minute += parseInt(matches[1], 10); break;
+                                       case 'h': hour += parseInt(matches[1], 10); break;
+                                       case 'd': day += parseInt(matches[1], 10); break;
+                                       case 'w': day += parseInt(matches[1], 10) * 7; break;
+                                       case 'o':
+                                               month += parseInt(matches[1], 10);
+                                               day = Math.min(day, $.countdown._getDaysInMonth(year, month));
+                                               break;
+                                       case 'y':
+                                               year += parseInt(matches[1], 10);
+                                               day = Math.min(day, $.countdown._getDaysInMonth(year, month));
+                                               break;
+                               }
+                               matches = pattern.exec(offset);
+                       }
+                       return new Date(year, month, day, hour, minute, second, 0);
+               };
+               var time = (setting == null ? defaultTime :
+                       (typeof setting == 'string' ? offsetString(setting) :
+                       (typeof setting == 'number' ? offsetNumeric(setting) : setting)));
+               if (time) time.setMilliseconds(0);
+               return time;
+       },
+
+       /* Determine the number of days in a month.
+          @param  year   (number) the year
+          @param  month  (number) the month
+          @return  (number) the days in that month */
+       _getDaysInMonth: function(year, month) {
+               return 32 - new Date(year, month, 32).getDate();
+       },
+
+       /* Determine which set of labels should be used for an amount.
+          @param  num  (number) the amount to be displayed
+          @return  (number) the set of labels to be used for this amount */
+       _normalLabels: function(num) {
+               return num;
+       },
+
+       /* Generate the HTML to display the countdown widget.
+          @param  inst  (object) the current settings for this instance
+          @return  (string) the new HTML for the countdown display */
+       _generateHTML: function(inst) {
+               // Determine what to show
+               var significant = this._get(inst, 'significant');
+               inst._periods = (inst._hold ? inst._periods :
+                       this._calculatePeriods(inst, inst._show, significant, new Date()));
+               // Show all 'asNeeded' after first non-zero value
+               var shownNonZero = false;
+               var showCount = 0;
+               var sigCount = significant;
+               var show = $.extend({}, inst._show);
+               for (var period = Y; period <= S; period++) {
+                       shownNonZero |= (inst._show[period] == '?' && inst._periods[period] > 0);
+                       show[period] = (inst._show[period] == '?' && !shownNonZero ? null : inst._show[period]);
+                       showCount += (show[period] ? 1 : 0);
+                       sigCount -= (inst._periods[period] > 0 ? 1 : 0);
+               }
+               var showSignificant = [false, false, false, false, false, false, false];
+               for (var period = S; period >= Y; period--) { // Determine significant periods
+                       if (inst._show[period]) {
+                               if (inst._periods[period]) {
+                                       showSignificant[period] = true;
+                               }
+                               else {
+                                       showSignificant[period] = sigCount > 0;
+                                       sigCount--;
+                               }
+                       }
+               }
+               var compact = this._get(inst, 'compact');
+               var layout = this._get(inst, 'layout');
+               var labels = (compact ? this._get(inst, 'compactLabels') : this._get(inst, 'labels'));
+               var whichLabels = this._get(inst, 'whichLabels') || this._normalLabels;
+               var timeSeparator = this._get(inst, 'timeSeparator');
+               var description = this._get(inst, 'description') || '';
+               var showCompact = function(period) {
+                       var labelsNum = $.countdown._get(inst,
+                               'compactLabels' + whichLabels(inst._periods[period]));
+                       return (show[period] ? inst._periods[period] +
+                               (labelsNum ? labelsNum[period] : labels[period]) + ' ' : '');
+               };
+               var showFull = function(period) {
+                       var labelsNum = $.countdown._get(inst, 'labels' + whichLabels(inst._periods[period]));
+                       return ((!significant && show[period]) || (significant && showSignificant[period]) ?
+                               '<span class="countdown_section"><span class="countdown_amount">' +
+                               inst._periods[period] + '</span><br/>' +
+                               (labelsNum ? labelsNum[period] : labels[period]) + '</span>' : '');
+               };
+               return (layout ? this._buildLayout(inst, show, layout, compact, significant, showSignificant) :
+                       ((compact ? // Compact version
+                       '<span class="countdown_row countdown_amount' +
+                       (inst._hold ? ' countdown_holding' : '') + '">' +
+                       showCompact(Y) + showCompact(O) + showCompact(W) + showCompact(D) +
+                       (show[H] ? this._minDigits(inst._periods[H], 2) : '') +
+                       (show[M] ? (show[H] ? timeSeparator : '') +
+                       this._minDigits(inst._periods[M], 2) : '') +
+                       (show[S] ? (show[H] || show[M] ? timeSeparator : '') +
+                       this._minDigits(inst._periods[S], 2) : '') :
+                       // Full version
+                       '<span class="countdown_row countdown_show' + (significant || showCount) +
+                       (inst._hold ? ' countdown_holding' : '') + '">' +
+                       showFull(Y) + showFull(O) + showFull(W) + showFull(D) +
+                       showFull(H) + showFull(M) + showFull(S)) + '</span>' +
+                       (description ? '<span class="countdown_row countdown_descr">' + description + '</span>' : '')));
+       },
+
+       /* Construct a custom layout.
+          @param  inst             (object) the current settings for this instance
+          @param  show             (string[7]) flags indicating which periods are requested
+          @param  layout           (string) the customised layout
+          @param  compact          (boolean) true if using compact labels
+          @param  significant      (number) the number of periods with values to show, zero for all
+          @param  showSignificant  (boolean[7]) other periods to show for significance
+          @return  (string) the custom HTML */
+       _buildLayout: function(inst, show, layout, compact, significant, showSignificant) {
+               var labels = this._get(inst, (compact ? 'compactLabels' : 'labels'));
+               var whichLabels = this._get(inst, 'whichLabels') || this._normalLabels;
+               var labelFor = function(index) {
+                       return ($.countdown._get(inst,
+                               (compact ? 'compactLabels' : 'labels') + whichLabels(inst._periods[index])) ||
+                               labels)[index];
+               };
+               var digit = function(value, position) {
+                       return Math.floor(value / position) % 10;
+               };
+               var subs = {desc: this._get(inst, 'description'), sep: this._get(inst, 'timeSeparator'),
+                       yl: labelFor(Y), yn: inst._periods[Y], ynn: this._minDigits(inst._periods[Y], 2),
+                       ynnn: this._minDigits(inst._periods[Y], 3), y1: digit(inst._periods[Y], 1),
+                       y10: digit(inst._periods[Y], 10), y100: digit(inst._periods[Y], 100),
+                       y1000: digit(inst._periods[Y], 1000),
+                       ol: labelFor(O), on: inst._periods[O], onn: this._minDigits(inst._periods[O], 2),
+                       onnn: this._minDigits(inst._periods[O], 3), o1: digit(inst._periods[O], 1),
+                       o10: digit(inst._periods[O], 10), o100: digit(inst._periods[O], 100),
+                       o1000: digit(inst._periods[O], 1000),
+                       wl: labelFor(W), wn: inst._periods[W], wnn: this._minDigits(inst._periods[W], 2),
+                       wnnn: this._minDigits(inst._periods[W], 3), w1: digit(inst._periods[W], 1),
+                       w10: digit(inst._periods[W], 10), w100: digit(inst._periods[W], 100),
+                       w1000: digit(inst._periods[W], 1000),
+                       dl: labelFor(D), dn: inst._periods[D], dnn: this._minDigits(inst._periods[D], 2),
+                       dnnn: this._minDigits(inst._periods[D], 3), d1: digit(inst._periods[D], 1),
+                       d10: digit(inst._periods[D], 10), d100: digit(inst._periods[D], 100),
+                       d1000: digit(inst._periods[D], 1000),
+                       hl: labelFor(H), hn: inst._periods[H], hnn: this._minDigits(inst._periods[H], 2),
+                       hnnn: this._minDigits(inst._periods[H], 3), h1: digit(inst._periods[H], 1),
+                       h10: digit(inst._periods[H], 10), h100: digit(inst._periods[H], 100),
+                       h1000: digit(inst._periods[H], 1000),
+                       ml: labelFor(M), mn: inst._periods[M], mnn: this._minDigits(inst._periods[M], 2),
+                       mnnn: this._minDigits(inst._periods[M], 3), m1: digit(inst._periods[M], 1),
+                       m10: digit(inst._periods[M], 10), m100: digit(inst._periods[M], 100),
+                       m1000: digit(inst._periods[M], 1000),
+                       sl: labelFor(S), sn: inst._periods[S], snn: this._minDigits(inst._periods[S], 2),
+                       snnn: this._minDigits(inst._periods[S], 3), s1: digit(inst._periods[S], 1),
+                       s10: digit(inst._periods[S], 10), s100: digit(inst._periods[S], 100),
+                       s1000: digit(inst._periods[S], 1000)};
+               var html = layout;
+               // Replace period containers: {p<}...{p>}
+               for (var i = Y; i <= S; i++) {
+                       var period = 'yowdhms'.charAt(i);
+                       var re = new RegExp('\\{' + period + '<\\}(.*)\\{' + period + '>\\}', 'g');
+                       html = html.replace(re, ((!significant && show[i]) ||
+                               (significant && showSignificant[i]) ? '$1' : ''));
+               }
+               // Replace period values: {pn}
+               $.each(subs, function(n, v) {
+                       var re = new RegExp('\\{' + n + '\\}', 'g');
+                       html = html.replace(re, v);
+               });
+               return html;
+       },
+
+       /* Ensure a numeric value has at least n digits for display.
+          @param  value  (number) the value to display
+          @param  len    (number) the minimum length
+          @return  (string) the display text */
+       _minDigits: function(value, len) {
+               value = '' + value;
+               if (value.length >= len) {
+                       return value;
+               }
+               value = '0000000000' + value;
+               return value.substr(value.length - len);
+       },
+
+       /* Translate the format into flags for each period.
+          @param  inst  (object) the current settings for this instance
+          @return  (string[7]) flags indicating which periods are requested (?) or
+                   required (!) by year, month, week, day, hour, minute, second */
+       _determineShow: function(inst) {
+               var format = this._get(inst, 'format');
+               var show = [];
+               show[Y] = (format.match('y') ? '?' : (format.match('Y') ? '!' : null));
+               show[O] = (format.match('o') ? '?' : (format.match('O') ? '!' : null));
+               show[W] = (format.match('w') ? '?' : (format.match('W') ? '!' : null));
+               show[D] = (format.match('d') ? '?' : (format.match('D') ? '!' : null));
+               show[H] = (format.match('h') ? '?' : (format.match('H') ? '!' : null));
+               show[M] = (format.match('m') ? '?' : (format.match('M') ? '!' : null));
+               show[S] = (format.match('s') ? '?' : (format.match('S') ? '!' : null));
+               return show;
+       },
+
+       /* Calculate the requested periods between now and the target time.
+          @param  inst         (object) the current settings for this instance
+          @param  show         (string[7]) flags indicating which periods are requested/required
+          @param  significant  (number) the number of periods with values to show, zero for all
+          @param  now          (Date) the current date and time
+          @return  (number[7]) the current time periods (always positive)
+                   by year, month, week, day, hour, minute, second */
+       _calculatePeriods: function(inst, show, significant, now) {
+               // Find endpoints
+               inst._now = now;
+               inst._now.setMilliseconds(0);
+               var until = new Date(inst._now.getTime());
+               if (inst._since) {
+                       if (now.getTime() < inst._since.getTime()) {
+                               inst._now = now = until;
+                       }
+                       else {
+                               now = inst._since;
+                       }
+               }
+               else {
+                       until.setTime(inst._until.getTime());
+                       if (now.getTime() > inst._until.getTime()) {
+                               inst._now = now = until;
+                       }
+               }
+               // Calculate differences by period
+               var periods = [0, 0, 0, 0, 0, 0, 0];
+               if (show[Y] || show[O]) {
+                       // Treat end of months as the same
+                       var lastNow = $.countdown._getDaysInMonth(now.getFullYear(), now.getMonth());
+                       var lastUntil = $.countdown._getDaysInMonth(until.getFullYear(), until.getMonth());
+                       var sameDay = (until.getDate() == now.getDate() ||
+                               (until.getDate() >= Math.min(lastNow, lastUntil) &&
+                               now.getDate() >= Math.min(lastNow, lastUntil)));
+                       var getSecs = function(date) {
+                               return (date.getHours() * 60 + date.getMinutes()) * 60 + date.getSeconds();
+                       };
+                       var months = Math.max(0,
+                               (until.getFullYear() - now.getFullYear()) * 12 + until.getMonth() - now.getMonth() +
+                               ((until.getDate() < now.getDate() && !sameDay) ||
+                               (sameDay && getSecs(until) < getSecs(now)) ? -1 : 0));
+                       periods[Y] = (show[Y] ? Math.floor(months / 12) : 0);
+                       periods[O] = (show[O] ? months - periods[Y] * 12 : 0);
+                       // Adjust for months difference and end of month if necessary
+                       now = new Date(now.getTime());
+                       var wasLastDay = (now.getDate() == lastNow);
+                       var lastDay = $.countdown._getDaysInMonth(now.getFullYear() + periods[Y],
+                               now.getMonth() + periods[O]);
+                       if (now.getDate() > lastDay) {
+                               now.setDate(lastDay);
+                       }
+                       now.setFullYear(now.getFullYear() + periods[Y]);
+                       now.setMonth(now.getMonth() + periods[O]);
+                       if (wasLastDay) {
+                               now.setDate(lastDay);
+                       }
+               }
+               var diff = Math.floor((until.getTime() - now.getTime()) / 1000);
+               var extractPeriod = function(period, numSecs) {
+                       periods[period] = (show[period] ? Math.floor(diff / numSecs) : 0);
+                       diff -= periods[period] * numSecs;
+               };
+               extractPeriod(W, 604800);
+               extractPeriod(D, 86400);
+               extractPeriod(H, 3600);
+               extractPeriod(M, 60);
+               extractPeriod(S, 1);
+               if (diff > 0 && !inst._since) { // Round up if left overs
+                       var multiplier = [1, 12, 4.3482, 7, 24, 60, 60];
+                       var lastShown = S;
+                       var max = 1;
+                       for (var period = S; period >= Y; period--) {
+                               if (show[period]) {
+                                       if (periods[lastShown] >= max) {
+                                               periods[lastShown] = 0;
+                                               diff = 1;
+                                       }
+                                       if (diff > 0) {
+                                               periods[period]++;
+                                               diff = 0;
+                                               lastShown = period;
+                                               max = 1;
+                                       }
+                               }
+                               max *= multiplier[period];
+                       }
+               }
+               if (significant) { // Zero out insignificant periods
+                       for (var period = Y; period <= S; period++) {
+                               if (significant && periods[period]) {
+                                       significant--;
+                               }
+                               else if (!significant) {
+                                       periods[period] = 0;
+                               }
+                       }
+               }
+               return periods;
+       }
+});
+
+/* jQuery extend now ignores nulls!
+   @param  target  (object) the object to update
+   @param  props   (object) the new settings
+   @return  (object) the updated object */
+function extendRemove(target, props) {
+       $.extend(target, props);
+       for (var name in props) {
+               if (props[name] == null) {
+                       target[name] = null;
+               }
+       }
+       return target;
+}
+
+/* Process the countdown functionality for a jQuery selection.
+   @param  command  (string) the command to run (optional, default 'attach')
+   @param  options  (object) the new settings to use for these countdown instances
+   @return  (jQuery) for chaining further calls */
+$.fn.countdown = function(options) {
+       var otherArgs = Array.prototype.slice.call(arguments, 1);
+       if (options == 'getTimes' || options == 'settings') {
+               return $.countdown['_' + options + 'Countdown'].
+                       apply($.countdown, [this[0]].concat(otherArgs));
+       }
+       return this.each(function() {
+               if (typeof options == 'string') {
+                       $.countdown['_' + options + 'Countdown'].apply($.countdown, [this].concat(otherArgs));
+               }
+               else {
+                       $.countdown._attachCountdown(this, options);
+               }
+       });
+};
+
+/* Initialise the countdown functionality. */
+$.countdown = new Countdown(); // singleton instance
+
+})(jQuery);
index 5ecba6e..52fce07 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
  * jQuery Event Delegation Plugin - jquery.eventdelegation.js
  * Fast flexible event handling
  *
                'keydown',
                'keypress',
                'keyup'
-               ], function(i, eventName) {     
+               ], function(i, eventName) {
                        allowed[eventName] = true;
        });
-       
+
        $.fn.extend({
                delegate: function (event, selector, f) {
                        return $(this).each(function () {
@@ -32,7 +32,7 @@
                                        $(this).bind(event, function (e) {
                                                var el = $(e.target),
                                                        result = false;
-                                               
+
                                                while (!$(el).is('body')) {
                                                        if ($(el).is(selector)) {
                                                                result = f.apply($(el)[0], [e]);
@@ -40,7 +40,7 @@
                                                                        e.preventDefault();
                                                                return;
                                                        }
-                                                       
+
                                                        el = $(el).parent();
                                                }
                                        });
index 659baa9..36af6b1 100644 (file)
@@ -13,7 +13,7 @@
 (function($) {
 
 /*
-    Usage Note:  
+    Usage Note:
     -----------
     Do not use both ajaxSubmit and ajaxForm on the same form.  These
     functions are intended to be exclusive.  Use ajaxSubmit if you want
             target: '#output'
         });
     });
-        
+
     When using ajaxForm, the ajaxSubmit function will be invoked for you
-    at the appropriate time.  
+    at the appropriate time.
 */
 
 /**
- * ajaxSubmit() provides a mechanism for immediately submitting 
+ * ajaxSubmit() provides a mechanism for immediately submitting
  * an HTML form using AJAX.
  */
 $.fn.ajaxSubmit = function(options) {
@@ -80,14 +80,14 @@ $.fn.ajaxSubmit = function(options) {
     if (options.beforeSubmit && options.beforeSubmit(a, this, options) === false) {
         log('ajaxSubmit: submit aborted via beforeSubmit callback');
         return this;
-    }    
+    }
 
     // fire vetoable 'validate' event
     this.trigger('form-submit-validate', [a, this, options, veto]);
     if (veto.veto) {
         log('ajaxSubmit: submit vetoed via form-submit-validate trigger');
         return this;
-    }    
+    }
 
     var q = $.param(a);
 
@@ -125,7 +125,7 @@ $.fn.ajaxSubmit = function(options) {
             found = true;
 
     // options.iframe allows user to force iframe mode
-   if (options.iframe || found) { 
+   if (options.iframe || found) {
        // hack to fix Safari hang (thanks to Tim Molendijk for this)
        // see:  http://groups.google.com/group/jquery-dev/browse_thread/thread/36395b7ab510dd5d
        if ($.browser.safari && options.closeKeepAlive)
@@ -144,19 +144,19 @@ $.fn.ajaxSubmit = function(options) {
     // private function for handling file uploads (hat tip to YAHOO!)
     function fileUpload() {
         var form = $form[0];
-        
+
         if ($(':input[@name=submit]', form).length) {
             alert('Error: Form elements must not be named "submit".');
             return;
         }
-        
+
         var opts = $.extend({}, $.ajaxSettings, options);
 
         var id = 'jqFormIO' + (new Date().getTime());
         var $io = $('<iframe id="' + id + '" name="' + id + '" />');
         var io = $io[0];
 
-        if ($.browser.msie || $.browser.opera) 
+        if ($.browser.msie || $.browser.opera)
             io.src = 'javascript:false;document.write("");';
         $io.css({ position: 'absolute', top: '-1000px', left: '-1000px' });
 
@@ -191,7 +191,7 @@ $.fn.ajaxSubmit = function(options) {
                 }
             }
         }
-        
+
         // take a breath so that pending repaints get some cpu time before the upload starts
         setTimeout(function() {
             // make sure form attrs are set
@@ -216,7 +216,7 @@ $.fn.ajaxSubmit = function(options) {
                         extraInputs.push(
                             $('<input type="hidden" name="'+n+'" value="'+options.extraData[n]+'" />')
                                 .appendTo(form)[0]);
-            
+
                 // add iframe to doc and submit the form
                 $io.appendTo('body');
                 io.attachEvent ? io.attachEvent('onload', cb) : io.addEventListener('load', cb, false);
@@ -232,7 +232,7 @@ $.fn.ajaxSubmit = function(options) {
 
         function cb() {
             if (cbInvoked++) return;
-            
+
             io.detachEvent ? io.detachEvent('onload', cb) : io.removeEventListener('load', cb, false);
 
             var operaHack = 0;
@@ -243,7 +243,7 @@ $.fn.ajaxSubmit = function(options) {
                 var data, doc;
 
                 doc = io.contentWindow ? io.contentWindow.document : io.contentDocument ? io.contentDocument : io.document;
-                
+
                 if (doc.body == null && !operaHack && $.browser.opera) {
                     // In Opera 9.2.x the iframe DOM is not always traversable when
                     // the onload callback fires so we give Opera 100ms to right itself
@@ -252,7 +252,7 @@ $.fn.ajaxSubmit = function(options) {
                     setTimeout(cb, 100);
                     return;
                 }
-                
+
                 xhr.responseText = doc.body ? doc.body.innerHTML : null;
                 xhr.responseXML = doc.XMLDocument ? doc.XMLDocument : doc;
                 xhr.getResponseHeader = function(header){
@@ -317,7 +317,7 @@ $.fn.ajaxSubmit = function(options) {
  * The options argument for ajaxForm works exactly as it does for ajaxSubmit.  ajaxForm merely
  * passes the options argument along after properly binding events for submit elements and
  * the form itself.
- */ 
+ */
 $.fn.ajaxForm = function(options) {
     return this.ajaxFormUnbind().bind('submit.form-plugin',function() {
         $(this).ajaxSubmit(options);
@@ -563,10 +563,10 @@ $.fn.resetForm = function() {
 /**
  * Enables or disables any matching elements.
  */
-$.fn.enable = function(b) { 
+$.fn.enable = function(b) {
     if (b == undefined) b = true;
-    return this.each(function() { 
-        this.disabled = !b 
+    return this.each(function() {
+        this.disabled = !b
     });
 };
 
@@ -576,7 +576,7 @@ $.fn.enable = function(b) {
  */
 $.fn.select = function(select) {
     if (select == undefined) select = true;
-    return this.each(function() { 
+    return this.each(function() {
         var t = this.type;
         if (t == 'checkbox' || t == 'radio')
             this.checked = select;
index 600cfe1..bbe39f0 100644 (file)
@@ -12,9 +12,9 @@
  * As of now (Aug. 16, 2006) the plugin has been written with the 1.0.1 release of jQuery (rev 249) which
  * is available from http://jquery.com/src/jquery-1.0.1.js
  *
- * A note regarding rgb() syntax: I noticed that most browsers implement rgb syntax as either an integer 
- * (0-255) or percentage (0-100%) value for each field, that is, rgb(i/p,i/p,i/p); however, the W3C 
- * standard clearly defines it as "either three integer values or three percentage values" [http://www.w3.org/TR/CSS21/syndata.html] 
+ * A note regarding rgb() syntax: I noticed that most browsers implement rgb syntax as either an integer
+ * (0-255) or percentage (0-100%) value for each field, that is, rgb(i/p,i/p,i/p); however, the W3C
+ * standard clearly defines it as "either three integer values or three percentage values" [http://www.w3.org/TR/CSS21/syndata.html]
  * which I choose to follow despite the error redundancy of the typical behaviour browsers employ.
  *
  * Changelog:
@@ -42,7 +42,7 @@
  *        - Fixed bug where multiple events on the same element would speed each subsequent event
  *    0.1:
  *        - Initial Release
- * 
+ *
  * @author          Blair Mitchelmore (blair@offput.ca)
  * @version         0.5
  */
@@ -73,7 +73,7 @@ jQuery.fn.highlightFade = function(settings) {
 };
 
 jQuery.highlightFade = function(e,a,o,t) {
-       e.highlighting[a].timer = window.setInterval(function() { 
+       e.highlighting[a].timer = window.setInterval(function() {
                var newR = t(e.highlighting[a].start[0],e.highlighting[a].end[0],e.highlighting[a].steps,e.highlighting[a].currentStep);
                var newG = t(e.highlighting[a].start[1],e.highlighting[a].end[1],e.highlighting[a].steps,e.highlighting[a].currentStep);
                var newB = t(e.highlighting[a].start[2],e.highlighting[a].end[2],e.highlighting[a].steps,e.highlighting[a].currentStep);
@@ -119,7 +119,7 @@ jQuery.highlightFade.getBaseValue = function(e,a,b) {
        t = a = a || jQuery.highlightFade.defaults['attr'];
        do {
                s = jQuery(e).css(t || 'backgroundColor');
-               if ((s  != '' && s != 'transparent') || (e.tagName.toLowerCase() == "body") || (!b && e.highlighting && e.highlighting[a] && e.highlighting[a].end)) break; 
+               if ((s  != '' && s != 'transparent') || (e.tagName.toLowerCase() == "body") || (!b && e.highlighting && e.highlighting[a] && e.highlighting[a].end)) break;
                t = false;
        } while (e = e.parentNode);
        if (!b && e.highlighting && e.highlighting[a] && e.highlighting[a].end) s = e.highlighting[a].end;
index 966336a..248bb19 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 2007 Brice Burgess <bhb@iceburg.net>, http://www.iceburg.net
  * Licensed under the MIT License:
  * http://www.opensource.org/licenses/mit-license.php
- * 
+ *
  * $Version: 2007.??.?? +r12 beta
  * Requires: jQuery 1.1.3+
  */
  * notices, modal windows, and image containers. An expando ("_jqm") containing
  * the UUID or "serial" of the modal is added to each element. This expando helps
  * reference the modal's settings in the jqModal Hash Object (jQuery.jqm.hash)
- * 
+ *
  * Accepts a parameter object with the following modal settings;
- * 
- * (Integer) zIndex - Desired z-Index of the modal. This setting does not override (has no effect on) preexisting z-Index styling (set via CSS or inline style).  
- * (Integer) overlay - [0-100] Translucency percentage (opacity) of the body covering overlay. Set to 0 for NO overlay, and up to 100 for a 100% opaque overlay.  
+ *
+ * (Integer) zIndex - Desired z-Index of the modal. This setting does not override (has no effect on) preexisting z-Index styling (set via CSS or inline style).
+ * (Integer) overlay - [0-100] Translucency percentage (opacity) of the body covering overlay. Set to 0 for NO overlay, and up to 100 for a 100% opaque overlay.
  * (String) overlayClass - This class is applied to the body covering overlay. Allows CSS control of the overlay look (tint, background image, etc.).
  * (String) closeClass - A close trigger is added to all elements matching this class within the modal.
  * (Mixed) trigger - An open trigger is added to all matching elements within the DOM. Trigger can be a selector String, a jQuery collection of elements, a DOM element, or a False boolean.
@@ -59,7 +59,7 @@ onLoad: false
 //    *AND*...
 return this.each(function(){if(this._jqm)return;s++;this._jqm=s;
 
-// ... Add this element's serial to the jqModal Hash Object 
+// ... Add this element's serial to the jqModal Hash Object
 //  Hash is globally accessible via jQuery.jqm.hash. It consists of;
 //   c: {obj} config/options
 //   a: {bool} active state (true: active/visible, false: inactive/hidden)
@@ -74,7 +74,7 @@ o.trigger&&$(this).jqmAddTrigger(o.trigger);
 });};
 
 // Adds behavior to triggering elements via the hide-show (HS) function.
-// 
+//
 $.fn.jqmAddClose=function(e){return HS(this,e,'jqmHide');};
 $.fn.jqmAddTrigger=function(e){return HS(this,e,'jqmShow');};
 
@@ -98,23 +98,23 @@ hash:{},
 // mark this modal as active (h.a === true)
 // set the triggering object (h.t) and the modal's z-Index.
 open:function(s,t){var h=H[s],c=h.c,cc='.'+c.closeClass,z=/^\d+$/.test(h.w.css('z-index'))&&h.w.css('z-index')||c.zIndex,o=$('<div></div>').css({height:'100%',width:'100%',position:'fixed',left:0,top:0,'z-index':z-1,opacity:c.overlay/100});h.t=t;h.a=true;h.w.css('z-index',z);
+
  // IF the modal argument was passed as true;
  //    Bind the Keep Focus Function if no other Modals are open (!A[0]),
  //    Add this modal to the opened modals stack (A) for nested modal support,
  //    and Mark overlay to show wait cursor when mouse hovers over it.
  if(c.modal) {!A[0]&&F('bind');A.push(s);o.css('cursor','wait');}
+
  // ELSE IF an overlay was requested (translucency set greater than 0);
  //    Attach a Close event to overlay to hide modal when overlay is clicked.
  else if(c.overlay > 0)h.w.jqmAddClose(o);
+
  // ELSE disable the overlay
  else o=false;
 
  // Add the Overlay to BODY if not disabled.
  h.o=(o)?o.addClass(c.overlayClass).prependTo('body'):false;
+
  // IF IE6;
  //  Set the Overlay to 100% height/width, and fix-position it via JS workaround
  if(ie6&&$('html,body').css({height:'100%',width:'100%'})&&o){o=o.css({position:'absolute'})[0];for(var y in {Top:1,Left:1})o.style.setExpression(y.toLowerCase(),"(_=(document.documentElement.scroll"+y+" || document.body.scroll"+y+"))+'px'");}
@@ -123,13 +123,13 @@ open:function(s,t){var h=H[s],c=h.c,cc='.'+c.closeClass,z=/^\d+$/.test(h.w.css('
  //  determine the target element {JQ} to recieve content (r),
  //  determine the URL {STR} to load content from (u)
  if(c.ajax) {var r=c.target||h.w,u=c.ajax,r=(typeof r == 'string')?$(r,h.w):$(r),u=(u.substr(0,1) == '@')?$(t).attr(u.substring(1)):u;
+
   // Load the Content (and once loaded);
    // Fire the onLoad callback (if exists),
    // Attach closing events to elements inside the modal that match the closingClass,
    // and Execute the jqModal default Open Callback
   r.load(u,function(){c.onLoad&&c.onLoad.call(this,h);cc&&h.w.jqmAddClose($(cc,h.w));O(h);});}
+
  // ELSE the modal content is NOT to be loaded via ajax;
  //  Attach closing events to elements inside the modal that match the closingClass
  else cc&&h.w.jqmAddClose($(cc,h.w));
@@ -137,13 +137,13 @@ open:function(s,t){var h=H[s],c=h.c,cc='.'+c.closeClass,z=/^\d+$/.test(h.w.css('
  // IF toTop was passed and an overlay exists;
  //  Remember the DOM posistion of the modal by inserting a tagged (matching serial) <SPAN> before the modal
  //  Move the Modal from its current position to a first child of the body tag (after the overlay)
- c.toTop&&h.o&&h.w.before('<span id="jqmP'+h.w[0]._jqm+'"></span>').insertAfter(h.o);  
+ c.toTop&&h.o&&h.w.before('<span id="jqmP'+h.w[0]._jqm+'"></span>').insertAfter(h.o);
+
  // Execute user defined onShow callback, or else show (make visible) the modal.
  // Execute the jqModal default Open Callback.
  // Return false to prevent trigger click from being followed.
  (c.onShow)?c.onShow(h):h.w.show();O(h);return false;
+
 },
 
 // Function is executed by $.jqmHide to hide a modal
@@ -152,11 +152,11 @@ close:function(s){var h=H[s];h.a=false;
  // If modal, remove from modal stack.
    // If no modals in modal stack, unbind the Keep Focus Function
  if(h.c.modal){A.pop();!A[0]&&F('unbind');}
+
  // IF toTop was passed and an overlay exists;
  //  Move modal back to its previous ("remembered") position.
  h.c.toTop&&h.o&&$('#jqmP'+h.w[0]._jqm).after(h.w).remove();
+
  // Execute user defined onHide callback, or else hide (make invisible) the modal and remove the overlay.
  if(h.c.onHide)h.c.onHide(h);else{h.w.hide()&&h.o&&h.o.remove()}return false;
 }};
@@ -191,10 +191,10 @@ F=function(t){$()[t]("keypress",x)[t]("keydown",x)[t]("mousedown",x);},
 //      ELSE if so (r===false); follow event (return true [!false])
 x=function(e){var h=H[A[A.length-1]],r=(!$(e.target).parents('.jqmID'+h.s)[0]);r&&f(h);return !r;},
 
-// hide-show function; assigns click events to trigger elements that 
+// hide-show function; assigns click events to trigger elements that
 //   hide, show, or hide AND show modals.
 
-// Expandos (jqmShow and/or jqmHide) are added to all trigger elements. 
+// Expandos (jqmShow and/or jqmHide) are added to all trigger elements.
 // These Expandos hold an array of modal serials {INT} to show or hide.
 
 //  w: {DOM Element} The modal element (window/dialog/notice/etc. container)
@@ -207,7 +207,7 @@ HS=function(w,e,y){var s=[];w.each(function(){s.push(this._jqm)});
 // for each triggering element attach the jqmHide or jqmShow expando (y)
 //  or else expand the expando with the current serial array
  $(e).each(function(){if(this[y])$.extend(this[y],s);
+
  // Assign a click event on the trigger element which examines the element's
  //  jqmHide/Show expandos and attempts to execute $.jqmHide/Show on matching modals
  else{this[y]=s;$(this).click(function(){for(var i in {jqmShow:1,jqmHide:1})for(var s in this[i])if(H[this[i][s]])H[this[i][s]].w[i](this);return false;});}});return w;};
index 82b98e1..7c24308 100644 (file)
-/*
- * jQuery 1.2.6 - New Wave Javascript
+/*!
+ * jQuery JavaScript Library v1.4.2
+ * http://jquery.com/
  *
- * Copyright (c) 2008 John Resig (jquery.com)
- * Dual licensed under the MIT (MIT-LICENSE.txt)
- * and GPL (GPL-LICENSE.txt) licenses.
+ * Copyright 2010, John Resig
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
  *
- * $Date: 2008-05-24 14:22:17 -0400 (Sat, 24 May 2008) $
- * $Rev: 5685 $
+ * Includes Sizzle.js
+ * http://sizzlejs.com/
+ * Copyright 2010, The Dojo Foundation
+ * Released under the MIT, BSD, and GPL Licenses.
+ *
+ * Date: Sat Feb 13 22:33:48 2010 -0500
  */
-(function(){var _jQuery=window.jQuery,_$=window.$;var jQuery=window.jQuery=window.$=function(selector,context){return new jQuery.fn.init(selector,context);};var quickExpr=/^[^<]*(<(.|\s)+>)[^>]*$|^#(\w+)$/,isSimple=/^.[^:#\[\.]*$/,undefined;jQuery.fn=jQuery.prototype={init:function(selector,context){selector=selector||document;if(selector.nodeType){this[0]=selector;this.length=1;return this;}if(typeof selector=="string"){var match=quickExpr.exec(selector);if(match&&(match[1]||!context)){if(match[1])selector=jQuery.clean([match[1]],context);else{var elem=document.getElementById(match[3]);if(elem){if(elem.id!=match[3])return jQuery().find(selector);return jQuery(elem);}selector=[];}}else
-return jQuery(context).find(selector);}else if(jQuery.isFunction(selector))return jQuery(document)[jQuery.fn.ready?"ready":"load"](selector);return this.setArray(jQuery.makeArray(selector));},jquery:"1.2.6",size:function(){return this.length;},length:0,get:function(num){return num==undefined?jQuery.makeArray(this):this[num];},pushStack:function(elems){var ret=jQuery(elems);ret.prevObject=this;return ret;},setArray:function(elems){this.length=0;Array.prototype.push.apply(this,elems);return this;},each:function(callback,args){return jQuery.each(this,callback,args);},index:function(elem){var ret=-1;return jQuery.inArray(elem&&elem.jquery?elem[0]:elem,this);},attr:function(name,value,type){var options=name;if(name.constructor==String)if(value===undefined)return this[0]&&jQuery[type||"attr"](this[0],name);else{options={};options[name]=value;}return this.each(function(i){for(name in options)jQuery.attr(type?this.style:this,name,jQuery.prop(this,options[name],type,i,name));});},css:function(key,value){if((key=='width'||key=='height')&&parseFloat(value)<0)value=undefined;return this.attr(key,value,"curCSS");},text:function(text){if(typeof text!="object"&&text!=null)return this.empty().append((this[0]&&this[0].ownerDocument||document).createTextNode(text));var ret="";jQuery.each(text||this,function(){jQuery.each(this.childNodes,function(){if(this.nodeType!=8)ret+=this.nodeType!=1?this.nodeValue:jQuery.fn.text([this]);});});return ret;},wrapAll:function(html){if(this[0])jQuery(html,this[0].ownerDocument).clone().insertBefore(this[0]).map(function(){var elem=this;while(elem.firstChild)elem=elem.firstChild;return elem;}).append(this);return this;},wrapInner:function(html){return this.each(function(){jQuery(this).contents().wrapAll(html);});},wrap:function(html){return this.each(function(){jQuery(this).wrapAll(html);});},append:function(){return this.domManip(arguments,true,false,function(elem){if(this.nodeType==1)this.appendChild(elem);});},prepend:function(){return this.domManip(arguments,true,true,function(elem){if(this.nodeType==1)this.insertBefore(elem,this.firstChild);});},before:function(){return this.domManip(arguments,false,false,function(elem){this.parentNode.insertBefore(elem,this);});},after:function(){return this.domManip(arguments,false,true,function(elem){this.parentNode.insertBefore(elem,this.nextSibling);});},end:function(){return this.prevObject||jQuery([]);},find:function(selector){var elems=jQuery.map(this,function(elem){return jQuery.find(selector,elem);});return this.pushStack(/[^+>] [^+>]/.test(selector)||selector.indexOf("..")>-1?jQuery.unique(elems):elems);},clone:function(events){var ret=this.map(function(){if(jQuery.browser.msie&&!jQuery.isXMLDoc(this)){var clone=this.cloneNode(true),container=document.createElement("div");container.appendChild(clone);return jQuery.clean([container.innerHTML])[0];}else
-return this.cloneNode(true);});var clone=ret.find("*").andSelf().each(function(){if(this[expando]!=undefined)this[expando]=null;});if(events===true)this.find("*").andSelf().each(function(i){if(this.nodeType==3)return;var events=jQuery.data(this,"events");for(var type in events)for(var handler in events[type])jQuery.event.add(clone[i],type,events[type][handler],events[type][handler].data);});return ret;},filter:function(selector){return this.pushStack(jQuery.isFunction(selector)&&jQuery.grep(this,function(elem,i){return selector.call(elem,i);})||jQuery.multiFilter(selector,this));},not:function(selector){if(selector.constructor==String)if(isSimple.test(selector))return this.pushStack(jQuery.multiFilter(selector,this,true));else
-selector=jQuery.multiFilter(selector,this);var isArrayLike=selector.length&&selector[selector.length-1]!==undefined&&!selector.nodeType;return this.filter(function(){return isArrayLike?jQuery.inArray(this,selector)<0:this!=selector;});},add:function(selector){return this.pushStack(jQuery.unique(jQuery.merge(this.get(),typeof selector=='string'?jQuery(selector):jQuery.makeArray(selector))));},is:function(selector){return!!selector&&jQuery.multiFilter(selector,this).length>0;},hasClass:function(selector){return this.is("."+selector);},val:function(value){if(value==undefined){if(this.length){var elem=this[0];if(jQuery.nodeName(elem,"select")){var index=elem.selectedIndex,values=[],options=elem.options,one=elem.type=="select-one";if(index<0)return null;for(var i=one?index:0,max=one?index+1:options.length;i<max;i++){var option=options[i];if(option.selected){value=jQuery.browser.msie&&!option.attributes.value.specified?option.text:option.value;if(one)return value;values.push(value);}}return values;}else
-return(this[0].value||"").replace(/\r/g,"");}return undefined;}if(value.constructor==Number)value+='';return this.each(function(){if(this.nodeType!=1)return;if(value.constructor==Array&&/radio|checkbox/.test(this.type))this.checked=(jQuery.inArray(this.value,value)>=0||jQuery.inArray(this.name,value)>=0);else if(jQuery.nodeName(this,"select")){var values=jQuery.makeArray(value);jQuery("option",this).each(function(){this.selected=(jQuery.inArray(this.value,values)>=0||jQuery.inArray(this.text,values)>=0);});if(!values.length)this.selectedIndex=-1;}else
-this.value=value;});},html:function(value){return value==undefined?(this[0]?this[0].innerHTML:null):this.empty().append(value);},replaceWith:function(value){return this.after(value).remove();},eq:function(i){return this.slice(i,i+1);},slice:function(){return this.pushStack(Array.prototype.slice.apply(this,arguments));},map:function(callback){return this.pushStack(jQuery.map(this,function(elem,i){return callback.call(elem,i,elem);}));},andSelf:function(){return this.add(this.prevObject);},data:function(key,value){var parts=key.split(".");parts[1]=parts[1]?"."+parts[1]:"";if(value===undefined){var data=this.triggerHandler("getData"+parts[1]+"!",[parts[0]]);if(data===undefined&&this.length)data=jQuery.data(this[0],key);return data===undefined&&parts[1]?this.data(parts[0]):data;}else
-return this.trigger("setData"+parts[1]+"!",[parts[0],value]).each(function(){jQuery.data(this,key,value);});},removeData:function(key){return this.each(function(){jQuery.removeData(this,key);});},domManip:function(args,table,reverse,callback){var clone=this.length>1,elems;return this.each(function(){if(!elems){elems=jQuery.clean(args,this.ownerDocument);if(reverse)elems.reverse();}var obj=this;if(table&&jQuery.nodeName(this,"table")&&jQuery.nodeName(elems[0],"tr"))obj=this.getElementsByTagName("tbody")[0]||this.appendChild(this.ownerDocument.createElement("tbody"));var scripts=jQuery([]);jQuery.each(elems,function(){var elem=clone?jQuery(this).clone(true)[0]:this;if(jQuery.nodeName(elem,"script"))scripts=scripts.add(elem);else{if(elem.nodeType==1)scripts=scripts.add(jQuery("script",elem).remove());callback.call(obj,elem);}});scripts.each(evalScript);});}};jQuery.fn.init.prototype=jQuery.fn;function evalScript(i,elem){if(elem.src)jQuery.ajax({url:elem.src,async:false,dataType:"script"});else
-jQuery.globalEval(elem.text||elem.textContent||elem.innerHTML||"");if(elem.parentNode)elem.parentNode.removeChild(elem);}function now(){return+new Date;}jQuery.extend=jQuery.fn.extend=function(){var target=arguments[0]||{},i=1,length=arguments.length,deep=false,options;if(target.constructor==Boolean){deep=target;target=arguments[1]||{};i=2;}if(typeof target!="object"&&typeof target!="function")target={};if(length==i){target=this;--i;}for(;i<length;i++)if((options=arguments[i])!=null)for(var name in options){var src=target[name],copy=options[name];if(target===copy)continue;if(deep&&copy&&typeof copy=="object"&&!copy.nodeType)target[name]=jQuery.extend(deep,src||(copy.length!=null?[]:{}),copy);else if(copy!==undefined)target[name]=copy;}return target;};var expando="jQuery"+now(),uuid=0,windowData={},exclude=/z-?index|font-?weight|opacity|zoom|line-?height/i,defaultView=document.defaultView||{};jQuery.extend({noConflict:function(deep){window.$=_$;if(deep)window.jQuery=_jQuery;return jQuery;},isFunction:function(fn){return!!fn&&typeof fn!="string"&&!fn.nodeName&&fn.constructor!=Array&&/^[\s[]?function/.test(fn+"");},isXMLDoc:function(elem){return elem.documentElement&&!elem.body||elem.tagName&&elem.ownerDocument&&!elem.ownerDocument.body;},globalEval:function(data){data=jQuery.trim(data);if(data){var head=document.getElementsByTagName("head")[0]||document.documentElement,script=document.createElement("script");script.type="text/javascript";if(jQuery.browser.msie)script.text=data;else
-script.appendChild(document.createTextNode(data));head.insertBefore(script,head.firstChild);head.removeChild(script);}},nodeName:function(elem,name){return elem.nodeName&&elem.nodeName.toUpperCase()==name.toUpperCase();},cache:{},data:function(elem,name,data){elem=elem==window?windowData:elem;var id=elem[expando];if(!id)id=elem[expando]=++uuid;if(name&&!jQuery.cache[id])jQuery.cache[id]={};if(data!==undefined)jQuery.cache[id][name]=data;return name?jQuery.cache[id][name]:id;},removeData:function(elem,name){elem=elem==window?windowData:elem;var id=elem[expando];if(name){if(jQuery.cache[id]){delete jQuery.cache[id][name];name="";for(name in jQuery.cache[id])break;if(!name)jQuery.removeData(elem);}}else{try{delete elem[expando];}catch(e){if(elem.removeAttribute)elem.removeAttribute(expando);}delete jQuery.cache[id];}},each:function(object,callback,args){var name,i=0,length=object.length;if(args){if(length==undefined){for(name in object)if(callback.apply(object[name],args)===false)break;}else
-for(;i<length;)if(callback.apply(object[i++],args)===false)break;}else{if(length==undefined){for(name in object)if(callback.call(object[name],name,object[name])===false)break;}else
-for(var value=object[0];i<length&&callback.call(value,i,value)!==false;value=object[++i]){}}return object;},prop:function(elem,value,type,i,name){if(jQuery.isFunction(value))value=value.call(elem,i);return value&&value.constructor==Number&&type=="curCSS"&&!exclude.test(name)?value+"px":value;},className:{add:function(elem,classNames){jQuery.each((classNames||"").split(/\s+/),function(i,className){if(elem.nodeType==1&&!jQuery.className.has(elem.className,className))elem.className+=(elem.className?" ":"")+className;});},remove:function(elem,classNames){if(elem.nodeType==1)elem.className=classNames!=undefined?jQuery.grep(elem.className.split(/\s+/),function(className){return!jQuery.className.has(classNames,className);}).join(" "):"";},has:function(elem,className){return jQuery.inArray(className,(elem.className||elem).toString().split(/\s+/))>-1;}},swap:function(elem,options,callback){var old={};for(var name in options){old[name]=elem.style[name];elem.style[name]=options[name];}callback.call(elem);for(var name in options)elem.style[name]=old[name];},css:function(elem,name,force){if(name=="width"||name=="height"){var val,props={position:"absolute",visibility:"hidden",display:"block"},which=name=="width"?["Left","Right"]:["Top","Bottom"];function getWH(){val=name=="width"?elem.offsetWidth:elem.offsetHeight;var padding=0,border=0;jQuery.each(which,function(){padding+=parseFloat(jQuery.curCSS(elem,"padding"+this,true))||0;border+=parseFloat(jQuery.curCSS(elem,"border"+this+"Width",true))||0;});val-=Math.round(padding+border);}if(jQuery(elem).is(":visible"))getWH();else
-jQuery.swap(elem,props,getWH);return Math.max(0,val);}return jQuery.curCSS(elem,name,force);},curCSS:function(elem,name,force){var ret,style=elem.style;function color(elem){if(!jQuery.browser.safari)return false;var ret=defaultView.getComputedStyle(elem,null);return!ret||ret.getPropertyValue("color")=="";}if(name=="opacity"&&jQuery.browser.msie){ret=jQuery.attr(style,"opacity");return ret==""?"1":ret;}if(jQuery.browser.opera&&name=="display"){var save=style.outline;style.outline="0 solid black";style.outline=save;}if(name.match(/float/i))name=styleFloat;if(!force&&style&&style[name])ret=style[name];else if(defaultView.getComputedStyle){if(name.match(/float/i))name="float";name=name.replace(/([A-Z])/g,"-$1").toLowerCase();var computedStyle=defaultView.getComputedStyle(elem,null);if(computedStyle&&!color(elem))ret=computedStyle.getPropertyValue(name);else{var swap=[],stack=[],a=elem,i=0;for(;a&&color(a);a=a.parentNode)stack.unshift(a);for(;i<stack.length;i++)if(color(stack[i])){swap[i]=stack[i].style.display;stack[i].style.display="block";}ret=name=="display"&&swap[stack.length-1]!=null?"none":(computedStyle&&computedStyle.getPropertyValue(name))||"";for(i=0;i<swap.length;i++)if(swap[i]!=null)stack[i].style.display=swap[i];}if(name=="opacity"&&ret=="")ret="1";}else if(elem.currentStyle){var camelCase=name.replace(/\-(\w)/g,function(all,letter){return letter.toUpperCase();});ret=elem.currentStyle[name]||elem.currentStyle[camelCase];if(!/^\d+(px)?$/i.test(ret)&&/^\d/.test(ret)){var left=style.left,rsLeft=elem.runtimeStyle.left;elem.runtimeStyle.left=elem.currentStyle.left;style.left=ret||0;ret=style.pixelLeft+"px";style.left=left;elem.runtimeStyle.left=rsLeft;}}return ret;},clean:function(elems,context){var ret=[];context=context||document;if(typeof context.createElement=='undefined')context=context.ownerDocument||context[0]&&context[0].ownerDocument||document;jQuery.each(elems,function(i,elem){if(!elem)return;if(elem.constructor==Number)elem+='';if(typeof elem=="string"){elem=elem.replace(/(<(\w+)[^>]*?)\/>/g,function(all,front,tag){return tag.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i)?all:front+"></"+tag+">";});var tags=jQuery.trim(elem).toLowerCase(),div=context.createElement("div");var wrap=!tags.indexOf("<opt")&&[1,"<select multiple='multiple'>","</select>"]||!tags.indexOf("<leg")&&[1,"<fieldset>","</fieldset>"]||tags.match(/^<(thead|tbody|tfoot|colg|cap)/)&&[1,"<table>","</table>"]||!tags.indexOf("<tr")&&[2,"<table><tbody>","</tbody></table>"]||(!tags.indexOf("<td")||!tags.indexOf("<th"))&&[3,"<table><tbody><tr>","</tr></tbody></table>"]||!tags.indexOf("<col")&&[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"]||jQuery.browser.msie&&[1,"div<div>","</div>"]||[0,"",""];div.innerHTML=wrap[1]+elem+wrap[2];while(wrap[0]--)div=div.lastChild;if(jQuery.browser.msie){var tbody=!tags.indexOf("<table")&&tags.indexOf("<tbody")<0?div.firstChild&&div.firstChild.childNodes:wrap[1]=="<table>"&&tags.indexOf("<tbody")<0?div.childNodes:[];for(var j=tbody.length-1;j>=0;--j)if(jQuery.nodeName(tbody[j],"tbody")&&!tbody[j].childNodes.length)tbody[j].parentNode.removeChild(tbody[j]);if(/^\s/.test(elem))div.insertBefore(context.createTextNode(elem.match(/^\s*/)[0]),div.firstChild);}elem=jQuery.makeArray(div.childNodes);}if(elem.length===0&&(!jQuery.nodeName(elem,"form")&&!jQuery.nodeName(elem,"select")))return;if(elem[0]==undefined||jQuery.nodeName(elem,"form")||elem.options)ret.push(elem);else
-ret=jQuery.merge(ret,elem);});return ret;},attr:function(elem,name,value){if(!elem||elem.nodeType==3||elem.nodeType==8)return undefined;var notxml=!jQuery.isXMLDoc(elem),set=value!==undefined,msie=jQuery.browser.msie;name=notxml&&jQuery.props[name]||name;if(elem.tagName){var special=/href|src|style/.test(name);if(name=="selected"&&jQuery.browser.safari)elem.parentNode.selectedIndex;if(name in elem&&notxml&&!special){if(set){if(name=="type"&&jQuery.nodeName(elem,"input")&&elem.parentNode)throw"type property can't be changed";elem[name]=value;}if(jQuery.nodeName(elem,"form")&&elem.getAttributeNode(name))return elem.getAttributeNode(name).nodeValue;return elem[name];}if(msie&&notxml&&name=="style")return jQuery.attr(elem.style,"cssText",value);if(set)elem.setAttribute(name,""+value);var attr=msie&&notxml&&special?elem.getAttribute(name,2):elem.getAttribute(name);return attr===null?undefined:attr;}if(msie&&name=="opacity"){if(set){elem.zoom=1;elem.filter=(elem.filter||"").replace(/alpha\([^)]*\)/,"")+(parseInt(value)+''=="NaN"?"":"alpha(opacity="+value*100+")");}return elem.filter&&elem.filter.indexOf("opacity=")>=0?(parseFloat(elem.filter.match(/opacity=([^)]*)/)[1])/100)+'':"";}name=name.replace(/-([a-z])/ig,function(all,letter){return letter.toUpperCase();});if(set)elem[name]=value;return elem[name];},trim:function(text){return(text||"").replace(/^\s+|\s+$/g,"");},makeArray:function(array){var ret=[];if(array!=null){var i=array.length;if(i==null||array.split||array.setInterval||array.call)ret[0]=array;else
-while(i)ret[--i]=array[i];}return ret;},inArray:function(elem,array){for(var i=0,length=array.length;i<length;i++)if(array[i]===elem)return i;return-1;},merge:function(first,second){var i=0,elem,pos=first.length;if(jQuery.browser.msie){while(elem=second[i++])if(elem.nodeType!=8)first[pos++]=elem;}else
-while(elem=second[i++])first[pos++]=elem;return first;},unique:function(array){var ret=[],done={};try{for(var i=0,length=array.length;i<length;i++){var id=jQuery.data(array[i]);if(!done[id]){done[id]=true;ret.push(array[i]);}}}catch(e){ret=array;}return ret;},grep:function(elems,callback,inv){var ret=[];for(var i=0,length=elems.length;i<length;i++)if(!inv!=!callback(elems[i],i))ret.push(elems[i]);return ret;},map:function(elems,callback){var ret=[];for(var i=0,length=elems.length;i<length;i++){var value=callback(elems[i],i);if(value!=null)ret[ret.length]=value;}return ret.concat.apply([],ret);}});var userAgent=navigator.userAgent.toLowerCase();jQuery.browser={version:(userAgent.match(/.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/)||[])[1],safari:/webkit/.test(userAgent),opera:/opera/.test(userAgent),msie:/msie/.test(userAgent)&&!/opera/.test(userAgent),mozilla:/mozilla/.test(userAgent)&&!/(compatible|webkit)/.test(userAgent)};var styleFloat=jQuery.browser.msie?"styleFloat":"cssFloat";jQuery.extend({boxModel:!jQuery.browser.msie||document.compatMode=="CSS1Compat",props:{"for":"htmlFor","class":"className","float":styleFloat,cssFloat:styleFloat,styleFloat:styleFloat,readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing"}});jQuery.each({parent:function(elem){return elem.parentNode;},parents:function(elem){return jQuery.dir(elem,"parentNode");},next:function(elem){return jQuery.nth(elem,2,"nextSibling");},prev:function(elem){return jQuery.nth(elem,2,"previousSibling");},nextAll:function(elem){return jQuery.dir(elem,"nextSibling");},prevAll:function(elem){return jQuery.dir(elem,"previousSibling");},siblings:function(elem){return jQuery.sibling(elem.parentNode.firstChild,elem);},children:function(elem){return jQuery.sibling(elem.firstChild);},contents:function(elem){return jQuery.nodeName(elem,"iframe")?elem.contentDocument||elem.contentWindow.document:jQuery.makeArray(elem.childNodes);}},function(name,fn){jQuery.fn[name]=function(selector){var ret=jQuery.map(this,fn);if(selector&&typeof selector=="string")ret=jQuery.multiFilter(selector,ret);return this.pushStack(jQuery.unique(ret));};});jQuery.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(name,original){jQuery.fn[name]=function(){var args=arguments;return this.each(function(){for(var i=0,length=args.length;i<length;i++)jQuery(args[i])[original](this);});};});jQuery.each({removeAttr:function(name){jQuery.attr(this,name,"");if(this.nodeType==1)this.removeAttribute(name);},addClass:function(classNames){jQuery.className.add(this,classNames);},removeClass:function(classNames){jQuery.className.remove(this,classNames);},toggleClass:function(classNames){jQuery.className[jQuery.className.has(this,classNames)?"remove":"add"](this,classNames);},remove:function(selector){if(!selector||jQuery.filter(selector,[this]).r.length){jQuery("*",this).add(this).each(function(){jQuery.event.remove(this);jQuery.removeData(this);});if(this.parentNode)this.parentNode.removeChild(this);}},empty:function(){jQuery(">*",this).remove();while(this.firstChild)this.removeChild(this.firstChild);}},function(name,fn){jQuery.fn[name]=function(){return this.each(fn,arguments);};});jQuery.each(["Height","Width"],function(i,name){var type=name.toLowerCase();jQuery.fn[type]=function(size){return this[0]==window?jQuery.browser.opera&&document.body["client"+name]||jQuery.browser.safari&&window["inner"+name]||document.compatMode=="CSS1Compat"&&document.documentElement["client"+name]||document.body["client"+name]:this[0]==document?Math.max(Math.max(document.body["scroll"+name],document.documentElement["scroll"+name]),Math.max(document.body["offset"+name],document.documentElement["offset"+name])):size==undefined?(this.length?jQuery.css(this[0],type):null):this.css(type,size.constructor==String?size:size+"px");};});function num(elem,prop){return elem[0]&&parseInt(jQuery.curCSS(elem[0],prop,true),10)||0;}var chars=jQuery.browser.safari&&parseInt(jQuery.browser.version)<417?"(?:[\\w*_-]|\\\\.)":"(?:[\\w\u0128-\uFFFF*_-]|\\\\.)",quickChild=new RegExp("^>\\s*("+chars+"+)"),quickID=new RegExp("^("+chars+"+)(#)("+chars+"+)"),quickClass=new RegExp("^([#.]?)("+chars+"*)");jQuery.extend({expr:{"":function(a,i,m){return m[2]=="*"||jQuery.nodeName(a,m[2]);},"#":function(a,i,m){return a.getAttribute("id")==m[2];},":":{lt:function(a,i,m){return i<m[3]-0;},gt:function(a,i,m){return i>m[3]-0;},nth:function(a,i,m){return m[3]-0==i;},eq:function(a,i,m){return m[3]-0==i;},first:function(a,i){return i==0;},last:function(a,i,m,r){return i==r.length-1;},even:function(a,i){return i%2==0;},odd:function(a,i){return i%2;},"first-child":function(a){return a.parentNode.getElementsByTagName("*")[0]==a;},"last-child":function(a){return jQuery.nth(a.parentNode.lastChild,1,"previousSibling")==a;},"only-child":function(a){return!jQuery.nth(a.parentNode.lastChild,2,"previousSibling");},parent:function(a){return a.firstChild;},empty:function(a){return!a.firstChild;},contains:function(a,i,m){return(a.textContent||a.innerText||jQuery(a).text()||"").indexOf(m[3])>=0;},visible:function(a){return"hidden"!=a.type&&jQuery.css(a,"display")!="none"&&jQuery.css(a,"visibility")!="hidden";},hidden:function(a){return"hidden"==a.type||jQuery.css(a,"display")=="none"||jQuery.css(a,"visibility")=="hidden";},enabled:function(a){return!a.disabled;},disabled:function(a){return a.disabled;},checked:function(a){return a.checked;},selected:function(a){return a.selected||jQuery.attr(a,"selected");},text:function(a){return"text"==a.type;},radio:function(a){return"radio"==a.type;},checkbox:function(a){return"checkbox"==a.type;},file:function(a){return"file"==a.type;},password:function(a){return"password"==a.type;},submit:function(a){return"submit"==a.type;},image:function(a){return"image"==a.type;},reset:function(a){return"reset"==a.type;},button:function(a){return"button"==a.type||jQuery.nodeName(a,"button");},input:function(a){return/input|select|textarea|button/i.test(a.nodeName);},has:function(a,i,m){return jQuery.find(m[3],a).length;},header:function(a){return/h\d/i.test(a.nodeName);},animated:function(a){return jQuery.grep(jQuery.timers,function(fn){return a==fn.elem;}).length;}}},parse:[/^(\[) *@?([\w-]+) *([!*$^~=]*) *('?"?)(.*?)\4 *\]/,/^(:)([\w-]+)\("?'?(.*?(\(.*?\))?[^(]*?)"?'?\)/,new RegExp("^([:.#]*)("+chars+"+)")],multiFilter:function(expr,elems,not){var old,cur=[];while(expr&&expr!=old){old=expr;var f=jQuery.filter(expr,elems,not);expr=f.t.replace(/^\s*,\s*/,"");cur=not?elems=f.r:jQuery.merge(cur,f.r);}return cur;},find:function(t,context){if(typeof t!="string")return[t];if(context&&context.nodeType!=1&&context.nodeType!=9)return[];context=context||document;var ret=[context],done=[],last,nodeName;while(t&&last!=t){var r=[];last=t;t=jQuery.trim(t);var foundToken=false,re=quickChild,m=re.exec(t);if(m){nodeName=m[1].toUpperCase();for(var i=0;ret[i];i++)for(var c=ret[i].firstChild;c;c=c.nextSibling)if(c.nodeType==1&&(nodeName=="*"||c.nodeName.toUpperCase()==nodeName))r.push(c);ret=r;t=t.replace(re,"");if(t.indexOf(" ")==0)continue;foundToken=true;}else{re=/^([>+~])\s*(\w*)/i;if((m=re.exec(t))!=null){r=[];var merge={};nodeName=m[2].toUpperCase();m=m[1];for(var j=0,rl=ret.length;j<rl;j++){var n=m=="~"||m=="+"?ret[j].nextSibling:ret[j].firstChild;for(;n;n=n.nextSibling)if(n.nodeType==1){var id=jQuery.data(n);if(m=="~"&&merge[id])break;if(!nodeName||n.nodeName.toUpperCase()==nodeName){if(m=="~")merge[id]=true;r.push(n);}if(m=="+")break;}}ret=r;t=jQuery.trim(t.replace(re,""));foundToken=true;}}if(t&&!foundToken){if(!t.indexOf(",")){if(context==ret[0])ret.shift();done=jQuery.merge(done,ret);r=ret=[context];t=" "+t.substr(1,t.length);}else{var re2=quickID;var m=re2.exec(t);if(m){m=[0,m[2],m[3],m[1]];}else{re2=quickClass;m=re2.exec(t);}m[2]=m[2].replace(/\\/g,"");var elem=ret[ret.length-1];if(m[1]=="#"&&elem&&elem.getElementById&&!jQuery.isXMLDoc(elem)){var oid=elem.getElementById(m[2]);if((jQuery.browser.msie||jQuery.browser.opera)&&oid&&typeof oid.id=="string"&&oid.id!=m[2])oid=jQuery('[@id="'+m[2]+'"]',elem)[0];ret=r=oid&&(!m[3]||jQuery.nodeName(oid,m[3]))?[oid]:[];}else{for(var i=0;ret[i];i++){var tag=m[1]=="#"&&m[3]?m[3]:m[1]!=""||m[0]==""?"*":m[2];if(tag=="*"&&ret[i].nodeName.toLowerCase()=="object")tag="param";r=jQuery.merge(r,ret[i].getElementsByTagName(tag));}if(m[1]==".")r=jQuery.classFilter(r,m[2]);if(m[1]=="#"){var tmp=[];for(var i=0;r[i];i++)if(r[i].getAttribute("id")==m[2]){tmp=[r[i]];break;}r=tmp;}ret=r;}t=t.replace(re2,"");}}if(t){var val=jQuery.filter(t,r);ret=r=val.r;t=jQuery.trim(val.t);}}if(t)ret=[];if(ret&&context==ret[0])ret.shift();done=jQuery.merge(done,ret);return done;},classFilter:function(r,m,not){m=" "+m+" ";var tmp=[];for(var i=0;r[i];i++){var pass=(" "+r[i].className+" ").indexOf(m)>=0;if(!not&&pass||not&&!pass)tmp.push(r[i]);}return tmp;},filter:function(t,r,not){var last;while(t&&t!=last){last=t;var p=jQuery.parse,m;for(var i=0;p[i];i++){m=p[i].exec(t);if(m){t=t.substring(m[0].length);m[2]=m[2].replace(/\\/g,"");break;}}if(!m)break;if(m[1]==":"&&m[2]=="not")r=isSimple.test(m[3])?jQuery.filter(m[3],r,true).r:jQuery(r).not(m[3]);else if(m[1]==".")r=jQuery.classFilter(r,m[2],not);else if(m[1]=="["){var tmp=[],type=m[3];for(var i=0,rl=r.length;i<rl;i++){var a=r[i],z=a[jQuery.props[m[2]]||m[2]];if(z==null||/href|src|selected/.test(m[2]))z=jQuery.attr(a,m[2])||'';if((type==""&&!!z||type=="="&&z==m[5]||type=="!="&&z!=m[5]||type=="^="&&z&&!z.indexOf(m[5])||type=="$="&&z.substr(z.length-m[5].length)==m[5]||(type=="*="||type=="~=")&&z.indexOf(m[5])>=0)^not)tmp.push(a);}r=tmp;}else if(m[1]==":"&&m[2]=="nth-child"){var merge={},tmp=[],test=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(m[3]=="even"&&"2n"||m[3]=="odd"&&"2n+1"||!/\D/.test(m[3])&&"0n+"+m[3]||m[3]),first=(test[1]+(test[2]||1))-0,last=test[3]-0;for(var i=0,rl=r.length;i<rl;i++){var node=r[i],parentNode=node.parentNode,id=jQuery.data(parentNode);if(!merge[id]){var c=1;for(var n=parentNode.firstChild;n;n=n.nextSibling)if(n.nodeType==1)n.nodeIndex=c++;merge[id]=true;}var add=false;if(first==0){if(node.nodeIndex==last)add=true;}else if((node.nodeIndex-last)%first==0&&(node.nodeIndex-last)/first>=0)add=true;if(add^not)tmp.push(node);}r=tmp;}else{var fn=jQuery.expr[m[1]];if(typeof fn=="object")fn=fn[m[2]];if(typeof fn=="string")fn=eval("false||function(a,i){return "+fn+";}");r=jQuery.grep(r,function(elem,i){return fn(elem,i,m,r);},not);}}return{r:r,t:t};},dir:function(elem,dir){var matched=[],cur=elem[dir];while(cur&&cur!=document){if(cur.nodeType==1)matched.push(cur);cur=cur[dir];}return matched;},nth:function(cur,result,dir,elem){result=result||1;var num=0;for(;cur;cur=cur[dir])if(cur.nodeType==1&&++num==result)break;return cur;},sibling:function(n,elem){var r=[];for(;n;n=n.nextSibling){if(n.nodeType==1&&n!=elem)r.push(n);}return r;}});jQuery.event={add:function(elem,types,handler,data){if(elem.nodeType==3||elem.nodeType==8)return;if(jQuery.browser.msie&&elem.setInterval)elem=window;if(!handler.guid)handler.guid=this.guid++;if(data!=undefined){var fn=handler;handler=this.proxy(fn,function(){return fn.apply(this,arguments);});handler.data=data;}var events=jQuery.data(elem,"events")||jQuery.data(elem,"events",{}),handle=jQuery.data(elem,"handle")||jQuery.data(elem,"handle",function(){if(typeof jQuery!="undefined"&&!jQuery.event.triggered)return jQuery.event.handle.apply(arguments.callee.elem,arguments);});handle.elem=elem;jQuery.each(types.split(/\s+/),function(index,type){var parts=type.split(".");type=parts[0];handler.type=parts[1];var handlers=events[type];if(!handlers){handlers=events[type]={};if(!jQuery.event.special[type]||jQuery.event.special[type].setup.call(elem)===false){if(elem.addEventListener)elem.addEventListener(type,handle,false);else if(elem.attachEvent)elem.attachEvent("on"+type,handle);}}handlers[handler.guid]=handler;jQuery.event.global[type]=true;});elem=null;},guid:1,global:{},remove:function(elem,types,handler){if(elem.nodeType==3||elem.nodeType==8)return;var events=jQuery.data(elem,"events"),ret,index;if(events){if(types==undefined||(typeof types=="string"&&types.charAt(0)=="."))for(var type in events)this.remove(elem,type+(types||""));else{if(types.type){handler=types.handler;types=types.type;}jQuery.each(types.split(/\s+/),function(index,type){var parts=type.split(".");type=parts[0];if(events[type]){if(handler)delete events[type][handler.guid];else
-for(handler in events[type])if(!parts[1]||events[type][handler].type==parts[1])delete events[type][handler];for(ret in events[type])break;if(!ret){if(!jQuery.event.special[type]||jQuery.event.special[type].teardown.call(elem)===false){if(elem.removeEventListener)elem.removeEventListener(type,jQuery.data(elem,"handle"),false);else if(elem.detachEvent)elem.detachEvent("on"+type,jQuery.data(elem,"handle"));}ret=null;delete events[type];}}});}for(ret in events)break;if(!ret){var handle=jQuery.data(elem,"handle");if(handle)handle.elem=null;jQuery.removeData(elem,"events");jQuery.removeData(elem,"handle");}}},trigger:function(type,data,elem,donative,extra){data=jQuery.makeArray(data);if(type.indexOf("!")>=0){type=type.slice(0,-1);var exclusive=true;}if(!elem){if(this.global[type])jQuery("*").add([window,document]).trigger(type,data);}else{if(elem.nodeType==3||elem.nodeType==8)return undefined;var val,ret,fn=jQuery.isFunction(elem[type]||null),event=!data[0]||!data[0].preventDefault;if(event){data.unshift({type:type,target:elem,preventDefault:function(){},stopPropagation:function(){},timeStamp:now()});data[0][expando]=true;}data[0].type=type;if(exclusive)data[0].exclusive=true;var handle=jQuery.data(elem,"handle");if(handle)val=handle.apply(elem,data);if((!fn||(jQuery.nodeName(elem,'a')&&type=="click"))&&elem["on"+type]&&elem["on"+type].apply(elem,data)===false)val=false;if(event)data.shift();if(extra&&jQuery.isFunction(extra)){ret=extra.apply(elem,val==null?data:data.concat(val));if(ret!==undefined)val=ret;}if(fn&&donative!==false&&val!==false&&!(jQuery.nodeName(elem,'a')&&type=="click")){this.triggered=true;try{elem[type]();}catch(e){}}this.triggered=false;}return val;},handle:function(event){var val,ret,namespace,all,handlers;event=arguments[0]=jQuery.event.fix(event||window.event);namespace=event.type.split(".");event.type=namespace[0];namespace=namespace[1];all=!namespace&&!event.exclusive;handlers=(jQuery.data(this,"events")||{})[event.type];for(var j in handlers){var handler=handlers[j];if(all||handler.type==namespace){event.handler=handler;event.data=handler.data;ret=handler.apply(this,arguments);if(val!==false)val=ret;if(ret===false){event.preventDefault();event.stopPropagation();}}}return val;},fix:function(event){if(event[expando]==true)return event;var originalEvent=event;event={originalEvent:originalEvent};var props="altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode metaKey newValue originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target timeStamp toElement type view wheelDelta which".split(" ");for(var i=props.length;i;i--)event[props[i]]=originalEvent[props[i]];event[expando]=true;event.preventDefault=function(){if(originalEvent.preventDefault)originalEvent.preventDefault();originalEvent.returnValue=false;};event.stopPropagation=function(){if(originalEvent.stopPropagation)originalEvent.stopPropagation();originalEvent.cancelBubble=true;};event.timeStamp=event.timeStamp||now();if(!event.target)event.target=event.srcElement||document;if(event.target.nodeType==3)event.target=event.target.parentNode;if(!event.relatedTarget&&event.fromElement)event.relatedTarget=event.fromElement==event.target?event.toElement:event.fromElement;if(event.pageX==null&&event.clientX!=null){var doc=document.documentElement,body=document.body;event.pageX=event.clientX+(doc&&doc.scrollLeft||body&&body.scrollLeft||0)-(doc.clientLeft||0);event.pageY=event.clientY+(doc&&doc.scrollTop||body&&body.scrollTop||0)-(doc.clientTop||0);}if(!event.which&&((event.charCode||event.charCode===0)?event.charCode:event.keyCode))event.which=event.charCode||event.keyCode;if(!event.metaKey&&event.ctrlKey)event.metaKey=event.ctrlKey;if(!event.which&&event.button)event.which=(event.button&1?1:(event.button&2?3:(event.button&4?2:0)));return event;},proxy:function(fn,proxy){proxy.guid=fn.guid=fn.guid||proxy.guid||this.guid++;return proxy;},special:{ready:{setup:function(){bindReady();return;},teardown:function(){return;}},mouseenter:{setup:function(){if(jQuery.browser.msie)return false;jQuery(this).bind("mouseover",jQuery.event.special.mouseenter.handler);return true;},teardown:function(){if(jQuery.browser.msie)return false;jQuery(this).unbind("mouseover",jQuery.event.special.mouseenter.handler);return true;},handler:function(event){if(withinElement(event,this))return true;event.type="mouseenter";return jQuery.event.handle.apply(this,arguments);}},mouseleave:{setup:function(){if(jQuery.browser.msie)return false;jQuery(this).bind("mouseout",jQuery.event.special.mouseleave.handler);return true;},teardown:function(){if(jQuery.browser.msie)return false;jQuery(this).unbind("mouseout",jQuery.event.special.mouseleave.handler);return true;},handler:function(event){if(withinElement(event,this))return true;event.type="mouseleave";return jQuery.event.handle.apply(this,arguments);}}}};jQuery.fn.extend({bind:function(type,data,fn){return type=="unload"?this.one(type,data,fn):this.each(function(){jQuery.event.add(this,type,fn||data,fn&&data);});},one:function(type,data,fn){var one=jQuery.event.proxy(fn||data,function(event){jQuery(this).unbind(event,one);return(fn||data).apply(this,arguments);});return this.each(function(){jQuery.event.add(this,type,one,fn&&data);});},unbind:function(type,fn){return this.each(function(){jQuery.event.remove(this,type,fn);});},trigger:function(type,data,fn){return this.each(function(){jQuery.event.trigger(type,data,this,true,fn);});},triggerHandler:function(type,data,fn){return this[0]&&jQuery.event.trigger(type,data,this[0],false,fn);},toggle:function(fn){var args=arguments,i=1;while(i<args.length)jQuery.event.proxy(fn,args[i++]);return this.click(jQuery.event.proxy(fn,function(event){this.lastToggle=(this.lastToggle||0)%i;event.preventDefault();return args[this.lastToggle++].apply(this,arguments)||false;}));},hover:function(fnOver,fnOut){return this.bind('mouseenter',fnOver).bind('mouseleave',fnOut);},ready:function(fn){bindReady();if(jQuery.isReady)fn.call(document,jQuery);else
-jQuery.readyList.push(function(){return fn.call(this,jQuery);});return this;}});jQuery.extend({isReady:false,readyList:[],ready:function(){if(!jQuery.isReady){jQuery.isReady=true;if(jQuery.readyList){jQuery.each(jQuery.readyList,function(){this.call(document);});jQuery.readyList=null;}jQuery(document).triggerHandler("ready");}}});var readyBound=false;function bindReady(){if(readyBound)return;readyBound=true;if(document.addEventListener&&!jQuery.browser.opera)document.addEventListener("DOMContentLoaded",jQuery.ready,false);if(jQuery.browser.msie&&window==top)(function(){if(jQuery.isReady)return;try{document.documentElement.doScroll("left");}catch(error){setTimeout(arguments.callee,0);return;}jQuery.ready();})();if(jQuery.browser.opera)document.addEventListener("DOMContentLoaded",function(){if(jQuery.isReady)return;for(var i=0;i<document.styleSheets.length;i++)if(document.styleSheets[i].disabled){setTimeout(arguments.callee,0);return;}jQuery.ready();},false);if(jQuery.browser.safari){var numStyles;(function(){if(jQuery.isReady)return;if(document.readyState!="loaded"&&document.readyState!="complete"){setTimeout(arguments.callee,0);return;}if(numStyles===undefined)numStyles=jQuery("style, link[rel=stylesheet]").length;if(document.styleSheets.length!=numStyles){setTimeout(arguments.callee,0);return;}jQuery.ready();})();}jQuery.event.add(window,"load",jQuery.ready);}jQuery.each(("blur,focus,load,resize,scroll,unload,click,dblclick,"+"mousedown,mouseup,mousemove,mouseover,mouseout,change,select,"+"submit,keydown,keypress,keyup,error").split(","),function(i,name){jQuery.fn[name]=function(fn){return fn?this.bind(name,fn):this.trigger(name);};});var withinElement=function(event,elem){var parent=event.relatedTarget;while(parent&&parent!=elem)try{parent=parent.parentNode;}catch(error){parent=elem;}return parent==elem;};jQuery(window).bind("unload",function(){jQuery("*").add(document).unbind();});jQuery.fn.extend({_load:jQuery.fn.load,load:function(url,params,callback){if(typeof url!='string')return this._load(url);var off=url.indexOf(" ");if(off>=0){var selector=url.slice(off,url.length);url=url.slice(0,off);}callback=callback||function(){};var type="GET";if(params)if(jQuery.isFunction(params)){callback=params;params=null;}else{params=jQuery.param(params);type="POST";}var self=this;jQuery.ajax({url:url,type:type,dataType:"html",data:params,complete:function(res,status){if(status=="success"||status=="notmodified")self.html(selector?jQuery("<div/>").append(res.responseText.replace(/<script(.|\s)*?\/script>/g,"")).find(selector):res.responseText);self.each(callback,[res.responseText,status,res]);}});return this;},serialize:function(){return jQuery.param(this.serializeArray());},serializeArray:function(){return this.map(function(){return jQuery.nodeName(this,"form")?jQuery.makeArray(this.elements):this;}).filter(function(){return this.name&&!this.disabled&&(this.checked||/select|textarea/i.test(this.nodeName)||/text|hidden|password/i.test(this.type));}).map(function(i,elem){var val=jQuery(this).val();return val==null?null:val.constructor==Array?jQuery.map(val,function(val,i){return{name:elem.name,value:val};}):{name:elem.name,value:val};}).get();}});jQuery.each("ajaxStart,ajaxStop,ajaxComplete,ajaxError,ajaxSuccess,ajaxSend".split(","),function(i,o){jQuery.fn[o]=function(f){return this.bind(o,f);};});var jsc=now();jQuery.extend({get:function(url,data,callback,type){if(jQuery.isFunction(data)){callback=data;data=null;}return jQuery.ajax({type:"GET",url:url,data:data,success:callback,dataType:type});},getScript:function(url,callback){return jQuery.get(url,null,callback,"script");},getJSON:function(url,data,callback){return jQuery.get(url,data,callback,"json");},post:function(url,data,callback,type){if(jQuery.isFunction(data)){callback=data;data={};}return jQuery.ajax({type:"POST",url:url,data:data,success:callback,dataType:type});},ajaxSetup:function(settings){jQuery.extend(jQuery.ajaxSettings,settings);},ajaxSettings:{url:location.href,global:true,type:"GET",timeout:0,contentType:"application/x-www-form-urlencoded",processData:true,async:true,data:null,username:null,password:null,accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},ajax:function(s){s=jQuery.extend(true,s,jQuery.extend(true,{},jQuery.ajaxSettings,s));var jsonp,jsre=/=\?(&|$)/g,status,data,type=s.type.toUpperCase();if(s.data&&s.processData&&typeof s.data!="string")s.data=jQuery.param(s.data);if(s.dataType=="jsonp"){if(type=="GET"){if(!s.url.match(jsre))s.url+=(s.url.match(/\?/)?"&":"?")+(s.jsonp||"callback")+"=?";}else if(!s.data||!s.data.match(jsre))s.data=(s.data?s.data+"&":"")+(s.jsonp||"callback")+"=?";s.dataType="json";}if(s.dataType=="json"&&(s.data&&s.data.match(jsre)||s.url.match(jsre))){jsonp="jsonp"+jsc++;if(s.data)s.data=(s.data+"").replace(jsre,"="+jsonp+"$1");s.url=s.url.replace(jsre,"="+jsonp+"$1");s.dataType="script";window[jsonp]=function(tmp){data=tmp;success();complete();window[jsonp]=undefined;try{delete window[jsonp];}catch(e){}if(head)head.removeChild(script);};}if(s.dataType=="script"&&s.cache==null)s.cache=false;if(s.cache===false&&type=="GET"){var ts=now();var ret=s.url.replace(/(\?|&)_=.*?(&|$)/,"$1_="+ts+"$2");s.url=ret+((ret==s.url)?(s.url.match(/\?/)?"&":"?")+"_="+ts:"");}if(s.data&&type=="GET"){s.url+=(s.url.match(/\?/)?"&":"?")+s.data;s.data=null;}if(s.global&&!jQuery.active++)jQuery.event.trigger("ajaxStart");var remote=/^(?:\w+:)?\/\/([^\/?#]+)/;if(s.dataType=="script"&&type=="GET"&&remote.test(s.url)&&remote.exec(s.url)[1]!=location.host){var head=document.getElementsByTagName("head")[0];var script=document.createElement("script");script.src=s.url;if(s.scriptCharset)script.charset=s.scriptCharset;if(!jsonp){var done=false;script.onload=script.onreadystatechange=function(){if(!done&&(!this.readyState||this.readyState=="loaded"||this.readyState=="complete")){done=true;success();complete();head.removeChild(script);}};}head.appendChild(script);return undefined;}var requestDone=false;var xhr=window.ActiveXObject?new ActiveXObject("Microsoft.XMLHTTP"):new XMLHttpRequest();if(s.username)xhr.open(type,s.url,s.async,s.username,s.password);else
-xhr.open(type,s.url,s.async);try{if(s.data)xhr.setRequestHeader("Content-Type",s.contentType);if(s.ifModified)xhr.setRequestHeader("If-Modified-Since",jQuery.lastModified[s.url]||"Thu, 01 Jan 1970 00:00:00 GMT");xhr.setRequestHeader("X-Requested-With","XMLHttpRequest");xhr.setRequestHeader("Accept",s.dataType&&s.accepts[s.dataType]?s.accepts[s.dataType]+", */*":s.accepts._default);}catch(e){}if(s.beforeSend&&s.beforeSend(xhr,s)===false){s.global&&jQuery.active--;xhr.abort();return false;}if(s.global)jQuery.event.trigger("ajaxSend",[xhr,s]);var onreadystatechange=function(isTimeout){if(!requestDone&&xhr&&(xhr.readyState==4||isTimeout=="timeout")){requestDone=true;if(ival){clearInterval(ival);ival=null;}status=isTimeout=="timeout"&&"timeout"||!jQuery.httpSuccess(xhr)&&"error"||s.ifModified&&jQuery.httpNotModified(xhr,s.url)&&"notmodified"||"success";if(status=="success"){try{data=jQuery.httpData(xhr,s.dataType,s.dataFilter);}catch(e){status="parsererror";}}if(status=="success"){var modRes;try{modRes=xhr.getResponseHeader("Last-Modified");}catch(e){}if(s.ifModified&&modRes)jQuery.lastModified[s.url]=modRes;if(!jsonp)success();}else
-jQuery.handleError(s,xhr,status);complete();if(s.async)xhr=null;}};if(s.async){var ival=setInterval(onreadystatechange,13);if(s.timeout>0)setTimeout(function(){if(xhr){xhr.abort();if(!requestDone)onreadystatechange("timeout");}},s.timeout);}try{xhr.send(s.data);}catch(e){jQuery.handleError(s,xhr,null,e);}if(!s.async)onreadystatechange();function success(){if(s.success)s.success(data,status);if(s.global)jQuery.event.trigger("ajaxSuccess",[xhr,s]);}function complete(){if(s.complete)s.complete(xhr,status);if(s.global)jQuery.event.trigger("ajaxComplete",[xhr,s]);if(s.global&&!--jQuery.active)jQuery.event.trigger("ajaxStop");}return xhr;},handleError:function(s,xhr,status,e){if(s.error)s.error(xhr,status,e);if(s.global)jQuery.event.trigger("ajaxError",[xhr,s,e]);},active:0,httpSuccess:function(xhr){try{return!xhr.status&&location.protocol=="file:"||(xhr.status>=200&&xhr.status<300)||xhr.status==304||xhr.status==1223||jQuery.browser.safari&&xhr.status==undefined;}catch(e){}return false;},httpNotModified:function(xhr,url){try{var xhrRes=xhr.getResponseHeader("Last-Modified");return xhr.status==304||xhrRes==jQuery.lastModified[url]||jQuery.browser.safari&&xhr.status==undefined;}catch(e){}return false;},httpData:function(xhr,type,filter){var ct=xhr.getResponseHeader("content-type"),xml=type=="xml"||!type&&ct&&ct.indexOf("xml")>=0,data=xml?xhr.responseXML:xhr.responseText;if(xml&&data.documentElement.tagName=="parsererror")throw"parsererror";if(filter)data=filter(data,type);if(type=="script")jQuery.globalEval(data);if(type=="json")data=eval("("+data+")");return data;},param:function(a){var s=[];if(a.constructor==Array||a.jquery)jQuery.each(a,function(){s.push(encodeURIComponent(this.name)+"="+encodeURIComponent(this.value));});else
-for(var j in a)if(a[j]&&a[j].constructor==Array)jQuery.each(a[j],function(){s.push(encodeURIComponent(j)+"="+encodeURIComponent(this));});else
-s.push(encodeURIComponent(j)+"="+encodeURIComponent(jQuery.isFunction(a[j])?a[j]():a[j]));return s.join("&").replace(/%20/g,"+");}});jQuery.fn.extend({show:function(speed,callback){return speed?this.animate({height:"show",width:"show",opacity:"show"},speed,callback):this.filter(":hidden").each(function(){this.style.display=this.oldblock||"";if(jQuery.css(this,"display")=="none"){var elem=jQuery("<"+this.tagName+" />").appendTo("body");this.style.display=elem.css("display");if(this.style.display=="none")this.style.display="block";elem.remove();}}).end();},hide:function(speed,callback){return speed?this.animate({height:"hide",width:"hide",opacity:"hide"},speed,callback):this.filter(":visible").each(function(){this.oldblock=this.oldblock||jQuery.css(this,"display");this.style.display="none";}).end();},_toggle:jQuery.fn.toggle,toggle:function(fn,fn2){return jQuery.isFunction(fn)&&jQuery.isFunction(fn2)?this._toggle.apply(this,arguments):fn?this.animate({height:"toggle",width:"toggle",opacity:"toggle"},fn,fn2):this.each(function(){jQuery(this)[jQuery(this).is(":hidden")?"show":"hide"]();});},slideDown:function(speed,callback){return this.animate({height:"show"},speed,callback);},slideUp:function(speed,callback){return this.animate({height:"hide"},speed,callback);},slideToggle:function(speed,callback){return this.animate({height:"toggle"},speed,callback);},fadeIn:function(speed,callback){return this.animate({opacity:"show"},speed,callback);},fadeOut:function(speed,callback){return this.animate({opacity:"hide"},speed,callback);},fadeTo:function(speed,to,callback){return this.animate({opacity:to},speed,callback);},animate:function(prop,speed,easing,callback){var optall=jQuery.speed(speed,easing,callback);return this[optall.queue===false?"each":"queue"](function(){if(this.nodeType!=1)return false;var opt=jQuery.extend({},optall),p,hidden=jQuery(this).is(":hidden"),self=this;for(p in prop){if(prop[p]=="hide"&&hidden||prop[p]=="show"&&!hidden)return opt.complete.call(this);if(p=="height"||p=="width"){opt.display=jQuery.css(this,"display");opt.overflow=this.style.overflow;}}if(opt.overflow!=null)this.style.overflow="hidden";opt.curAnim=jQuery.extend({},prop);jQuery.each(prop,function(name,val){var e=new jQuery.fx(self,opt,name);if(/toggle|show|hide/.test(val))e[val=="toggle"?hidden?"show":"hide":val](prop);else{var parts=val.toString().match(/^([+-]=)?([\d+-.]+)(.*)$/),start=e.cur(true)||0;if(parts){var end=parseFloat(parts[2]),unit=parts[3]||"px";if(unit!="px"){self.style[name]=(end||1)+unit;start=((end||1)/e.cur(true))*start;self.style[name]=start+unit;}if(parts[1])end=((parts[1]=="-="?-1:1)*end)+start;e.custom(start,end,unit);}else
-e.custom(start,val,"");}});return true;});},queue:function(type,fn){if(jQuery.isFunction(type)||(type&&type.constructor==Array)){fn=type;type="fx";}if(!type||(typeof type=="string"&&!fn))return queue(this[0],type);return this.each(function(){if(fn.constructor==Array)queue(this,type,fn);else{queue(this,type).push(fn);if(queue(this,type).length==1)fn.call(this);}});},stop:function(clearQueue,gotoEnd){var timers=jQuery.timers;if(clearQueue)this.queue([]);this.each(function(){for(var i=timers.length-1;i>=0;i--)if(timers[i].elem==this){if(gotoEnd)timers[i](true);timers.splice(i,1);}});if(!gotoEnd)this.dequeue();return this;}});var queue=function(elem,type,array){if(elem){type=type||"fx";var q=jQuery.data(elem,type+"queue");if(!q||array)q=jQuery.data(elem,type+"queue",jQuery.makeArray(array));}return q;};jQuery.fn.dequeue=function(type){type=type||"fx";return this.each(function(){var q=queue(this,type);q.shift();if(q.length)q[0].call(this);});};jQuery.extend({speed:function(speed,easing,fn){var opt=speed&&speed.constructor==Object?speed:{complete:fn||!fn&&easing||jQuery.isFunction(speed)&&speed,duration:speed,easing:fn&&easing||easing&&easing.constructor!=Function&&easing};opt.duration=(opt.duration&&opt.duration.constructor==Number?opt.duration:jQuery.fx.speeds[opt.duration])||jQuery.fx.speeds.def;opt.old=opt.complete;opt.complete=function(){if(opt.queue!==false)jQuery(this).dequeue();if(jQuery.isFunction(opt.old))opt.old.call(this);};return opt;},easing:{linear:function(p,n,firstNum,diff){return firstNum+diff*p;},swing:function(p,n,firstNum,diff){return((-Math.cos(p*Math.PI)/2)+0.5)*diff+firstNum;}},timers:[],timerId:null,fx:function(elem,options,prop){this.options=options;this.elem=elem;this.prop=prop;if(!options.orig)options.orig={};}});jQuery.fx.prototype={update:function(){if(this.options.step)this.options.step.call(this.elem,this.now,this);(jQuery.fx.step[this.prop]||jQuery.fx.step._default)(this);if(this.prop=="height"||this.prop=="width")this.elem.style.display="block";},cur:function(force){if(this.elem[this.prop]!=null&&this.elem.style[this.prop]==null)return this.elem[this.prop];var r=parseFloat(jQuery.css(this.elem,this.prop,force));return r&&r>-10000?r:parseFloat(jQuery.curCSS(this.elem,this.prop))||0;},custom:function(from,to,unit){this.startTime=now();this.start=from;this.end=to;this.unit=unit||this.unit||"px";this.now=this.start;this.pos=this.state=0;this.update();var self=this;function t(gotoEnd){return self.step(gotoEnd);}t.elem=this.elem;jQuery.timers.push(t);if(jQuery.timerId==null){jQuery.timerId=setInterval(function(){var timers=jQuery.timers;for(var i=0;i<timers.length;i++)if(!timers[i]())timers.splice(i--,1);if(!timers.length){clearInterval(jQuery.timerId);jQuery.timerId=null;}},13);}},show:function(){this.options.orig[this.prop]=jQuery.attr(this.elem.style,this.prop);this.options.show=true;this.custom(0,this.cur());if(this.prop=="width"||this.prop=="height")this.elem.style[this.prop]="1px";jQuery(this.elem).show();},hide:function(){this.options.orig[this.prop]=jQuery.attr(this.elem.style,this.prop);this.options.hide=true;this.custom(this.cur(),0);},step:function(gotoEnd){var t=now();if(gotoEnd||t>this.options.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;var done=true;for(var i in this.options.curAnim)if(this.options.curAnim[i]!==true)done=false;if(done){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;this.elem.style.display=this.options.display;if(jQuery.css(this.elem,"display")=="none")this.elem.style.display="block";}if(this.options.hide)this.elem.style.display="none";if(this.options.hide||this.options.show)for(var p in this.options.curAnim)jQuery.attr(this.elem.style,p,this.options.orig[p]);}if(done)this.options.complete.call(this.elem);return false;}else{var n=t-this.startTime;this.state=n/this.options.duration;this.pos=jQuery.easing[this.options.easing||(jQuery.easing.swing?"swing":"linear")](this.state,n,0,1,this.options.duration);this.now=this.start+((this.end-this.start)*this.pos);this.update();}return true;}};jQuery.extend(jQuery.fx,{speeds:{slow:600,fast:200,def:400},step:{scrollLeft:function(fx){fx.elem.scrollLeft=fx.now;},scrollTop:function(fx){fx.elem.scrollTop=fx.now;},opacity:function(fx){jQuery.attr(fx.elem.style,"opacity",fx.now);},_default:function(fx){fx.elem.style[fx.prop]=fx.now+fx.unit;}}});jQuery.fn.offset=function(){var left=0,top=0,elem=this[0],results;if(elem)with(jQuery.browser){var parent=elem.parentNode,offsetChild=elem,offsetParent=elem.offsetParent,doc=elem.ownerDocument,safari2=safari&&parseInt(version)<522&&!/adobeair/i.test(userAgent),css=jQuery.curCSS,fixed=css(elem,"position")=="fixed";if(elem.getBoundingClientRect){var box=elem.getBoundingClientRect();add(box.left+Math.max(doc.documentElement.scrollLeft,doc.body.scrollLeft),box.top+Math.max(doc.documentElement.scrollTop,doc.body.scrollTop));add(-doc.documentElement.clientLeft,-doc.documentElement.clientTop);}else{add(elem.offsetLeft,elem.offsetTop);while(offsetParent){add(offsetParent.offsetLeft,offsetParent.offsetTop);if(mozilla&&!/^t(able|d|h)$/i.test(offsetParent.tagName)||safari&&!safari2)border(offsetParent);if(!fixed&&css(offsetParent,"position")=="fixed")fixed=true;offsetChild=/^body$/i.test(offsetParent.tagName)?offsetChild:offsetParent;offsetParent=offsetParent.offsetParent;}while(parent&&parent.tagName&&!/^body|html$/i.test(parent.tagName)){if(!/^inline|table.*$/i.test(css(parent,"display")))add(-parent.scrollLeft,-parent.scrollTop);if(mozilla&&css(parent,"overflow")!="visible")border(parent);parent=parent.parentNode;}if((safari2&&(fixed||css(offsetChild,"position")=="absolute"))||(mozilla&&css(offsetChild,"position")!="absolute"))add(-doc.body.offsetLeft,-doc.body.offsetTop);if(fixed)add(Math.max(doc.documentElement.scrollLeft,doc.body.scrollLeft),Math.max(doc.documentElement.scrollTop,doc.body.scrollTop));}results={top:top,left:left};}function border(elem){add(jQuery.curCSS(elem,"borderLeftWidth",true),jQuery.curCSS(elem,"borderTopWidth",true));}function add(l,t){left+=parseInt(l,10)||0;top+=parseInt(t,10)||0;}return results;};jQuery.fn.extend({position:function(){var left=0,top=0,results;if(this[0]){var offsetParent=this.offsetParent(),offset=this.offset(),parentOffset=/^body|html$/i.test(offsetParent[0].tagName)?{top:0,left:0}:offsetParent.offset();offset.top-=num(this,'marginTop');offset.left-=num(this,'marginLeft');parentOffset.top+=num(offsetParent,'borderTopWidth');parentOffset.left+=num(offsetParent,'borderLeftWidth');results={top:offset.top-parentOffset.top,left:offset.left-parentOffset.left};}return results;},offsetParent:function(){var offsetParent=this[0].offsetParent;while(offsetParent&&(!/^body|html$/i.test(offsetParent.tagName)&&jQuery.css(offsetParent,'position')=='static'))offsetParent=offsetParent.offsetParent;return jQuery(offsetParent);}});jQuery.each(['Left','Top'],function(i,name){var method='scroll'+name;jQuery.fn[method]=function(val){if(!this[0])return;return val!=undefined?this.each(function(){this==window||this==document?window.scrollTo(!i?val:jQuery(window).scrollLeft(),i?val:jQuery(window).scrollTop()):this[method]=val;}):this[0]==window||this[0]==document?self[i?'pageYOffset':'pageXOffset']||jQuery.boxModel&&document.documentElement[method]||document.body[method]:this[0][method];};});jQuery.each(["Height","Width"],function(i,name){var tl=i?"Left":"Top",br=i?"Right":"Bottom";jQuery.fn["inner"+name]=function(){return this[name.toLowerCase()]()+num(this,"padding"+tl)+num(this,"padding"+br);};jQuery.fn["outer"+name]=function(margin){return this["inner"+name]()+num(this,"border"+tl+"Width")+num(this,"border"+br+"Width")+(margin?num(this,"margin"+tl)+num(this,"margin"+br):0);};});})();
\ No newline at end of file
+(function(A,w){function ma(){if(!c.isReady){try{s.documentElement.doScroll("left")}catch(a){setTimeout(ma,1);return}c.ready()}}function Qa(a,b){b.src?c.ajax({url:b.src,async:false,dataType:"script"}):c.globalEval(b.text||b.textContent||b.innerHTML||"");b.parentNode&&b.parentNode.removeChild(b)}function X(a,b,d,f,e,j){var i=a.length;if(typeof b==="object"){for(var o in b)X(a,o,b[o],f,e,d);return a}if(d!==w){f=!j&&f&&c.isFunction(d);for(o=0;o<i;o++)e(a[o],b,f?d.call(a[o],o,e(a[o],b)):d,j);return a}return i?
+e(a[0],b):w}function J(){return(new Date).getTime()}function Y(){return false}function Z(){return true}function na(a,b,d){d[0].type=a;return c.event.handle.apply(b,d)}function oa(a){var b,d=[],f=[],e=arguments,j,i,o,k,n,r;i=c.data(this,"events");if(!(a.liveFired===this||!i||!i.live||a.button&&a.type==="click")){a.liveFired=this;var u=i.live.slice(0);for(k=0;k<u.length;k++){i=u[k];i.origType.replace(O,"")===a.type?f.push(i.selector):u.splice(k--,1)}j=c(a.target).closest(f,a.currentTarget);n=0;for(r=
+j.length;n<r;n++)for(k=0;k<u.length;k++){i=u[k];if(j[n].selector===i.selector){o=j[n].elem;f=null;if(i.preType==="mouseenter"||i.preType==="mouseleave")f=c(a.relatedTarget).closest(i.selector)[0];if(!f||f!==o)d.push({elem:o,handleObj:i})}}n=0;for(r=d.length;n<r;n++){j=d[n];a.currentTarget=j.elem;a.data=j.handleObj.data;a.handleObj=j.handleObj;if(j.handleObj.origHandler.apply(j.elem,e)===false){b=false;break}}return b}}function pa(a,b){return"live."+(a&&a!=="*"?a+".":"")+b.replace(/\./g,"`").replace(/ /g,
+"&")}function qa(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function ra(a,b){var d=0;b.each(function(){if(this.nodeName===(a[d]&&a[d].nodeName)){var f=c.data(a[d++]),e=c.data(this,f);if(f=f&&f.events){delete e.handle;e.events={};for(var j in f)for(var i in f[j])c.event.add(this,j,f[j][i],f[j][i].data)}}})}function sa(a,b,d){var f,e,j;b=b&&b[0]?b[0].ownerDocument||b[0]:s;if(a.length===1&&typeof a[0]==="string"&&a[0].length<512&&b===s&&!ta.test(a[0])&&(c.support.checkClone||!ua.test(a[0]))){e=
+true;if(j=c.fragments[a[0]])if(j!==1)f=j}if(!f){f=b.createDocumentFragment();c.clean(a,b,f,d)}if(e)c.fragments[a[0]]=j?f:1;return{fragment:f,cacheable:e}}function K(a,b){var d={};c.each(va.concat.apply([],va.slice(0,b)),function(){d[this]=a});return d}function wa(a){return"scrollTo"in a&&a.document?a:a.nodeType===9?a.defaultView||a.parentWindow:false}var c=function(a,b){return new c.fn.init(a,b)},Ra=A.jQuery,Sa=A.$,s=A.document,T,Ta=/^[^<]*(<[\w\W]+>)[^>]*$|^#([\w-]+)$/,Ua=/^.[^:#\[\.,]*$/,Va=/\S/,
+Wa=/^(\s|\u00A0)+|(\s|\u00A0)+$/g,Xa=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,P=navigator.userAgent,xa=false,Q=[],L,$=Object.prototype.toString,aa=Object.prototype.hasOwnProperty,ba=Array.prototype.push,R=Array.prototype.slice,ya=Array.prototype.indexOf;c.fn=c.prototype={init:function(a,b){var d,f;if(!a)return this;if(a.nodeType){this.context=this[0]=a;this.length=1;return this}if(a==="body"&&!b){this.context=s;this[0]=s.body;this.selector="body";this.length=1;return this}if(typeof a==="string")if((d=Ta.exec(a))&&
+(d[1]||!b))if(d[1]){f=b?b.ownerDocument||b:s;if(a=Xa.exec(a))if(c.isPlainObject(b)){a=[s.createElement(a[1])];c.fn.attr.call(a,b,true)}else a=[f.createElement(a[1])];else{a=sa([d[1]],[f]);a=(a.cacheable?a.fragment.cloneNode(true):a.fragment).childNodes}return c.merge(this,a)}else{if(b=s.getElementById(d[2])){if(b.id!==d[2])return T.find(a);this.length=1;this[0]=b}this.context=s;this.selector=a;return this}else if(!b&&/^\w+$/.test(a)){this.selector=a;this.context=s;a=s.getElementsByTagName(a);return c.merge(this,
+a)}else return!b||b.jquery?(b||T).find(a):c(b).find(a);else if(c.isFunction(a))return T.ready(a);if(a.selector!==w){this.selector=a.selector;this.context=a.context}return c.makeArray(a,this)},selector:"",jquery:"1.4.2",length:0,size:function(){return this.length},toArray:function(){return R.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this.slice(a)[0]:this[a]},pushStack:function(a,b,d){var f=c();c.isArray(a)?ba.apply(f,a):c.merge(f,a);f.prevObject=this;f.context=this.context;if(b===
+"find")f.selector=this.selector+(this.selector?" ":"")+d;else if(b)f.selector=this.selector+"."+b+"("+d+")";return f},each:function(a,b){return c.each(this,a,b)},ready:function(a){c.bindReady();if(c.isReady)a.call(s,c);else Q&&Q.push(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(R.apply(this,arguments),"slice",R.call(arguments).join(","))},map:function(a){return this.pushStack(c.map(this,
+function(b,d){return a.call(b,d,b)}))},end:function(){return this.prevObject||c(null)},push:ba,sort:[].sort,splice:[].splice};c.fn.init.prototype=c.fn;c.extend=c.fn.extend=function(){var a=arguments[0]||{},b=1,d=arguments.length,f=false,e,j,i,o;if(typeof a==="boolean"){f=a;a=arguments[1]||{};b=2}if(typeof a!=="object"&&!c.isFunction(a))a={};if(d===b){a=this;--b}for(;b<d;b++)if((e=arguments[b])!=null)for(j in e){i=a[j];o=e[j];if(a!==o)if(f&&o&&(c.isPlainObject(o)||c.isArray(o))){i=i&&(c.isPlainObject(i)||
+c.isArray(i))?i:c.isArray(o)?[]:{};a[j]=c.extend(f,i,o)}else if(o!==w)a[j]=o}return a};c.extend({noConflict:function(a){A.$=Sa;if(a)A.jQuery=Ra;return c},isReady:false,ready:function(){if(!c.isReady){if(!s.body)return setTimeout(c.ready,13);c.isReady=true;if(Q){for(var a,b=0;a=Q[b++];)a.call(s,c);Q=null}c.fn.triggerHandler&&c(s).triggerHandler("ready")}},bindReady:function(){if(!xa){xa=true;if(s.readyState==="complete")return c.ready();if(s.addEventListener){s.addEventListener("DOMContentLoaded",
+L,false);A.addEventListener("load",c.ready,false)}else if(s.attachEvent){s.attachEvent("onreadystatechange",L);A.attachEvent("onload",c.ready);var a=false;try{a=A.frameElement==null}catch(b){}s.documentElement.doScroll&&a&&ma()}}},isFunction:function(a){return $.call(a)==="[object Function]"},isArray:function(a){return $.call(a)==="[object Array]"},isPlainObject:function(a){if(!a||$.call(a)!=="[object Object]"||a.nodeType||a.setInterval)return false;if(a.constructor&&!aa.call(a,"constructor")&&!aa.call(a.constructor.prototype,
+"isPrototypeOf"))return false;var b;for(b in a);return b===w||aa.call(a,b)},isEmptyObject:function(a){for(var b in a)return false;return true},error:function(a){throw a;},parseJSON:function(a){if(typeof a!=="string"||!a)return null;a=c.trim(a);if(/^[\],:{}\s]*$/.test(a.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,"")))return A.JSON&&A.JSON.parse?A.JSON.parse(a):(new Function("return "+
+a))();else c.error("Invalid JSON: "+a)},noop:function(){},globalEval:function(a){if(a&&Va.test(a)){var b=s.getElementsByTagName("head")[0]||s.documentElement,d=s.createElement("script");d.type="text/javascript";if(c.support.scriptEval)d.appendChild(s.createTextNode(a));else d.text=a;b.insertBefore(d,b.firstChild);b.removeChild(d)}},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,b,d){var f,e=0,j=a.length,i=j===w||c.isFunction(a);if(d)if(i)for(f in a){if(b.apply(a[f],
+d)===false)break}else for(;e<j;){if(b.apply(a[e++],d)===false)break}else if(i)for(f in a){if(b.call(a[f],f,a[f])===false)break}else for(d=a[0];e<j&&b.call(d,e,d)!==false;d=a[++e]);return a},trim:function(a){return(a||"").replace(Wa,"")},makeArray:function(a,b){b=b||[];if(a!=null)a.length==null||typeof a==="string"||c.isFunction(a)||typeof a!=="function"&&a.setInterval?ba.call(b,a):c.merge(b,a);return b},inArray:function(a,b){if(b.indexOf)return b.indexOf(a);for(var d=0,f=b.length;d<f;d++)if(b[d]===
+a)return d;return-1},merge:function(a,b){var d=a.length,f=0;if(typeof b.length==="number")for(var e=b.length;f<e;f++)a[d++]=b[f];else for(;b[f]!==w;)a[d++]=b[f++];a.length=d;return a},grep:function(a,b,d){for(var f=[],e=0,j=a.length;e<j;e++)!d!==!b(a[e],e)&&f.push(a[e]);return f},map:function(a,b,d){for(var f=[],e,j=0,i=a.length;j<i;j++){e=b(a[j],j,d);if(e!=null)f[f.length]=e}return f.concat.apply([],f)},guid:1,proxy:function(a,b,d){if(arguments.length===2)if(typeof b==="string"){d=a;a=d[b];b=w}else if(b&&
+!c.isFunction(b)){d=b;b=w}if(!b&&a)b=function(){return a.apply(d||this,arguments)};if(a)b.guid=a.guid=a.guid||b.guid||c.guid++;return b},uaMatch:function(a){a=a.toLowerCase();a=/(webkit)[ \/]([\w.]+)/.exec(a)||/(opera)(?:.*version)?[ \/]([\w.]+)/.exec(a)||/(msie) ([\w.]+)/.exec(a)||!/compatible/.test(a)&&/(mozilla)(?:.*? rv:([\w.]+))?/.exec(a)||[];return{browser:a[1]||"",version:a[2]||"0"}},browser:{}});P=c.uaMatch(P);if(P.browser){c.browser[P.browser]=true;c.browser.version=P.version}if(c.browser.webkit)c.browser.safari=
+true;if(ya)c.inArray=function(a,b){return ya.call(b,a)};T=c(s);if(s.addEventListener)L=function(){s.removeEventListener("DOMContentLoaded",L,false);c.ready()};else if(s.attachEvent)L=function(){if(s.readyState==="complete"){s.detachEvent("onreadystatechange",L);c.ready()}};(function(){c.support={};var a=s.documentElement,b=s.createElement("script"),d=s.createElement("div"),f="script"+J();d.style.display="none";d.innerHTML="   <link/><table></table><a href='/a' style='color:red;float:left;opacity:.55;'>a</a><input type='checkbox'/>";
+var e=d.getElementsByTagName("*"),j=d.getElementsByTagName("a")[0];if(!(!e||!e.length||!j)){c.support={leadingWhitespace:d.firstChild.nodeType===3,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/red/.test(j.getAttribute("style")),hrefNormalized:j.getAttribute("href")==="/a",opacity:/^0.55$/.test(j.style.opacity),cssFloat:!!j.style.cssFloat,checkOn:d.getElementsByTagName("input")[0].value==="on",optSelected:s.createElement("select").appendChild(s.createElement("option")).selected,
+parentNode:d.removeChild(d.appendChild(s.createElement("div"))).parentNode===null,deleteExpando:true,checkClone:false,scriptEval:false,noCloneEvent:true,boxModel:null};b.type="text/javascript";try{b.appendChild(s.createTextNode("window."+f+"=1;"))}catch(i){}a.insertBefore(b,a.firstChild);if(A[f]){c.support.scriptEval=true;delete A[f]}try{delete b.test}catch(o){c.support.deleteExpando=false}a.removeChild(b);if(d.attachEvent&&d.fireEvent){d.attachEvent("onclick",function k(){c.support.noCloneEvent=
+false;d.detachEvent("onclick",k)});d.cloneNode(true).fireEvent("onclick")}d=s.createElement("div");d.innerHTML="<input type='radio' name='radiotest' checked='checked'/>";a=s.createDocumentFragment();a.appendChild(d.firstChild);c.support.checkClone=a.cloneNode(true).cloneNode(true).lastChild.checked;c(function(){var k=s.createElement("div");k.style.width=k.style.paddingLeft="1px";s.body.appendChild(k);c.boxModel=c.support.boxModel=k.offsetWidth===2;s.body.removeChild(k).style.display="none"});a=function(k){var n=
+s.createElement("div");k="on"+k;var r=k in n;if(!r){n.setAttribute(k,"return;");r=typeof n[k]==="function"}return r};c.support.submitBubbles=a("submit");c.support.changeBubbles=a("change");a=b=d=e=j=null}})();c.props={"for":"htmlFor","class":"className",readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",colspan:"colSpan",tabindex:"tabIndex",usemap:"useMap",frameborder:"frameBorder"};var G="jQuery"+J(),Ya=0,za={};c.extend({cache:{},expando:G,noData:{embed:true,object:true,
+applet:true},data:function(a,b,d){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var f=a[G],e=c.cache;if(!f&&typeof b==="string"&&d===w)return null;f||(f=++Ya);if(typeof b==="object"){a[G]=f;e[f]=c.extend(true,{},b)}else if(!e[f]){a[G]=f;e[f]={}}a=e[f];if(d!==w)a[b]=d;return typeof b==="string"?a[b]:a}},removeData:function(a,b){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var d=a[G],f=c.cache,e=f[d];if(b){if(e){delete e[b];c.isEmptyObject(e)&&c.removeData(a)}}else{if(c.support.deleteExpando)delete a[c.expando];
+else a.removeAttribute&&a.removeAttribute(c.expando);delete f[d]}}}});c.fn.extend({data:function(a,b){if(typeof a==="undefined"&&this.length)return c.data(this[0]);else if(typeof a==="object")return this.each(function(){c.data(this,a)});var d=a.split(".");d[1]=d[1]?"."+d[1]:"";if(b===w){var f=this.triggerHandler("getData"+d[1]+"!",[d[0]]);if(f===w&&this.length)f=c.data(this[0],a);return f===w&&d[1]?this.data(d[0]):f}else return this.trigger("setData"+d[1]+"!",[d[0],b]).each(function(){c.data(this,
+a,b)})},removeData:function(a){return this.each(function(){c.removeData(this,a)})}});c.extend({queue:function(a,b,d){if(a){b=(b||"fx")+"queue";var f=c.data(a,b);if(!d)return f||[];if(!f||c.isArray(d))f=c.data(a,b,c.makeArray(d));else f.push(d);return f}},dequeue:function(a,b){b=b||"fx";var d=c.queue(a,b),f=d.shift();if(f==="inprogress")f=d.shift();if(f){b==="fx"&&d.unshift("inprogress");f.call(a,function(){c.dequeue(a,b)})}}});c.fn.extend({queue:function(a,b){if(typeof a!=="string"){b=a;a="fx"}if(b===
+w)return c.queue(this[0],a);return this.each(function(){var d=c.queue(this,a,b);a==="fx"&&d[0]!=="inprogress"&&c.dequeue(this,a)})},dequeue:function(a){return this.each(function(){c.dequeue(this,a)})},delay:function(a,b){a=c.fx?c.fx.speeds[a]||a:a;b=b||"fx";return this.queue(b,function(){var d=this;setTimeout(function(){c.dequeue(d,b)},a)})},clearQueue:function(a){return this.queue(a||"fx",[])}});var Aa=/[\n\t]/g,ca=/\s+/,Za=/\r/g,$a=/href|src|style/,ab=/(button|input)/i,bb=/(button|input|object|select|textarea)/i,
+cb=/^(a|area)$/i,Ba=/radio|checkbox/;c.fn.extend({attr:function(a,b){return X(this,a,b,true,c.attr)},removeAttr:function(a){return this.each(function(){c.attr(this,a,"");this.nodeType===1&&this.removeAttribute(a)})},addClass:function(a){if(c.isFunction(a))return this.each(function(n){var r=c(this);r.addClass(a.call(this,n,r.attr("class")))});if(a&&typeof a==="string")for(var b=(a||"").split(ca),d=0,f=this.length;d<f;d++){var e=this[d];if(e.nodeType===1)if(e.className){for(var j=" "+e.className+" ",
+i=e.className,o=0,k=b.length;o<k;o++)if(j.indexOf(" "+b[o]+" ")<0)i+=" "+b[o];e.className=c.trim(i)}else e.className=a}return this},removeClass:function(a){if(c.isFunction(a))return this.each(function(k){var n=c(this);n.removeClass(a.call(this,k,n.attr("class")))});if(a&&typeof a==="string"||a===w)for(var b=(a||"").split(ca),d=0,f=this.length;d<f;d++){var e=this[d];if(e.nodeType===1&&e.className)if(a){for(var j=(" "+e.className+" ").replace(Aa," "),i=0,o=b.length;i<o;i++)j=j.replace(" "+b[i]+" ",
+" ");e.className=c.trim(j)}else e.className=""}return this},toggleClass:function(a,b){var d=typeof a,f=typeof b==="boolean";if(c.isFunction(a))return this.each(function(e){var j=c(this);j.toggleClass(a.call(this,e,j.attr("class"),b),b)});return this.each(function(){if(d==="string")for(var e,j=0,i=c(this),o=b,k=a.split(ca);e=k[j++];){o=f?o:!i.hasClass(e);i[o?"addClass":"removeClass"](e)}else if(d==="undefined"||d==="boolean"){this.className&&c.data(this,"__className__",this.className);this.className=
+this.className||a===false?"":c.data(this,"__className__")||""}})},hasClass:function(a){a=" "+a+" ";for(var b=0,d=this.length;b<d;b++)if((" "+this[b].className+" ").replace(Aa," ").indexOf(a)>-1)return true;return false},val:function(a){if(a===w){var b=this[0];if(b){if(c.nodeName(b,"option"))return(b.attributes.value||{}).specified?b.value:b.text;if(c.nodeName(b,"select")){var d=b.selectedIndex,f=[],e=b.options;b=b.type==="select-one";if(d<0)return null;var j=b?d:0;for(d=b?d+1:e.length;j<d;j++){var i=
+e[j];if(i.selected){a=c(i).val();if(b)return a;f.push(a)}}return f}if(Ba.test(b.type)&&!c.support.checkOn)return b.getAttribute("value")===null?"on":b.value;return(b.value||"").replace(Za,"")}return w}var o=c.isFunction(a);return this.each(function(k){var n=c(this),r=a;if(this.nodeType===1){if(o)r=a.call(this,k,n.val());if(typeof r==="number")r+="";if(c.isArray(r)&&Ba.test(this.type))this.checked=c.inArray(n.val(),r)>=0;else if(c.nodeName(this,"select")){var u=c.makeArray(r);c("option",this).each(function(){this.selected=
+c.inArray(c(this).val(),u)>=0});if(!u.length)this.selectedIndex=-1}else this.value=r}})}});c.extend({attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true},attr:function(a,b,d,f){if(!a||a.nodeType===3||a.nodeType===8)return w;if(f&&b in c.attrFn)return c(a)[b](d);f=a.nodeType!==1||!c.isXMLDoc(a);var e=d!==w;b=f&&c.props[b]||b;if(a.nodeType===1){var j=$a.test(b);if(b in a&&f&&!j){if(e){b==="type"&&ab.test(a.nodeName)&&a.parentNode&&c.error("type property can't be changed");
+a[b]=d}if(c.nodeName(a,"form")&&a.getAttributeNode(b))return a.getAttributeNode(b).nodeValue;if(b==="tabIndex")return(b=a.getAttributeNode("tabIndex"))&&b.specified?b.value:bb.test(a.nodeName)||cb.test(a.nodeName)&&a.href?0:w;return a[b]}if(!c.support.style&&f&&b==="style"){if(e)a.style.cssText=""+d;return a.style.cssText}e&&a.setAttribute(b,""+d);a=!c.support.hrefNormalized&&f&&j?a.getAttribute(b,2):a.getAttribute(b);return a===null?w:a}return c.style(a,b,d)}});var O=/\.(.*)$/,db=function(a){return a.replace(/[^\w\s\.\|`]/g,
+function(b){return"\\"+b})};c.event={add:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){if(a.setInterval&&a!==A&&!a.frameElement)a=A;var e,j;if(d.handler){e=d;d=e.handler}if(!d.guid)d.guid=c.guid++;if(j=c.data(a)){var i=j.events=j.events||{},o=j.handle;if(!o)j.handle=o=function(){return typeof c!=="undefined"&&!c.event.triggered?c.event.handle.apply(o.elem,arguments):w};o.elem=a;b=b.split(" ");for(var k,n=0,r;k=b[n++];){j=e?c.extend({},e):{handler:d,data:f};if(k.indexOf(".")>-1){r=k.split(".");
+k=r.shift();j.namespace=r.slice(0).sort().join(".")}else{r=[];j.namespace=""}j.type=k;j.guid=d.guid;var u=i[k],z=c.event.special[k]||{};if(!u){u=i[k]=[];if(!z.setup||z.setup.call(a,f,r,o)===false)if(a.addEventListener)a.addEventListener(k,o,false);else a.attachEvent&&a.attachEvent("on"+k,o)}if(z.add){z.add.call(a,j);if(!j.handler.guid)j.handler.guid=d.guid}u.push(j);c.event.global[k]=true}a=null}}},global:{},remove:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){var e,j=0,i,o,k,n,r,u,z=c.data(a),
+C=z&&z.events;if(z&&C){if(b&&b.type){d=b.handler;b=b.type}if(!b||typeof b==="string"&&b.charAt(0)==="."){b=b||"";for(e in C)c.event.remove(a,e+b)}else{for(b=b.split(" ");e=b[j++];){n=e;i=e.indexOf(".")<0;o=[];if(!i){o=e.split(".");e=o.shift();k=new RegExp("(^|\\.)"+c.map(o.slice(0).sort(),db).join("\\.(?:.*\\.)?")+"(\\.|$)")}if(r=C[e])if(d){n=c.event.special[e]||{};for(B=f||0;B<r.length;B++){u=r[B];if(d.guid===u.guid){if(i||k.test(u.namespace)){f==null&&r.splice(B--,1);n.remove&&n.remove.call(a,u)}if(f!=
+null)break}}if(r.length===0||f!=null&&r.length===1){if(!n.teardown||n.teardown.call(a,o)===false)Ca(a,e,z.handle);delete C[e]}}else for(var B=0;B<r.length;B++){u=r[B];if(i||k.test(u.namespace)){c.event.remove(a,n,u.handler,B);r.splice(B--,1)}}}if(c.isEmptyObject(C)){if(b=z.handle)b.elem=null;delete z.events;delete z.handle;c.isEmptyObject(z)&&c.removeData(a)}}}}},trigger:function(a,b,d,f){var e=a.type||a;if(!f){a=typeof a==="object"?a[G]?a:c.extend(c.Event(e),a):c.Event(e);if(e.indexOf("!")>=0){a.type=
+e=e.slice(0,-1);a.exclusive=true}if(!d){a.stopPropagation();c.event.global[e]&&c.each(c.cache,function(){this.events&&this.events[e]&&c.event.trigger(a,b,this.handle.elem)})}if(!d||d.nodeType===3||d.nodeType===8)return w;a.result=w;a.target=d;b=c.makeArray(b);b.unshift(a)}a.currentTarget=d;(f=c.data(d,"handle"))&&f.apply(d,b);f=d.parentNode||d.ownerDocument;try{if(!(d&&d.nodeName&&c.noData[d.nodeName.toLowerCase()]))if(d["on"+e]&&d["on"+e].apply(d,b)===false)a.result=false}catch(j){}if(!a.isPropagationStopped()&&
+f)c.event.trigger(a,b,f,true);else if(!a.isDefaultPrevented()){f=a.target;var i,o=c.nodeName(f,"a")&&e==="click",k=c.event.special[e]||{};if((!k._default||k._default.call(d,a)===false)&&!o&&!(f&&f.nodeName&&c.noData[f.nodeName.toLowerCase()])){try{if(f[e]){if(i=f["on"+e])f["on"+e]=null;c.event.triggered=true;f[e]()}}catch(n){}if(i)f["on"+e]=i;c.event.triggered=false}}},handle:function(a){var b,d,f,e;a=arguments[0]=c.event.fix(a||A.event);a.currentTarget=this;b=a.type.indexOf(".")<0&&!a.exclusive;
+if(!b){d=a.type.split(".");a.type=d.shift();f=new RegExp("(^|\\.)"+d.slice(0).sort().join("\\.(?:.*\\.)?")+"(\\.|$)")}e=c.data(this,"events");d=e[a.type];if(e&&d){d=d.slice(0);e=0;for(var j=d.length;e<j;e++){var i=d[e];if(b||f.test(i.namespace)){a.handler=i.handler;a.data=i.data;a.handleObj=i;i=i.handler.apply(this,arguments);if(i!==w){a.result=i;if(i===false){a.preventDefault();a.stopPropagation()}}if(a.isImmediatePropagationStopped())break}}}return a.result},props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),
+fix:function(a){if(a[G])return a;var b=a;a=c.Event(b);for(var d=this.props.length,f;d;){f=this.props[--d];a[f]=b[f]}if(!a.target)a.target=a.srcElement||s;if(a.target.nodeType===3)a.target=a.target.parentNode;if(!a.relatedTarget&&a.fromElement)a.relatedTarget=a.fromElement===a.target?a.toElement:a.fromElement;if(a.pageX==null&&a.clientX!=null){b=s.documentElement;d=s.body;a.pageX=a.clientX+(b&&b.scrollLeft||d&&d.scrollLeft||0)-(b&&b.clientLeft||d&&d.clientLeft||0);a.pageY=a.clientY+(b&&b.scrollTop||
+d&&d.scrollTop||0)-(b&&b.clientTop||d&&d.clientTop||0)}if(!a.which&&(a.charCode||a.charCode===0?a.charCode:a.keyCode))a.which=a.charCode||a.keyCode;if(!a.metaKey&&a.ctrlKey)a.metaKey=a.ctrlKey;if(!a.which&&a.button!==w)a.which=a.button&1?1:a.button&2?3:a.button&4?2:0;return a},guid:1E8,proxy:c.proxy,special:{ready:{setup:c.bindReady,teardown:c.noop},live:{add:function(a){c.event.add(this,a.origType,c.extend({},a,{handler:oa}))},remove:function(a){var b=true,d=a.origType.replace(O,"");c.each(c.data(this,
+"events").live||[],function(){if(d===this.origType.replace(O,""))return b=false});b&&c.event.remove(this,a.origType,oa)}},beforeunload:{setup:function(a,b,d){if(this.setInterval)this.onbeforeunload=d;return false},teardown:function(a,b){if(this.onbeforeunload===b)this.onbeforeunload=null}}}};var Ca=s.removeEventListener?function(a,b,d){a.removeEventListener(b,d,false)}:function(a,b,d){a.detachEvent("on"+b,d)};c.Event=function(a){if(!this.preventDefault)return new c.Event(a);if(a&&a.type){this.originalEvent=
+a;this.type=a.type}else this.type=a;this.timeStamp=J();this[G]=true};c.Event.prototype={preventDefault:function(){this.isDefaultPrevented=Z;var a=this.originalEvent;if(a){a.preventDefault&&a.preventDefault();a.returnValue=false}},stopPropagation:function(){this.isPropagationStopped=Z;var a=this.originalEvent;if(a){a.stopPropagation&&a.stopPropagation();a.cancelBubble=true}},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=Z;this.stopPropagation()},isDefaultPrevented:Y,isPropagationStopped:Y,
+isImmediatePropagationStopped:Y};var Da=function(a){var b=a.relatedTarget;try{for(;b&&b!==this;)b=b.parentNode;if(b!==this){a.type=a.data;c.event.handle.apply(this,arguments)}}catch(d){}},Ea=function(a){a.type=a.data;c.event.handle.apply(this,arguments)};c.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){c.event.special[a]={setup:function(d){c.event.add(this,b,d&&d.selector?Ea:Da,a)},teardown:function(d){c.event.remove(this,b,d&&d.selector?Ea:Da)}}});if(!c.support.submitBubbles)c.event.special.submit=
+{setup:function(){if(this.nodeName.toLowerCase()!=="form"){c.event.add(this,"click.specialSubmit",function(a){var b=a.target,d=b.type;if((d==="submit"||d==="image")&&c(b).closest("form").length)return na("submit",this,arguments)});c.event.add(this,"keypress.specialSubmit",function(a){var b=a.target,d=b.type;if((d==="text"||d==="password")&&c(b).closest("form").length&&a.keyCode===13)return na("submit",this,arguments)})}else return false},teardown:function(){c.event.remove(this,".specialSubmit")}};
+if(!c.support.changeBubbles){var da=/textarea|input|select/i,ea,Fa=function(a){var b=a.type,d=a.value;if(b==="radio"||b==="checkbox")d=a.checked;else if(b==="select-multiple")d=a.selectedIndex>-1?c.map(a.options,function(f){return f.selected}).join("-"):"";else if(a.nodeName.toLowerCase()==="select")d=a.selectedIndex;return d},fa=function(a,b){var d=a.target,f,e;if(!(!da.test(d.nodeName)||d.readOnly)){f=c.data(d,"_change_data");e=Fa(d);if(a.type!=="focusout"||d.type!=="radio")c.data(d,"_change_data",
+e);if(!(f===w||e===f))if(f!=null||e){a.type="change";return c.event.trigger(a,b,d)}}};c.event.special.change={filters:{focusout:fa,click:function(a){var b=a.target,d=b.type;if(d==="radio"||d==="checkbox"||b.nodeName.toLowerCase()==="select")return fa.call(this,a)},keydown:function(a){var b=a.target,d=b.type;if(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(d==="checkbox"||d==="radio")||d==="select-multiple")return fa.call(this,a)},beforeactivate:function(a){a=a.target;c.data(a,
+"_change_data",Fa(a))}},setup:function(){if(this.type==="file")return false;for(var a in ea)c.event.add(this,a+".specialChange",ea[a]);return da.test(this.nodeName)},teardown:function(){c.event.remove(this,".specialChange");return da.test(this.nodeName)}};ea=c.event.special.change.filters}s.addEventListener&&c.each({focus:"focusin",blur:"focusout"},function(a,b){function d(f){f=c.event.fix(f);f.type=b;return c.event.handle.call(this,f)}c.event.special[b]={setup:function(){this.addEventListener(a,
+d,true)},teardown:function(){this.removeEventListener(a,d,true)}}});c.each(["bind","one"],function(a,b){c.fn[b]=function(d,f,e){if(typeof d==="object"){for(var j in d)this[b](j,f,d[j],e);return this}if(c.isFunction(f)){e=f;f=w}var i=b==="one"?c.proxy(e,function(k){c(this).unbind(k,i);return e.apply(this,arguments)}):e;if(d==="unload"&&b!=="one")this.one(d,f,e);else{j=0;for(var o=this.length;j<o;j++)c.event.add(this[j],d,i,f)}return this}});c.fn.extend({unbind:function(a,b){if(typeof a==="object"&&
+!a.preventDefault)for(var d in a)this.unbind(d,a[d]);else{d=0;for(var f=this.length;d<f;d++)c.event.remove(this[d],a,b)}return this},delegate:function(a,b,d,f){return this.live(b,d,f,a)},undelegate:function(a,b,d){return arguments.length===0?this.unbind("live"):this.die(b,null,d,a)},trigger:function(a,b){return this.each(function(){c.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0]){a=c.Event(a);a.preventDefault();a.stopPropagation();c.event.trigger(a,b,this[0]);return a.result}},
+toggle:function(a){for(var b=arguments,d=1;d<b.length;)c.proxy(a,b[d++]);return this.click(c.proxy(a,function(f){var e=(c.data(this,"lastToggle"+a.guid)||0)%d;c.data(this,"lastToggle"+a.guid,e+1);f.preventDefault();return b[e].apply(this,arguments)||false}))},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}});var Ga={focus:"focusin",blur:"focusout",mouseenter:"mouseover",mouseleave:"mouseout"};c.each(["live","die"],function(a,b){c.fn[b]=function(d,f,e,j){var i,o=0,k,n,r=j||this.selector,
+u=j?this:c(this.context);if(c.isFunction(f)){e=f;f=w}for(d=(d||"").split(" ");(i=d[o++])!=null;){j=O.exec(i);k="";if(j){k=j[0];i=i.replace(O,"")}if(i==="hover")d.push("mouseenter"+k,"mouseleave"+k);else{n=i;if(i==="focus"||i==="blur"){d.push(Ga[i]+k);i+=k}else i=(Ga[i]||i)+k;b==="live"?u.each(function(){c.event.add(this,pa(i,r),{data:f,selector:r,handler:e,origType:i,origHandler:e,preType:n})}):u.unbind(pa(i,r),e)}}return this}});c.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error".split(" "),
+function(a,b){c.fn[b]=function(d){return d?this.bind(b,d):this.trigger(b)};if(c.attrFn)c.attrFn[b]=true});A.attachEvent&&!A.addEventListener&&A.attachEvent("onunload",function(){for(var a in c.cache)if(c.cache[a].handle)try{c.event.remove(c.cache[a].handle.elem)}catch(b){}});(function(){function a(g){for(var h="",l,m=0;g[m];m++){l=g[m];if(l.nodeType===3||l.nodeType===4)h+=l.nodeValue;else if(l.nodeType!==8)h+=a(l.childNodes)}return h}function b(g,h,l,m,q,p){q=0;for(var v=m.length;q<v;q++){var t=m[q];
+if(t){t=t[g];for(var y=false;t;){if(t.sizcache===l){y=m[t.sizset];break}if(t.nodeType===1&&!p){t.sizcache=l;t.sizset=q}if(t.nodeName.toLowerCase()===h){y=t;break}t=t[g]}m[q]=y}}}function d(g,h,l,m,q,p){q=0;for(var v=m.length;q<v;q++){var t=m[q];if(t){t=t[g];for(var y=false;t;){if(t.sizcache===l){y=m[t.sizset];break}if(t.nodeType===1){if(!p){t.sizcache=l;t.sizset=q}if(typeof h!=="string"){if(t===h){y=true;break}}else if(k.filter(h,[t]).length>0){y=t;break}}t=t[g]}m[q]=y}}}var f=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,
+e=0,j=Object.prototype.toString,i=false,o=true;[0,0].sort(function(){o=false;return 0});var k=function(g,h,l,m){l=l||[];var q=h=h||s;if(h.nodeType!==1&&h.nodeType!==9)return[];if(!g||typeof g!=="string")return l;for(var p=[],v,t,y,S,H=true,M=x(h),I=g;(f.exec(""),v=f.exec(I))!==null;){I=v[3];p.push(v[1]);if(v[2]){S=v[3];break}}if(p.length>1&&r.exec(g))if(p.length===2&&n.relative[p[0]])t=ga(p[0]+p[1],h);else for(t=n.relative[p[0]]?[h]:k(p.shift(),h);p.length;){g=p.shift();if(n.relative[g])g+=p.shift();
+t=ga(g,t)}else{if(!m&&p.length>1&&h.nodeType===9&&!M&&n.match.ID.test(p[0])&&!n.match.ID.test(p[p.length-1])){v=k.find(p.shift(),h,M);h=v.expr?k.filter(v.expr,v.set)[0]:v.set[0]}if(h){v=m?{expr:p.pop(),set:z(m)}:k.find(p.pop(),p.length===1&&(p[0]==="~"||p[0]==="+")&&h.parentNode?h.parentNode:h,M);t=v.expr?k.filter(v.expr,v.set):v.set;if(p.length>0)y=z(t);else H=false;for(;p.length;){var D=p.pop();v=D;if(n.relative[D])v=p.pop();else D="";if(v==null)v=h;n.relative[D](y,v,M)}}else y=[]}y||(y=t);y||k.error(D||
+g);if(j.call(y)==="[object Array]")if(H)if(h&&h.nodeType===1)for(g=0;y[g]!=null;g++){if(y[g]&&(y[g]===true||y[g].nodeType===1&&E(h,y[g])))l.push(t[g])}else for(g=0;y[g]!=null;g++)y[g]&&y[g].nodeType===1&&l.push(t[g]);else l.push.apply(l,y);else z(y,l);if(S){k(S,q,l,m);k.uniqueSort(l)}return l};k.uniqueSort=function(g){if(B){i=o;g.sort(B);if(i)for(var h=1;h<g.length;h++)g[h]===g[h-1]&&g.splice(h--,1)}return g};k.matches=function(g,h){return k(g,null,null,h)};k.find=function(g,h,l){var m,q;if(!g)return[];
+for(var p=0,v=n.order.length;p<v;p++){var t=n.order[p];if(q=n.leftMatch[t].exec(g)){var y=q[1];q.splice(1,1);if(y.substr(y.length-1)!=="\\"){q[1]=(q[1]||"").replace(/\\/g,"");m=n.find[t](q,h,l);if(m!=null){g=g.replace(n.match[t],"");break}}}}m||(m=h.getElementsByTagName("*"));return{set:m,expr:g}};k.filter=function(g,h,l,m){for(var q=g,p=[],v=h,t,y,S=h&&h[0]&&x(h[0]);g&&h.length;){for(var H in n.filter)if((t=n.leftMatch[H].exec(g))!=null&&t[2]){var M=n.filter[H],I,D;D=t[1];y=false;t.splice(1,1);if(D.substr(D.length-
+1)!=="\\"){if(v===p)p=[];if(n.preFilter[H])if(t=n.preFilter[H](t,v,l,p,m,S)){if(t===true)continue}else y=I=true;if(t)for(var U=0;(D=v[U])!=null;U++)if(D){I=M(D,t,U,v);var Ha=m^!!I;if(l&&I!=null)if(Ha)y=true;else v[U]=false;else if(Ha){p.push(D);y=true}}if(I!==w){l||(v=p);g=g.replace(n.match[H],"");if(!y)return[];break}}}if(g===q)if(y==null)k.error(g);else break;q=g}return v};k.error=function(g){throw"Syntax error, unrecognized expression: "+g;};var n=k.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF-]|\\.)+)/,
+CLASS:/\.((?:[\w\u00c0-\uFFFF-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/},leftMatch:{},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(g){return g.getAttribute("href")}},
+relative:{"+":function(g,h){var l=typeof h==="string",m=l&&!/\W/.test(h);l=l&&!m;if(m)h=h.toLowerCase();m=0;for(var q=g.length,p;m<q;m++)if(p=g[m]){for(;(p=p.previousSibling)&&p.nodeType!==1;);g[m]=l||p&&p.nodeName.toLowerCase()===h?p||false:p===h}l&&k.filter(h,g,true)},">":function(g,h){var l=typeof h==="string";if(l&&!/\W/.test(h)){h=h.toLowerCase();for(var m=0,q=g.length;m<q;m++){var p=g[m];if(p){l=p.parentNode;g[m]=l.nodeName.toLowerCase()===h?l:false}}}else{m=0;for(q=g.length;m<q;m++)if(p=g[m])g[m]=
+l?p.parentNode:p.parentNode===h;l&&k.filter(h,g,true)}},"":function(g,h,l){var m=e++,q=d;if(typeof h==="string"&&!/\W/.test(h)){var p=h=h.toLowerCase();q=b}q("parentNode",h,m,g,p,l)},"~":function(g,h,l){var m=e++,q=d;if(typeof h==="string"&&!/\W/.test(h)){var p=h=h.toLowerCase();q=b}q("previousSibling",h,m,g,p,l)}},find:{ID:function(g,h,l){if(typeof h.getElementById!=="undefined"&&!l)return(g=h.getElementById(g[1]))?[g]:[]},NAME:function(g,h){if(typeof h.getElementsByName!=="undefined"){var l=[];
+h=h.getElementsByName(g[1]);for(var m=0,q=h.length;m<q;m++)h[m].getAttribute("name")===g[1]&&l.push(h[m]);return l.length===0?null:l}},TAG:function(g,h){return h.getElementsByTagName(g[1])}},preFilter:{CLASS:function(g,h,l,m,q,p){g=" "+g[1].replace(/\\/g,"")+" ";if(p)return g;p=0;for(var v;(v=h[p])!=null;p++)if(v)if(q^(v.className&&(" "+v.className+" ").replace(/[\t\n]/g," ").indexOf(g)>=0))l||m.push(v);else if(l)h[p]=false;return false},ID:function(g){return g[1].replace(/\\/g,"")},TAG:function(g){return g[1].toLowerCase()},
+CHILD:function(g){if(g[1]==="nth"){var h=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(g[2]==="even"&&"2n"||g[2]==="odd"&&"2n+1"||!/\D/.test(g[2])&&"0n+"+g[2]||g[2]);g[2]=h[1]+(h[2]||1)-0;g[3]=h[3]-0}g[0]=e++;return g},ATTR:function(g,h,l,m,q,p){h=g[1].replace(/\\/g,"");if(!p&&n.attrMap[h])g[1]=n.attrMap[h];if(g[2]==="~=")g[4]=" "+g[4]+" ";return g},PSEUDO:function(g,h,l,m,q){if(g[1]==="not")if((f.exec(g[3])||"").length>1||/^\w/.test(g[3]))g[3]=k(g[3],null,null,h);else{g=k.filter(g[3],h,l,true^q);l||m.push.apply(m,
+g);return false}else if(n.match.POS.test(g[0])||n.match.CHILD.test(g[0]))return true;return g},POS:function(g){g.unshift(true);return g}},filters:{enabled:function(g){return g.disabled===false&&g.type!=="hidden"},disabled:function(g){return g.disabled===true},checked:function(g){return g.checked===true},selected:function(g){return g.selected===true},parent:function(g){return!!g.firstChild},empty:function(g){return!g.firstChild},has:function(g,h,l){return!!k(l[3],g).length},header:function(g){return/h\d/i.test(g.nodeName)},
+text:function(g){return"text"===g.type},radio:function(g){return"radio"===g.type},checkbox:function(g){return"checkbox"===g.type},file:function(g){return"file"===g.type},password:function(g){return"password"===g.type},submit:function(g){return"submit"===g.type},image:function(g){return"image"===g.type},reset:function(g){return"reset"===g.type},button:function(g){return"button"===g.type||g.nodeName.toLowerCase()==="button"},input:function(g){return/input|select|textarea|button/i.test(g.nodeName)}},
+setFilters:{first:function(g,h){return h===0},last:function(g,h,l,m){return h===m.length-1},even:function(g,h){return h%2===0},odd:function(g,h){return h%2===1},lt:function(g,h,l){return h<l[3]-0},gt:function(g,h,l){return h>l[3]-0},nth:function(g,h,l){return l[3]-0===h},eq:function(g,h,l){return l[3]-0===h}},filter:{PSEUDO:function(g,h,l,m){var q=h[1],p=n.filters[q];if(p)return p(g,l,h,m);else if(q==="contains")return(g.textContent||g.innerText||a([g])||"").indexOf(h[3])>=0;else if(q==="not"){h=
+h[3];l=0;for(m=h.length;l<m;l++)if(h[l]===g)return false;return true}else k.error("Syntax error, unrecognized expression: "+q)},CHILD:function(g,h){var l=h[1],m=g;switch(l){case "only":case "first":for(;m=m.previousSibling;)if(m.nodeType===1)return false;if(l==="first")return true;m=g;case "last":for(;m=m.nextSibling;)if(m.nodeType===1)return false;return true;case "nth":l=h[2];var q=h[3];if(l===1&&q===0)return true;h=h[0];var p=g.parentNode;if(p&&(p.sizcache!==h||!g.nodeIndex)){var v=0;for(m=p.firstChild;m;m=
+m.nextSibling)if(m.nodeType===1)m.nodeIndex=++v;p.sizcache=h}g=g.nodeIndex-q;return l===0?g===0:g%l===0&&g/l>=0}},ID:function(g,h){return g.nodeType===1&&g.getAttribute("id")===h},TAG:function(g,h){return h==="*"&&g.nodeType===1||g.nodeName.toLowerCase()===h},CLASS:function(g,h){return(" "+(g.className||g.getAttribute("class"))+" ").indexOf(h)>-1},ATTR:function(g,h){var l=h[1];g=n.attrHandle[l]?n.attrHandle[l](g):g[l]!=null?g[l]:g.getAttribute(l);l=g+"";var m=h[2];h=h[4];return g==null?m==="!=":m===
+"="?l===h:m==="*="?l.indexOf(h)>=0:m==="~="?(" "+l+" ").indexOf(h)>=0:!h?l&&g!==false:m==="!="?l!==h:m==="^="?l.indexOf(h)===0:m==="$="?l.substr(l.length-h.length)===h:m==="|="?l===h||l.substr(0,h.length+1)===h+"-":false},POS:function(g,h,l,m){var q=n.setFilters[h[2]];if(q)return q(g,l,h,m)}}},r=n.match.POS;for(var u in n.match){n.match[u]=new RegExp(n.match[u].source+/(?![^\[]*\])(?![^\(]*\))/.source);n.leftMatch[u]=new RegExp(/(^(?:.|\r|\n)*?)/.source+n.match[u].source.replace(/\\(\d+)/g,function(g,
+h){return"\\"+(h-0+1)}))}var z=function(g,h){g=Array.prototype.slice.call(g,0);if(h){h.push.apply(h,g);return h}return g};try{Array.prototype.slice.call(s.documentElement.childNodes,0)}catch(C){z=function(g,h){h=h||[];if(j.call(g)==="[object Array]")Array.prototype.push.apply(h,g);else if(typeof g.length==="number")for(var l=0,m=g.length;l<m;l++)h.push(g[l]);else for(l=0;g[l];l++)h.push(g[l]);return h}}var B;if(s.documentElement.compareDocumentPosition)B=function(g,h){if(!g.compareDocumentPosition||
+!h.compareDocumentPosition){if(g==h)i=true;return g.compareDocumentPosition?-1:1}g=g.compareDocumentPosition(h)&4?-1:g===h?0:1;if(g===0)i=true;return g};else if("sourceIndex"in s.documentElement)B=function(g,h){if(!g.sourceIndex||!h.sourceIndex){if(g==h)i=true;return g.sourceIndex?-1:1}g=g.sourceIndex-h.sourceIndex;if(g===0)i=true;return g};else if(s.createRange)B=function(g,h){if(!g.ownerDocument||!h.ownerDocument){if(g==h)i=true;return g.ownerDocument?-1:1}var l=g.ownerDocument.createRange(),m=
+h.ownerDocument.createRange();l.setStart(g,0);l.setEnd(g,0);m.setStart(h,0);m.setEnd(h,0);g=l.compareBoundaryPoints(Range.START_TO_END,m);if(g===0)i=true;return g};(function(){var g=s.createElement("div"),h="script"+(new Date).getTime();g.innerHTML="<a name='"+h+"'/>";var l=s.documentElement;l.insertBefore(g,l.firstChild);if(s.getElementById(h)){n.find.ID=function(m,q,p){if(typeof q.getElementById!=="undefined"&&!p)return(q=q.getElementById(m[1]))?q.id===m[1]||typeof q.getAttributeNode!=="undefined"&&
+q.getAttributeNode("id").nodeValue===m[1]?[q]:w:[]};n.filter.ID=function(m,q){var p=typeof m.getAttributeNode!=="undefined"&&m.getAttributeNode("id");return m.nodeType===1&&p&&p.nodeValue===q}}l.removeChild(g);l=g=null})();(function(){var g=s.createElement("div");g.appendChild(s.createComment(""));if(g.getElementsByTagName("*").length>0)n.find.TAG=function(h,l){l=l.getElementsByTagName(h[1]);if(h[1]==="*"){h=[];for(var m=0;l[m];m++)l[m].nodeType===1&&h.push(l[m]);l=h}return l};g.innerHTML="<a href='#'></a>";
+if(g.firstChild&&typeof g.firstChild.getAttribute!=="undefined"&&g.firstChild.getAttribute("href")!=="#")n.attrHandle.href=function(h){return h.getAttribute("href",2)};g=null})();s.querySelectorAll&&function(){var g=k,h=s.createElement("div");h.innerHTML="<p class='TEST'></p>";if(!(h.querySelectorAll&&h.querySelectorAll(".TEST").length===0)){k=function(m,q,p,v){q=q||s;if(!v&&q.nodeType===9&&!x(q))try{return z(q.querySelectorAll(m),p)}catch(t){}return g(m,q,p,v)};for(var l in g)k[l]=g[l];h=null}}();
+(function(){var g=s.createElement("div");g.innerHTML="<div class='test e'></div><div class='test'></div>";if(!(!g.getElementsByClassName||g.getElementsByClassName("e").length===0)){g.lastChild.className="e";if(g.getElementsByClassName("e").length!==1){n.order.splice(1,0,"CLASS");n.find.CLASS=function(h,l,m){if(typeof l.getElementsByClassName!=="undefined"&&!m)return l.getElementsByClassName(h[1])};g=null}}})();var E=s.compareDocumentPosition?function(g,h){return!!(g.compareDocumentPosition(h)&16)}:
+function(g,h){return g!==h&&(g.contains?g.contains(h):true)},x=function(g){return(g=(g?g.ownerDocument||g:0).documentElement)?g.nodeName!=="HTML":false},ga=function(g,h){var l=[],m="",q;for(h=h.nodeType?[h]:h;q=n.match.PSEUDO.exec(g);){m+=q[0];g=g.replace(n.match.PSEUDO,"")}g=n.relative[g]?g+"*":g;q=0;for(var p=h.length;q<p;q++)k(g,h[q],l);return k.filter(m,l)};c.find=k;c.expr=k.selectors;c.expr[":"]=c.expr.filters;c.unique=k.uniqueSort;c.text=a;c.isXMLDoc=x;c.contains=E})();var eb=/Until$/,fb=/^(?:parents|prevUntil|prevAll)/,
+gb=/,/;R=Array.prototype.slice;var Ia=function(a,b,d){if(c.isFunction(b))return c.grep(a,function(e,j){return!!b.call(e,j,e)===d});else if(b.nodeType)return c.grep(a,function(e){return e===b===d});else if(typeof b==="string"){var f=c.grep(a,function(e){return e.nodeType===1});if(Ua.test(b))return c.filter(b,f,!d);else b=c.filter(b,f)}return c.grep(a,function(e){return c.inArray(e,b)>=0===d})};c.fn.extend({find:function(a){for(var b=this.pushStack("","find",a),d=0,f=0,e=this.length;f<e;f++){d=b.length;
+c.find(a,this[f],b);if(f>0)for(var j=d;j<b.length;j++)for(var i=0;i<d;i++)if(b[i]===b[j]){b.splice(j--,1);break}}return b},has:function(a){var b=c(a);return this.filter(function(){for(var d=0,f=b.length;d<f;d++)if(c.contains(this,b[d]))return true})},not:function(a){return this.pushStack(Ia(this,a,false),"not",a)},filter:function(a){return this.pushStack(Ia(this,a,true),"filter",a)},is:function(a){return!!a&&c.filter(a,this).length>0},closest:function(a,b){if(c.isArray(a)){var d=[],f=this[0],e,j=
+{},i;if(f&&a.length){e=0;for(var o=a.length;e<o;e++){i=a[e];j[i]||(j[i]=c.expr.match.POS.test(i)?c(i,b||this.context):i)}for(;f&&f.ownerDocument&&f!==b;){for(i in j){e=j[i];if(e.jquery?e.index(f)>-1:c(f).is(e)){d.push({selector:i,elem:f});delete j[i]}}f=f.parentNode}}return d}var k=c.expr.match.POS.test(a)?c(a,b||this.context):null;return this.map(function(n,r){for(;r&&r.ownerDocument&&r!==b;){if(k?k.index(r)>-1:c(r).is(a))return r;r=r.parentNode}return null})},index:function(a){if(!a||typeof a===
+"string")return c.inArray(this[0],a?c(a):this.parent().children());return c.inArray(a.jquery?a[0]:a,this)},add:function(a,b){a=typeof a==="string"?c(a,b||this.context):c.makeArray(a);b=c.merge(this.get(),a);return this.pushStack(qa(a[0])||qa(b[0])?b:c.unique(b))},andSelf:function(){return this.add(this.prevObject)}});c.each({parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},parents:function(a){return c.dir(a,"parentNode")},parentsUntil:function(a,b,d){return c.dir(a,"parentNode",
+d)},next:function(a){return c.nth(a,2,"nextSibling")},prev:function(a){return c.nth(a,2,"previousSibling")},nextAll:function(a){return c.dir(a,"nextSibling")},prevAll:function(a){return c.dir(a,"previousSibling")},nextUntil:function(a,b,d){return c.dir(a,"nextSibling",d)},prevUntil:function(a,b,d){return c.dir(a,"previousSibling",d)},siblings:function(a){return c.sibling(a.parentNode.firstChild,a)},children:function(a){return c.sibling(a.firstChild)},contents:function(a){return c.nodeName(a,"iframe")?
+a.contentDocument||a.contentWindow.document:c.makeArray(a.childNodes)}},function(a,b){c.fn[a]=function(d,f){var e=c.map(this,b,d);eb.test(a)||(f=d);if(f&&typeof f==="string")e=c.filter(f,e);e=this.length>1?c.unique(e):e;if((this.length>1||gb.test(f))&&fb.test(a))e=e.reverse();return this.pushStack(e,a,R.call(arguments).join(","))}});c.extend({filter:function(a,b,d){if(d)a=":not("+a+")";return c.find.matches(a,b)},dir:function(a,b,d){var f=[];for(a=a[b];a&&a.nodeType!==9&&(d===w||a.nodeType!==1||!c(a).is(d));){a.nodeType===
+1&&f.push(a);a=a[b]}return f},nth:function(a,b,d){b=b||1;for(var f=0;a;a=a[d])if(a.nodeType===1&&++f===b)break;return a},sibling:function(a,b){for(var d=[];a;a=a.nextSibling)a.nodeType===1&&a!==b&&d.push(a);return d}});var Ja=/ jQuery\d+="(?:\d+|null)"/g,V=/^\s+/,Ka=/(<([\w:]+)[^>]*?)\/>/g,hb=/^(?:area|br|col|embed|hr|img|input|link|meta|param)$/i,La=/<([\w:]+)/,ib=/<tbody/i,jb=/<|&#?\w+;/,ta=/<script|<object|<embed|<option|<style/i,ua=/checked\s*(?:[^=]|=\s*.checked.)/i,Ma=function(a,b,d){return hb.test(d)?
+a:b+"></"+d+">"},F={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]};F.optgroup=F.option;F.tbody=F.tfoot=F.colgroup=F.caption=F.thead;F.th=F.td;if(!c.support.htmlSerialize)F._default=[1,"div<div>","</div>"];c.fn.extend({text:function(a){if(c.isFunction(a))return this.each(function(b){var d=
+c(this);d.text(a.call(this,b,d.text()))});if(typeof a!=="object"&&a!==w)return this.empty().append((this[0]&&this[0].ownerDocument||s).createTextNode(a));return c.text(this)},wrapAll:function(a){if(c.isFunction(a))return this.each(function(d){c(this).wrapAll(a.call(this,d))});if(this[0]){var b=c(a,this[0].ownerDocument).eq(0).clone(true);this[0].parentNode&&b.insertBefore(this[0]);b.map(function(){for(var d=this;d.firstChild&&d.firstChild.nodeType===1;)d=d.firstChild;return d}).append(this)}return this},
+wrapInner:function(a){if(c.isFunction(a))return this.each(function(b){c(this).wrapInner(a.call(this,b))});return this.each(function(){var b=c(this),d=b.contents();d.length?d.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){c(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){c.nodeName(this,"body")||c(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.appendChild(a)})},
+prepend:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this)});else if(arguments.length){var a=c(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,
+this.nextSibling)});else if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,c(arguments[0]).toArray());return a}},remove:function(a,b){for(var d=0,f;(f=this[d])!=null;d++)if(!a||c.filter(a,[f]).length){if(!b&&f.nodeType===1){c.cleanData(f.getElementsByTagName("*"));c.cleanData([f])}f.parentNode&&f.parentNode.removeChild(f)}return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++)for(b.nodeType===1&&c.cleanData(b.getElementsByTagName("*"));b.firstChild;)b.removeChild(b.firstChild);
+return this},clone:function(a){var b=this.map(function(){if(!c.support.noCloneEvent&&!c.isXMLDoc(this)){var d=this.outerHTML,f=this.ownerDocument;if(!d){d=f.createElement("div");d.appendChild(this.cloneNode(true));d=d.innerHTML}return c.clean([d.replace(Ja,"").replace(/=([^="'>\s]+\/)>/g,'="$1">').replace(V,"")],f)[0]}else return this.cloneNode(true)});if(a===true){ra(this,b);ra(this.find("*"),b.find("*"))}return b},html:function(a){if(a===w)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(Ja,
+""):null;else if(typeof a==="string"&&!ta.test(a)&&(c.support.leadingWhitespace||!V.test(a))&&!F[(La.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Ka,Ma);try{for(var b=0,d=this.length;b<d;b++)if(this[b].nodeType===1){c.cleanData(this[b].getElementsByTagName("*"));this[b].innerHTML=a}}catch(f){this.empty().append(a)}}else c.isFunction(a)?this.each(function(e){var j=c(this),i=j.html();j.empty().append(function(){return a.call(this,e,i)})}):this.empty().append(a);return this},replaceWith:function(a){if(this[0]&&
+this[0].parentNode){if(c.isFunction(a))return this.each(function(b){var d=c(this),f=d.html();d.replaceWith(a.call(this,b,f))});if(typeof a!=="string")a=c(a).detach();return this.each(function(){var b=this.nextSibling,d=this.parentNode;c(this).remove();b?c(b).before(a):c(d).append(a)})}else return this.pushStack(c(c.isFunction(a)?a():a),"replaceWith",a)},detach:function(a){return this.remove(a,true)},domManip:function(a,b,d){function f(u){return c.nodeName(u,"table")?u.getElementsByTagName("tbody")[0]||
+u.appendChild(u.ownerDocument.createElement("tbody")):u}var e,j,i=a[0],o=[],k;if(!c.support.checkClone&&arguments.length===3&&typeof i==="string"&&ua.test(i))return this.each(function(){c(this).domManip(a,b,d,true)});if(c.isFunction(i))return this.each(function(u){var z=c(this);a[0]=i.call(this,u,b?z.html():w);z.domManip(a,b,d)});if(this[0]){e=i&&i.parentNode;e=c.support.parentNode&&e&&e.nodeType===11&&e.childNodes.length===this.length?{fragment:e}:sa(a,this,o);k=e.fragment;if(j=k.childNodes.length===
+1?(k=k.firstChild):k.firstChild){b=b&&c.nodeName(j,"tr");for(var n=0,r=this.length;n<r;n++)d.call(b?f(this[n],j):this[n],n>0||e.cacheable||this.length>1?k.cloneNode(true):k)}o.length&&c.each(o,Qa)}return this}});c.fragments={};c.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){c.fn[a]=function(d){var f=[];d=c(d);var e=this.length===1&&this[0].parentNode;if(e&&e.nodeType===11&&e.childNodes.length===1&&d.length===1){d[b](this[0]);
+return this}else{e=0;for(var j=d.length;e<j;e++){var i=(e>0?this.clone(true):this).get();c.fn[b].apply(c(d[e]),i);f=f.concat(i)}return this.pushStack(f,a,d.selector)}}});c.extend({clean:function(a,b,d,f){b=b||s;if(typeof b.createElement==="undefined")b=b.ownerDocument||b[0]&&b[0].ownerDocument||s;for(var e=[],j=0,i;(i=a[j])!=null;j++){if(typeof i==="number")i+="";if(i){if(typeof i==="string"&&!jb.test(i))i=b.createTextNode(i);else if(typeof i==="string"){i=i.replace(Ka,Ma);var o=(La.exec(i)||["",
+""])[1].toLowerCase(),k=F[o]||F._default,n=k[0],r=b.createElement("div");for(r.innerHTML=k[1]+i+k[2];n--;)r=r.lastChild;if(!c.support.tbody){n=ib.test(i);o=o==="table"&&!n?r.firstChild&&r.firstChild.childNodes:k[1]==="<table>"&&!n?r.childNodes:[];for(k=o.length-1;k>=0;--k)c.nodeName(o[k],"tbody")&&!o[k].childNodes.length&&o[k].parentNode.removeChild(o[k])}!c.support.leadingWhitespace&&V.test(i)&&r.insertBefore(b.createTextNode(V.exec(i)[0]),r.firstChild);i=r.childNodes}if(i.nodeType)e.push(i);else e=
+c.merge(e,i)}}if(d)for(j=0;e[j];j++)if(f&&c.nodeName(e[j],"script")&&(!e[j].type||e[j].type.toLowerCase()==="text/javascript"))f.push(e[j].parentNode?e[j].parentNode.removeChild(e[j]):e[j]);else{e[j].nodeType===1&&e.splice.apply(e,[j+1,0].concat(c.makeArray(e[j].getElementsByTagName("script"))));d.appendChild(e[j])}return e},cleanData:function(a){for(var b,d,f=c.cache,e=c.event.special,j=c.support.deleteExpando,i=0,o;(o=a[i])!=null;i++)if(d=o[c.expando]){b=f[d];if(b.events)for(var k in b.events)e[k]?
+c.event.remove(o,k):Ca(o,k,b.handle);if(j)delete o[c.expando];else o.removeAttribute&&o.removeAttribute(c.expando);delete f[d]}}});var kb=/z-?index|font-?weight|opacity|zoom|line-?height/i,Na=/alpha\([^)]*\)/,Oa=/opacity=([^)]*)/,ha=/float/i,ia=/-([a-z])/ig,lb=/([A-Z])/g,mb=/^-?\d+(?:px)?$/i,nb=/^-?\d/,ob={position:"absolute",visibility:"hidden",display:"block"},pb=["Left","Right"],qb=["Top","Bottom"],rb=s.defaultView&&s.defaultView.getComputedStyle,Pa=c.support.cssFloat?"cssFloat":"styleFloat",ja=
+function(a,b){return b.toUpperCase()};c.fn.css=function(a,b){return X(this,a,b,true,function(d,f,e){if(e===w)return c.curCSS(d,f);if(typeof e==="number"&&!kb.test(f))e+="px";c.style(d,f,e)})};c.extend({style:function(a,b,d){if(!a||a.nodeType===3||a.nodeType===8)return w;if((b==="width"||b==="height")&&parseFloat(d)<0)d=w;var f=a.style||a,e=d!==w;if(!c.support.opacity&&b==="opacity"){if(e){f.zoom=1;b=parseInt(d,10)+""==="NaN"?"":"alpha(opacity="+d*100+")";a=f.filter||c.curCSS(a,"filter")||"";f.filter=
+Na.test(a)?a.replace(Na,b):b}return f.filter&&f.filter.indexOf("opacity=")>=0?parseFloat(Oa.exec(f.filter)[1])/100+"":""}if(ha.test(b))b=Pa;b=b.replace(ia,ja);if(e)f[b]=d;return f[b]},css:function(a,b,d,f){if(b==="width"||b==="height"){var e,j=b==="width"?pb:qb;function i(){e=b==="width"?a.offsetWidth:a.offsetHeight;f!=="border"&&c.each(j,function(){f||(e-=parseFloat(c.curCSS(a,"padding"+this,true))||0);if(f==="margin")e+=parseFloat(c.curCSS(a,"margin"+this,true))||0;else e-=parseFloat(c.curCSS(a,
+"border"+this+"Width",true))||0})}a.offsetWidth!==0?i():c.swap(a,ob,i);return Math.max(0,Math.round(e))}return c.curCSS(a,b,d)},curCSS:function(a,b,d){var f,e=a.style;if(!c.support.opacity&&b==="opacity"&&a.currentStyle){f=Oa.test(a.currentStyle.filter||"")?parseFloat(RegExp.$1)/100+"":"";return f===""?"1":f}if(ha.test(b))b=Pa;if(!d&&e&&e[b])f=e[b];else if(rb){if(ha.test(b))b="float";b=b.replace(lb,"-$1").toLowerCase();e=a.ownerDocument.defaultView;if(!e)return null;if(a=e.getComputedStyle(a,null))f=
+a.getPropertyValue(b);if(b==="opacity"&&f==="")f="1"}else if(a.currentStyle){d=b.replace(ia,ja);f=a.currentStyle[b]||a.currentStyle[d];if(!mb.test(f)&&nb.test(f)){b=e.left;var j=a.runtimeStyle.left;a.runtimeStyle.left=a.currentStyle.left;e.left=d==="fontSize"?"1em":f||0;f=e.pixelLeft+"px";e.left=b;a.runtimeStyle.left=j}}return f},swap:function(a,b,d){var f={};for(var e in b){f[e]=a.style[e];a.style[e]=b[e]}d.call(a);for(e in b)a.style[e]=f[e]}});if(c.expr&&c.expr.filters){c.expr.filters.hidden=function(a){var b=
+a.offsetWidth,d=a.offsetHeight,f=a.nodeName.toLowerCase()==="tr";return b===0&&d===0&&!f?true:b>0&&d>0&&!f?false:c.curCSS(a,"display")==="none"};c.expr.filters.visible=function(a){return!c.expr.filters.hidden(a)}}var sb=J(),tb=/<script(.|\s)*?\/script>/gi,ub=/select|textarea/i,vb=/color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week/i,N=/=\?(&|$)/,ka=/\?/,wb=/(\?|&)_=.*?(&|$)/,xb=/^(\w+:)?\/\/([^\/?#]+)/,yb=/%20/g,zb=c.fn.load;c.fn.extend({load:function(a,b,d){if(typeof a!==
+"string")return zb.call(this,a);else if(!this.length)return this;var f=a.indexOf(" ");if(f>=0){var e=a.slice(f,a.length);a=a.slice(0,f)}f="GET";if(b)if(c.isFunction(b)){d=b;b=null}else if(typeof b==="object"){b=c.param(b,c.ajaxSettings.traditional);f="POST"}var j=this;c.ajax({url:a,type:f,dataType:"html",data:b,complete:function(i,o){if(o==="success"||o==="notmodified")j.html(e?c("<div />").append(i.responseText.replace(tb,"")).find(e):i.responseText);d&&j.each(d,[i.responseText,o,i])}});return this},
+serialize:function(){return c.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?c.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||ub.test(this.nodeName)||vb.test(this.type))}).map(function(a,b){a=c(this).val();return a==null?null:c.isArray(a)?c.map(a,function(d){return{name:b.name,value:d}}):{name:b.name,value:a}}).get()}});c.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),
+function(a,b){c.fn[b]=function(d){return this.bind(b,d)}});c.extend({get:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b=null}return c.ajax({type:"GET",url:a,data:b,success:d,dataType:f})},getScript:function(a,b){return c.get(a,null,b,"script")},getJSON:function(a,b,d){return c.get(a,b,d,"json")},post:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b={}}return c.ajax({type:"POST",url:a,data:b,success:d,dataType:f})},ajaxSetup:function(a){c.extend(c.ajaxSettings,a)},ajaxSettings:{url:location.href,
+global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:A.XMLHttpRequest&&(A.location.protocol!=="file:"||!A.ActiveXObject)?function(){return new A.XMLHttpRequest}:function(){try{return new A.ActiveXObject("Microsoft.XMLHTTP")}catch(a){}},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},etag:{},ajax:function(a){function b(){e.success&&
+e.success.call(k,o,i,x);e.global&&f("ajaxSuccess",[x,e])}function d(){e.complete&&e.complete.call(k,x,i);e.global&&f("ajaxComplete",[x,e]);e.global&&!--c.active&&c.event.trigger("ajaxStop")}function f(q,p){(e.context?c(e.context):c.event).trigger(q,p)}var e=c.extend(true,{},c.ajaxSettings,a),j,i,o,k=a&&a.context||e,n=e.type.toUpperCase();if(e.data&&e.processData&&typeof e.data!=="string")e.data=c.param(e.data,e.traditional);if(e.dataType==="jsonp"){if(n==="GET")N.test(e.url)||(e.url+=(ka.test(e.url)?
+"&":"?")+(e.jsonp||"callback")+"=?");else if(!e.data||!N.test(e.data))e.data=(e.data?e.data+"&":"")+(e.jsonp||"callback")+"=?";e.dataType="json"}if(e.dataType==="json"&&(e.data&&N.test(e.data)||N.test(e.url))){j=e.jsonpCallback||"jsonp"+sb++;if(e.data)e.data=(e.data+"").replace(N,"="+j+"$1");e.url=e.url.replace(N,"="+j+"$1");e.dataType="script";A[j]=A[j]||function(q){o=q;b();d();A[j]=w;try{delete A[j]}catch(p){}z&&z.removeChild(C)}}if(e.dataType==="script"&&e.cache===null)e.cache=false;if(e.cache===
+false&&n==="GET"){var r=J(),u=e.url.replace(wb,"$1_="+r+"$2");e.url=u+(u===e.url?(ka.test(e.url)?"&":"?")+"_="+r:"")}if(e.data&&n==="GET")e.url+=(ka.test(e.url)?"&":"?")+e.data;e.global&&!c.active++&&c.event.trigger("ajaxStart");r=(r=xb.exec(e.url))&&(r[1]&&r[1]!==location.protocol||r[2]!==location.host);if(e.dataType==="script"&&n==="GET"&&r){var z=s.getElementsByTagName("head")[0]||s.documentElement,C=s.createElement("script");C.src=e.url;if(e.scriptCharset)C.charset=e.scriptCharset;if(!j){var B=
+false;C.onload=C.onreadystatechange=function(){if(!B&&(!this.readyState||this.readyState==="loaded"||this.readyState==="complete")){B=true;b();d();C.onload=C.onreadystatechange=null;z&&C.parentNode&&z.removeChild(C)}}}z.insertBefore(C,z.firstChild);return w}var E=false,x=e.xhr();if(x){e.username?x.open(n,e.url,e.async,e.username,e.password):x.open(n,e.url,e.async);try{if(e.data||a&&a.contentType)x.setRequestHeader("Content-Type",e.contentType);if(e.ifModified){c.lastModified[e.url]&&x.setRequestHeader("If-Modified-Since",
+c.lastModified[e.url]);c.etag[e.url]&&x.setRequestHeader("If-None-Match",c.etag[e.url])}r||x.setRequestHeader("X-Requested-With","XMLHttpRequest");x.setRequestHeader("Accept",e.dataType&&e.accepts[e.dataType]?e.accepts[e.dataType]+", */*":e.accepts._default)}catch(ga){}if(e.beforeSend&&e.beforeSend.call(k,x,e)===false){e.global&&!--c.active&&c.event.trigger("ajaxStop");x.abort();return false}e.global&&f("ajaxSend",[x,e]);var g=x.onreadystatechange=function(q){if(!x||x.readyState===0||q==="abort"){E||
+d();E=true;if(x)x.onreadystatechange=c.noop}else if(!E&&x&&(x.readyState===4||q==="timeout")){E=true;x.onreadystatechange=c.noop;i=q==="timeout"?"timeout":!c.httpSuccess(x)?"error":e.ifModified&&c.httpNotModified(x,e.url)?"notmodified":"success";var p;if(i==="success")try{o=c.httpData(x,e.dataType,e)}catch(v){i="parsererror";p=v}if(i==="success"||i==="notmodified")j||b();else c.handleError(e,x,i,p);d();q==="timeout"&&x.abort();if(e.async)x=null}};try{var h=x.abort;x.abort=function(){x&&h.call(x);
+g("abort")}}catch(l){}e.async&&e.timeout>0&&setTimeout(function(){x&&!E&&g("timeout")},e.timeout);try{x.send(n==="POST"||n==="PUT"||n==="DELETE"?e.data:null)}catch(m){c.handleError(e,x,null,m);d()}e.async||g();return x}},handleError:function(a,b,d,f){if(a.error)a.error.call(a.context||a,b,d,f);if(a.global)(a.context?c(a.context):c.event).trigger("ajaxError",[b,a,f])},active:0,httpSuccess:function(a){try{return!a.status&&location.protocol==="file:"||a.status>=200&&a.status<300||a.status===304||a.status===
+1223||a.status===0}catch(b){}return false},httpNotModified:function(a,b){var d=a.getResponseHeader("Last-Modified"),f=a.getResponseHeader("Etag");if(d)c.lastModified[b]=d;if(f)c.etag[b]=f;return a.status===304||a.status===0},httpData:function(a,b,d){var f=a.getResponseHeader("content-type")||"",e=b==="xml"||!b&&f.indexOf("xml")>=0;a=e?a.responseXML:a.responseText;e&&a.documentElement.nodeName==="parsererror"&&c.error("parsererror");if(d&&d.dataFilter)a=d.dataFilter(a,b);if(typeof a==="string")if(b===
+"json"||!b&&f.indexOf("json")>=0)a=c.parseJSON(a);else if(b==="script"||!b&&f.indexOf("javascript")>=0)c.globalEval(a);return a},param:function(a,b){function d(i,o){if(c.isArray(o))c.each(o,function(k,n){b||/\[\]$/.test(i)?f(i,n):d(i+"["+(typeof n==="object"||c.isArray(n)?k:"")+"]",n)});else!b&&o!=null&&typeof o==="object"?c.each(o,function(k,n){d(i+"["+k+"]",n)}):f(i,o)}function f(i,o){o=c.isFunction(o)?o():o;e[e.length]=encodeURIComponent(i)+"="+encodeURIComponent(o)}var e=[];if(b===w)b=c.ajaxSettings.traditional;
+if(c.isArray(a)||a.jquery)c.each(a,function(){f(this.name,this.value)});else for(var j in a)d(j,a[j]);return e.join("&").replace(yb,"+")}});var la={},Ab=/toggle|show|hide/,Bb=/^([+-]=)?([\d+-.]+)(.*)$/,W,va=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];c.fn.extend({show:function(a,b){if(a||a===0)return this.animate(K("show",3),a,b);else{a=0;for(b=this.length;a<b;a++){var d=c.data(this[a],"olddisplay");
+this[a].style.display=d||"";if(c.css(this[a],"display")==="none"){d=this[a].nodeName;var f;if(la[d])f=la[d];else{var e=c("<"+d+" />").appendTo("body");f=e.css("display");if(f==="none")f="block";e.remove();la[d]=f}c.data(this[a],"olddisplay",f)}}a=0;for(b=this.length;a<b;a++)this[a].style.display=c.data(this[a],"olddisplay")||"";return this}},hide:function(a,b){if(a||a===0)return this.animate(K("hide",3),a,b);else{a=0;for(b=this.length;a<b;a++){var d=c.data(this[a],"olddisplay");!d&&d!=="none"&&c.data(this[a],
+"olddisplay",c.css(this[a],"display"))}a=0;for(b=this.length;a<b;a++)this[a].style.display="none";return this}},_toggle:c.fn.toggle,toggle:function(a,b){var d=typeof a==="boolean";if(c.isFunction(a)&&c.isFunction(b))this._toggle.apply(this,arguments);else a==null||d?this.each(function(){var f=d?a:c(this).is(":hidden");c(this)[f?"show":"hide"]()}):this.animate(K("toggle",3),a,b);return this},fadeTo:function(a,b,d){return this.filter(":hidden").css("opacity",0).show().end().animate({opacity:b},a,d)},
+animate:function(a,b,d,f){var e=c.speed(b,d,f);if(c.isEmptyObject(a))return this.each(e.complete);return this[e.queue===false?"each":"queue"](function(){var j=c.extend({},e),i,o=this.nodeType===1&&c(this).is(":hidden"),k=this;for(i in a){var n=i.replace(ia,ja);if(i!==n){a[n]=a[i];delete a[i];i=n}if(a[i]==="hide"&&o||a[i]==="show"&&!o)return j.complete.call(this);if((i==="height"||i==="width")&&this.style){j.display=c.css(this,"display");j.overflow=this.style.overflow}if(c.isArray(a[i])){(j.specialEasing=
+j.specialEasing||{})[i]=a[i][1];a[i]=a[i][0]}}if(j.overflow!=null)this.style.overflow="hidden";j.curAnim=c.extend({},a);c.each(a,function(r,u){var z=new c.fx(k,j,r);if(Ab.test(u))z[u==="toggle"?o?"show":"hide":u](a);else{var C=Bb.exec(u),B=z.cur(true)||0;if(C){u=parseFloat(C[2]);var E=C[3]||"px";if(E!=="px"){k.style[r]=(u||1)+E;B=(u||1)/z.cur(true)*B;k.style[r]=B+E}if(C[1])u=(C[1]==="-="?-1:1)*u+B;z.custom(B,u,E)}else z.custom(B,u,"")}});return true})},stop:function(a,b){var d=c.timers;a&&this.queue([]);
+this.each(function(){for(var f=d.length-1;f>=0;f--)if(d[f].elem===this){b&&d[f](true);d.splice(f,1)}});b||this.dequeue();return this}});c.each({slideDown:K("show",1),slideUp:K("hide",1),slideToggle:K("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(a,b){c.fn[a]=function(d,f){return this.animate(b,d,f)}});c.extend({speed:function(a,b,d){var f=a&&typeof a==="object"?a:{complete:d||!d&&b||c.isFunction(a)&&a,duration:a,easing:d&&b||b&&!c.isFunction(b)&&b};f.duration=c.fx.off?0:typeof f.duration===
+"number"?f.duration:c.fx.speeds[f.duration]||c.fx.speeds._default;f.old=f.complete;f.complete=function(){f.queue!==false&&c(this).dequeue();c.isFunction(f.old)&&f.old.call(this)};return f},easing:{linear:function(a,b,d,f){return d+f*a},swing:function(a,b,d,f){return(-Math.cos(a*Math.PI)/2+0.5)*f+d}},timers:[],fx:function(a,b,d){this.options=b;this.elem=a;this.prop=d;if(!b.orig)b.orig={}}});c.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this);(c.fx.step[this.prop]||
+c.fx.step._default)(this);if((this.prop==="height"||this.prop==="width")&&this.elem.style)this.elem.style.display="block"},cur:function(a){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];return(a=parseFloat(c.css(this.elem,this.prop,a)))&&a>-10000?a:parseFloat(c.curCSS(this.elem,this.prop))||0},custom:function(a,b,d){function f(j){return e.step(j)}this.startTime=J();this.start=a;this.end=b;this.unit=d||this.unit||"px";this.now=this.start;
+this.pos=this.state=0;var e=this;f.elem=this.elem;if(f()&&c.timers.push(f)&&!W)W=setInterval(c.fx.tick,13)},show:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.show=true;this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur());c(this.elem).show()},hide:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.hide=true;this.custom(this.cur(),0)},step:function(a){var b=J(),d=true;if(a||b>=this.options.duration+this.startTime){this.now=
+this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;for(var f in this.options.curAnim)if(this.options.curAnim[f]!==true)d=false;if(d){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;a=c.data(this.elem,"olddisplay");this.elem.style.display=a?a:this.options.display;if(c.css(this.elem,"display")==="none")this.elem.style.display="block"}this.options.hide&&c(this.elem).hide();if(this.options.hide||this.options.show)for(var e in this.options.curAnim)c.style(this.elem,
+e,this.options.orig[e]);this.options.complete.call(this.elem)}return false}else{e=b-this.startTime;this.state=e/this.options.duration;a=this.options.easing||(c.easing.swing?"swing":"linear");this.pos=c.easing[this.options.specialEasing&&this.options.specialEasing[this.prop]||a](this.state,e,0,1,this.options.duration);this.now=this.start+(this.end-this.start)*this.pos;this.update()}return true}};c.extend(c.fx,{tick:function(){for(var a=c.timers,b=0;b<a.length;b++)a[b]()||a.splice(b--,1);a.length||
+c.fx.stop()},stop:function(){clearInterval(W);W=null},speeds:{slow:600,fast:200,_default:400},step:{opacity:function(a){c.style(a.elem,"opacity",a.now)},_default:function(a){if(a.elem.style&&a.elem.style[a.prop]!=null)a.elem.style[a.prop]=(a.prop==="width"||a.prop==="height"?Math.max(0,a.now):a.now)+a.unit;else a.elem[a.prop]=a.now}}});if(c.expr&&c.expr.filters)c.expr.filters.animated=function(a){return c.grep(c.timers,function(b){return a===b.elem}).length};c.fn.offset="getBoundingClientRect"in s.documentElement?
+function(a){var b=this[0];if(a)return this.each(function(e){c.offset.setOffset(this,a,e)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);var d=b.getBoundingClientRect(),f=b.ownerDocument;b=f.body;f=f.documentElement;return{top:d.top+(self.pageYOffset||c.support.boxModel&&f.scrollTop||b.scrollTop)-(f.clientTop||b.clientTop||0),left:d.left+(self.pageXOffset||c.support.boxModel&&f.scrollLeft||b.scrollLeft)-(f.clientLeft||b.clientLeft||0)}}:function(a){var b=
+this[0];if(a)return this.each(function(r){c.offset.setOffset(this,a,r)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);c.offset.initialize();var d=b.offsetParent,f=b,e=b.ownerDocument,j,i=e.documentElement,o=e.body;f=(e=e.defaultView)?e.getComputedStyle(b,null):b.currentStyle;for(var k=b.offsetTop,n=b.offsetLeft;(b=b.parentNode)&&b!==o&&b!==i;){if(c.offset.supportsFixedPosition&&f.position==="fixed")break;j=e?e.getComputedStyle(b,null):b.currentStyle;
+k-=b.scrollTop;n-=b.scrollLeft;if(b===d){k+=b.offsetTop;n+=b.offsetLeft;if(c.offset.doesNotAddBorder&&!(c.offset.doesAddBorderForTableAndCells&&/^t(able|d|h)$/i.test(b.nodeName))){k+=parseFloat(j.borderTopWidth)||0;n+=parseFloat(j.borderLeftWidth)||0}f=d;d=b.offsetParent}if(c.offset.subtractsBorderForOverflowNotVisible&&j.overflow!=="visible"){k+=parseFloat(j.borderTopWidth)||0;n+=parseFloat(j.borderLeftWidth)||0}f=j}if(f.position==="relative"||f.position==="static"){k+=o.offsetTop;n+=o.offsetLeft}if(c.offset.supportsFixedPosition&&
+f.position==="fixed"){k+=Math.max(i.scrollTop,o.scrollTop);n+=Math.max(i.scrollLeft,o.scrollLeft)}return{top:k,left:n}};c.offset={initialize:function(){var a=s.body,b=s.createElement("div"),d,f,e,j=parseFloat(c.curCSS(a,"marginTop",true))||0;c.extend(b.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"});b.innerHTML="<div style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;'><div></div></div><table style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;' cellpadding='0' cellspacing='0'><tr><td></td></tr></table>";
+a.insertBefore(b,a.firstChild);d=b.firstChild;f=d.firstChild;e=d.nextSibling.firstChild.firstChild;this.doesNotAddBorder=f.offsetTop!==5;this.doesAddBorderForTableAndCells=e.offsetTop===5;f.style.position="fixed";f.style.top="20px";this.supportsFixedPosition=f.offsetTop===20||f.offsetTop===15;f.style.position=f.style.top="";d.style.overflow="hidden";d.style.position="relative";this.subtractsBorderForOverflowNotVisible=f.offsetTop===-5;this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==j;a.removeChild(b);
+c.offset.initialize=c.noop},bodyOffset:function(a){var b=a.offsetTop,d=a.offsetLeft;c.offset.initialize();if(c.offset.doesNotIncludeMarginInBodyOffset){b+=parseFloat(c.curCSS(a,"marginTop",true))||0;d+=parseFloat(c.curCSS(a,"marginLeft",true))||0}return{top:b,left:d}},setOffset:function(a,b,d){if(/static/.test(c.curCSS(a,"position")))a.style.position="relative";var f=c(a),e=f.offset(),j=parseInt(c.curCSS(a,"top",true),10)||0,i=parseInt(c.curCSS(a,"left",true),10)||0;if(c.isFunction(b))b=b.call(a,
+d,e);d={top:b.top-e.top+j,left:b.left-e.left+i};"using"in b?b.using.call(a,d):f.css(d)}};c.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),d=this.offset(),f=/^body|html$/i.test(b[0].nodeName)?{top:0,left:0}:b.offset();d.top-=parseFloat(c.curCSS(a,"marginTop",true))||0;d.left-=parseFloat(c.curCSS(a,"marginLeft",true))||0;f.top+=parseFloat(c.curCSS(b[0],"borderTopWidth",true))||0;f.left+=parseFloat(c.curCSS(b[0],"borderLeftWidth",true))||0;return{top:d.top-
+f.top,left:d.left-f.left}},offsetParent:function(){return this.map(function(){for(var a=this.offsetParent||s.body;a&&!/^body|html$/i.test(a.nodeName)&&c.css(a,"position")==="static";)a=a.offsetParent;return a})}});c.each(["Left","Top"],function(a,b){var d="scroll"+b;c.fn[d]=function(f){var e=this[0],j;if(!e)return null;if(f!==w)return this.each(function(){if(j=wa(this))j.scrollTo(!a?f:c(j).scrollLeft(),a?f:c(j).scrollTop());else this[d]=f});else return(j=wa(e))?"pageXOffset"in j?j[a?"pageYOffset":
+"pageXOffset"]:c.support.boxModel&&j.document.documentElement[d]||j.document.body[d]:e[d]}});c.each(["Height","Width"],function(a,b){var d=b.toLowerCase();c.fn["inner"+b]=function(){return this[0]?c.css(this[0],d,false,"padding"):null};c.fn["outer"+b]=function(f){return this[0]?c.css(this[0],d,false,f?"margin":"border"):null};c.fn[d]=function(f){var e=this[0];if(!e)return f==null?null:this;if(c.isFunction(f))return this.each(function(j){var i=c(this);i[d](f.call(this,j,i[d]()))});return"scrollTo"in
+e&&e.document?e.document.compatMode==="CSS1Compat"&&e.document.documentElement["client"+b]||e.document.body["client"+b]:e.nodeType===9?Math.max(e.documentElement["client"+b],e.body["scroll"+b],e.documentElement["scroll"+b],e.body["offset"+b],e.documentElement["offset"+b]):f===w?c.css(e,d):this.css(d,typeof f==="string"?f:f+"px")}});A.jQuery=A.$=c})(window);
index 13196b2..49b76a3 100644 (file)
@@ -12,7 +12,7 @@
  *
  * You can also pass an options object with the following keys:
  *   text
- *     "title" to get the in-field label from the field's title attribute 
+ *     "title" to get the in-field label from the field's title attribute
  *      (this is the default)
  *     "label" to get the in-field label from the inner text of the field's label
  *      (note that the label must be attached to the field with for="fieldid")
@@ -22,7 +22,7 @@
  *   labelledClass
  *     a class that will be applied to the input field when it contains the
  *      label and removed when it contains user input. Defaults to blank.
- *  
+ *
  */
 jQuery.fn.labelify = function(settings) {
   settings = jQuery.extend({
@@ -51,7 +51,7 @@ jQuery.fn.labelify = function(settings) {
     if (!lookupval) { return; }
 
     // need to strip newlines because the browser strips them
-    // if you set textbox.value to a string containing them    
+    // if you set textbox.value to a string containing them
     $(this).data("label",lookup(this).replace(/\n/g,''));
     $(this).focus(function() {
       if (this.value === $(this).data("label")) {
@@ -64,7 +64,7 @@ jQuery.fn.labelify = function(settings) {
         $(this).addClass(settings.labelledClass);
       }
     });
-    
+
     var removeValuesOnExit = function() {
       jQuery_labellified_elements.each(function(){
         if (this.value === $(this).data("label")) {
@@ -73,10 +73,10 @@ jQuery.fn.labelify = function(settings) {
         }
       })
     };
-    
+
     $(this).parents("form").submit(removeValuesOnExit);
     $(window).unload(removeValuesOnExit);
-    
+
     if (this.value !== this.defaultValue) {
       // user already started typing; don't overwrite their work!
       return;
diff --git a/wolnelektury/static/js/jquery.marquee.js b/wolnelektury/static/js/jquery.marquee.js
new file mode 100644 (file)
index 0000000..d0200ef
--- /dev/null
@@ -0,0 +1,155 @@
+/**
+* author Remy Sharp
+* url http://remysharp.com/tag/marquee
+*/
+
+(function ($) {
+    $.fn.marquee = function (klass) {
+        var newMarquee = [],
+            last = this.length;
+
+        // works out the left or right hand reset position, based on scroll
+        // behavior, current direction and new direction
+        function getReset(newDir, marqueeRedux, marqueeState) {
+            var behavior = marqueeState.behavior, width = marqueeState.width, dir = marqueeState.dir;
+            var r = 0;
+            if (behavior == 'alternate') {
+                r = newDir == 1 ? marqueeRedux[marqueeState.widthAxis] - (width*2) : width;
+            } else if (behavior == 'slide') {
+                if (newDir == -1) {
+                    r = dir == -1 ? marqueeRedux[marqueeState.widthAxis] : width;
+                } else {
+                    r = dir == -1 ? marqueeRedux[marqueeState.widthAxis] - (width*2) : 0;
+                }
+            } else {
+                r = newDir == -1 ? marqueeRedux[marqueeState.widthAxis] : 0;
+            }
+            return r;
+        }
+
+        // single "thread" animation
+        function animateMarquee() {
+            var i = newMarquee.length,
+                marqueeRedux = null,
+                $marqueeRedux = null,
+                marqueeState = {},
+                newMarqueeList = [],
+                hitedge = false;
+                
+            while (i--) {
+                marqueeRedux = newMarquee[i];
+                $marqueeRedux = $(marqueeRedux);
+                marqueeState = $marqueeRedux.data('marqueeState');
+                
+                if ($marqueeRedux.data('paused') !== true) {
+                    // TODO read scrollamount, dir, behavior, loops and last from data
+                    marqueeRedux[marqueeState.axis] += (marqueeState.scrollamount * marqueeState.dir);
+
+                    // only true if it's hit the end
+                    hitedge = marqueeState.dir == -1 ? marqueeRedux[marqueeState.axis] <= getReset(marqueeState.dir * -1, marqueeRedux, marqueeState) : marqueeRedux[marqueeState.axis] >= getReset(marqueeState.dir * -1, marqueeRedux, marqueeState);
+                    
+                    if ((marqueeState.behavior == 'scroll' && marqueeState.last == marqueeRedux[marqueeState.axis]) || (marqueeState.behavior == 'alternate' && hitedge && marqueeState.last != -1) || (marqueeState.behavior == 'slide' && hitedge && marqueeState.last != -1)) {                        
+                        if (marqueeState.behavior == 'alternate') {
+                            marqueeState.dir *= -1; // flip
+                        }
+                        marqueeState.last = -1;
+
+                        $marqueeRedux.trigger('stop');
+
+                        marqueeState.loops--;
+                        if (marqueeState.loops === 0) {
+                            if (marqueeState.behavior != 'slide') {
+                                marqueeRedux[marqueeState.axis] = getReset(marqueeState.dir, marqueeRedux, marqueeState);
+                            } else {
+                                // corrects the position
+                                marqueeRedux[marqueeState.axis] = getReset(marqueeState.dir * -1, marqueeRedux, marqueeState);
+                            }
+
+                            $marqueeRedux.trigger('end');
+                        } else {
+                            // keep this marquee going
+                            newMarqueeList.push(marqueeRedux);
+                            $marqueeRedux.trigger('start');
+                            marqueeRedux[marqueeState.axis] = getReset(marqueeState.dir, marqueeRedux, marqueeState);
+                        }
+                    } else {
+                        newMarqueeList.push(marqueeRedux);
+                    }
+                    marqueeState.last = marqueeRedux[marqueeState.axis];
+
+                    // store updated state only if we ran an animation
+                    $marqueeRedux.data('marqueeState', marqueeState);
+                } else {
+                    // even though it's paused, keep it in the list
+                    newMarqueeList.push(marqueeRedux);                    
+                }
+            }
+
+            newMarquee = newMarqueeList;
+            
+            if (newMarquee.length) {
+                setTimeout(animateMarquee, 25);
+            }            
+        }
+        
+        // TODO consider whether using .html() in the wrapping process could lead to loosing predefined events...
+        this.each(function (i) {
+            var $marquee = $(this),
+                width = $marquee.attr('width') || $marquee.width(),
+                height = $marquee.attr('height') || $marquee.height(),
+                $marqueeRedux = $marquee.after('<div ' + (klass ? 'class="' + klass + '" ' : '') + 'style="display: block-inline; width: ' + width + 'px; height: ' + height + 'px; overflow: hidden;"><div style="float: left; white-space: nowrap;">' + $marquee.html() + '</div></div>').next(),
+                marqueeRedux = $marqueeRedux.get(0),
+                hitedge = 0,
+                direction = ($marquee.attr('direction') || 'left').toLowerCase(),
+                marqueeState = {
+                    dir : /down|right/.test(direction) ? -1 : 1,
+                    axis : /left|right/.test(direction) ? 'scrollLeft' : 'scrollTop',
+                    widthAxis : /left|right/.test(direction) ? 'scrollWidth' : 'scrollHeight',
+                    last : -1,
+                    loops : $marquee.attr('loop') || -1,
+                    scrollamount : $marquee.attr('scrollamount') || this.scrollAmount || 2,
+                    behavior : ($marquee.attr('behavior') || 'scroll').toLowerCase(),
+                    width : /left|right/.test(direction) ? width : height
+                };
+            
+            // corrects a bug in Firefox - the default loops for slide is -1
+            if ($marquee.attr('loop') == -1 && marqueeState.behavior == 'slide') {
+                marqueeState.loops = 1;
+            }
+
+            $marquee.remove();
+            
+            // add padding
+            if (/left|right/.test(direction)) {
+                $marqueeRedux.find('> div').css('padding', '0 ' + width + 'px');
+            } else {
+                $marqueeRedux.find('> div').css('padding', height + 'px 0');
+            }
+            
+            // events
+            $marqueeRedux.bind('stop', function () {
+                $marqueeRedux.data('paused', true);
+            }).bind('pause', function () {
+                $marqueeRedux.data('paused', true);
+            }).bind('start', function () {
+                $marqueeRedux.data('paused', false);
+            }).bind('unpause', function () {
+                $marqueeRedux.data('paused', false);
+            }).data('marqueeState', marqueeState); // finally: store the state
+            
+            // todo - rerender event allowing us to do an ajax hit and redraw the marquee
+
+            newMarquee.push(marqueeRedux);
+
+            marqueeRedux[marqueeState.axis] = getReset(marqueeState.dir, marqueeRedux, marqueeState);
+            $marqueeRedux.trigger('start');
+            
+            // on the very last marquee, trigger the animation
+            if (i+1 == last) {
+                animateMarquee();
+            }
+        });            
+
+        return $(newMarquee);
+    };
+}(jQuery));
index 7f42489..c403ab9 100644 (file)
-/**\r
- * jQuery.ScrollTo\r
- * Copyright (c) 2007-2008 Ariel Flesler - aflesler(at)gmail(dot)com | http://flesler.blogspot.com\r
- * Dual licensed under MIT and GPL.\r
- * Date: 9/11/2008\r
- *\r
- * @projectDescription Easy element scrolling using jQuery.\r
- * http://flesler.blogspot.com/2007/10/jqueryscrollto.html\r
- * Tested with jQuery 1.2.6. On FF 2/3, IE 6/7, Opera 9.2/5 and Safari 3. on Windows.\r
- *\r
- * @author Ariel Flesler\r
- * @version 1.4\r
- *\r
- * @id jQuery.scrollTo\r
- * @id jQuery.fn.scrollTo\r
- * @param {String, Number, DOMElement, jQuery, Object} target Where to scroll the matched elements.\r
- *       The different options for target are:\r
- *             - A number position (will be applied to all axes).\r
- *             - A string position ('44', '100px', '+=90', etc ) will be applied to all axes\r
- *             - A jQuery/DOM element ( logically, child of the element to scroll )\r
- *             - A string selector, that will be relative to the element to scroll ( 'li:eq(2)', etc )\r
- *             - A hash { top:x, left:y }, x and y can be any kind of number/string like above.\r
- * @param {Number} duration The OVERALL length of the animation, this argument can be the settings object instead.\r
- * @param {Object,Function} settings Optional set of settings or the onAfter callback.\r
- *      @option {String} axis Which axis must be scrolled, use 'x', 'y', 'xy' or 'yx'.\r
- *      @option {Number} duration The OVERALL length of the animation.\r
- *      @option {String} easing The easing method for the animation.\r
- *      @option {Boolean} margin If true, the margin of the target element will be deducted from the final position.\r
- *      @option {Object, Number} offset Add/deduct from the end position. One number for both axes or { top:x, left:y }.\r
- *      @option {Object, Number} over Add/deduct the height/width multiplied by 'over', can be { top:x, left:y } when using both axes.\r
- *      @option {Boolean} queue If true, and both axis are given, the 2nd axis will only be animated after the first one ends.\r
- *      @option {Function} onAfter Function to be called after the scrolling ends. \r
- *      @option {Function} onAfterFirst If queuing is activated, this function will be called after the first scrolling ends.\r
- * @return {jQuery} Returns the same jQuery object, for chaining.\r
- *\r
- * @desc Scroll to a fixed position\r
- * @example $('div').scrollTo( 340 );\r
- *\r
- * @desc Scroll relatively to the actual position\r
- * @example $('div').scrollTo( '+=340px', { axis:'y' } );\r
- *\r
- * @dec Scroll using a selector (relative to the scrolled element)\r
- * @example $('div').scrollTo( 'p.paragraph:eq(2)', 500, { easing:'swing', queue:true, axis:'xy' } );\r
- *\r
- * @ Scroll to a DOM element (same for jQuery object)\r
- * @example var second_child = document.getElementById('container').firstChild.nextSibling;\r
- *                     $('#container').scrollTo( second_child, { duration:500, axis:'x', onAfter:function(){\r
- *                             alert('scrolled!!');                                                                                                                               \r
- *                     }});\r
- *\r
- * @desc Scroll on both axes, to different values\r
- * @example $('div').scrollTo( { top: 300, left:'+=200' }, { axis:'xy', offset:-20 } );\r
- */\r
-;(function( $ ){\r
-       \r
-       var $scrollTo = $.scrollTo = function( target, duration, settings ){\r
-               $(window).scrollTo( target, duration, settings );\r
-       };\r
-\r
-       $scrollTo.defaults = {\r
-               axis:'y',\r
-               duration:1\r
-       };\r
-\r
-       // Returns the element that needs to be animated to scroll the window.\r
-       // Kept for backwards compatibility (specially for localScroll & serialScroll)\r
-       $scrollTo.window = function( scope ){\r
-               return $(window).scrollable();\r
-       };\r
-\r
-       // Hack, hack, hack... stay away!\r
-       // Returns the real elements to scroll (supports window/iframes, documents and regular nodes)\r
-       $.fn.scrollable = function(){\r
-               return this.map(function(){\r
-                       // Just store it, we might need it\r
-                       var win = this.parentWindow || this.defaultView,\r
-                               // If it's a document, get its iframe or the window if it's THE document\r
-                               elem = this.nodeName == '#document' ? win.frameElement || win : this,\r
-                               // Get the corresponding document\r
-                               doc = elem.contentDocument || (elem.contentWindow || elem).document,\r
-                               isWin = elem.setInterval;\r
-\r
-                       return elem.nodeName == 'IFRAME' || isWin && $.browser.safari ? doc.body\r
-                               : isWin ? doc.documentElement\r
-                               : this;\r
-               });\r
-       };\r
-\r
-       $.fn.scrollTo = function( target, duration, settings ){\r
-               if( typeof duration == 'object' ){\r
-                       settings = duration;\r
-                       duration = 0;\r
-               }\r
-               if( typeof settings == 'function' )\r
-                       settings = { onAfter:settings };\r
-                       \r
-               settings = $.extend( {}, $scrollTo.defaults, settings );\r
-               // Speed is still recognized for backwards compatibility\r
-               duration = duration || settings.speed || settings.duration;\r
-               // Make sure the settings are given right\r
-               settings.queue = settings.queue && settings.axis.length > 1;\r
-               \r
-               if( settings.queue )\r
-                       // Let's keep the overall duration\r
-                       duration /= 2;\r
-               settings.offset = both( settings.offset );\r
-               settings.over = both( settings.over );\r
-\r
-               return this.scrollable().each(function(){\r
-                       var elem = this,\r
-                               $elem = $(elem),\r
-                               targ = target, toff, attr = {},\r
-                               win = $elem.is('html,body');\r
-\r
-                       switch( typeof targ ){\r
-                               // A number will pass the regex\r
-                               case 'number':\r
-                               case 'string':\r
-                                       if( /^([+-]=)?\d+(px)?$/.test(targ) ){\r
-                                               targ = both( targ );\r
-                                               // We are done\r
-                                               break;\r
-                                       }\r
-                                       // Relative selector, no break!\r
-                                       targ = $(targ,this);\r
-                               case 'object':\r
-                                       // DOMElement / jQuery\r
-                                       if( targ.is || targ.style )\r
-                                               // Get the real position of the target \r
-                                               toff = (targ = $(targ)).offset();\r
-                       }\r
-                       $.each( settings.axis.split(''), function( i, axis ){\r
-                               var Pos = axis == 'x' ? 'Left' : 'Top',\r
-                                       pos = Pos.toLowerCase(),\r
-                                       key = 'scroll' + Pos,\r
-                                       old = elem[key],\r
-                                       Dim = axis == 'x' ? 'Width' : 'Height',\r
-                                       dim = Dim.toLowerCase();\r
-\r
-                               if( toff ){// jQuery / DOMElement\r
-                                       attr[key] = toff[pos] + ( win ? 0 : old - $elem.offset()[pos] );\r
-\r
-                                       // If it's a dom element, reduce the margin\r
-                                       if( settings.margin ){\r
-                                               attr[key] -= parseInt(targ.css('margin'+Pos)) || 0;\r
-                                               attr[key] -= parseInt(targ.css('border'+Pos+'Width')) || 0;\r
-                                       }\r
-                                       \r
-                                       attr[key] += settings.offset[pos] || 0;\r
-                                       \r
-                                       if( settings.over[pos] )\r
-                                               // Scroll to a fraction of its width/height\r
-                                               attr[key] += targ[dim]() * settings.over[pos];\r
-                               }else\r
-                                       attr[key] = targ[pos];\r
-\r
-                               // Number or 'number'\r
-                               if( /^\d+$/.test(attr[key]) )\r
-                                       // Check the limits\r
-                                       attr[key] = attr[key] <= 0 ? 0 : Math.min( attr[key], max(Dim) );\r
-\r
-                               // Queueing axes\r
-                               if( !i && settings.queue ){\r
-                                       // Don't waste time animating, if there's no need.\r
-                                       if( old != attr[key] )\r
-                                               // Intermediate animation\r
-                                               animate( settings.onAfterFirst );\r
-                                       // Don't animate this axis again in the next iteration.\r
-                                       delete attr[key];\r
-                               }\r
-                       });                     \r
-                       animate( settings.onAfter );                    \r
-\r
-                       function animate( callback ){\r
-                               $elem.animate( attr, duration, settings.easing, callback && function(){\r
-                                       callback.call(this, target, settings);\r
-                               });\r
-                       };\r
-                       function max( Dim ){\r
-                               var attr ='scroll'+Dim,\r
-                                       doc = elem.ownerDocument;\r
-                               \r
-                               return win\r
-                                               ? Math.max( doc.documentElement[attr], doc.body[attr]  )\r
-                                               : elem[attr];\r
-                       };\r
-               }).end();\r
-       };\r
-\r
-       function both( val ){\r
-               return typeof val == 'object' ? val : { top:val, left:val };\r
-       };\r
-\r
+/**
+ * jQuery.ScrollTo
+ * Copyright (c) 2007-2008 Ariel Flesler - aflesler(at)gmail(dot)com | http://flesler.blogspot.com
+ * Dual licensed under MIT and GPL.
+ * Date: 9/11/2008
+ *
+ * @projectDescription Easy element scrolling using jQuery.
+ * http://flesler.blogspot.com/2007/10/jqueryscrollto.html
+ * Tested with jQuery 1.2.6. On FF 2/3, IE 6/7, Opera 9.2/5 and Safari 3. on Windows.
+ *
+ * @author Ariel Flesler
+ * @version 1.4
+ *
+ * @id jQuery.scrollTo
+ * @id jQuery.fn.scrollTo
+ * @param {String, Number, DOMElement, jQuery, Object} target Where to scroll the matched elements.
+ *       The different options for target are:
+ *             - A number position (will be applied to all axes).
+ *             - A string position ('44', '100px', '+=90', etc ) will be applied to all axes
+ *             - A jQuery/DOM element ( logically, child of the element to scroll )
+ *             - A string selector, that will be relative to the element to scroll ( 'li:eq(2)', etc )
+ *             - A hash { top:x, left:y }, x and y can be any kind of number/string like above.
+ * @param {Number} duration The OVERALL length of the animation, this argument can be the settings object instead.
+ * @param {Object,Function} settings Optional set of settings or the onAfter callback.
+ *      @option {String} axis Which axis must be scrolled, use 'x', 'y', 'xy' or 'yx'.
+ *      @option {Number} duration The OVERALL length of the animation.
+ *      @option {String} easing The easing method for the animation.
+ *      @option {Boolean} margin If true, the margin of the target element will be deducted from the final position.
+ *      @option {Object, Number} offset Add/deduct from the end position. One number for both axes or { top:x, left:y }.
+ *      @option {Object, Number} over Add/deduct the height/width multiplied by 'over', can be { top:x, left:y } when using both axes.
+ *      @option {Boolean} queue If true, and both axis are given, the 2nd axis will only be animated after the first one ends.
+ *      @option {Function} onAfter Function to be called after the scrolling ends.
+ *      @option {Function} onAfterFirst If queuing is activated, this function will be called after the first scrolling ends.
+ * @return {jQuery} Returns the same jQuery object, for chaining.
+ *
+ * @desc Scroll to a fixed position
+ * @example $('div').scrollTo( 340 );
+ *
+ * @desc Scroll relatively to the actual position
+ * @example $('div').scrollTo( '+=340px', { axis:'y' } );
+ *
+ * @dec Scroll using a selector (relative to the scrolled element)
+ * @example $('div').scrollTo( 'p.paragraph:eq(2)', 500, { easing:'swing', queue:true, axis:'xy' } );
+ *
+ * @ Scroll to a DOM element (same for jQuery object)
+ * @example var second_child = document.getElementById('container').firstChild.nextSibling;
+ *                     $('#container').scrollTo( second_child, { duration:500, axis:'x', onAfter:function(){
+ *                             alert('scrolled!!');
+ *                     }});
+ *
+ * @desc Scroll on both axes, to different values
+ * @example $('div').scrollTo( { top: 300, left:'+=200' }, { axis:'xy', offset:-20 } );
+ */
+;(function( $ ){
+
+       var $scrollTo = $.scrollTo = function( target, duration, settings ){
+               $(window).scrollTo( target, duration, settings );
+       };
+
+       $scrollTo.defaults = {
+               axis:'y',
+               duration:1
+       };
+
+       // Returns the element that needs to be animated to scroll the window.
+       // Kept for backwards compatibility (specially for localScroll & serialScroll)
+       $scrollTo.window = function( scope ){
+               return $(window).scrollable();
+       };
+
+       // Hack, hack, hack... stay away!
+       // Returns the real elements to scroll (supports window/iframes, documents and regular nodes)
+       $.fn.scrollable = function(){
+               return this.map(function(){
+                       // Just store it, we might need it
+                       var win = this.parentWindow || this.defaultView,
+                               // If it's a document, get its iframe or the window if it's THE document
+                               elem = this.nodeName == '#document' ? win.frameElement || win : this,
+                               // Get the corresponding document
+                               doc = elem.contentDocument || (elem.contentWindow || elem).document,
+                               isWin = elem.setInterval;
+
+                       return elem.nodeName == 'IFRAME' || isWin && $.browser.safari ? doc.body
+                               : isWin ? doc.documentElement
+                               : this;
+               });
+       };
+
+       $.fn.scrollTo = function( target, duration, settings ){
+               if( typeof duration == 'object' ){
+                       settings = duration;
+                       duration = 0;
+               }
+               if( typeof settings == 'function' )
+                       settings = { onAfter:settings };
+
+               settings = $.extend( {}, $scrollTo.defaults, settings );
+               // Speed is still recognized for backwards compatibility
+               duration = duration || settings.speed || settings.duration;
+               // Make sure the settings are given right
+               settings.queue = settings.queue && settings.axis.length > 1;
+
+               if( settings.queue )
+                       // Let's keep the overall duration
+                       duration /= 2;
+               settings.offset = both( settings.offset );
+               settings.over = both( settings.over );
+
+               return this.scrollable().each(function(){
+                       var elem = this,
+                               $elem = $(elem),
+                               targ = target, toff, attr = {},
+                               win = $elem.is('html,body');
+
+                       switch( typeof targ ){
+                               // A number will pass the regex
+                               case 'number':
+                               case 'string':
+                                       if( /^([+-]=)?\d+(px)?$/.test(targ) ){
+                                               targ = both( targ );
+                                               // We are done
+                                               break;
+                                       }
+                                       // Relative selector, no break!
+                                       targ = $(targ,this);
+                               case 'object':
+                                       // DOMElement / jQuery
+                                       if( targ.is || targ.style )
+                                               // Get the real position of the target
+                                               toff = (targ = $(targ)).offset();
+                       }
+                       $.each( settings.axis.split(''), function( i, axis ){
+                               var Pos = axis == 'x' ? 'Left' : 'Top',
+                                       pos = Pos.toLowerCase(),
+                                       key = 'scroll' + Pos,
+                                       old = elem[key],
+                                       Dim = axis == 'x' ? 'Width' : 'Height',
+                                       dim = Dim.toLowerCase();
+
+                               if( toff ){// jQuery / DOMElement
+                                       attr[key] = toff[pos] + ( win ? 0 : old - $elem.offset()[pos] );
+
+                                       // If it's a dom element, reduce the margin
+                                       if( settings.margin ){
+                                               attr[key] -= parseInt(targ.css('margin'+Pos)) || 0;
+                                               attr[key] -= parseInt(targ.css('border'+Pos+'Width')) || 0;
+                                       }
+
+                                       attr[key] += settings.offset[pos] || 0;
+
+                                       if( settings.over[pos] )
+                                               // Scroll to a fraction of its width/height
+                                               attr[key] += targ[dim]() * settings.over[pos];
+                               }else
+                                       attr[key] = targ[pos];
+
+                               // Number or 'number'
+                               if( /^\d+$/.test(attr[key]) )
+                                       // Check the limits
+                                       attr[key] = attr[key] <= 0 ? 0 : Math.min( attr[key], max(Dim) );
+
+                               // Queueing axes
+                               if( !i && settings.queue ){
+                                       // Don't waste time animating, if there's no need.
+                                       if( old != attr[key] )
+                                               // Intermediate animation
+                                               animate( settings.onAfterFirst );
+                                       // Don't animate this axis again in the next iteration.
+                                       delete attr[key];
+                               }
+                       });
+                       animate( settings.onAfter );
+
+                       function animate( callback ){
+                               $elem.animate( attr, duration, settings.easing, callback && function(){
+                                       callback.call(this, target, settings);
+                               });
+                       };
+                       function max( Dim ){
+                               var attr ='scroll'+Dim,
+                                       doc = elem.ownerDocument;
+
+                               return win
+                                               ? Math.max( doc.documentElement[attr], doc.body[attr]  )
+                                               : elem[attr];
+                       };
+               }).end();
+       };
+
+       function both( val ){
+               return typeof val == 'object' ? val : { top:val, left:val };
+       };
+
 })( jQuery );
\ No newline at end of file
index e4fd74d..06ad40c 100644 (file)
@@ -4,10 +4,10 @@
       choices: []
     };
     $.extend(settings, options);
-    
+
     var input = $(this).hide();
     var values = input.val().split(',');
-    
+
     var container = $('<div></div>').insertAfter($(this));
     var choicesList = $('<ol class="choices connectedSortable"></ol>').appendTo(container).css({
       width: 200, float: 'left', minHeight: 200, backgroundColor: '#eee', margin: 0, padding: 0
@@ -19,7 +19,7 @@
     $.each(settings.choices, function() {
       choiceIds.push('' + this.id);
     });
-    
+
     function createItem(hash) {
       return $('<li>' + hash.name + '</li>').css({
         backgroundColor: '#cff',
         margin: 0
       }).data('obj-id', hash.id);
     }
-    
+
     $.each(settings.choices, function() {
       if ($.inArray('' + this.id, values) == -1) {
         choicesList.append(createItem(this));
       }
     });
-    
+
     $.each(values, function() {
       var index = $.inArray('' + this, choiceIds); // Why this[0]?
       if (index != -1) {
         valuesList.append(createItem(settings.choices[index]));
       }
     });
-    
+
     choicesList.sortable({
                connectWith: '.connectedSortable'
        }).disableSelection();
-       
+
        valuesList.sortable({
                connectWith: '.connectedSortable',
                update: function() {
diff --git a/wolnelektury/static/js/widget.js b/wolnelektury/static/js/widget.js
new file mode 100644 (file)
index 0000000..8a82024
--- /dev/null
@@ -0,0 +1,64 @@
+/* create basic elements */
+var id          = "wl";
+var widget      = document.getElementById(id);
+var linkLogo    = document.createElement('a');
+var logo        = document.createElement('img');
+var form        = document.createElement('form');
+var inputText   = document.createElement('input');
+var inputSubmit = document.createElement('input');
+var body        = document.getElementsByTagName('body')
+var stylesheet = document.createElement('link');
+
+/* set attributes of created elements */
+stylesheet.setAttribute('type', 'text/css');
+stylesheet.setAttribute('rel', 'stylesheet');
+stylesheet.setAttribute('href', 'http://lektury.staging.nowoczesnapolska.org.pl/static/css/widget.css');
+linkLogo.setAttribute('href', 'http://lektury.staging.nowoczesnapolska.org.pl');
+logo.setAttribute('src', 'http://lektury.staging.nowoczesnapolska.org.pl/static/img/logo.png');
+form.setAttribute('action', 'http://lektury.staging.nowoczesnapolska.org.pl/katalog/szukaj/');
+form.setAttribute('method', 'get');
+form.setAttribute('accept-charset', 'utf-8');
+form.setAttribute('id', 'wl-form');
+inputText.setAttribute('type', 'text');
+inputText.setAttribute('title', 'tytul, autor, motyw/temat, epoka, rodzaj, gatunek');
+inputText.setAttribute('value', '');
+inputText.setAttribute('name', 'q');
+inputText.setAttribute('id', 'id_qq');
+inputText.setAttribute('size', '13');
+inputSubmit.setAttribute('type', 'image');
+inputSubmit.setAttribute('src', 'http://lektury.staging.nowoczesnapolska.org.pl/static/img/search.png');
+inputSubmit.setAttribute('style', 'position:relative; top:5px; margin-left:5px');
+
+/* import jquery and autocomplete */
+var scriptJ = document.createElement('script');
+scriptJ.setAttribute('type', 'text/javascript');
+scriptJ.setAttribute('src', 'http://lektury.staging.nowoczesnapolska.org.pl/static/js/jquery.js');
+
+var scriptAutoComplete = document.createElement('script');
+scriptAutoComplete.setAttribute('type', 'text/javascript');
+scriptAutoComplete.setAttribute('src', 'http://lektury.staging.nowoczesnapolska.org.pl/static/js/jquery-ui-1.8.2.custom.min.js');
+
+var scriptInit = document.createElement('script');
+scriptInit.setAttribute('type', 'text/javascript');
+scriptInit.setAttribute('src', 'http://lektury.staging.nowoczesnapolska.org.pl/static/js/widgetInit.js');
+
+body[0].appendChild(scriptJ);
+body[0].appendChild(scriptAutoComplete);
+body[0].appendChild(scriptInit);
+
+/* append elements to widget */
+widget.appendChild(stylesheet);
+widget.appendChild(linkLogo);
+linkLogo.appendChild(logo);
+widget.appendChild(form);
+form.appendChild(inputText);
+form.appendChild(inputSubmit);
+
+/* ...and a little make-up */
+widget.style.borderColor = "#84BF2A";
+widget.style.borderWidth = "2px";
+widget.style.borderStyle = "solid";
+widget.style.width = "160px";
+widget.style.padding = "10px";
+widget.style.fontSize = "12px";
+form.style.paddingTop = "10px";
diff --git a/wolnelektury/static/js/widgetInit.js b/wolnelektury/static/js/widgetInit.js
new file mode 100644 (file)
index 0000000..0a6e405
--- /dev/null
@@ -0,0 +1,29 @@
+       $(function() {          
+               $("#id_qq").autocomplete({
+                       source: function(request, response) {
+                               $.ajax({
+                                       url: "http://lektury.staging.nowoczesnapolska.org.pl/katalog/jtags/",
+                                       dataType: "jsonp",
+                                       data: {
+                                               featureClass: "P",
+                                               style: "full",
+                                               maxRows: 10,
+                                               q: request.term
+                                       },
+                                       success: function(data) {
+                                               response($.map(data.matches, function(item) {
+                                                       return {
+                                                               label: item,
+                                                               value: item
+                                                       }
+                                               }))
+                                       }                                       
+                               })
+                       },
+                       minLength: 2,
+            select: function(event, ui) {
+                $("#id_qq").val(ui.item.value);
+                $("#wl-form").submit();
+            }                  
+               });
+       });
index 0e2a01e..1277bd2 100644 (file)
     margin: 0;
     padding: 2px;
     list-style: none;
-    min-height: 320px;
+    min-height: 400px;
 }
 
 .sponsors-sponsor {
     margin: 0 40px 2px 0;
     width: 120px;
-    height: 60px;
+    height: 120px;
     border: 1px solid #CCC;
     background-color: #EEE;
     cursor: default;
index 4cb5eb6..33c794a 100644 (file)
@@ -4,12 +4,12 @@
       sponsors: []
     };
     $.extend(settings, options);
-    
+
     var input = $(this).hide();
-    
+
     var container = $('<div class="sponsors"></div>').appendTo(input.parent());
     var groups = $.evalJSON(input.val());
-    
+
     var unusedDiv = $('<div class="sponsors-sponsor-group sponsors-unused-sponsor-group"></div>')
       .appendTo(container)
       .append('<p class="sponsors-sponsor-group-name sponsors-unused-sponsor-group-name">dostępni sponsorzy</p>');
         .sortable({
           connectWith: '.sponsors-sponsor-group-list'
                });
-    
+
     // Edit group name inline
     function editNameInline(name) {
       name.unbind('click.sponsorsFooter');
       var inlineInput = $('<input></input>').val(name.html());
       name.html('');
-      
+
       function endEditing() {
         name.html(inlineInput.val());
         inlineInput.remove();
         input.parents('form').unbind('submit.sponsorsFooter', endEditing);
         return false;
       }
-      
+
       inlineInput.appendTo(name).focus().blur(endEditing);
       input.parents('form').bind('submit.sponsorsFooter', endEditing);
     }
-    
+
     // Remove sponsor with passed id from sponsors array and return it
     function popSponsor(id) {
       for (var i=0; i < settings.sponsors.length; i++) {
       }
       return null;
     }
-    
+
     // Create sponsor group and bind events
     function createGroup(name, sponsors) {
       if (!sponsors) {
         sponsors = [];
       }
-      
+
       var groupDiv = $('<div class="sponsors-sponsor-group"></div>');
-      
+
       $('<a class="sponsors-remove-sponsor-group">X</a>')
         .click(function() {
           groupDiv.fadeOut('slow', function() {
             groupDiv.remove();
           });
         }).appendTo(groupDiv);
-      
+
       $('<p class="sponsors-sponsor-group-name">' + name + '</p>')
         .bind('click.sponsorsFooter', function() {
           editNameInline($(this));
         }).appendTo(groupDiv);
-      
+
       var groupList = $('<ol class="sponsors-sponsor-group-list"></ol>')
         .appendTo(groupDiv)
         .sortable({
           connectWith: '.sponsors-sponsor-group-list'
                });
-      
-      
+
+
       for (var i = 0; i < sponsors.length; i++) {
         $('<li class="sponsors-sponsor"><img src="' + sponsors[i].image + '" alt="' + sponsors[i].name + '"/></li>')
           .data('obj_id', sponsors[i].id)
       }
       return groupDiv;
     }
-    
+
     // Create groups from data in input value
     for (var i = 0; i < groups.length; i++) {
       var group = groups[i];
       var sponsors = [];
-      
+
       for (var j = 0; j < group.sponsors.length; j++) {
         var s = popSponsor(group.sponsors[j]);
         if (s) {
       }
       createGroup(group.name, sponsors).appendTo(container);
     }
-    
+
     // Serialize input value before submiting form
     input.parents('form').submit(function(event) {
       var groups = [];
       });
       input.val($.toJSON(groups));
     });
-    
+
     for (i = 0; i < settings.sponsors.length; i++) {
       $('<li class="sponsors-sponsor"><img src="' + settings.sponsors[i].image + '" alt="' + settings.sponsors[i].name + '"/></li>')
         .data('obj_id', settings.sponsors[i].id)
         .appendTo(unusedList);
     }
-    
+
     $('<button type="button">Dodaj nową grupę</button>')
       .click(function() {
         var newGroup = createGroup('').appendTo(container);
         editNameInline($('.sponsors-sponsor-group-name', newGroup));
       }).prependTo(input.parent());
-    
+
     input.parent().append('<div style="clear: both"></div>');
   };
 })(jQuery);
diff --git a/wolnelektury/static/widget.html b/wolnelektury/static/widget.html
new file mode 100644 (file)
index 0000000..67e5009
--- /dev/null
@@ -0,0 +1,12 @@
+<html>
+<body>
+<!-- START Umiescic ten element, w miejscu w ktorym ma sie pojawic widget -->
+<div id="wl"></div>
+<!-- KONIEC -->
+
+<!-- START Umiescic ten element zaraz przed zamknieciem taga body: </body> -->
+<script type="text/javascript" src="http://lektury.staging.nowoczesnapolska.org.pl/static/js/widget.js"></script>
+<!-- KONIEC -->
+
+</body>
+</html>
index 7ecb7a2..86ad6ac 100644 (file)
@@ -1,27 +1,28 @@
 {% extends 'base.html' %}
+{% load i18n %}
 
 {% block title %}1% podatku na WolneLektury.pl{% endblock title %}
 
 {% block extrahead %}
-    <link rel="stylesheet" href="/static/css/reset.css" type="text/css" charset="utf-8" />
-    <link rel="stylesheet" href="/static/css/960.css" type="text/css" charset="utf-8" />
-    <link rel="stylesheet" href="/static/css/text.css" type="text/css" charset="utf-8" />
-    <link rel="stylesheet" href="/static/css/1percent.css" type="text/css" charset="utf-8" />
+    <link rel="stylesheet" href="{{ STATIC_URL }}css/reset.css" type="text/css" charset="utf-8" />
+    <link rel="stylesheet" href="{{ STATIC_URL }}css/960.css" type="text/css" charset="utf-8" />
+    <link rel="stylesheet" href="{{ STATIC_URL }}css/text.css" type="text/css" charset="utf-8" />
+    <link rel="stylesheet" href="{{ STATIC_URL }}css/1percent.css" type="text/css" charset="utf-8" />
 {% endblock extrahead %}
 
 {% block bodycontent %}
     <div id="onepercent-content" class="container_12">
-        
+
         <div id="header" class="grid_12">
             <div id="logos" class="alpha grid_5 suffix_1">
-                <img src="/static/img/logo-big.png" />
-                <img src="/static/img/1percent-big.png" />
+                <img src="{{ STATIC_URL }}img/logo-big.png" />
+                <img src="{{ STATIC_URL }}img/1percent-big.png" />
             </div>
             <div id="title" class="omega grid_6">
-                <img src="/static/img/tagline.png" />
+                <img src="{{ STATIC_URL }}img/tagline.png" />
             </div>
         </div>
-        
+
         <div id="lists" class="grid_12">
             <div id="why" class="alpha grid_6">
                 <h2>Dlaczego warto?</h2>
                 <p>Przy wypełnianiu formularza PIT w polu <em>wniosek o przekazanie 1% podatku na rzecz OPP</em> wpisz:</p>
 <pre>Fundacja Nowoczesna Polska
 KRS 0000070056</pre>
-                <img src="/static/img/pit37.png" />
+                <img src="{{ STATIC_URL }}img/pit37.png" />
                 <a href="https://www.pitroczny.pl/pit?krs=0000070056"><img src="http://www.pitroczny.pl/pl/resources/images/1oppmini.png" alt="1% dla OPP" style="float: left; margin: 8px 8px 0 0" ></a>
                 <p>Skorzystaj z programu ułatwiającego przygotowanie deklaracji podatkowej on-line.</p>
             </div>
         </div>
-        
+
         <div id="copy" class="grid_12">
             <p>Biblioteka Wolne Lektury to projekt realizowany przez Fundację Nowoczesna Polska. Rozwijamy się tylko dzięki pomocy wolontariuszy i darczyńców. Pomóż nam! Dzięki 1% podatku dodajemy nowe lektury i nowe funkcjonalności.</p>
             <p>Fundacja jest organizacją pożytku publicznego. Bez ponoszenia dodatkowych kosztów Twoi rodzice mogą wspomóc rozwój internetowej biblioteki Wolne Lektury. Co ważne, te pieniądze i tak nie zostaną w ich kieszeni. Jeśli nie podarują ich Fundacji Nowoczesna Polska lub innej organizacji pożytku publicznego, to rząd zdecyduje, jak je wydać. Powiedz rodzicom o możliwości przekazania 1% podatku i przekonaj ich, że warto samodzielnie zadecydować, co stanie się z częścią ich podatków.

Dzięki uzyskanym w ten sposób środkom będziemy mogli opublikować na stronie Wolnych Lektur jeszcze więcej tekstów oraz dodać nowe narzędzia ułatwiające czytanie. Dzięki temu biblioteka będzie jeszcze bardziej przydatnym i przyjaznym miejscem w sieci.</p>
         </div>
-        
+
         <div class="grid_12">
             <a id="back" href="{% url main_page %}">Wróć do serwisu Wolne Lektury</a>
         </div>
index e51ec82..50a56ea 100644 (file)
@@ -1,19 +1,20 @@
+{% load i18n %}
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
         "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 <html xmlns="http://www.w3.org/1999/xhtml" lang="pl" xml:lang="pl">
 <head>
-<title>404 - Zagubiona strona w WolneLektury.pl</title>
+<title>404 - {% trans "Page does not exist" %} - WolneLektury.pl</title>
 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
-<link rel="stylesheet" type="text/css" href="http://yui.yahooapis.com/2.5.2/build/reset/reset-min.css"> 
-<link rel="stylesheet" href="/static/css/error.css" type="text/css" />
+<link rel="stylesheet" type="text/css" href="http://yui.yahooapis.com/2.5.2/build/reset/reset-min.css">
+<link rel="stylesheet" href="{{ STATIC_URL }}css/error.css" type="text/css" />
 </head>
 
 <body>
 
-<a href="/"><img src="/static/img/logo.png" /></a>
-<p class="haj" style="font-weight: bold">Podana strona nie istnieje</p>
+<a href="/"><img src="{{ STATIC_URL }}img/logo.png" /></a>
+<p class="haj" style="font-weight: bold">{% trans "Page does not exist" %}</p>
 <p>
-Przepraszamy, ale ta strona nie istnieje. Sprawdź czy podałeś dobry adres, lub przejdź do <a href="/">strony głównej</a>.
+{% trans "We are sorry, but this page does not exist. Please check if you entered correct address or go to "%} <a href="/">{% trans "main page" %}</a>.
 </p>
 
 <script src="http://www.google-analytics.com/urchin.js" type="text/javascript">
index 8346afe..e0b2bbb 100644 (file)
@@ -1,20 +1,58 @@
+{% load i18n %}
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
         "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 <html xmlns="http://www.w3.org/1999/xhtml" lang="pl" xml:lang="pl">
 <head>
-<title>500 - Błąd serwera w WolneLektury.pl</title>
+<title>500 - {% trans "Server error" %} WolneLektury.pl</title>
 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
-<link rel="stylesheet" type="text/css" href="http://yui.yahooapis.com/2.5.2/build/reset/reset-min.css"> 
-<link rel="stylesheet" href="/static/css/error.css" type="text/css" />
+<link rel="stylesheet" type="text/css" href="http://yui.yahooapis.com/2.5.2/build/reset/reset-min.css">
+<style type="text/css">
+
+body {
+font-family: verdana, arial, sans-serif;
+margin: 2em;
+font-size: 100%;
+}
+
+p {
+width: 450px;
+margin-top: 0.5em;
+}
+
+img {
+    border: none;
+}
+
+.haj {
+    background-color: #ffc;
+    font-weight: bold;
+}
+
+a:link {
+    color: #037;
+    text-decoration: underline;
+}
+
+a:visited {
+    color: #636;
+}
+
+a:active {
+    color: #900;
+    text-decoration: none;
+}
+a:hover {
+    color: #d46400;
+}
+</style>
+
 </head>
 
 <body>
 
-<a href="/"><img src="/static/img/logo.png" /></a>
-<p class="haj" style="font-weight: bold">Błąd serwera</p>
-<p>
-Przepraszamy, ale wystąpił błąd serwera. Na pewno już się nim zajmujemy i postaramy się naprawić tak szybko jak to tylko możliwe. Do tego czasu proponujemy żebyś przeszedł do <a href="/">strony głównej</a>.
-</p>
+<a href="/"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAABKCAYAAAD+IBtNAAAACXBIWXMAAAMTAAADEwE9ZoPHAAAgAElEQVR4nO2dd5iU1fX4P+e+78zs7MIqIIigsLusikFBWERRUazYNSr4jVKjASMqIGCJbdAkVLGiwZ+NYgnExGiMGkSwIrJUgwpIF1B63d0p7z2/P2Zm2Q4LKyXO53n22SnnnnvOfee8t7y3CDXAY5/mnOClmc+MZal15DOJ6We73ILPQ23XbqwJ/XuLKrJzWq1f+aweF7hg1wci6IHMP8X/HlITSobl5zRx1axU5QfQo0QkLfHVd9YyTZQPNvy09aMRV2/cURP5JVFFdn3oP9lVOd8xpiPQAaEegEvhsXIBa2oyvxS/PGokQABGzmq2wqj8Y0dG4J7MbdFTY0bbi6Nng14gSB0gqsoMa3nf8XuvDWqzfCXAqFm53WJil9/bdtlne5OPKhKb4p4jrr+bWr0SoQGqEYWZKuZjUXuuiJzsnl9YL1WDpNhf3JpSpPCxwrmhFgsjwFeJvydDismccUJb6/cuRuUix2GIRk3/0MtZTUO9VhSB9nOsWQtUGSDbPwycEDBOj8hU29U40sSqXYSVN4xrP3AKwtPlSgoAIlMDX6PyWSo4UtQENRcgnpmuju06dEGTOve1XLUl+XlIsLA4GTB/HDH7hA4G+0ntk92LgbctLBToUJne8BROEkkbKyIdsLpZRF61nnnJf/GueeVsmEhmTOVXGMbXlF8pftmYmlJkC51pghh/xH9hVXIFbRZ/rqo/euh1AGrtLBHNejz/pGMqTOCkPYxQX6x3vbu58Bj3gsI7KwoOgHDDtHaImKgX+3S/HUqRghoMkPvO+26FKsvV04urkgsJVlX+IXDl2Pw8X6ETfkORaNSLdSsrqxPJNMpVWEa4F0XelC5EqtIt1pyDakGwTnT2/vqTIgXUYIAktL2H0GlPYmLM3wWps0W2nR9qu3ajKu8YY7uWlYs2Srsexfq2FE3em+zF6CUY/UTaEt0X81OkKEuNBoiV2AREjhv9xQntqpJrunzxNLDrfJbOAMboOyCnDMvPaVJSTixdrZo3pQs795S3fkg9QfM85YP98yJFit3UaIDck7fiSxVdYl29uSq5Ll3wgAlWuSYU6ujuNJEpAG6MK5Iy+kHwOISO1rOv7E3eERu8GBEjsfD7++NDihQlqdkmFiAwHvT/QvmN0quSi4h9WYR6mZetuDDUZvVaVBdax7k8+X3YZ6+3sCqtU9H0vcrYlU4WXRnoxHf750GKFLup8QCJoeMRrZ0RC1xbldwf2q74DsuXFuf3AIJMEbXnj83P8wEYlevxzPg9Pc/QSfiLpmR0MlYvdaymmlcpapQaD5B72y5bpapTxXUGDc9vep5q5U/rrcOLKlwxdFrzLM9Gp4hI2k7deLL+M72RKGdorGBcRen0ZdJiU/zXhaemvRqrG1zvGPs+4BShz9S0Pyl+2dR4gADYSPQ+taijvo8em52zbPjM3NCjM0/MLitXEAyMF9FVbnr4tvXBoo9R9Tzx5YVredcqfJ52GUtLykc+Ss+LTQmOiTUJrlXj/A2hgwjjY55e6H5W2LDWRZGvfw5/UvxyqbG5WBXxp1nNTg6g3VTNjSLaGJhurX2lwAn/LdR2bQHAiJnZ3R1jnosaudbx9C0xZkC/rWuuVWPf8J9f9JI+RSDcPP0WY7S3CC2BHxQmx2xsUvDC6MzUlJIUPyc/a4AkCSkmMKdZR8dqF1G5GiRDlMkxx76cs2zZjFVNc9/CcAWqhSYWbnnzpg2SuTG8Otw4vYfj6AOgR1vh7yYae9a9OPZpMih0Ko1j1t8LkTPFSHM8/cC9KPz7A+FTil8GByRAShJSjP/LZu0dV6911FzjmegthXkrPw7Mzr6QHYHFiSfyEpmW9rqxXGPVDPMHCsbKOawDCH9Ac3UDFzrWXILoJQhWkQXGyvyota8GOxV9dKB9SvG/ywEPEIBpWVlpzWOxlkE1tQs0Nr/R2tILq/RdmsbSgiuwDN4Z079lOF4HFd+FRvQChMaoWoWZ1upfA2H/q3LljgO6MCvFL4cDEiAKZn3j3NN9fr0cy6UoLTGJmcQqmwuNd2bj5csXFcuHMNGz074VkRNKKNlkRaeK5/3LF057LxUUKQ4EP1uAKJjNTZpcIPi6IVyWWOkXQfnCWpkS1aIP/a5rRM0XotKrzqqlpYZ0dTwZXuPAOQjiRM3X0qlw9c9la4oUlVGjAbIlO7upetoHIyermjwRGmH5XsR7Rz1nSuSHnZ805Kddmpfn27Jp0/Wo8yiAGys6PXPNmk15vXunazjtJN/6TUt21orYQFqjfIx8LMibtVce8dH06aFYTdqbIsWeqNEA2dgku6uIjBXkO1HmYL2JdX5Y8XHy+zWNGh3ndwK/cx3prUgdPJ6P+Hk0LeZmXJP9m9XbmmydIUJbsN/FdhRc5Dsi0MB6/l6C/Y0VEdT+Uzwz+Yg1R05JBUuKA8HP3gdZddRxjWqn+6+3jnYRy5kI21HzWlhiI45ZsWLF6nonNE6vFVvy23bt265Or79Q4DaFQWr5fO6EJ7oDtOgc8gfStl6hoj0EuUxhsxheR+2EOeOeSq39SPGz8bMEyJbs7KZW5VqxXItwFqAiZqoSe3k+/OO8FSuKkrKbs3LuVZVzLz73ij4qsjJG7Gq/9cc8Y9/xbFGrBRP+8t+Supt1G9SgthO7UTx6iqGVqn5rxYTmj3t80s/hS4pfNjUaIGsbNUoPumn/VCMXoqqKzLTGvhkJh//aeO3aCjvZW7JyFlnVEfVWLn+xdfcBm8Xo+DmvPDGgTfd+S0Bmzxn/xA2V5df6t3e1Ek/vV7WXRgrXHrNw8uQ9rhtJkaI61OhcLNfxX6lGLgS9T2PhJvVWLm1ff/nyUZUFx09Nm56pVnJ8schbAKI6V1UuAlSU5xSuad/55rqV5Tf3pdHzd4Wj/RFJD6Qf07kmfUmRAmo4QIxxO6mypu6KZcPqrVnzw57kXXV7Wkc/zlyzZhOAODJF0F+d0PnWxhEv8hKiGg7UurEqHYveeGYt2P+oSs8aciNFimJqNEAE7WTiU8/3yGoIYrjBIMV9h6hX+C+A9Iy0i75+7bktKB/gmJ57VBbTF4EOp/bsn7VvlqdIUTE1FiCbc3JOEaGR9dirAAk2yb5OIGC86OQWN/U7rWXX35+4YMJf/quWlXj2ooRxfwXNa9nt1pOr0hWJ1HtbkE0OttzOKClS7A81V4OoXIKqt93oh3sl70hPq/rukatWbfE7Ms2YwHgAMfzLiLk4r3dvX1Hh2rfBFgn+m6pStXByKCIi/7Qq+xwgj+efdMyw/Jyz9zV9itLk9ejd7MT/u73RwbZjf6mxAFHlAkVmZq9YsXVPsluys5say/mInQCAEDTCMQAxMRMRjortSrti4eTJO1HeM2Ku35POGPxHkOPzevRuti/2ezYyxVXz6bDZuXvctijFnrGS/mJGwPf2wbZjf6mRANG4nvai3sd7kl3fqGlrPEaB2VIvI+PfAKJYVa0DsOCV0V8q8o3jSncAa/VNEXJb//auVlXpTS/Y/qGCVdLO2ScnhACAG9N9S18DjMrPHjhq1vFPHaz8axTVpoq2btE55D/YpuwPNRIgG7KyWgpkiuN+WdH32xs3rrelSVa/zVk5C1y/O8caczoSu10WLowAqKgnIrXyevf2ASD2U1HaAjjp6f9SJWKiWmUtMmPyi5tVybdizt0XHyxmMYA45qR9SV+SQfOPzhg+o2m19SimD+gdZfcHOxwRxRMwZOyqdJj+cKBGNq826p6FKGGjxQHy07HHtvT5Ap3E04tjRs5R1ZioeUs1MrDuqlVTBWxSVlQsAnZL9Ehgg8T4rzrS56yr7q79+fPDt7Xpfue7VuT+1t37X6JiP3BU3q+9qs6X5eZjCdPFo9IHi1XhqC5W4TJPtfm+lkOS+uGMa4xjHgVyqpVQid9tram9vzYcdESjIAQKo3WAHw+2OftKjdQggj0bZZPf0+s2ZTV7Y0tWzo8+NzAf5U+eYCz02bBre8O6K7+/qd6qVVNKBgeAoh6ADabXAYgV7HrLs3bY523SdwGEC9d1t0b7qdr1BhmgIp9ub7p1Y+tu/d5s1fPOO9reeEe7Fp1Dfteaj8XQ9MRut5TbIGKPGLsYwEBuKNRxv24cjshmEbJHfnlsy+qkE9QPIJFwcH/yPxRQlQhANC1a/2Dbsj/UzPEHyskY6oE8iTJb1bysjjctHA5/1mhtfHOGqkgGjKvE+yF/f+EH4L7k94kpJE8DT3PppYGWdXPOdsXfSYy90LFytfUZx+/bEvaURYKQTsb5wIvV8sHGFiN+AJ9z+cpmhFi0pySVEVZvXUBcjBu8Gliwt+lUjV8EJBg87AME2ArgF/fog23I/lAzAWLs76LG1NJlu2Y05Kdd1U2uGE9Q1HHq7FH4vffCC2Aq8T/Ouuru2kV1ou09j7MdY89G2W6MVLtjGNvlLXJqxV+neU5z2PcAwRasw8lErb0EeLQaKf0AnkYP/wARswEUz9MGB9uU/aFGAqTeihUVds73FsFaEFTNngOkDJ+/PWIH8J/E3z5zd8c1a0bnNytQJF1dexLwz33VFT19/YbArNqeIidWJ51IPEDcmHPYB4iqXS8iqJpUDbK/qGAFMHDkwbJBBB2VL0tQWkm8BimFKvL4jKxzrOu7UcQerWiBtfr+3acvL3eaVUiwI2fJTwKNhuXnHHFv22Xb9pT/47NOyPHw/CCo0Vsfy292uWclCAQF/CL63KDTlr5XQ+7+7GiiBnEcUgGyvyjxAPE8qXYNUsOGLAZaYUqPZIVezkp77CvnLXzSCZT4bqqCMfxm5Fe51w9u9/1VZVUJug6kkcE0A+YkPx/9fou6bvom585zftwAMPqLrHM913nGw56cXH1gRC5RBVNiMYKqRoHDJkDEeusxBpFUgOw3BlUQjBvLqAl9p/W67ThP/QNR2ojqD57qisDGTcNmvvfq9qrSechiBwV2B8joSQRtlu8dRC8AQNmsqu+KMdmgZ4voFaFpWUeGziszg8DKOgzg2RNJBMjj+ScdE7NFczwyjnx0VvapD562fJH1uf8SqKXKDhESw7s6DdHizr1AgYP7Qk2UzYHCcWS9Kqhy3MG2ZX/YrwBp1b3vCY74X7Nqv4oW1um/cHKo9BFpoZA5eeXmM/zW9LCqHsYuj+768blyC5vUKAJC8fnqnNzrzjOP2JT2daKPsde06d5/pGe1H+ADUBGMCNH6R3XI69270+znn690VM3BrgJBkCOSh5Fqk+y+yeBQlTcCdZb0vPN4wqH8RukZNn2biLjpmf5TgDLnIuqPIDgOpwCvA3he5BEx0hDANaYxsCgisQv94sSaLl06b1V2bvy5jth3B7Vd/lh1/D5YdO7c2VkWbNR4q/qKlk4YtT75uSAb4nvCanPiVeNhuUVsuQBp06PfP2I2/GDZpa4V4Yg7HDTPiOQF/RtfBT4HyOvZrzPITXbZtnNE4h1vIwLq4A82HpTXre9VsyeMmZnUo6IqCIk2N0d3G5Th96Kf7MosehQYAvGltkeYyOV46pf09DdmPz+8XLu+Vc8770AZVLxQUu00VScgRs9E5GwtTB8A/KlSh2K6ETeeNhZ2GgBbcMxvACx8W/Dvxt0Gh5bExubn+bbGNt8rDi7YdWmZ339VVpVV+6PBQT1zCsCwr3JbgPYCUFhaV4/8FOAPbVcUl8OoWaog4nnOHh8UPjYr57cW85TFjr3ntGUDIV7bAdzVhcJinbOb5eFpL3CaW/GWuJuC98eOCmc5ym1RsQP3pn9UGa16DOiyTBmmotmZxCKndu8/3rEFD82e+Py6GKyIP2ST9BO73ZK1aMILy/c1n4NJuQeFqnKmj0C5CXt53fqentf7niOS79t37hxEpViuwPVtjcsNeFRVJqlyNcI6z+NRYFlSToQGVnwTj+42aHdzSiVxd9E0gKN3ba2DiCNGOgGS13PAsEwTWwfmJRznL1oUXtfqxttL2diy511nOCrJu+4yK7SeM/6p8/0b11+Kxn8wNr6BdqVYv7sh+TpgfA2GTmuepUgbACNEal3+w2ujvmr2+XZv6w+O4zwIRFWcQXceT7isLsdxfgRQo6cAOOhIRBwAE4vd36ft7HLnKKqKByCqteLvkcdm5Q4b+VX278rKephBAhkG6T966gmNAbym2UNsdu764dMaH/vnGc3OGvlV7lys5COmL6IXGMyt9qiCXuJ5/6dws0/LT8sZld+sx2Ozcl8IzW9W4fBsm8635QK06drvdqP2DRXNhvgInBFu8Zzga4DMe+WJFaqsBwg6wSpPPj6UKRcgAsYabVvyo9bd+32sxvclRUXPJT+MZDTuhMTvWBY+/2bc4wvb3nhHOyv2fgCxOn5u9hGnzJ/4xENzxj3RLGLsWYouARAht5GNFU8KjPdBwEk2sTLcIxO2tGvTfcDbqnqPlLRVCDqO82Tx3C1ANHo9iE+VCNgu8155Yh6XXhqIHn3UJISggrVe7M2Svp7a7c6+eT36zW3T4874nT0S3r1bo9UGmQ2cjWj8KT9KK6AzImciUhfVLyIS6zC47ZLXKipYD/kxbqo0HTUj51oRuTT+jc6+64wVlWwwofEmlqMZAKO+yD1D4R7FKTXdf/QkgoKemNBvYrX0JgBr3AhQy8lIe9/nyHQRTi2RLIrlJW9H5K/GyC4AFS01KDLy89z2qrykcHPtiJbbBDyv58Dmmu5f1KZHv3/gyNMCq401l1uhjuL1ADBIx7zuA7rHLwozAcSaXhX7e+hTLkCsYEDyku9b9RjQWUTOAbAqZwJ07Bhy1dqHkjIqdiyAGre9iIiCLSqq8ztCoeIpJf99+akv1Orfku8FrVc2b03UINb1Z8aFxEE0fm6hqidWx6vKlrjlcqIWZlySTOuom/jB6FdrrP+7Nt1vv6FNgxOnJGs5g71nwatjpibl2/TsHzLGPKPIqSh3ABT6osU1iBHq922xcCdG/pvIvzAm9goh2iawcXO9Qe2WnlWyeZRk0PyjM+JlpcVHwakrJTvYRwyb3rxp2XQJf+M1iJUMAC9g6yYK61clxbyc438tSPG1M2K7A7iGLxN6WojggqrFjo2J7RBMD9QddPr3N99z3pofVDTRB9SOSR1PLSEgfl5K6lWN15yl8LvrUBWQa6y1r0VjkVPzJ4z+97xXntg6d9zT4xVdC6DGaxc32/4jbo60b9X9jtYV+nyIU64PIqiHktui5+CGGz3d4ao3TJPDjaJN8nr3Tt9asK2/EdMawMLmOtSdDBBD6zkAqhIIbvw18Nek3lN79s8Sj+L15TGf833ytUq8iaWJGsRfYLZQ3F1P4NFz9qtPTmzds98bqNwAIEZPBt4BsKJ1DGBFftVYouvBTY/r1LC1+vj8CU+NSqpq07N/COXhYtXiDAPIXLZ2l83OTRjoNQCwMe8d4zitEAk6Kk9GjPQeeNnmUqNhg+YfnXF0OP1GxfSWCG1GzKr9YEHb74fVmpW7HSFTiA9fx0eqJNdXK/LF6PycTne1XVbqwB9RPASMY2oB+CPuBuuzGKg//MvjexEr+tr43C6idnc/C0CkxYj83DY7dNeXtSh5NKT0uPu0pRPKlCSelR8dAdTc9NhXTSaGjVkT2eoMBUoOb5f7Qc9+fvi2Nj36LwdyPDHPfP3ac1vK2B9DAOs0AZiTXXdcm+VbBwCnODift+7W/28YPQPku7njnig3NH4oUsEols4WMZcEbPTJRkYcRYsn/omIaCRtpDj25uIxe09enD4xVAQgLi+hdrCISQP3jTbd+40QMVMUPQHVMzASH1my8sWCCaN3P31XVUTQRJMtbNesDrC7uyDYv8x+9amJADYmix0nkQxaFAtZ+zrGnGWgbvypPGtU7fioE3hq4YSRPwK06969XpR6IVRvL04GI5J7agVatHAKC8KJPOM1XMH7TYfUunT1aRjpJNDMZ2XqqFnNvsayFiEsxnga1gvigZCw19I+JNhRs5gJXJT4eGNsl3uar5Y3AczZVvWTYfk5V97bdtln5a6AZ9MBBrRfPGt0fu5/FC52HH0JJ1BaDrXJO76J0Tl0xtr7Rs7KXSrQzMK3g9t+P3FQ+QuMb8Wyv9vs3I3AUSr+D/0VjS+JHDd6EsG3nw1FdzTd/LTFfDJ33BOvW3SpQXJ81mtJKDSz9ZKtncRHJ1VygCYAntW5AIRC1nTtN9AzfCAiQRG6gYDaPQ4AHSpU0Adx/pF40UXQ6wBUyVfVxKiduU2QQPxznTFn03cPJtPOe+WJFYr2SXaKEWmi6M1AB0gEh+q3Rf5IqZ1KNNFJN4km1sLJk3cqWvxcYactGLFb2iue6yVocYA4weBE0N1DuKIFxsgxPoquzOs6oN+pPfu/EpO6y0V2B4eqvn18wZo/JN9vKNxiSfSHrLhHAIRC02P+TVu6qOqMEqV0CkY6IXKVqv4aIbOEzhkSsQMBPM8rvgmoxy33nffdik3bCq4B/R7kSMfKlFGfNCluPqkQr4BNfPGWCFrkbe+uyrxS5WV1PSK/d6JOeyAKYF1J7JbvDUd1NV50UGWnb93VhUIi9rK4HUm72WE974+KfTfxgTegM0Vbmmy5RDG3onoHgFhdDWCNadVq+bbrxeXfKP0Eriy+FuFI8eyC/IlPTvGsOVfhHat8JVb+mGnqVrlTzaFEuRpkzrjHnz+1253NjTEDAFD519wN313fqkHzEQ56Z1LOotOlcHsX3nuv1AjO3HFPj2/Z7dY5Lv5HwFyyuyOvP4GM82KRYd+OL1M1G7sOTFNUitd3iJrPEL1CkaklhwiN46xKvlZo0aJzyL9wcigy+/nh2/K69T1fxZ2ESBNBjgeON+r0VEcxJX4qFjYb7KC54596eW4JO0Jt1xaMnHX814K2VKOLk5/fednm7aqbzxo9O/d6tfpHSh7LQPxOjsh31vNG391u+UvJH+aGYMHwBoXp4vjcmYNOW/IvgKEXrtn02Kc5l2tAZohIXYK+s4FvKK2wuKq4/4z1P8H61qPmZDfVItNGYtFFuz7KWRwKTY8BjPzy2LbGBNoUSMEkgMHtlv8/4P+Vva5lGXTWslmqnDBketYRTm2vnhuQzfe1XLVlxKzcb+I1oWwTQTt2rPP+zmO3XLxFfPMBrHF+cFAQaaker6tRFRFJlMMKg+kze/Kz35fMa8HExz+l3HOiw4MKHxTOm/DUXSd2u+XpgJN5dN2VmflMfy9Wp+PpA3c02TIZ5XSs9595rz5T6YGZiWco1+b17p1OmGOiO2y47uZjf6xsw+mYuANc1bu8WKx4irrLpp5FXp2OxmVqSdloWJb4A8lfu/gC6ZtPAWYDzJ4wZmb7zje3jgRrPaNwMSKlBgJU+V7RKVK4/eE5k1/eQAUYvL+D5LpRp9TmE/Ef/feTJ03i70vrNz/OHyhspMY0iqqzccv6bbNHXL1xB8A9JdKMavXTLuBByjCww7LFw6c1bqUZwTOL/n3c30mcVSrKTwg5RgiUTTOozfKVwMr4u+J7BIPP+GEB1ZhSX96nFVtJTE0fNP/oDInoiYn5YJsAEtdsSjKN63mr1TGIyq8WTHz807Y9+5+vnuZ5jt2+zgu89tOEUdWezX0oc1BOmNof2nfuHAwHG32HSBMAK17vea88XeEd87Retx3nxQKnxkxUnIJdM+ZWEhRlCb2clRbqtXv/4APFYzNzPlFjOqC6cFC7pVVudfRzMPqLrHOtz50OgNoxg9otu72szCndB1ztE31LVTW3cK1v8uTJ3oG280BySMzFqg4zJk8ubP2bO7rjdz4SMI66KyuTnfXys6uBah+8czCCAwDVt4EOVvSAN0fG5uf5ttmto5KdUhNzy81SBnA9jeDGB2xWBoNHApsOnJUHnp/lnPSfm7mvP/2xUe2GMGT2uMf3ax3IocTAM5aPcsTX6O7Tlh3wk3p3smWIEWkLoGoX3XXm4nLTZwBwpHgGQKyw1sGdfX0AOOxqkCSzxz9Z4RPsw50Bbb9dd6DzHDojt6ONz1ZAUWuI9a1UOBqL4o+Ps4f9vlSApPjfJaSY2rNz+1urfyp+nmLtQwNPXzW1sjTRNIn6E/MjHGKZlcn9r5AKkF8go+ZkN1VPfm3ypZtCm8QoLVZ5c3C75X8eWEXaaKxgnT/+oB9x3MN+afCeSAXI/yhDFzSp4wv7vlKVLCMaUZUYqA/w44lTZoFG1EPvv/u0paMqe7iYZNGEF1ac2qP/ZoNNL9KChT+vFwefw7KTnmLPOAX2KJBcEVxF0hEyEQkmp9zHUQWdFpFYh3tOWzpyT8GRTGS98Jmeeq0O1zUe1eGwew6SYu8ZMev464y1l6iRUyQ+b60IYY1VWaOefuaGCyYOPLfi079SxNnnAAk9MuY2LFfjdwaE/nDrN3uWf/YuVK/B0QdCD9z+yT7nGxozBqEpPndQ6A99iqeUjxw5PsPzCt177+2zrTKZkjZkBDJnJ+X31ZbdeqtXFiUpaff+2pGi5tn3JpblFEUvlqi3d7tWqDZX1Q7i7fc+SWmqerlEvVLHHOwq2PFkUTi2KfTIs70rkylpQxn5Shky5JnBoSFj3h4y5LnrKhWqbllUbvf+2VEDHKh8DhfKBUho0qQqdyUMjRjT8M9/Hlc8x0nERKqSL49uHD78xdpjx471AUyaNMmpSCqkWmXwisjW0LCxTYrTG3kD1XdFrVOpTAkbKpKv0FokQ1WvVLHH7MmzqsqiUn9K2FFVueyNHaNHTwomr19Sz96UdXXzqS57upaHMqWaWKGhY3IJ68cIm0DeCqaljfQ81x+J7nwO1WxEjlfVI0RkGsoiRW91jHO2NVbw9G84cm3ogb5fhIY88wzKTYgsReQvoYdueyE0ZMzzqvo7I3K+Qh9UL8WYIag+gLKIAN1oVn+VfLuhh8LNKC0wMjD00G3Pl7IxNOZFRX8rIu+p6qWC/Nfvr9UxEt11D+g5Avep0rVimZ1Dd9sglyblH36477QKbQ6NGQp6o0ITQeYRkOtC9922bMiQZ3soOhjV+ZyOuCAAAAXaSURBVK7r3B2L2QcqKgtOqJ+/R3+GPDui2O7KyiXMzXtlh2eHA10Q7sLqoyLmAUU7VKQzdF/f7yvw4/aK8qn4ej7zH5D1oYf7dg2FxrwLfBMK9R0cGvLMMOBUghk9pbDgyqp8PxwoFdkS4SaFRqisVtUHC8Phq++7r/tmVOuBrAcSK+l2r9WwovWI6esodRxly5Ahz3ZWpS/Ct4DB2udCfxpTcm00wHaFTKzeBzpd0TMkwg18u2GEVX0e1doYHarWjg098uxdldh+iQjDgdxIZFd/VEVVT1fR+pXKlKSEfGU2i+iHSHy9BUKQKOeHhj6bo2pfSHx2XSxmiw+8KVsWe+VPabsrLJdq2FGgqj4s9wO11NG5lemsKH1F+VRxPa2q3jR06LN1QC8GvWvs2LE+VHqgXERhQaga1/KQpWzVtx1ARF6JLy2ngYhoKHT7BSKMAo4VWJyRnrn7LEBrn1A4VsQ89OCDfb9V1fg6cUfuFnhOwcWjkrP/dCOuPAKg6NGZtevfZ0S6ipgQyi1x/VrZkWh/Ji3wTHwdu+5enyHs3KNMSYSdldn88MO3TxVkQlxMHgw9dNsLEtHzFFxBkjPbd58BUqYsquVPKbtLl0t17VC0ISJDQw/0/aIynRWlryifSq+nyhKAcFSvVHAVzLr1sfMUbQjyRWbt+gOqcS0PWUoFiOPwNxH5VtVeg8M5rpG/AoQef/lIhXGoRvH5fjN4cPfiOf+qZIuI5zj2DQAksQw2PfANyYNTlKyKc5cXjafJyW+1treuH1W40qqdBFL1sQlGpktRJL5uWnTpPstU02bVeLAr+hyKg8iMEt+VKotq+VPa7lLlUl07BFlwTEO39K7yZXRWlb4UlZSNiCxOvO4iyZaFx80AIvr2Pvt+iFEqQGLpgV1+X/BchAAx3rRWjgJge8FfVPU4EflD6P4+c0qmEWSBqjoxTybEO4GJ5lc4cqQK8d07koVZLnOz+6IoAT755gFVvUGQURXJl0VVzkgYMW9/ZKpjMxBff4/2MsY9R9DicxnLlUU1/UlSrlyqa4eYR/r06VNq360KdJZLr6oVDPtXXDbq2Pnxr/UiRD4QkR2IXg2gPt87++r7oUbpJtb28JBwpGA9sFjRBla9XkOGjLlZVW8QYYMKTig05umRI8fv3vTN1TsE3lbVDt98u/FpVOIrDWO0ROP7a5nEir+KsI6TvCgG5QJB5gENgYqbRLtT+sF2FWR9RjDzXaSiZzplZEpSUr4Km7XMQIaIJs6BN35rvZDC45AYpSlXFnvhT4V2lymXvbcjMXVIK1zPUlJnRemHTJ7sK5tPpWWTeeQ8EVEFPyJfoCxUJSAi60J/6PNd9a7loUvpAKnlDpH4es54h1ZYrMq1AKrUV6vDFb29oGDH+cUXQY3f5wv0FpHVYBs6jvO8wGY8HYtyk4gssc2P+np3XppJor2sSi2J2dMTuacbo4NAcxTtiugjIoSTa9qLSW52Zhmv0AQjwxNNvoYJe5pUIVPShmL5KmyG4iaOZgLoUTJVhBmq9m3QjoLpBRRUVBZ75U9Juyspl2rYkbyeR5XQX6HOitKHunSJlM2nsrIJ3dl1O2h8x0yRBYjGb4Ia/7+Xvh/ylAqQ0KA+GzMzGzTHmKsc47QJPdT3WTJMLzFyh2Ocs30uWVL3yCMefrjvOxkZmQ8Yca4NuMy+//7f/US6aXtMQ98NDz5465JgMJglojdizB2uoxeFunSJUDtwtxjTR9MCs8lMv14cc5GeVG/aSSfVf0Vc9zT8vnseeuj2mcZwpmOcs0MP3f7HzNoN6pDmL7UDhmMCA43IICNcbkRuzAjWGguQWbv+78Thclz3o8pkStpQUr5Sm4GHH7ptsLhyls8XfBsg1Lfvzocf6nsWPt/puE6Hhx/+/QeVlcXe+FPSjsrKZW/t4KQGvcVxztO0wJTdGVSss8L0FeRTVdn4fentjUjXjLSMmRwl9xpxrsWRpwH2xvcUKVKkSJEiRYoUv0j+P1GPgO+VXwPOAAAAAElFTkSuQmCC" /></a>
+<p class="haj" style="font-weight: bold">{% trans "Server error" %}</p>
+{% trans "<p>The Wolnelektury.pl site is currently unavailable. Meanwhile, visit our <a href='http://nowoczesnapolska.org.pl'>blog</a>.</p> <p>Inform our <a href='mailto:fundacja@nowoczesnapolska.org.pl'>administrators</a> about the error.</p>" %}
 
 <script src="http://www.google-analytics.com/urchin.js" type="text/javascript">
 </script>
diff --git a/wolnelektury/templates/503.html b/wolnelektury/templates/503.html
new file mode 100644 (file)
index 0000000..3b9ebe1
--- /dev/null
@@ -0,0 +1,66 @@
+{% load i18n %}
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" lang="pl" xml:lang="pl">
+<head>
+<title>503 - {% trans "Service unavailable" %} WolneLektury.pl</title>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<link rel="stylesheet" type="text/css" href="http://yui.yahooapis.com/2.5.2/build/reset/reset-min.css">
+<style type="text/css">
+
+body {
+font-family: verdana, arial, sans-serif;
+margin: 2em;
+font-size: 100%;
+}
+
+p {
+width: 450px;
+margin-top: 0.5em;
+}
+
+img {
+    border: none;
+}
+
+.haj {
+    background-color: #ffc;
+    font-weight: bold;
+}
+
+a:link {
+    color: #037;
+    text-decoration: underline;
+}
+
+a:visited {
+    color: #636;
+}
+
+a:active {
+    color: #900;
+    text-decoration: none;
+}
+a:hover {
+    color: #d46400;
+}
+</style>
+
+</head>
+
+<body>
+
+<a href="/"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAABKCAYAAAD+IBtNAAAACXBIWXMAAAMTAAADEwE9ZoPHAAAgAElEQVR4nO2dd5iU1fX4P+e+78zs7MIqIIigsLusikFBWERRUazYNSr4jVKjASMqIGCJbdAkVLGiwZ+NYgnExGiMGkSwIrJUgwpIF1B63d0p7z2/P2Zm2Q4LKyXO53n22SnnnnvOfee8t7y3CDXAY5/mnOClmc+MZal15DOJ6We73ILPQ23XbqwJ/XuLKrJzWq1f+aweF7hg1wci6IHMP8X/HlITSobl5zRx1axU5QfQo0QkLfHVd9YyTZQPNvy09aMRV2/cURP5JVFFdn3oP9lVOd8xpiPQAaEegEvhsXIBa2oyvxS/PGokQABGzmq2wqj8Y0dG4J7MbdFTY0bbi6Nng14gSB0gqsoMa3nf8XuvDWqzfCXAqFm53WJil9/bdtlne5OPKhKb4p4jrr+bWr0SoQGqEYWZKuZjUXuuiJzsnl9YL1WDpNhf3JpSpPCxwrmhFgsjwFeJvydDismccUJb6/cuRuUix2GIRk3/0MtZTUO9VhSB9nOsWQtUGSDbPwycEDBOj8hU29U40sSqXYSVN4xrP3AKwtPlSgoAIlMDX6PyWSo4UtQENRcgnpmuju06dEGTOve1XLUl+XlIsLA4GTB/HDH7hA4G+0ntk92LgbctLBToUJne8BROEkkbKyIdsLpZRF61nnnJf/GueeVsmEhmTOVXGMbXlF8pftmYmlJkC51pghh/xH9hVXIFbRZ/rqo/euh1AGrtLBHNejz/pGMqTOCkPYxQX6x3vbu58Bj3gsI7KwoOgHDDtHaImKgX+3S/HUqRghoMkPvO+26FKsvV04urkgsJVlX+IXDl2Pw8X6ETfkORaNSLdSsrqxPJNMpVWEa4F0XelC5EqtIt1pyDakGwTnT2/vqTIgXUYIAktL2H0GlPYmLM3wWps0W2nR9qu3ajKu8YY7uWlYs2Srsexfq2FE3em+zF6CUY/UTaEt0X81OkKEuNBoiV2AREjhv9xQntqpJrunzxNLDrfJbOAMboOyCnDMvPaVJSTixdrZo3pQs795S3fkg9QfM85YP98yJFit3UaIDck7fiSxVdYl29uSq5Ll3wgAlWuSYU6ujuNJEpAG6MK5Iy+kHwOISO1rOv7E3eERu8GBEjsfD7++NDihQlqdkmFiAwHvT/QvmN0quSi4h9WYR6mZetuDDUZvVaVBdax7k8+X3YZ6+3sCqtU9H0vcrYlU4WXRnoxHf750GKFLup8QCJoeMRrZ0RC1xbldwf2q74DsuXFuf3AIJMEbXnj83P8wEYlevxzPg9Pc/QSfiLpmR0MlYvdaymmlcpapQaD5B72y5bpapTxXUGDc9vep5q5U/rrcOLKlwxdFrzLM9Gp4hI2k7deLL+M72RKGdorGBcRen0ZdJiU/zXhaemvRqrG1zvGPs+4BShz9S0Pyl+2dR4gADYSPQ+taijvo8em52zbPjM3NCjM0/MLitXEAyMF9FVbnr4tvXBoo9R9Tzx5YVredcqfJ52GUtLykc+Ss+LTQmOiTUJrlXj/A2hgwjjY55e6H5W2LDWRZGvfw5/UvxyqbG5WBXxp1nNTg6g3VTNjSLaGJhurX2lwAn/LdR2bQHAiJnZ3R1jnosaudbx9C0xZkC/rWuuVWPf8J9f9JI+RSDcPP0WY7S3CC2BHxQmx2xsUvDC6MzUlJIUPyc/a4AkCSkmMKdZR8dqF1G5GiRDlMkxx76cs2zZjFVNc9/CcAWqhSYWbnnzpg2SuTG8Otw4vYfj6AOgR1vh7yYae9a9OPZpMih0Ko1j1t8LkTPFSHM8/cC9KPz7A+FTil8GByRAShJSjP/LZu0dV6911FzjmegthXkrPw7Mzr6QHYHFiSfyEpmW9rqxXGPVDPMHCsbKOawDCH9Ac3UDFzrWXILoJQhWkQXGyvyota8GOxV9dKB9SvG/ywEPEIBpWVlpzWOxlkE1tQs0Nr/R2tILq/RdmsbSgiuwDN4Z079lOF4HFd+FRvQChMaoWoWZ1upfA2H/q3LljgO6MCvFL4cDEiAKZn3j3NN9fr0cy6UoLTGJmcQqmwuNd2bj5csXFcuHMNGz074VkRNKKNlkRaeK5/3LF057LxUUKQ4EP1uAKJjNTZpcIPi6IVyWWOkXQfnCWpkS1aIP/a5rRM0XotKrzqqlpYZ0dTwZXuPAOQjiRM3X0qlw9c9la4oUlVGjAbIlO7upetoHIyermjwRGmH5XsR7Rz1nSuSHnZ805Kddmpfn27Jp0/Wo8yiAGys6PXPNmk15vXunazjtJN/6TUt21orYQFqjfIx8LMibtVce8dH06aFYTdqbIsWeqNEA2dgku6uIjBXkO1HmYL2JdX5Y8XHy+zWNGh3ndwK/cx3prUgdPJ6P+Hk0LeZmXJP9m9XbmmydIUJbsN/FdhRc5Dsi0MB6/l6C/Y0VEdT+Uzwz+Yg1R05JBUuKA8HP3gdZddRxjWqn+6+3jnYRy5kI21HzWlhiI45ZsWLF6nonNE6vFVvy23bt265Or79Q4DaFQWr5fO6EJ7oDtOgc8gfStl6hoj0EuUxhsxheR+2EOeOeSq39SPGz8bMEyJbs7KZW5VqxXItwFqAiZqoSe3k+/OO8FSuKkrKbs3LuVZVzLz73ij4qsjJG7Gq/9cc8Y9/xbFGrBRP+8t+Supt1G9SgthO7UTx6iqGVqn5rxYTmj3t80s/hS4pfNjUaIGsbNUoPumn/VCMXoqqKzLTGvhkJh//aeO3aCjvZW7JyFlnVEfVWLn+xdfcBm8Xo+DmvPDGgTfd+S0Bmzxn/xA2V5df6t3e1Ek/vV7WXRgrXHrNw8uQ9rhtJkaI61OhcLNfxX6lGLgS9T2PhJvVWLm1ff/nyUZUFx09Nm56pVnJ8schbAKI6V1UuAlSU5xSuad/55rqV5Tf3pdHzd4Wj/RFJD6Qf07kmfUmRAmo4QIxxO6mypu6KZcPqrVnzw57kXXV7Wkc/zlyzZhOAODJF0F+d0PnWxhEv8hKiGg7UurEqHYveeGYt2P+oSs8aciNFimJqNEAE7WTiU8/3yGoIYrjBIMV9h6hX+C+A9Iy0i75+7bktKB/gmJ57VBbTF4EOp/bsn7VvlqdIUTE1FiCbc3JOEaGR9dirAAk2yb5OIGC86OQWN/U7rWXX35+4YMJf/quWlXj2ooRxfwXNa9nt1pOr0hWJ1HtbkE0OttzOKClS7A81V4OoXIKqt93oh3sl70hPq/rukatWbfE7Ms2YwHgAMfzLiLk4r3dvX1Hh2rfBFgn+m6pStXByKCIi/7Qq+xwgj+efdMyw/Jyz9zV9itLk9ejd7MT/u73RwbZjf6mxAFHlAkVmZq9YsXVPsluys5say/mInQCAEDTCMQAxMRMRjortSrti4eTJO1HeM2Ku35POGPxHkOPzevRuti/2ezYyxVXz6bDZuXvctijFnrGS/mJGwPf2wbZjf6mRANG4nvai3sd7kl3fqGlrPEaB2VIvI+PfAKJYVa0DsOCV0V8q8o3jSncAa/VNEXJb//auVlXpTS/Y/qGCVdLO2ScnhACAG9N9S18DjMrPHjhq1vFPHaz8axTVpoq2btE55D/YpuwPNRIgG7KyWgpkiuN+WdH32xs3rrelSVa/zVk5C1y/O8caczoSu10WLowAqKgnIrXyevf2ASD2U1HaAjjp6f9SJWKiWmUtMmPyi5tVybdizt0XHyxmMYA45qR9SV+SQfOPzhg+o2m19SimD+gdZfcHOxwRxRMwZOyqdJj+cKBGNq826p6FKGGjxQHy07HHtvT5Ap3E04tjRs5R1ZioeUs1MrDuqlVTBWxSVlQsAnZL9Ehgg8T4rzrS56yr7q79+fPDt7Xpfue7VuT+1t37X6JiP3BU3q+9qs6X5eZjCdPFo9IHi1XhqC5W4TJPtfm+lkOS+uGMa4xjHgVyqpVQid9tram9vzYcdESjIAQKo3WAHw+2OftKjdQggj0bZZPf0+s2ZTV7Y0tWzo8+NzAf5U+eYCz02bBre8O6K7+/qd6qVVNKBgeAoh6ADabXAYgV7HrLs3bY523SdwGEC9d1t0b7qdr1BhmgIp9ub7p1Y+tu/d5s1fPOO9reeEe7Fp1Dfteaj8XQ9MRut5TbIGKPGLsYwEBuKNRxv24cjshmEbJHfnlsy+qkE9QPIJFwcH/yPxRQlQhANC1a/2Dbsj/UzPEHyskY6oE8iTJb1bysjjctHA5/1mhtfHOGqkgGjKvE+yF/f+EH4L7k94kpJE8DT3PppYGWdXPOdsXfSYy90LFytfUZx+/bEvaURYKQTsb5wIvV8sHGFiN+AJ9z+cpmhFi0pySVEVZvXUBcjBu8Gliwt+lUjV8EJBg87AME2ArgF/fog23I/lAzAWLs76LG1NJlu2Y05Kdd1U2uGE9Q1HHq7FH4vffCC2Aq8T/Ouuru2kV1ou09j7MdY89G2W6MVLtjGNvlLXJqxV+neU5z2PcAwRasw8lErb0EeLQaKf0AnkYP/wARswEUz9MGB9uU/aFGAqTeihUVds73FsFaEFTNngOkDJ+/PWIH8J/E3z5zd8c1a0bnNytQJF1dexLwz33VFT19/YbArNqeIidWJ51IPEDcmHPYB4iqXS8iqJpUDbK/qGAFMHDkwbJBBB2VL0tQWkm8BimFKvL4jKxzrOu7UcQerWiBtfr+3acvL3eaVUiwI2fJTwKNhuXnHHFv22Xb9pT/47NOyPHw/CCo0Vsfy292uWclCAQF/CL63KDTlr5XQ+7+7GiiBnEcUgGyvyjxAPE8qXYNUsOGLAZaYUqPZIVezkp77CvnLXzSCZT4bqqCMfxm5Fe51w9u9/1VZVUJug6kkcE0A+YkPx/9fou6bvom585zftwAMPqLrHM913nGw56cXH1gRC5RBVNiMYKqRoHDJkDEeusxBpFUgOw3BlUQjBvLqAl9p/W67ThP/QNR2ojqD57qisDGTcNmvvfq9qrSechiBwV2B8joSQRtlu8dRC8AQNmsqu+KMdmgZ4voFaFpWUeGziszg8DKOgzg2RNJBMjj+ScdE7NFczwyjnx0VvapD562fJH1uf8SqKXKDhESw7s6DdHizr1AgYP7Qk2UzYHCcWS9Kqhy3MG2ZX/YrwBp1b3vCY74X7Nqv4oW1um/cHKo9BFpoZA5eeXmM/zW9LCqHsYuj+768blyC5vUKAJC8fnqnNzrzjOP2JT2daKPsde06d5/pGe1H+ADUBGMCNH6R3XI69270+znn690VM3BrgJBkCOSh5Fqk+y+yeBQlTcCdZb0vPN4wqH8RukZNn2biLjpmf5TgDLnIuqPIDgOpwCvA3he5BEx0hDANaYxsCgisQv94sSaLl06b1V2bvy5jth3B7Vd/lh1/D5YdO7c2VkWbNR4q/qKlk4YtT75uSAb4nvCanPiVeNhuUVsuQBp06PfP2I2/GDZpa4V4Yg7HDTPiOQF/RtfBT4HyOvZrzPITXbZtnNE4h1vIwLq4A82HpTXre9VsyeMmZnUo6IqCIk2N0d3G5Th96Kf7MosehQYAvGltkeYyOV46pf09DdmPz+8XLu+Vc8770AZVLxQUu00VScgRs9E5GwtTB8A/KlSh2K6ETeeNhZ2GgBbcMxvACx8W/Dvxt0Gh5bExubn+bbGNt8rDi7YdWmZ339VVpVV+6PBQT1zCsCwr3JbgPYCUFhaV4/8FOAPbVcUl8OoWaog4nnOHh8UPjYr57cW85TFjr3ntGUDIV7bAdzVhcJinbOb5eFpL3CaW/GWuJuC98eOCmc5ym1RsQP3pn9UGa16DOiyTBmmotmZxCKndu8/3rEFD82e+Py6GKyIP2ST9BO73ZK1aMILy/c1n4NJuQeFqnKmj0C5CXt53fqentf7niOS79t37hxEpViuwPVtjcsNeFRVJqlyNcI6z+NRYFlSToQGVnwTj+42aHdzSiVxd9E0gKN3ba2DiCNGOgGS13PAsEwTWwfmJRznL1oUXtfqxttL2diy511nOCrJu+4yK7SeM/6p8/0b11+Kxn8wNr6BdqVYv7sh+TpgfA2GTmuepUgbACNEal3+w2ujvmr2+XZv6w+O4zwIRFWcQXceT7isLsdxfgRQo6cAOOhIRBwAE4vd36ft7HLnKKqKByCqteLvkcdm5Q4b+VX278rKephBAhkG6T966gmNAbym2UNsdu764dMaH/vnGc3OGvlV7lys5COmL6IXGMyt9qiCXuJ5/6dws0/LT8sZld+sx2Ozcl8IzW9W4fBsm8635QK06drvdqP2DRXNhvgInBFu8Zzga4DMe+WJFaqsBwg6wSpPPj6UKRcgAsYabVvyo9bd+32sxvclRUXPJT+MZDTuhMTvWBY+/2bc4wvb3nhHOyv2fgCxOn5u9hGnzJ/4xENzxj3RLGLsWYouARAht5GNFU8KjPdBwEk2sTLcIxO2tGvTfcDbqnqPlLRVCDqO82Tx3C1ANHo9iE+VCNgu8155Yh6XXhqIHn3UJISggrVe7M2Svp7a7c6+eT36zW3T4874nT0S3r1bo9UGmQ2cjWj8KT9KK6AzImciUhfVLyIS6zC47ZLXKipYD/kxbqo0HTUj51oRuTT+jc6+64wVlWwwofEmlqMZAKO+yD1D4R7FKTXdf/QkgoKemNBvYrX0JgBr3AhQy8lIe9/nyHQRTi2RLIrlJW9H5K/GyC4AFS01KDLy89z2qrykcHPtiJbbBDyv58Dmmu5f1KZHv3/gyNMCq401l1uhjuL1ADBIx7zuA7rHLwozAcSaXhX7e+hTLkCsYEDyku9b9RjQWUTOAbAqZwJ07Bhy1dqHkjIqdiyAGre9iIiCLSqq8ztCoeIpJf99+akv1Orfku8FrVc2b03UINb1Z8aFxEE0fm6hqidWx6vKlrjlcqIWZlySTOuom/jB6FdrrP+7Nt1vv6FNgxOnJGs5g71nwatjpibl2/TsHzLGPKPIqSh3ABT6osU1iBHq922xcCdG/pvIvzAm9goh2iawcXO9Qe2WnlWyeZRk0PyjM+JlpcVHwakrJTvYRwyb3rxp2XQJf+M1iJUMAC9g6yYK61clxbyc438tSPG1M2K7A7iGLxN6WojggqrFjo2J7RBMD9QddPr3N99z3pofVDTRB9SOSR1PLSEgfl5K6lWN15yl8LvrUBWQa6y1r0VjkVPzJ4z+97xXntg6d9zT4xVdC6DGaxc32/4jbo60b9X9jtYV+nyIU64PIqiHktui5+CGGz3d4ao3TJPDjaJN8nr3Tt9asK2/EdMawMLmOtSdDBBD6zkAqhIIbvw18Nek3lN79s8Sj+L15TGf833ytUq8iaWJGsRfYLZQ3F1P4NFz9qtPTmzds98bqNwAIEZPBt4BsKJ1DGBFftVYouvBTY/r1LC1+vj8CU+NSqpq07N/COXhYtXiDAPIXLZ2l83OTRjoNQCwMe8d4zitEAk6Kk9GjPQeeNnmUqNhg+YfnXF0OP1GxfSWCG1GzKr9YEHb74fVmpW7HSFTiA9fx0eqJNdXK/LF6PycTne1XVbqwB9RPASMY2oB+CPuBuuzGKg//MvjexEr+tr43C6idnc/C0CkxYj83DY7dNeXtSh5NKT0uPu0pRPKlCSelR8dAdTc9NhXTSaGjVkT2eoMBUoOb5f7Qc9+fvi2Nj36LwdyPDHPfP3ac1vK2B9DAOs0AZiTXXdcm+VbBwCnODift+7W/28YPQPku7njnig3NH4oUsEols4WMZcEbPTJRkYcRYsn/omIaCRtpDj25uIxe09enD4xVAQgLi+hdrCISQP3jTbd+40QMVMUPQHVMzASH1my8sWCCaN3P31XVUTQRJMtbNesDrC7uyDYv8x+9amJADYmix0nkQxaFAtZ+zrGnGWgbvypPGtU7fioE3hq4YSRPwK06969XpR6IVRvL04GI5J7agVatHAKC8KJPOM1XMH7TYfUunT1aRjpJNDMZ2XqqFnNvsayFiEsxnga1gvigZCw19I+JNhRs5gJXJT4eGNsl3uar5Y3AczZVvWTYfk5V97bdtln5a6AZ9MBBrRfPGt0fu5/FC52HH0JJ1BaDrXJO76J0Tl0xtr7Rs7KXSrQzMK3g9t+P3FQ+QuMb8Wyv9vs3I3AUSr+D/0VjS+JHDd6EsG3nw1FdzTd/LTFfDJ33BOvW3SpQXJ81mtJKDSz9ZKtncRHJ1VygCYAntW5AIRC1nTtN9AzfCAiQRG6gYDaPQ4AHSpU0Adx/pF40UXQ6wBUyVfVxKiduU2QQPxznTFn03cPJtPOe+WJFYr2SXaKEWmi6M1AB0gEh+q3Rf5IqZ1KNNFJN4km1sLJk3cqWvxcYactGLFb2iue6yVocYA4weBE0N1DuKIFxsgxPoquzOs6oN+pPfu/EpO6y0V2B4eqvn18wZo/JN9vKNxiSfSHrLhHAIRC02P+TVu6qOqMEqV0CkY6IXKVqv4aIbOEzhkSsQMBPM8rvgmoxy33nffdik3bCq4B/R7kSMfKlFGfNCluPqkQr4BNfPGWCFrkbe+uyrxS5WV1PSK/d6JOeyAKYF1J7JbvDUd1NV50UGWnb93VhUIi9rK4HUm72WE974+KfTfxgTegM0Vbmmy5RDG3onoHgFhdDWCNadVq+bbrxeXfKP0Eriy+FuFI8eyC/IlPTvGsOVfhHat8JVb+mGnqVrlTzaFEuRpkzrjHnz+1253NjTEDAFD519wN313fqkHzEQ56Z1LOotOlcHsX3nuv1AjO3HFPj2/Z7dY5Lv5HwFyyuyOvP4GM82KRYd+OL1M1G7sOTFNUitd3iJrPEL1CkaklhwiN46xKvlZo0aJzyL9wcigy+/nh2/K69T1fxZ2ESBNBjgeON+r0VEcxJX4qFjYb7KC54596eW4JO0Jt1xaMnHX814K2VKOLk5/fednm7aqbzxo9O/d6tfpHSh7LQPxOjsh31vNG391u+UvJH+aGYMHwBoXp4vjcmYNOW/IvgKEXrtn02Kc5l2tAZohIXYK+s4FvKK2wuKq4/4z1P8H61qPmZDfVItNGYtFFuz7KWRwKTY8BjPzy2LbGBNoUSMEkgMHtlv8/4P+Vva5lGXTWslmqnDBketYRTm2vnhuQzfe1XLVlxKzcb+I1oWwTQTt2rPP+zmO3XLxFfPMBrHF+cFAQaaker6tRFRFJlMMKg+kze/Kz35fMa8HExz+l3HOiw4MKHxTOm/DUXSd2u+XpgJN5dN2VmflMfy9Wp+PpA3c02TIZ5XSs9595rz5T6YGZiWco1+b17p1OmGOiO2y47uZjf6xsw+mYuANc1bu8WKx4irrLpp5FXp2OxmVqSdloWJb4A8lfu/gC6ZtPAWYDzJ4wZmb7zje3jgRrPaNwMSKlBgJU+V7RKVK4/eE5k1/eQAUYvL+D5LpRp9TmE/Ef/feTJ03i70vrNz/OHyhspMY0iqqzccv6bbNHXL1xB8A9JdKMavXTLuBByjCww7LFw6c1bqUZwTOL/n3c30mcVSrKTwg5RgiUTTOozfKVwMr4u+J7BIPP+GEB1ZhSX96nFVtJTE0fNP/oDInoiYn5YJsAEtdsSjKN63mr1TGIyq8WTHz807Y9+5+vnuZ5jt2+zgu89tOEUdWezX0oc1BOmNof2nfuHAwHG32HSBMAK17vea88XeEd87Retx3nxQKnxkxUnIJdM+ZWEhRlCb2clRbqtXv/4APFYzNzPlFjOqC6cFC7pVVudfRzMPqLrHOtz50OgNoxg9otu72szCndB1ztE31LVTW3cK1v8uTJ3oG280BySMzFqg4zJk8ubP2bO7rjdz4SMI66KyuTnfXys6uBah+8czCCAwDVt4EOVvSAN0fG5uf5ttmto5KdUhNzy81SBnA9jeDGB2xWBoNHApsOnJUHnp/lnPSfm7mvP/2xUe2GMGT2uMf3ax3IocTAM5aPcsTX6O7Tlh3wk3p3smWIEWkLoGoX3XXm4nLTZwBwpHgGQKyw1sGdfX0AOOxqkCSzxz9Z4RPsw50Bbb9dd6DzHDojt6ONz1ZAUWuI9a1UOBqL4o+Ps4f9vlSApPjfJaSY2rNz+1urfyp+nmLtQwNPXzW1sjTRNIn6E/MjHGKZlcn9r5AKkF8go+ZkN1VPfm3ypZtCm8QoLVZ5c3C75X8eWEXaaKxgnT/+oB9x3MN+afCeSAXI/yhDFzSp4wv7vlKVLCMaUZUYqA/w44lTZoFG1EPvv/u0paMqe7iYZNGEF1ac2qP/ZoNNL9KChT+vFwefw7KTnmLPOAX2KJBcEVxF0hEyEQkmp9zHUQWdFpFYh3tOWzpyT8GRTGS98Jmeeq0O1zUe1eGwew6SYu8ZMev464y1l6iRUyQ+b60IYY1VWaOefuaGCyYOPLfi079SxNnnAAk9MuY2LFfjdwaE/nDrN3uWf/YuVK/B0QdCD9z+yT7nGxozBqEpPndQ6A99iqeUjxw5PsPzCt177+2zrTKZkjZkBDJnJ+X31ZbdeqtXFiUpaff+2pGi5tn3JpblFEUvlqi3d7tWqDZX1Q7i7fc+SWmqerlEvVLHHOwq2PFkUTi2KfTIs70rkylpQxn5Shky5JnBoSFj3h4y5LnrKhWqbllUbvf+2VEDHKh8DhfKBUho0qQqdyUMjRjT8M9/Hlc8x0nERKqSL49uHD78xdpjx471AUyaNMmpSCqkWmXwisjW0LCxTYrTG3kD1XdFrVOpTAkbKpKv0FokQ1WvVLHH7MmzqsqiUn9K2FFVueyNHaNHTwomr19Sz96UdXXzqS57upaHMqWaWKGhY3IJ68cIm0DeCqaljfQ81x+J7nwO1WxEjlfVI0RkGsoiRW91jHO2NVbw9G84cm3ogb5fhIY88wzKTYgsReQvoYdueyE0ZMzzqvo7I3K+Qh9UL8WYIag+gLKIAN1oVn+VfLuhh8LNKC0wMjD00G3Pl7IxNOZFRX8rIu+p6qWC/Nfvr9UxEt11D+g5Avep0rVimZ1Dd9sglyblH36477QKbQ6NGQp6o0ITQeYRkOtC9922bMiQZ3soOhjV+ZyOuCAAAAXaSURBVK7r3B2L2QcqKgtOqJ+/R3+GPDui2O7KyiXMzXtlh2eHA10Q7sLqoyLmAUU7VKQzdF/f7yvw4/aK8qn4ej7zH5D1oYf7dg2FxrwLfBMK9R0cGvLMMOBUghk9pbDgyqp8PxwoFdkS4SaFRqisVtUHC8Phq++7r/tmVOuBrAcSK+l2r9WwovWI6esodRxly5Ahz3ZWpS/Ct4DB2udCfxpTcm00wHaFTKzeBzpd0TMkwg18u2GEVX0e1doYHarWjg098uxdldh+iQjDgdxIZFd/VEVVT1fR+pXKlKSEfGU2i+iHSHy9BUKQKOeHhj6bo2pfSHx2XSxmiw+8KVsWe+VPabsrLJdq2FGgqj4s9wO11NG5lemsKH1F+VRxPa2q3jR06LN1QC8GvWvs2LE+VHqgXERhQaga1/KQpWzVtx1ARF6JLy2ngYhoKHT7BSKMAo4VWJyRnrn7LEBrn1A4VsQ89OCDfb9V1fg6cUfuFnhOwcWjkrP/dCOuPAKg6NGZtevfZ0S6ipgQyi1x/VrZkWh/Ji3wTHwdu+5enyHs3KNMSYSdldn88MO3TxVkQlxMHgw9dNsLEtHzFFxBkjPbd58BUqYsquVPKbtLl0t17VC0ISJDQw/0/aIynRWlryifSq+nyhKAcFSvVHAVzLr1sfMUbQjyRWbt+gOqcS0PWUoFiOPwNxH5VtVeg8M5rpG/AoQef/lIhXGoRvH5fjN4cPfiOf+qZIuI5zj2DQAksQw2PfANyYNTlKyKc5cXjafJyW+1treuH1W40qqdBFL1sQlGpktRJL5uWnTpPstU02bVeLAr+hyKg8iMEt+VKotq+VPa7lLlUl07BFlwTEO39K7yZXRWlb4UlZSNiCxOvO4iyZaFx80AIvr2Pvt+iFEqQGLpgV1+X/BchAAx3rRWjgJge8FfVPU4EflD6P4+c0qmEWSBqjoxTybEO4GJ5lc4cqQK8d07koVZLnOz+6IoAT755gFVvUGQURXJl0VVzkgYMW9/ZKpjMxBff4/2MsY9R9DicxnLlUU1/UlSrlyqa4eYR/r06VNq360KdJZLr6oVDPtXXDbq2Pnxr/UiRD4QkR2IXg2gPt87++r7oUbpJtb28JBwpGA9sFjRBla9XkOGjLlZVW8QYYMKTig05umRI8fv3vTN1TsE3lbVDt98u/FpVOIrDWO0ROP7a5nEir+KsI6TvCgG5QJB5gENgYqbRLtT+sF2FWR9RjDzXaSiZzplZEpSUr4Km7XMQIaIJs6BN35rvZDC45AYpSlXFnvhT4V2lymXvbcjMXVIK1zPUlJnRemHTJ7sK5tPpWWTeeQ8EVEFPyJfoCxUJSAi60J/6PNd9a7loUvpAKnlDpH4es54h1ZYrMq1AKrUV6vDFb29oGDH+cUXQY3f5wv0FpHVYBs6jvO8wGY8HYtyk4gssc2P+np3XppJor2sSi2J2dMTuacbo4NAcxTtiugjIoSTa9qLSW52Zhmv0AQjwxNNvoYJe5pUIVPShmL5KmyG4iaOZgLoUTJVhBmq9m3QjoLpBRRUVBZ75U9Juyspl2rYkbyeR5XQX6HOitKHunSJlM2nsrIJ3dl1O2h8x0yRBYjGb4Ia/7+Xvh/ylAqQ0KA+GzMzGzTHmKsc47QJPdT3WTJMLzFyh2Ocs30uWVL3yCMefrjvOxkZmQ8Yca4NuMy+//7f/US6aXtMQ98NDz5465JgMJglojdizB2uoxeFunSJUDtwtxjTR9MCs8lMv14cc5GeVG/aSSfVf0Vc9zT8vnseeuj2mcZwpmOcs0MP3f7HzNoN6pDmL7UDhmMCA43IICNcbkRuzAjWGguQWbv+78Thclz3o8pkStpQUr5Sm4GHH7ptsLhyls8XfBsg1Lfvzocf6nsWPt/puE6Hhx/+/QeVlcXe+FPSjsrKZW/t4KQGvcVxztO0wJTdGVSss8L0FeRTVdn4fentjUjXjLSMmRwl9xpxrsWRpwH2xvcUKVKkSJEiRYoUv0j+P1GPgO+VXwPOAAAAAElFTkSuQmCC" /></a>
+<p class="haj">{% trans "Service unavailable" %}</p>
+<p>
+{% trans "The Wolnelektury.pl site is currently unavailable due to maintainance." %}
+</p>
+
+<script src="http://www.google-analytics.com/urchin.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+    _uacct = "UA-2576694-1";
+    urchinTracker();
+</script>
+</body>
+</html>
\ No newline at end of file
index d0ca937..23cfb59 100644 (file)
@@ -1,9 +1,11 @@
 {% extends "admin/base.html" %}
+{% load i18n %}
 
-{% block title %}{{ title }} | Administracja stroną WolneLektury.pl{% endblock %}
+{% block title %}{{ title }} | {% trans "Site administration" %} - WolneLektury.pl{% endblock %}
 
 {% block branding %}
-<h1 id="site-name">Administracja stroną WolneLektury.pl</h1>
+<h1 id="site-name">{% trans "Site administration" %} - WolneLektury.pl</h1>
+<p style="float: right; font-size: 11px; padding-right: 10px;"><a href="/rosetta/">{% trans "Translations" %}</a></p>
 {% endblock %}
 
 {% block nav-global %}{% endblock %}
\ No newline at end of file
index 3ded503..09e567a 100644 (file)
@@ -1,8 +1,9 @@
 {% extends "admin/change_list.html" %}
+{% load i18n %}
 
 {% block content %}
     <form action="{% url import_book %}" method="post" enctype="multipart/form-data">
-        <p><input type="file" id="id_book_xml_file" name="book_xml_file" /> <input type="submit" value="Importuj książkę"/></p>
+        <p><input type="file" id="id_book_xml_file" name="book_xml_file" /> <input type="submit" value="{% trans "Import book" %}"/></p>
     </form>
     {{ block.super }}
 {% endblock content %}
\ No newline at end of file
index 6db94aa..a168ff7 100644 (file)
@@ -1,24 +1,25 @@
 {% extends "base.html" %}
+{% load i18n %}
 
-{% block title %}Zaloguj / Zarejestruj się w WolneLektury.pl{% endblock %}
+{% block title %}{% trans "Sign in" %} / {% trans "Register on"%} WolneLektury.pl{% endblock %}
 
 {% block body %}
-    <h1>Zaloguj się / Załóż konto</h1>
+    <h1>{% trans "Sign in" %} / {% trans "Register"%}</h1>
     <form action="." method="get" accept-charset="utf-8" id="search-form">
-        <p><li>{{ search_form.q }} <input type="submit" value="Szukaj" /></li> <strong>lub</strong> <a href="{% url main_page %}">wróć do strony głównej</a></p>
+        <p><li>{{ search_form.q }} <input type="submit" value="{% trans "Search" %}" /></li> <strong>{% trans "or" %}</strong> <a href="{% url main_page %}">{% trans "return to main page" %}</a></p>
     </form>
     <form method="post" action="." id="login-form" class="cuteform">
-        <h2>Zaloguj się</h2>
+        <h2>{% trans "Sign in" %}</h2>
         <ol>
             {{ form.as_ul }}
-            <li><input type="submit" value="Zaloguj się" /></li>
+            <li><input type="submit" value="{% trans "Sign in" %}" /></li>
         </ol>
         <p><input type="hidden" name="next" value="{{ next }}" /></p>
     </form>
-    
+
     <form action="." method="post" accept-charset="utf-8" id="registration-form">
-        <h2>Załóż konto</h2>
+        <h2>{% trans "Register" %}</h2>
 
-        <p><input type="submit" value="Załóż konto"/></p>
+        <p><input type="submit" value="{% trans "Register" %}"/></p>
     </form>
 {% endblock %}
index 260ac6e..4d59dc8 100644 (file)
-{% load chunks compressed catalogue_tags sponsor_tags %}
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 <html xmlns="http://www.w3.org/1999/xhtml">
+       {% load i18n chunks compressed catalogue_tags sponsor_tags %}
     <head>
         <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
         <title>{% block title %}WolneLektury.pl{% endblock %}</title>
-        <link rel="icon" href="/static/img/favicon.png" type="image/x-icon" />
+        <link rel="icon" href="{{ STATIC_URL }}img/favicon.png" type="image/x-icon" />
         {% compressed_css "all" %}
+        <script type="text/javascript">var LANGUAGE_CODE = "{{ LANGUAGE_CODE }}";</script>
         {% compressed_js "jquery" %}
         {% compressed_js "all" %}
         {% block extrahead %}
         {% endblock %}
     </head>
     <body id="{% block bodyid %}base{% endblock %}">
-        <!--[if lt IE 7]><link href=/static/infobar/infobar.css rel=stylesheet>
+        <!--[if lt IE 7]><link href={{ STATIC_URL }}infobar/infobar.css rel=stylesheet>
         <div id=infobar><a href=http://browsehappy.pl/infobar>
-        Internet Explorer nie potrafi poprawnie wyświetlić tej strony. Kliknij tutaj, aby dowiedzieć się więcej...
-        </a></div><div id=viewplot><script src=/static/infobar/infobar.js></script><![endif]-->
+        {% trans "Internet Explorer cannot display this site properly. Click here to read more..." %}
+        </a></div><div id=viewplot><script src={{ STATIC_URL }}infobar/infobar.js></script><![endif]-->
         {% block bodycontent %}
         <div id="top-message">
             {% chunk "top-message" %}
         </div>
         <div id="header">
             <div id="logo">
-                <a href="/"><img src="/static/img/logo.png" alt="WolneLektury.pl - logo" /></a>
+                <a href="/"><img src="{{ STATIC_URL }}img/logo.png" alt="WolneLektury.pl - logo" /></a>
             </div>
             <div id="user-info" style="display:none">
                 {% if user.is_authenticated %}
                     <p>
-                        Witaj, <strong>{{ user.username }}</strong>
-                        | <a href="{% url user_shelves %}" id="user-shelves-link">Twoje półki</a>
+                        {% trans "Welcome" %}, <strong>{{ user.username }}</strong>
+                        | <a href="{% url user_shelves %}" id="user-shelves-link">{% trans "Your shelves" %}</a>
                         {% if user.is_staff %}
-                        | <a href="/admin/">Administracja</a>
+                        | <a href="/admin/">{% trans "Administration" %}</a>
                         {% endif %}
-                        | <a href="{% url logout %}?next={{ request.get_full_path }}">Wyloguj</a>
+                                               | <a href="{% url suggest %}" id="suggest-link">{% trans "Report a bug" %}</a>
+                        | <a href="{% url logout %}?next={{ request.get_full_path }}">{% trans "Logout" %}</a>
                     </p>
                 {% else %}
-                    <p><a href="{% url login %}" class="login-register-link">Zaloguj się / Załóż konto</a></p>
+                    <p><a href="{% url suggest %}" id="suggest-link">{% trans "Report a bug" %}</a>
+                        | <a href="{% url login %}" class="login-register-link">{% trans "Sign in" %} / {% trans "Register" %}</a></p>
                 {% endif %}
             </div>
             <div class="social-links" style="float:right">
-                <a href="http://pl-pl.facebook.com/pages/Wolne-Lektury/203084073268"><img src="/static/img/social/facebook.png" /></a>
-                <a href="http://twitter.com/wolnelektury"><img src="/static/img/social/twitter.png" /></a>
-                <a href="http://nasza-klasa.pl/profile/30441509"><img src="/static/img/social/naszaklasa.png" /></a>     
+                <a href="http://pl-pl.facebook.com/pages/Wolne-Lektury/203084073268"><img src="{{ STATIC_URL }}img/social/facebook.png" alt="WolneLektury @ Facebook" /></a>
+                <a href="http://nk.pl/profile/30441509"><img src="{{ STATIC_URL }}img/social/naszaklasa.png" alt="WolneLektury @ NK" /></a>
             </div>
+                       <div class="lang-menu" style="float:right;">
+                               <form action="{% url django.views.i18n.set_language %}" method="POST">
+                                       {% spaceless %}
+                                       {% for lang in LANGUAGES %}                                          
+                                           <button type="submit" name="language" title="{{ lang.1 }}"
+                                                       class="{% ifequal lang.0 LANGUAGE_CODE %}active{% endifequal %} {% if forloop.last %}last{% endif %}" 
+                                                       value="{{ lang.0 }}">{{ lang.0|upper }}</button>
+                                       {% endfor %}    
+                                       {% endspaceless %}                              
+                               </form>
+                       </div>
             <div class="clearboth"></div>
         </div>
         <div id="maincontent">
             {% block body %}
-            {% endblock %}    
+            {% endblock %}
         </div>
         <div class="clearboth"></div>
         <div id="footer">
             <p>
-                Wolne Lektury to projekt prowadzony przez <a href="http://nowoczesnapolska.org.pl/">Fundację Nowoczesna
-                Polska</a>. Reprodukcje cyfrowe wykonane przez <a href="http://www.bn.org.pl/">Bibliotekę Narodową</a>
-                z egzemplarzy pochodzących ze zbiorów BN. Hosting <a href="http://eo.pl/">EO Networks</a>.
+               {% blocktrans %}
+                               Wolne Lektury is a project lead by <a href="http://nowoczesnapolska.org.pl/">Modern Poland Foundation</a>.
+                               Digital reproductions are made by <a href="http://www.bn.org.pl/">The National Library</a>, based on TNL resources.
+                               Hosting <a href="http://eo.pl/">EO Networks</a>.
+                               {% endblocktrans %}
             </p>
             <p>
-                Fundacja Nowoczesna Polska, 00-514 Warszawa, ul. Marszałkowska 84/92 lok. 125, tel/fax: (22) 621-30-17,
+               {% blocktrans %}
+                               Modern Poland Foundation, 00-514 Warsaw, ul. Marszałkowska 84/92 lok. 125, tel/fax: (22) 621-30-17
                 e-mail: <a href="mailto:fundacja@nowoczesnapolska.org.pl">fundacja@nowoczesnapolska.org.pl</a>
+                               {% endblocktrans %}
             </p>
 
                        {% sponsor_page "footer" %}
         </div>
         <div id="login-register-window">
-            <div class="header"><a href="#" class="jqmClose">Zamknij</a></div>
+            <div class="header"><a href="#" class="jqmClose">{% trans "Close" %}</a></div>
             <div class="target">
                 <form method="post" action="{% url login %}" id="login-form" class="cuteform">
-                    <h2>Zaloguj się / <a href="#" id="show-registration-form" style="font-size: 0.85em; font-weight: normal">Załóż konto</a></h2>
+                    <h2>{% trans "Sign in" %} / <a href="#" id="show-registration-form" style="font-size: 0.85em; font-weight: normal">{% trans "Register" %}</a></h2>
                     <p><span id="id_login-__all__"></span></p>
                     <ol>
                         {% authentication_form %}
-                        <li><input type="submit" value="Zaloguj się" /></li>
+                        <li><input type="submit" value="{% trans "Sign in" %}" /></li>
                     </ol>
                 </form>
                 <form method="post" action="{% url register %}" id="registration-form" class="cuteform" style="display: none;">
-                    <h2><a href="#" id="show-login-form" style="font-size: 0.85em; font-weight: normal">Zaloguj się</a> / Załóż konto</h2>
+                    <h2><a href="#" id="show-login-form" style="font-size: 0.85em; font-weight: normal">{% trans "Sign in" %}</a> / {% trans "Register" %}</h2>
                     <p><span id="id_registration-__all__"></span></p>
                     <ol>
                         {% user_creation_form %}
-                        <li><input type="submit" value="Załóż konto" /></li>
+                        <li><input type="submit" value="{% trans "Register" %}" /></li>
                     </ol>
                 </form>
             </div>
         </div>
         <div id="user-shelves-window">
-            <div class="header"><a href="#" class="jqmClose">Zamknij</a></div>
+            <div class="header"><a href="#" class="jqmClose">{% trans "Close" %}</a></div>
             <div class="target">
-                <p><img src="/static/img/indicator.gif" alt="*"/> Ładowanie</p>
+                <p><img src="{{ STATIC_URL }}img/indicator.gif" alt="*"/> {% trans "Loading" %}</p>
+            </div>
+        </div>
+        <div id="suggest-window">
+            <div class="header"><a href="#" class="jqmClose">{% trans "Close" %}</a></div>
+            <div class="target">
+                <p><img src="{{ STATIC_URL }}img/indicator.gif" alt="*"/> {% trans "Loading" %}</p>
             </div>
         </div>
         {% endblock bodycontent %}
         pageTracker._trackPageview();
         </script>
     </body>
-</html>
+</html>
\ No newline at end of file
index f8991c9..fed2d5b 100644 (file)
@@ -1,62 +1,81 @@
 {% extends "base.html" %}
+{% load i18n %}
 {% load catalogue_tags pagination_tags %}
 
-{% block title %}Lektura {{ book.title }} w WolneLektury.pl{% endblock %}
+{% block title %}{{ book.title }} {% trans "on WolneLektury.pl" %}{% endblock %}
 
 {% block bodyid %}book-detail{% endblock %}
 
 {% block body %}
-    <h1>{{ book.title }}, {{ categories.author|join:", " }}</h1>
+    <h1>{% book_title book %}</h1>
     <form action="{% url search %}" method="get" accept-charset="utf-8" id="search-form">
-        <p>{{ form.q }} <input type="submit" value="Szukaj" /> <strong>lub</strong> <a href="{% url main_page %}">wróć do strony głównej</a></p>
+        <p>{{ form.q }} <input type="submit" value="{% trans "Search" %}" /> <strong>{% trans "or" %}</strong> <a href="{% url main_page %}">{% trans "return to main page" %}</a></p>
     </form>
-    
+
     <div id="books-list">
+        <div id='breadcrumbs'>
+            {% if categories.author %}
+                {% for tag in categories.author %}
+                    <a href="{{ tag.get_absolute_url }}">{{ tag }}</a>{% if not forloop.last %}, {% endif %}
+                {% endfor %}
+                &#187; 
+            {% endif %}
+            {% for parent in parents %}
+                <a href="{{ parent.get_absolute_url }}">{{ parent }}</a> &#187; 
+            {% endfor %}
+        </div>
+
         {% if extra_info.license %}
-        <p>Utwór jest udostępniony na licencji <a href="{{ extra_info.license }}">{{ extra_info.license_description }}</a>.</p>
+        <p>{% trans "Work is licensed under " %} <a href="{{ extra_info.license }}">{{ extra_info.license_description }}</a>.</p>
         {% endif %}
-        <p>Na podstawie: {{ extra_info.source_name }}</p>
+        <p>{% trans "Based on" %}: {{ extra_info.source_name }}</p>
         {% if book.has_description %}
             <div id="description">
-                {{ book.description|safe }}
+                <div id='description-long'>{{ book.description|safe }}</div>
+                <div id='description-short'>{{ book.description|safe|truncatewords_html:30 }}</div>
             </div>
-            <div id="toggle-description"><p>Zwiń opis ▲</p></div>
+            <div id="toggle-description"><p></p></div>
         {% endif %}
         <div id="formats">
-            <p class="change-sets">Wrzuć lekturę <span><a href="{% url catalogue.views.book_sets book.slug %}" class="jqm-trigger">na półkę!</a></span></p>
+            <p class="change-sets">{% trans "Put a book" %} <span><a href="{% url catalogue.views.book_sets book.slug %}" class="jqm-trigger">{% trans "on the shelf!" %}</a></span></p>
             <div class="clearboth"></div>
             <div class="wrap">
             {% if book.html_file %}
-                <a href="{% url book_text book.slug %}">Czytaj online</a>
+                <a href="{% url book_text book.slug %}">{% trans "Read online" %}</a>
             {% endif %}
             {% if book.pdf_file %}
-                <a href="{{ book.pdf_file.url }}">Pobierz plik PDF</a>
+                <a href="{{ book.pdf_file.url }}">{% trans "Download PDF" %}</a>
+            {% endif %}
+            {% if book.root_ancestor.epub_file %}
+                <a href="{{ book.root_ancestor.epub_file.url }}">{% trans "Download EPUB" %}</a>
             {% endif %}
             {% if book.odt_file %}
-                <a href="{{ book.odt_file.url }}">Pobierz plik ODT</a>
+                <a href="{{ book.odt_file.url }}">{% trans "Download ODT" %}</a>
             {% endif %}
             {% if book.txt_file %}
-                <a href="{{ book.txt_file.url }}">Pobierz plik TXT</a>
+                <a href="{{ book.txt_file.url }}">{% trans "Download TXT" %}</a>
             {% endif %}
             {% if book.mp3_file %}
                 <div id="czytamy-sluchajac-info">
-                    <a href="http://czytamysluchajac.pl/" id="czytamysluchajac-logo"><img src="/static/img/czytamysluchajac-logo-small.png" /></a>     
-                    <p>Czyta: {{ book.get_extra_info_value.artist_name }}</p>
-                    <p>Reżyseruje: {{ book.get_extra_info_value.director_name }}</p>
+                    <a href="http://czytamysluchajac.pl/" id="czytamysluchajac-logo"><img src="{{ STATIC_URL }}img/czytamysluchajac-logo-small.png" /></a>
+                    <p>{% trans "Artist" %}: {{ book.get_extra_info_value.artist_name }}</p>
+                                       {% if book.get_extra_info_value.director_name %}
+                        <p>{% trans "Director" %}: {{ book.get_extra_info_value.director_name }}</p>
+                                       {% endif %}
                 </div>
             {% endif %}
-            {% if book.mp3_file %}<a href="{{ book.mp3_file.url }}">Pobierz plik MP3</a>{% endif %}
-            {% if book.ogg_file %}<a href="{{ book.ogg_file.url }}">Pobierz plik Ogg Vorbis</a>{% endif %}
+            {% if book.mp3_file %}<a href="{{ book.mp3_file.url }}">{% trans "Download MP3" %}</a>{% endif %}
+            {% if book.ogg_file %}<a href="{{ book.ogg_file.url }}">{% trans "Download Ogg Vorbis" %}</a>{% endif %}
             {% if book.mp3_file %}
-            <object type="application/x-shockwave-flash" style="margin-top: 0.5em" data="/static/player.swf" width="426" height="20">
-                <param name="movie" value="/static/player.swf" />
+            <object type="application/x-shockwave-flash" style="margin-top: 0.5em" data="{{ STATIC_URL }}player.swf" width="426" height="20">
+                <param name="movie" value="{{ STATIC_URL }}player.swf" />
                 <param name="bgcolor" value="#ffffff" />
                 <param name="FlashVars" value="mp3={{ book.mp3_file.url }}&amp;width=426&amp;showvolume=1&amp;bgcolor1=eeeeee&amp;bgcolor2=eeeeee&amp;buttoncolor=666666" />
             </object>
             {% endif %}
             </div>
         </div>
-    
+
         {% if book_children %}
         {% autopaginate book_children 10 %}
         <div id="book-children">
         </div>
         {% paginate %}
         {% endif %}
-    
+
     </div>
-        
+
     <div id="tags-list">
         <div id="book-info">
-            <h2>O utworze</h2>
+            <h2>{% trans "Details" %}</h2>
             <ul>
                 <li>
-                    Autor: 
+                       
+                    {% trans "Author" %}:
                     {% for tag in categories.author %}
-                    <a href="{{ tag.get_absolute_url }}">{{ tag }}</a>
+                    <a href="{{ tag.get_absolute_url }}">{{ tag }}</a>{% if not forloop.last %}, {% endif %}
                     {% endfor %}
                 </li>
                 <li>
-                    Epoka:
+                    {% trans "Epoch" %}:
                     {% for tag in categories.epoch %}
-                    <a href="{{ tag.get_absolute_url }}">{{ tag }}</a>
+                    <a href="{{ tag.get_absolute_url }}">{{ tag }}</a>{% if not forloop.last %}, {% endif %}
                     {% endfor %}
                 </li>
                 <li>
-                    Rodzaj:
+                    {% trans "Kind" %}:
                     {% for tag in categories.kind %}
-                    <a href="{{ tag.get_absolute_url }}">{{ tag }}</a>
+                    <a href="{{ tag.get_absolute_url }}">{{ tag }}</a>{% if not forloop.last %}, {% endif %}
                     {% endfor %}
                 </li>
                 <li>
-                    Gatunek:
+                    {% trans "Genre" %}:
                     {% for tag in categories.genre %}
-                    <a href="{{ tag.get_absolute_url }}">{{ tag }}</a>
+                    <a href="{{ tag.get_absolute_url }}">{{ tag }}</a>{% if not forloop.last %}, {% endif %}
                     {% endfor %}
                 </li>
             </ul>
-            <h2>W innych miejscach</h2>
+            <h2>{% trans "Other resources" %}</h2>
             <ul>
-                <li><a href="{{ extra_info.about }}">Lektura na wiki projektu</a></li>
-                <li><a href="{{ extra_info.source_url }}">Lektura w CBN Polona</a></li>
+                <li><a href="{{ extra_info.about }}">{% trans "Book on project's wiki" %}</a></li>
+                <li><a href="{{ extra_info.source_url }}">{% trans "Source of the book" %}</a></li>
                 {% if book.gazeta_link %}
-                <li><a href="{{ book.gazeta_link }}">Opis lektury w Lektury.Gazeta.pl</a></li>
+                <li><a href="{{ book.gazeta_link }}">{% trans "Book description on Lektury.Gazeta.pl" %}</a></li>
                 {% endif %}
                 {% if book.wiki_link %}
-                <li><a href="{{ book.wiki_link }}">Opis lektury w Wikipedii</a></li>
+                <li><a href="{{ book.wiki_link }}">{% trans "Book description on Wikipedia" %}</a></li>
                 {% endif %}
             </ul>
         </div>
         <div id="themes-list">
-            <h2>Motywy w utworze</h2>
+            <h2>{% trans "Work's themes " %}</h2>
             <ul>
             {% for theme in book_themes %}
                 <li><a href="{% url book_fragments book.slug,theme.slug %}">{{ theme }} ({{ theme.count }})</a></li>
         <div class="clearboth"></div>
     </div>
     <div id="set-window">
-        <div class="header"><a href="#" class="jqmClose">Zamknij</a></div>
+        <div class="header"><a href="#" class="jqmClose">{% trans "Close" %}</a></div>
         <div class="target">
-            <p><img src="/static/img/indicator.gif" alt="*"/> Ładowanie</p>
+            <p><img src="{{ STATIC_URL }}img/indicator.gif" alt="*"/> {% trans "Loading" %}</p>
         </div>
     </div>
-{% endblock %}
+{% endblock %}
\ No newline at end of file
index f21b1a8..e71a190 100644 (file)
@@ -1,14 +1,15 @@
 {% extends "base.html" %}
+{% load i18n %}
 {% load catalogue_tags pagination_tags %}
 
-{% block title %}Motyw {{ theme }} w utworze {{ book }} w WolneLektury.pl{% endblock %}
+{% block title %}{% trans "Theme" %} {{ theme }} {% trans "in work " %} {{ book }} {% trans "on" %} WolneLektury.pl{% endblock %}
 
 {% block bodyid %}tagged-object-list{% endblock %}
 
 {% block body %}
-    <h1>Motyw {{ theme }} w utworze {{ book }}</h1>
+    <h1>{% trans "Theme" %} {{ theme }} {% trans "in work " %} {{ book }} </h1>
     <form action="{% url search %}" method="get" accept-charset="utf-8" id="search-form">
-        <p>{{ form.q }} <input type="submit" value="Szukaj" /> <strong>lub</strong> <a href="{{ book.get_absolute_url }}">wróć do strony utworu</a></p>
+        <p>{{ form.q }} <input type="submit" value="{% trans "Search" %}" /> <strong>{% trans "or" %}</strong> <a href="{{ book.get_absolute_url }}">{% trans "return to book's page" %}</a></p>
     </form>
 
     {% autopaginate fragments 10 %}
     </div>
     <div id="tags-list">
         <div id="categories-list">
-            Zobacz opis <a href="{{ book.get_absolute_url }}">utworu {{ book }}</a>
+            {% trans "See description" %} <a href="{{ book.get_absolute_url }}">{% trans "of the book "%} {{ book }}</a>
         </div>
         <div id="themes-list">
         </div>
         <div class="clearboth"></div>
     </div>
     <div id="set-window">
-        <div class="header"><a href="#" class="jqmClose">Zamknij</a></div>
+        <div class="header"><a href="#" class="jqmClose">{% trans "Close" %}</a></div>
         <div class="target">
-            <p><img src="/static/img/indicator.gif" alt="*"/> Ładowanie</p>
+            <p><img src="{{ STATIC_URL }}img/indicator.gif" alt="*"/> {% trans "Loading" %}</p>
         </div>
     </div>
 {% endblock %}
\ No newline at end of file
index 1f87217..7d49cff 100644 (file)
@@ -1,26 +1,26 @@
 {% extends "base.html" %}
+{% load i18n %}
 {% load catalogue_tags chunks %}
 
 {% block bodyid %}book-a-list{% endblock %}
 
-{% block title %}Alfabetyczny spis utworów w WolneLektury.pl{% endblock %}
+{% block title %}{% trans "Listing of all works on WolneLektury.pl" %}{% endblock %}
 
 {% block body %}
-    <h1>Alfabetyczny spis utworów</h1>
+    <h1>{% trans "Listing of all works" %}</h1>
     <form action="{% url search %}" method="GET" accept-charset="utf-8" id="search-form">
-        <p>{{ form.q }} <input type="submit" value="Szukaj" /> <strong>lub</strong> <a href="{% url main_page %}">wróć do strony głównej</a></p>
+        <p>{{ form.q }} <input type="submit" value="{% trans "Search" %}" /> <strong>{% trans "or" %}</strong> <a href="{% url main_page %}">{% trans "return to main page" %}</a></p>
     </form>
-    
+
     <div id="book-list">
-        {% for first_letter, group in books_by_first_letter.items %}
-        <div class="group">
-            <h2>{{ first_letter }}</h2>
-            <ol>
-            {% for book in group %}
-                <li><a href="{{ book.get_absolute_url }}">{{ book.title }}</a></li>
-            {% endfor %}
-            </ol>
-        </div>
-        {% endfor %}    
+        {% book_tree orphans books_by_parent %}
+        {% for author, group in books_by_author.items %}
+            {% if group %}
+                <div class="group">
+                    <h2><a href="{{ author.get_absolute_url }}">{{ author }}</a></h2>
+                    {% book_tree group books_by_parent %}
+                </div>
+            {% endif %}
+        {% endfor %}
     </div>
-{% endblock %}
+{% endblock %}
\ No newline at end of file
index fb5f6ae..2b713b4 100644 (file)
@@ -1,17 +1,18 @@
-<h2>Wrzuć lekturę na półkę</h2>
+{% load i18n %}
+<h2>{% trans "Put a book on the shelf!" %}</h2>
+<a href="#" id="createShelfTrigger">{% trans "Create new shelf" %}</a>
+<form id="createNewShelf" action="{% url catalogue.views.new_set %}" method="POST" accept-charset="utf-8" class="cuteform">
+<ol>
+    <li>{{ new_set_form.name }} <input type="submit" value="{% trans "Create new shelf" %}"/></li>
+</ol>
+</form>
 {% if not user.tag_set.count %}
-    <p>Nie posiadasz żadnych półek. Jeśli chcesz, możesz utworzyć nową półkę poniżej.</p>
+    <p>{% trans "You do not have any shelves. You can create one below, if you want to."%}</p>
 {% else %}
     <form action="{% url catalogue.views.book_sets book.slug %}" method="POST" accept-charset="utf-8" class="cuteform">
     <ol>
         <li>{{ form.set_ids }}</li>
-        <li><input type="submit" value="Wrzuć na półkę"/></li>
+        <li><input type="submit" value="{% trans "Put on the shelf!" %}"/></li>
     </ol>
     </form>
 {% endif %}
-<hr />
-<form action="{% url catalogue.views.new_set %}" method="POST" accept-charset="utf-8" class="cuteform">
-<ol>
-    <li>{{ new_set_form.name }} <input type="submit" value="Utwórz nową półkę"/></li>
-</ol>
-</form>
\ No newline at end of file
index 3012069..8b36718 100644 (file)
@@ -1,6 +1,7 @@
+{% load i18n %}
 <div class="book">
     <div class="change-sets">
-        <a href="{% url catalogue.views.book_sets book.slug %}" class="jqm-trigger">Na półkę!</a>
+        <a href="{% url catalogue.views.book_sets book.slug %}" class="jqm-trigger">{% trans "Put on the shelf!" %}</a>
     </div>
     {% if book.children.all|length %}
         <div class="book-parent-thumbnail"></div>
@@ -10,8 +11,8 @@
     <div class="book-description">
         <h2><a href="{{ book.get_absolute_url }}">{{ book.title }}</a></h2>
         {% if formats %}
-            <p style="margin: 0">Na skróty: {{ formats|join:", " }}</p>
+            <p style="margin: 0">{% trans "Jump to" %}: {{ formats|join:", " }}</p>
         {% endif %}
-        <p style="margin: 0">Utwór w kategoriach: {{ tags|join:", " }}</p>
+        <p style="margin: 0">{% trans "Categories" %}: {{ tags|join:", " }}</p>
     </div>
-</div>
+</div>
\ No newline at end of file
diff --git a/wolnelektury/templates/catalogue/book_stub_detail.html b/wolnelektury/templates/catalogue/book_stub_detail.html
new file mode 100644 (file)
index 0000000..e35d1d8
--- /dev/null
@@ -0,0 +1,36 @@
+{% extends "base.html" %}
+{% load i18n %}
+{% load catalogue_tags pagination_tags %}
+
+{% block title %}{{ book.title }} w WolneLektury.pl{% endblock %}
+
+{% block bodyid %}book-stub-detail{% endblock %}
+
+{% block body %}
+    <h1>{{ book.title }}, {{ book.author }}</h1>
+    <form action="{% url search %}" method="get" accept-charset="utf-8" id="search-form">
+        <p>{{ form.q }} <input type="submit" value="{% trans "Search" %}" /> <strong>{% trans "or" %}</strong> <a href="{% url main_page %}">{% trans "return to main page" %}</a></p>
+    </form>
+
+    <div id="books-list">
+    {% if book.in_pd %}
+               {% trans "This work is in public domain and will be published on Internet school library of Wolne Lektury soon." %}
+       {% else %}
+           {% if book.pd %}
+                       {% trans "This work will become part of public domain and will be allowed to be published without restrictions in" %}
+                   {% include "catalogue/pd_counter.html" %}
+                       {% trans "Find out why Internet libraries can't publish this work." %}
+               {% else %}
+                   {% trans "This work is copyrighted." %}
+               {% endif %}
+       {% endif %}
+    {% include "info/join_us.html" %}
+    </div>
+
+    <div id="set-window">
+        <div class="header"><a href="#" class="jqmClose">{% trans "Close" %}</a></div>
+        <div class="target">
+            <p><img src="{{ STATIC_URL }}img/indicator.gif" alt="*"/> {% trans "Loading" %}</p>
+        </div>
+    </div>
+{% endblock %}
\ No newline at end of file
index b3d18ea..d828265 100644 (file)
@@ -1,3 +1,4 @@
+{% load i18n %}
 {% load chunks compressed catalogue_tags %}
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
@@ -5,7 +6,7 @@
     <head>
         <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
         <title>{% block title %}WolneLektury.pl{% endblock %}</title>
-        <link rel="icon" href="/static/img/favicon.png" type="image/x-icon" />
+        <link rel="icon" href="{{ STATIC_URL }}img/favicon.png" type="image/x-icon" />
         {% compressed_css "book" %}
         {% compressed_js "jquery" %}
         {% compressed_js "book" %}
     <body>
         <div id="menu">
             <ul>
-                <li><a href="#toc">Spis treści</a></li>
-                <li><a href="#themes">Motywy</a></li>
+                <li><a href="#toc">{% trans "Table of contents" %}</a></li>
+                <li><a href="#themes">{% trans "Themes" %}</a></li>
             </ul>
         </div>
         <div id="header">
             <div id="logo">
-                <a href="/"><img src="/static/img/logo.png" alt="WolneLektury.pl - logo" /></a>
+                <a href="/"><img src="{{ STATIC_URL }}img/logo.png" alt="WolneLektury.pl - logo" /></a>
             </div>
         </div>
         <div id="themes">
index ecf8dba..5aafeb9 100644 (file)
@@ -1,12 +1,24 @@
+{% load i18n %}
 {% load catalogue_tags %}
-<form action="{% url search %}" method="get" accept-charset="utf-8" id="search-form">
-    <ol>
+<div id="searchContainer">
+    <form action="{% url search %}" method="get" accept-charset="utf-8" id="search-form">
+    <ul class="facelist-selections" style="float:left;">
         {% for tag in tag_list %}
-        <li class="category"><a href="{% catalogue_url tag %}">{{ tag }}</a> | <a href="{% catalogue_url tag_list -tag %}">x</a></li>
+        <li class="facelist-selection-item">
+               <span style="margin-left: 5px;">
+               <a href="{% catalogue_url tag %}">{{ tag }}</a>
+               <a class="facelist-close" href="{% catalogue_url tag_list -tag %}">x</a>
+               </span>
+           </li>
+        {% empty %}
+            <li class="facelist-selection-item">
+            </li>
         {% endfor %}
         {% if search_form %}
-            <li>{{ search_form.q }} {{ search_form.tags }} <input type="submit" value="Szukaj"/></li>
+            <li>{{ search_form.q }} {{ search_form.tags }}</li>
         {% endif %}
-    </ol>
-    <div class="clearboth"></div>
-</form>
\ No newline at end of file
+    </ul>
+    <input type="submit" value="{% trans "Search" %}" id="searchSubmit"/>
+    </form>
+</div>    
+<div class="clearboth"></div>
diff --git a/wolnelektury/templates/catalogue/differentiate_tags.html b/wolnelektury/templates/catalogue/differentiate_tags.html
new file mode 100644 (file)
index 0000000..1e7a1a7
--- /dev/null
@@ -0,0 +1,28 @@
+{% extends "base.html" %}
+{% load i18n %}
+{% load catalogue_tags %}
+
+{% block title %}{% title_from_tags tags %} w WolneLektury.pl{% endblock %}
+
+{% block bodyid %}differentiate_tags{% endblock %}
+
+{% block body %}
+    <h1>{% title_from_tags tags %}</h1>
+    {% breadcrumbs tags %}
+
+       <p>{% trans "The criteria are ambiguous. Please select one of the following options:" %}</p>
+    <div id="books-list">
+        {% for option in options %}
+        <div class="book-description"
+            <p><a href="{% url tagged_object_list option.url_args %}">{% if tags %}{% title_from_tags tags %}, {% endif %}<em>{%title_from_tags option.tags %}</em>{% if unparsed %}, {{unparsed|join:', '}}{% endif %}</a></p>
+               </div>
+        {% endfor %}
+    </div>
+
+    <div id="set-window">
+        <div class="header"><a href="#" class="jqmClose">{% trans "Close" %}</a></div>
+        <div class="target">
+            <p><img src="{{ STATIC_URL }}img/indicator.gif" alt="*"/> {% trans "Loading" %}</p>
+        </div>
+    </div>
+{% endblock %}
\ No newline at end of file
index 62896fc..a6ff53a 100644 (file)
@@ -1,6 +1,7 @@
+{% load i18n %}
 {% load catalogue_tags %}
 {% if one_tag %}
-    <p>Zobacz całą kategorię <a href="{% catalogue_url one_tag %}">{{ one_tag }}</a>.</p>
+    <p>{% trans "Show full category" %} <a href="{% catalogue_url one_tag %}">{{ one_tag }}</a>.</p>
 {% else %}
     <div class="shown-tags">
         <ul class="shown-tags">
@@ -9,7 +10,7 @@
             {% endfor %}
         </ul>
         {% if some_tags_hidden %}
-            <p><a href="#" class="show-all-tags">Zobacz więcej</a></p>
+            <p><a href="#" class="show-all-tags">{% trans "See more" %}</a></p>
         {% endif %}
     </div>
     <div class="all-tags">
@@ -17,7 +18,7 @@
             {% for tag in tags %}
                 <li><a href="{% catalogue_url choices tag %}">{{ tag }}&nbsp;({{ tag.count }})</a></li>
             {% endfor %}
-        </ul>    
-        <p><a href="#" class="hide-all-tags">Zwiń</a></p>
+        </ul>
+        <p><a href="#" class="hide-all-tags">{% trans "Hide" %}</a></p>
     </div>
 {% endif %}
index c7d641c..b270636 100644 (file)
@@ -1,17 +1,18 @@
-<h2>Półki zawierające fragment</h2>
+{% load i18n %}
+<h2>{% trans "Shelves containing fragment" %}</h2>
 {% if not user.tag_set.count %}
-    <p>Nie posiadasz żadnych półek. Jeśli chcesz, możesz utworzyć nową półkę poniżej.</p>
+    <p>{% trans "You do not own any shelves. You can create one below, if you want to." %}</p>
 {% else %}
     <form action="{% url catalogue.views.fragment_sets fragment.id %}" method="POST" accept-charset="utf-8" class="cuteform">
     <ol>
         <li>{{ form.set_ids }}</li>
-        <li><input type="submit" value="Zapisz półki"/></li>
+        <li><input type="submit" value="{% trans "Save all shelves" %}"/></li>
     </ol>
     </form>
 {% endif %}
 <hr />
 <form action="{% url catalogue.views.new_set %}" method="POST" accept-charset="utf-8" class="cuteform">
 <ol>
-    <li>{{ new_set_form.name }} <input type="submit" value="Utwórz nową półkę"/></li>
+    <li>{{ new_set_form.name }} <input type="submit" value="{% trans "Create new shelf" %}"/></li>
 </ol>
 </form>
\ No newline at end of file
index aaab2bf..4526857 100644 (file)
@@ -1,22 +1,21 @@
+{% load i18n %}
+{% load catalogue_tags %}
 <div class="fragment">
-    {# <div class="change-sets"> #}
-    {#     <a href="{% url catalogue.views.fragment_sets fragment.id %}" class="jqm-trigger">Półki</a> #}
-    {# </div> #}
     {% if fragment.short_text %}
     <div class='fragment-short-text'>
         {{ fragment.short_text|safe }}
-        <a href="#">↓ Rozwiń fragment ↓</a>
+        <a href="#">↓ {% trans "Expand fragment" %} ↓</a>
     </div>
     {% endif %}
     <div class="fragment-text" {% if fragment.short_text %}style="display:none;"{% endif %}>
         {{ fragment.text|safe }}
         {% if fragment.short_text %}
-            <a href="#">↑ Zwiń fragment ↑</a>
+            <a href="#">↑ {% trans "Hide fragment" %} ↑</a>
         {% endif %}
     </div>
     <div class="fragment-metadata">
-        <p><a href="{{ book.get_absolute_url }}">{{ book.title }}</a>, {{ book_authors|join:"," }}
-           <a href="{{ fragment.get_absolute_url }}">(Zobacz w utworze)</a></p>
+        <p>{% book_title_html fragment.book %}
+           <a href="{{ fragment.get_absolute_url }}">({% trans "See in a book" %})</a></p>
     </div>
     <div class="clearboth"></div>
 </div>
index 756bd74..cef3604 100644 (file)
@@ -1,4 +1,5 @@
 {% extends "base.html" %}
+{% load i18n %}
 {% load catalogue_tags chunks cache %}
 
 {% block bodyid %}main-page{% endblock %}
     </div>
     <div class="clearboth"></div>
     <form action="{% url search %}" method="get" accept-charset="utf-8" id="search-form">
-        <p>{{ form.q }} {{ form.tags }} <input type="submit" value="Szukaj" /> <strong>lub</strong> <a href="{% url catalogue.views.book_list %}">zobacz spis utworów</a> w naszym zbiorze</p>
+        <p>{{ form.q }} {{ form.tags }} <input type="submit" value="{% trans "Search" %}" /> <strong>{% trans "or" %}</strong> <a href="{% url catalogue.views.book_list %}">{% trans "check list of books" %}</a> {% trans "in our repository" %}</p>
     </form>
-    
+
     <div id="intro">
-        <p id="tags-description">↓ Przeglądaj lektury według wybranych kategorii ↓</p>
+        <p id="tags-description">↓ {% trans "Browse books by categories" %} ↓</p>
         <div id="propaganda">
-            <h2>Twoje półki z lekturami</h2>
+            <h2>{% trans "Wolne Lektury Widget" %}</h2>
+            <p>{% trans "Place our widget - search engine for Wolne Lektury which gives access to free books and audiobooks - on your homepage! Just copy the HTML code below onto your page:" %}</p>
+            <textarea rows="2" cols="35"><!-- START {% trans "Insert this element in place where you want display the widget" %} -->
+<div id="wl" />
+<!-- END -->
+<!-- START {% trans "Place this element just before closing body tag: </body>" %} -->
+<script type="text/javascript" src="http://www.wolnelektury.pl/static/js/widget.js"></script>
+<!-- END --></textarea>
+                <p class="see-more"><a href="{% url widget %}">{% trans "See more" %} ⇒</a></p>
+            <h2>{% trans "Your shelves with books" %}</h2>
             {% if user.is_authenticated %}
                 {% if shelves %}
                 <ul class="shelf-list">
                 {% for shelf in shelves %}
-                    <li><a href="{% url delete_shelf shelf.slug %}" class="delete-shelf">usuń</a> <a href="{{ shelf.get_absolute_url }}" class="visit-shelf">{{ shelf.name }} ({{ shelf.book_count }})</a></li>
+                    <li><a href="{% url delete_shelf shelf.slug %}" class="delete-shelf">{% trans "delete" %}</a> <a href="{{ shelf.get_absolute_url }}" class="visit-shelf">{{ shelf.name }} ({{ shelf.get_count }})</a></li>
                 {% endfor %}
                 </ul>
                 {% else %}
-                <p>Nie posiadasz żadnych półek. Jeśli chcesz, możesz utworzyć półkę poniżej.</p>
+                <p>{% trans "You do not own any shelves. You can create one below, if you want to." %}</p>
                 {% endif %}
                 <hr />
                 <form action="{% url catalogue.views.new_set %}" method="post" accept-charset="utf-8" class="cuteform">
                 <ol>
-                    <li>{{ new_set_form.name }} <input type="submit" value="Utwórz półkę"/></li>
+                    <li>{{ new_set_form.name }} <input type="submit" value="{% trans "Create shelf" %}"/></li>
                 </ol>
                 </form>
             {% else %}
-                <p>Stwórz własny zestaw lektur. Możesz się nim później podzielić z innymi, przesyłając im link do Twojej półki.</p>
-                <p>Aby zarządzać swoimi półkami, musisz się <a class="login-register-link" href="#">zalogować</a>.</p>
+                <p>{% trans "Create your own book set. You can share it with friends by sending them link to your shelf." %}</p>
+                <p>{% trans "You need to " %}<a class="login-register-link" href="#">{% trans "sign in" %}</a> {% trans "to manage your shelves." %}</p>
             {% endif %}
             <div id="lessons">
-                <h2><a href="{% url lessons_document_list %}">Materiały pomocnicze dla nauczycieli</a></h2>
-                <p>Scenariusze lekcji i inne pomysły na wykorzytanie serwisu WolneLektury.pl podczas nauczania.</p>
-                <p class="see-more"><a href="{% url lessons_document_list %}">Zobacz więcej ⇒</a></p>
+                <h2><a href="{% url lessons_document_list %}">{% trans "Hand-outs for teachers" %}</a></h2>
+                <p>{% trans "Lessons' prospects and other ideas for using Wolnelektury.pl for teaching." %}</p>
+                <p class="see-more"><a href="{% url lessons_document_list %}">{% trans "See more" %} ⇒</a></p>
             </div>
             <div id="czytamysluchajac">
-                <a href="http://czytamysluchajac.pl/"><img src="/static/img/czytamysluchajac-logo-small.png" /></a>
-                <p><a href="http://czytamysluchajac.pl/">Czytamy Słuchając</a> to profesjonalne nagrania tekstów literackich z naszego zbioru dostępne na wolnej licencji w formatach MP3, Ogg Vorbis oraz w systemie DAISY.</p>
-                <p class="see-more"><a href="http://czytamysluchajac.pl/index.php/o-projekcie/">Zobacz więcej ⇒</a></p>
+                <a href="http://czytamysluchajac.pl/"><img src="{{ STATIC_URL }}img/czytamysluchajac-logo-small.png" alt="CzytamySluchajac - logo" style="float:left; padding: 10px;" /></a>
+                <p style="padding-top:10px;"><a href="http://czytamysluchajac.pl/">Czytamy Słuchając</a> {% trans "are professional recordings of literary texts from our repository, available on free license in MP3 and Ogg Vorbis formats as well as in DAISY system." %}</p>
+                <p class="see-more"><a href="http://czytamysluchajac.pl/index.php/o-projekcie/">{% trans "See more" %} ⇒</a></p>
             </div>
         </div>
         <div id="tags-list">
             <div id="categories-list">
                 {% if categories.author %}
-                    <h2>Autorzy</h2>
+                    <h2>{% trans "Authors" %}</h2>
                     {% folded_tag_list categories.author %}
                 {% endif %}
                 {% if categories.kind %}
-                    <h2>Rodzaje</h2>
+                    <h2>{% trans "Kinds" %}</h2>
                     {% folded_tag_list categories.kind %}
                 {% endif %}
                 {% if categories.genre %}
-                    <h2>Gatunki</h2>
+                    <h2>{% trans "Genres" %}</h2>
                     {% folded_tag_list categories.genre %}
                 {% endif %}
                 {% if categories.epoch %}
-                    <h2>Epoki</h2>
+                    <h2>{% trans "Epochs" %}</h2>
                     {% folded_tag_list categories.epoch %}
                 {% endif %}
             </div>
             <div id="themes-list">
                 {% if fragment_tags %}
-                    <h2>Motywy i tematy</h2>
+                    <h2>{% trans "Themes and topics" %}</h2>
                     {% folded_tag_list fragment_tags %}
                 {% endif %}
-                <h2>Rodziny motywów</h2>
+                <h2>{% trans "Themes groups" %}</h2>
                 <div class="shown-tags">
                     <ol>
                         <li>środowisko miejskie i wiejskie
 
                         <li>polityczny obraz świata
                         <span class="subcategories"><a href="/katalog/panstwo/">Państwo</a>, <a href="/katalog/obowiazek/">Obowiązek</a>, <a href="/katalog/cnota/">Cnota</a>, <a href="/katalog/obywatel/">Obywatel</a>, <a href="/katalog/patriota/">Patriota</a>, <a href="/katalog/ojczyzna/">Ojczyzna</a>, <a href="/katalog/narod/">Naród</a>, <a href="/katalog/przywodca/">Przywódca</a>, <a href="/katalog/wladza/">Władza</a>, <a href="/katalog/urzednik/">Urzędnik</a>, <a href="/katalog/krol/">Król</a>, <a href="/katalog/rycerz/">Rycerz</a>, <a href="/katalog/zolnierz/">Żołnierz</a>, <a href="/katalog/wojna/">Wojna</a>, <a href="/katalog/wrog/">Wróg</a>, <a href="/katalog/zwyciestwo/">Zwycięstwo</a>, <a href="/katalog/walka/">Walka</a>, <a href="/katalog/sila/">Siła</a>, <a href="/katalog/historia/">Historia</a>, <a href="/katalog/powstanie/">Powstanie</a>, <a href="/katalog/smierc-bohaterska/">Śmierć bohaterska</a>, <a href="/katalog/slawa/">Sława</a>, <a href="/katalog/rewolucja/">Rewolucja</a>, <a href="/katalog/sad/">Sąd</a>, <a href="/katalog/zdrada/">Zdrada</a></span></li>
-                       
+
                         <li>przyroda
                         <span class="subcategories"><a href="/katalog/natura/">Natura</a>, <a href="/katalog/zywioly/">Żywioły</a>, <a href="/katalog/ogien/">Ogień</a>, <a href="/katalog/ziemia/">Ziemia</a>, <a href="/katalog/wiatr/">Wiatr</a>, <a href="/katalog/woda/">Woda</a>, <a href="/katalog/wiosna/">Wiosna</a>, <a href="/katalog/lato/">Lato</a>, <a href="/katalog/jesien/">Jesień</a>, <a href="/katalog/zima/">Zima</a>, <a href="/katalog/przemijanie/">Przemijanie</a>, <a href="/katalog/slonce/">Słońce</a>, <a href="/katalog/ksiezyc/">Księżyc</a>, <a href="/katalog/gwiazda/">Gwiazda</a>, <a href="/katalog/oblok/">Obłok</a>, <a href="/katalog/noc/">Noc</a>, <a href="/katalog/swiatlo/">Światło</a>, <a href="/katalog/gora/">Góra</a>, <a href="/katalog/rzeka/">Rzeka</a>, <a href="/katalog/morze/">Morze</a>, <a href="/katalog/burza/">Burza</a>, <a href="/katalog/deszcz/">Deszcz</a>, <a href="/katalog/bloto/">Błoto</a>, <a href="/katalog/przyroda-nieozywiona/">Przyroda nieożywiona</a>, <a href="/katalog/rosliny/">Rośliny</a>, <a href="/katalog/kwiaty/">Kwiaty</a>, <a href="/katalog/ogrod/">Ogród</a>, <a href="/katalog/sielanka/">Sielanka</a>, <a href="/katalog/raj/">Raj</a>, <a href="/katalog/jablko/">Jabłko</a>, <a href="/katalog/drzewo/">Drzewo</a>, <a href="/katalog/zwierzeta/">Zwierzęta</a>, <a href="/katalog/ptak/">Ptak</a>, <a href="/katalog/motyl/">Motyl</a>, <a href="/katalog/kot/">Kot</a>, <a href="/katalog/kon/">Koń</a>, <a href="/katalog/pies/">Pies</a>, <a href="/katalog/waz/">Wąż</a>, <a href="/katalog/potwor/">Potwór</a></span></li>
                     </ol>
-                    <p><a href="#" class="show-all-tags">Zobacz więcej</a></p>
+                    <p><a href="#" class="show-all-tags">{% trans "See more" %}</a></p>
                 </div>
                 <div class="all-tags">
                     <ol>
                     <li>żywioły
                     <span class="subcategories"><a href="/katalog/zywioly/">Żywioły</a>, <a href="/katalog/ogien/">Ogień</a>, <a href="/katalog/ziemia/">Ziemia</a>, <a href="/katalog/wiatr/">Wiatr</a>, <a href="/katalog/woda/">Woda</a>, <a href="/katalog/przestrzen/">Przestrzeń</a></span></li>
                     </ol>
-                    <p><a href="#" class="hide-all-tags">Zwiń</a></p>
+                    <p><a href="#" class="hide-all-tags">{% trans "Hide" %}</a></p>
                 </div>
             </div>
             <div class="clearboth"></div>
         </div>
     </div>
     <div class="clearboth"></div>
-    
+
     <div id="site-info">
         <div id="latest-blog-posts">
-            <h2>Aktualności</h2>
+            <h2>{% trans "News" %}</h2>
             {% cache 1800 latest-blog-posts %}
             {% latest_blog_posts "http://www.nowoczesnapolska.org.pl/tematy/wolne-lektury/feed/" %}
             {% endcache %}
-            <p class="see-more"><a href="http://www.nowoczesnapolska.org.pl/">Zobacz nasz blog ⇒</a></p>
+            <p class="see-more"><a href="http://www.nowoczesnapolska.org.pl/">{% trans "See our blog" %} ⇒</a></p>
         </div>
         <div id="you-can-help">
-            <h2>Możesz nam pomóc!</h2>
-            <p>Utwory włączane sukcesywnie do naszej biblioteki staramy się opracowywać jak najdokładniej. Jest to możliwe tylko dzięki współpracującym z nami wolontariuszom.</p>
-            <p>Zapraszamy wszystkie osoby, które chcą współtworzyć szkolną bibliotekę internetową Wolne Lektury.</p>
-            <p class="see-more"><a href="{% url help_us %}">Zobacz więcej ⇒</a></p>
+            <h2>{% trans "You can help us!" %}</h2>
+            <p>{% trans "We try our best to elaborate works appended to our library. It is possible only due to support of our volunteers." %}</p>
+            <p>{% trans "We invite people who want to take part in developing Internet school library Wolne Lektury." %}</p>
+            <p class="see-more"><a href="{% url help_us %}">{% trans "See more" %} ⇒</a></p>
         </div>
         <div id="about-us">
-            <h2>O projekcie</h2>
-            <p>Biblioteka internetowa z lekturami szkolnymi „Wolne Lektury” (<a href="http://wolnelektury.pl">www.wolnelektury.pl</a>) to projekt realizowany przez Fundację Nowoczesna Polska. Działa od 2007 roku i udostępnia w swoich zbiorach lektury szkolne, które są zalecane do użytku przez Ministerstwo Edukacji Narodowej i które trafiły już do domeny publicznej.
+            <h2>{% trans "About us" %}</h2>
+            <p>
+               {% blocktrans %}
+                       Internet library with school readings “Wolne Lektury” (<a href="http://wolnelektury.pl">www.wolnelektury.pl</a>) is a project made by Modern Poland Foundation. It started in 2007 and shares school readings, which are recommended by Ministry of National Education and are in public domain.
+                       {% endblocktrans %}
             </p>
-            <p class="see-more"><a href="{% url about_us %}">Zobacz więcej ⇒</a></p>
+            <p class="see-more"><a href="{% url about_us %}">{% trans "See more" %} ⇒</a></p>
         </div>
     </div>
 {% endblock %}
diff --git a/wolnelektury/templates/catalogue/pd_counter.html b/wolnelektury/templates/catalogue/pd_counter.html
new file mode 100644 (file)
index 0000000..79c0ada
--- /dev/null
@@ -0,0 +1,6 @@
+<div id='countdown'></div>
+<script>
+$.countdown.setDefaults($.countdown.regional['{{ LANGUAGE_CODE }}']);
+d = new Date({{ pd_counter }}, 1, 1);
+$('#countdown').countdown({until: d, format: 'ydHMS', serverSync: serverTime});
+</script>
diff --git a/wolnelektury/templates/catalogue/search_multiple_hits.html b/wolnelektury/templates/catalogue/search_multiple_hits.html
new file mode 100644 (file)
index 0000000..b569e7d
--- /dev/null
@@ -0,0 +1,34 @@
+{% extends "base.html" %}
+{% load i18n %}
+{% load catalogue_tags pagination_tags %}
+
+{% block title %}{% trans "Searching in" %} WolneLektury.pl{% endblock %}
+
+{% block bodyid %}tagged-object-list{% endblock %}
+
+{% block body %}
+    <h1>{% title_from_tags tags %}</h1>
+    {% breadcrumbs tags %}
+
+    <div id="books-list">
+        <p>{% trans "More than one result matching the criteria found." %}</p>
+        <ul class='matches'>
+        {% for match, link, type in results %}
+          <li>{% trans type %}: <a href='{{ link }}'>
+            {% ifequal type "book" %}
+                {% book_title match %}
+            {% else %}
+                {{ match.name }}
+            {% endifequal %}
+          </a></li>
+        {% endfor %}
+        </ul>
+    </div>
+
+    <div id="set-window">
+        <div class="header"><a href="#" class="jqmClose">{% trans "Close" %}</a></div>
+        <div class="target">
+            <p><img src="{{ STATIC_URL }}img/indicator.gif" alt="*"/> {% trans "Loading" %}</p>
+        </div>
+    </div>
+{% endblock %}
\ No newline at end of file
diff --git a/wolnelektury/templates/catalogue/search_no_hits.html b/wolnelektury/templates/catalogue/search_no_hits.html
new file mode 100644 (file)
index 0000000..1a92e4b
--- /dev/null
@@ -0,0 +1,27 @@
+{% extends "base.html" %}
+{% load i18n %}
+{% load catalogue_tags pagination_tags %}
+
+{% block title %}{% trans "Search in WolneLektury.pl" %}{% endblock %}
+
+{% block bodyid %}tagged-object-list{% endblock %}
+
+{% block body %}
+    <h1>{% title_from_tags tags %}</h1>
+    {% breadcrumbs tags %}
+
+    <div id="books-list">
+        <p>{% trans "Sorry! Search cirteria did not match any resources." %}</p>
+
+               <p>{% blocktrans %}Search engine supports following criteria: title, author, theme/topic, epoch, kind and genre.
+               As for now we do not support full text search.{% endblocktrans %}</p>
+        {% include "info/join_us.html" %}
+    </div>
+
+    <div id="set-window">
+        <div class="header"><a href="#" class="jqmClose">{% trans "Close" %}</a></div>
+        <div class="target">
+            <p><img src="{{ STATIC_URL }}img/indicator.gif" alt="*"/> {% trans "Loading" %}</p>
+        </div>
+    </div>
+{% endblock %}
\ No newline at end of file
diff --git a/wolnelektury/templates/catalogue/search_too_short.html b/wolnelektury/templates/catalogue/search_too_short.html
new file mode 100644 (file)
index 0000000..e10ddc2
--- /dev/null
@@ -0,0 +1,24 @@
+{% extends "base.html" %}
+{% load i18n %}
+{% load catalogue_tags pagination_tags %}
+
+{% block title %}{% trans "Searching in" %} WolneLektury.pl{% endblock %}
+
+{% block bodyid %}tagged-object-list{% endblock %}
+
+{% block body %}
+    <h1>{% title_from_tags tags %}</h1>
+    {% breadcrumbs tags %}
+
+    <div id="books-list">
+        <p>{% trans "Sorry! Search query must have at least two characters." %}</p>
+        {% include "info/join_us.html" %}
+    </div>
+
+    <div id="set-window">
+        <div class="header"><a href="#" class="jqmClose">{% trans "Close" %}</a></div>
+        <div class="target">
+            <p><img src="{{ STATIC_URL }}img/indicator.gif" alt="*"/> {% trans "Loading" %}</p>
+        </div>
+    </div>
+{% endblock %}
\ No newline at end of file
index 673135c..e96320e 100644 (file)
@@ -1,6 +1,7 @@
+{% load i18n %}
 {% load catalogue_tags %}
 {% if one_tag %}
-    <p>Zobacz całą kategorię <a href="{% catalogue_url one_tag %}">{{ one_tag }}</a></p>
+    <p>{% trans "See full category" %} <a href="{% catalogue_url one_tag %}">{{ one_tag }}</a></p>
 {% else %}
     <ul>
         {% for tag in tags %}
index 88c06f2..b24929c 100644 (file)
@@ -1,5 +1,6 @@
 {% extends "base.html" %}
-{% load catalogue_tags pagination_tags %}
+{% load i18n %}
+{% load catalogue_tags pagination_tags switch_tag %}
 
 {% block title %}{% title_from_tags tags %} w WolneLektury.pl{% endblock %}
 
@@ -8,11 +9,11 @@
 {% block body %}
     <h1>{% title_from_tags tags %}</h1>
     {% breadcrumbs tags %}
-    
-    {% if shelf_is_set and not object_list %}
+
+    {% if only_shelf and not object_list %}
     <div id="books-list">
-        <h2>Twoja półka jest pusta</h2>
-        <p>Możesz wrzucić książkę na półkę, wchodząc na stronę danej lektury i klikając na przycisk „Na półkę!”.</p>
+        <h2>{% trans "Your shelf is empty" %}</h2>
+        <p>{% trans "You can put a book on a shelf by entering page of the reading and clicking 'Put on the shelf'." %}</p>
     </div>
     {% else %}
     {% autopaginate object_list 10 %}
         {% with tags|last as last_tag %}
         {% if last_tag.has_description %}
             <div id="description">
-                {{ last_tag.description|safe }}
+                <div id='description-long'>{{ last_tag.description|safe }}</div>
+                <div id='description-short'>{{ last_tag.description|safe|truncatewords_html:30 }}</div>
             </div>
             <div class="clearboth"></div>
-            <div id="toggle-description"><p>Zwiń opis ▲</p></div>
+            <div id="toggle-description"><p></p></div>
         {% endif %}
-        {% if shelf_is_set %}
+        {% if only_shelf %}
             <a id="download-shelf" href="{% url download_shelf last_tag.slug %}">
-                Pobierz wszystkie książki z tej półki
+                {% trans "Download all books from this shelf" %}
             </a>
             <div id="download-shelf-menu" style="display:none;">
                 <form action="{% url download_shelf last_tag.slug %}" method="get" accept-charset="utf-8" id="download-formats-form" data-formats-feed="{% url shelf_book_formats last_tag.slug %}">
-                    <p>Wybierz formaty książek, które chcesz pobrać:</p>
-                    <li data-format="pdf"><label for="id_formats_2"><input type="checkbox" name="formats" value="pdf" id="id_formats_2" /> PDF</label> <em><strong>do czytania</strong> i drukowania przy pomocy <a href="http://get.adobe.com/reader/">Adobe Reader</a></em></li>
-                    <li data-format="odt"><label for="id_formats_3"><input type="checkbox" name="formats" value="odt" id="id_formats_3" /> ODT</label> <em><strong>do czytania</strong> i edytowania przy pomocy <a href="http://pl.openoffice.org/">OpenOffice.org</a></em></li>
-                    <li data-format="txt"><label for="id_formats_4"><input type="checkbox" name="formats" value="txt" id="id_formats_4" /> TXT</label> <em><strong>do czytania</strong> na małych ekranach, np. na komórce</em></li>
-                    <li data-format="mp3"><label for="id_formats_0"><input type="checkbox" name="formats" value="mp3" id="id_formats_0" /> MP3</label> <em><strong>do słuchania</strong> w ulubionym odtwarzaczu MP3</em></li>
-                    <li data-format="ogg"><label for="id_formats_1"><input type="checkbox" name="formats" value="ogg" id="id_formats_1" /> Ogg Vorbis</label> <em><strong>do słuchania</strong> &mdash; otwarty format <a href="http://www.vorbis.com/">Fundacji Xiph.Org</a></em></li>
-                    <li id="download-formats-form-submit-li"><label><input type="submit" name="submit" value="Pobierz" id="download-formats-form-submit" disabled="disabled" />&nbsp;<img src="/static/img/indicator.gif" /></label> <span id="updating-formats">Uaktualniam listę formatów książek na półce.</span><span id="formats-updated" style="display:none;">lub <a href="#" id="download-formats-form-cancel">anuluj</a></span></li>
+                    <p>{% trans "Choose books' formats which you want to download:" %}</p>
+                    <li data-format="pdf"><label for="id_formats_2"><input type="checkbox" name="formats" value="pdf" id="id_formats_2" /> PDF</label> <em><strong>{% trans "for reading" %}</strong> {% trans "and printing using" %} <a href="http://get.adobe.com/reader/">Adobe Reader</a></em></li>
+                    <li data-format="epub"><label for="id_formats_5"><input type="checkbox" name="formats" value="epub" id="id_formats_5" /> EPUB</label> </li>
+                    <li data-format="odt"><label for="id_formats_3"><input type="checkbox" name="formats" value="odt" id="id_formats_3" /> ODT</label> <em><strong>{% trans "for reading" %}</strong> {% trans "and editing using" %} <a href="http://pl.openoffice.org/">OpenOffice.org</a></em></li>
+                    <li data-format="txt"><label for="id_formats_4"><input type="checkbox" name="formats" value="txt" id="id_formats_4" /> TXT</label> <em><strong>{% trans "for reading" %}</strong> {% trans "on small displays, for example mobile phones" %}</em></li>
+                    <li data-format="mp3"><label for="id_formats_0"><input type="checkbox" name="formats" value="mp3" id="id_formats_0" /> MP3</label> <em><strong>{% trans "for listening" %}</strong> {% trans "on favourite MP3 player" %}</em></li>
+                    <li data-format="ogg"><label for="id_formats_1"><input type="checkbox" name="formats" value="ogg" id="id_formats_1" /> Ogg Vorbis</label> <em><strong>{% trans "for listening" %}</strong> &mdash; {% trans "open format" %} <a href="http://www.vorbis.com/">{% trans "Xiph.org Foundation" %}</a></em></li>
+                    <li id="download-formats-form-submit-li"><label><input type="submit" name="submit" value="{% trans "Download" %}" id="download-formats-form-submit" disabled="disabled" />&nbsp;<img src="{{ STATIC_URL }}img/indicator.gif" /></label> <span id="updating-formats">{% trans "Updating list of books' formats on the shelf" %}</span><span id="formats-updated" style="display:none;">{% trans "or" %} <a href="#" id="download-formats-form-cancel">{% trans "cancel" %}</a></span></li>
                     <div class="clearboth"></div>
                 </form>
             </div>
+            {% if only_my_shelf %}
+            <div id="toggle-share-shelf"><p>{% trans "Share this shelf" %}</p></div>
+            <div id="share-shelf">
+                <p>{% trans "Copy this link and share it with other people to let them see your shelf." %}
+                <input id="share-shelf-url" value='http://{{ request.META.HTTP_HOST }}{{ request.path }}' />
+                </p>
+            </div>
+                       {% endif %}
         {% endif %}
         {% if last_tag.gazeta_link %}
         <p><a href="{{ last_tag.gazeta_link }}">
-            {% ifequal last_tag.category "author" %}Przeczytaj omówienia utworów autora w serwisie Lektury.Gazeta.pl{% endifequal %}
-            {% ifequal last_tag.category "epoch"  %}Przeczytaj omówienia z epoki {{ last_tag }} w serwisie Lektury.Gazeta.pl{% endifequal %}
+            {% switch last_tag.category %}
+                {% case "author" %}
+                    {% trans "Read work's study of this author on Lektury.Gazeta.pl" %}
+                {% case "epoch" %}
+                    {% blocktrans %}Read study of epoch {{ last_tag }} on Lektury.Gazeta.pl{% endblocktrans %}
+                {% case "kind" %}
+                    {% blocktrans %}Read study of kind {{ last_tag }} on Lektury.Gazeta.pl{% endblocktrans %}
+                {% case "genre" %}
+                    {% blocktrans %}Read study of genre {{ last_tag }} on Lektury.Gazeta.pl{% endblocktrans %}
+                {% else %}
+                    {% trans "Read related study on Lektury.Gazeta.pl" %}
+            {% endswitch %}
         </a></p>
         {% endif %}
         {% if last_tag.wiki_link %}
         <p><a href="{{ last_tag.wiki_link }}">
-            {% ifequal last_tag.category "author" %}Przeczytaj artykuł o autorze w Wikipedii{% endifequal %}
-            {% ifequal last_tag.category "epoch"  %}Przeczytaj artykuł o epoce {{ last_tag }} w Wikipedii{% endifequal %}
+               {% switch last_tag.category %}
+                           {% case "author" %}
+                                   {% trans "Read article about this author on Wikipedia" %}
+                               {% case "epoch" %}
+                    {% blocktrans %}Read article about epoch {{ last_tag }} on Wikipedia{% endblocktrans %}
+                               {% case "kind" %}
+                    {% blocktrans %}Read article about kind {{ last_tag }} on Wikipedia{% endblocktrans %}
+                               {% case "genre" %}
+                    {% blocktrans %}Read article about genre {{ last_tag }} on Wikipedia{% endblocktrans %}
+                               {% else %}
+                                   {% trans "Read related article on Wikipedia" %}
+                       {% endswitch %}
         </a></p>
         {% endif %}
-        <ol>
-        {% for book in object_list %}
-            <li>
-                {% if user_is_owner %}
-                    <a href="{% url remove_from_shelf last_tag.slug book.slug %}" class="remove-from-shelf">Usuń</a>
+
+        {% if object_list %}
+            <ol>
+            {% for book in object_list %}
+                <li>
+                    {% if user_is_owner %}
+                        <a href="{% url remove_from_shelf last_tag.slug book.slug %}" class="remove-from-shelf">{% trans "Delete" %}</a>
+                    {% endif %}
+                    {{ book.short_html }}</li>
+            {% endfor %}
+            </ol>
+        {% else %}
+                       {% if only_author %}
+                   {% if last_tag.alive %}
+                                       {% trans "This author's works are copyrighted." %}
+                               {% else %}{% comment %} Is dead {% endcomment %}
+                   {% if last_tag.in_pd %}
+                                               <p>{% trans "This author's works are in public domain and will be published on Internet school library of Wolne Lektury soon." %}</p>
+                       {% else %}
+                                               {% comment %} Is dead, but not yet in public domain {% endcomment %}
+                       <div>
+                               <p>{% trans "This author's works will become part of public domain and will be allowed to be published without restrictions in" %}</p>
+                                                       {% include "catalogue/pd_counter.html" %}
+                            <p>{% trans "Find out why Internet libraries can't publish this author's works." %}</p>
+                                               </div>
+                       {% endif %}
                 {% endif %}
-                {{ book.short_html }}</li>
-        {% endfor %}
-        </ol>
+                       {% else %}
+                           {% trans "Sorry! Search cirteria did not match any resources." %}
+                       {% endif %}
+            {% include "info/join_us.html" %}
+        {% endif %}
         {% endwith %}
         {% paginate %}
     </div>
+       {% if object_list %}
+       {% comment %} If we didn't find anything there will be nothing on the right side as well {% endcomment %}
     <div id="tags-list">
         <div id="categories-list">
             {% if categories.author %}
-                <h2>Autorzy</h2>
+                <h2>{% trans "Authors" %}</h2>
                 {% tag_list categories.author tags %}
             {% endif %}
             {% if categories.kind %}
-                <h2>Rodzaje</h2>
+                <h2>{% trans "Kinds" %}</h2>
                 {% tag_list categories.kind tags %}
             {% endif %}
             {% if categories.genre %}
-                <h2>Gatunki literackie</h2>
+                <h2>{% trans "Genres" %}</h2>
                 {% tag_list categories.genre tags %}
             {% endif %}
             {% if categories.epoch %}
-                <h2>Epoki</h2>
+                <h2>{% trans "Epochs" %}</h2>
                 {% tag_list categories.epoch tags %}
-            {% endif %}        
+            {% endif %}
         </div>
         <div id="themes-list">
             {% if categories.theme %}
-                <h2>Motywy</h2>
+                <h2>{% trans "Themes" %}</h2>
                 {% tag_list categories.theme tags %}
             {% endif %}
         </div>
         <div class="clearboth"></div>
     </div>
+       {% endif %}
     {% endif %}
     <div id="set-window">
-        <div class="header"><a href="#" class="jqmClose">Zamknij</a></div>
+        <div class="header"><a href="#" class="jqmClose">{% trans "Close" %}</a></div>
         <div class="target">
-            <p><img src="/static/img/indicator.gif" alt="*"/> Ładowanie</p>
+            <p><img src="{{ STATIC_URL }}img/indicator.gif" alt="*"/> {% trans "Loading" %}</p>
         </div>
     </div>
 {% endblock %}
\ No newline at end of file
index ab34fe4..d047dbe 100644 (file)
@@ -1,16 +1,17 @@
-<h2>Twoje półki z lekturami</h2>
+{% load i18n %}
+<h2>{% trans "Your shelves with books" %}</h2>
 {% if shelves %}
 <ul class="shelf-list">
 {% for shelf in shelves %}
-    <li><a href="{% url delete_shelf shelf.slug %}" class="delete-shelf">usuń</a> <a href="{{ shelf.get_absolute_url }}" class="visit-shelf">{{ shelf.name }} ({{ shelf.book_count }})</a></li>
+    <li><a href="{% url delete_shelf shelf.slug %}" class="delete-shelf">{% trans "remove" %}</a> <a href="{{ shelf.get_absolute_url }}" class="visit-shelf">{{ shelf.name }} ({{ shelf.get_count }})</a></li>
 {% endfor %}
 </ul>
 {% else %}
-<p>Nie posiadasz żadnych półek. Jeśli chcesz, możesz utworzyć półkę poniżej.</p>
+<p>{% trans "You do not own any shelves. You can create one below if you want to" %}.</p>
 {% endif %}
 <hr />
 <form action="{% url catalogue.views.new_set %}" method="post" accept-charset="utf-8" class="cuteform">
 <ol>
-    <li>{{ new_set_form.name }} <input type="submit" value="Utwórz półkę"/></li>
+    <li>{{ new_set_form.name }} <input type="submit" value="{% trans "Create shelf" %}"/></li>
 </ol>
 </form>
\ No newline at end of file
diff --git a/wolnelektury/templates/info/about_us.html b/wolnelektury/templates/info/about_us.html
deleted file mode 100644 (file)
index 37ad44b..0000000
+++ /dev/null
@@ -1,124 +0,0 @@
-{% extends "base.html" %}
-
-{% block title %}O projekcie WolneLektury.pl{% endblock %}
-
-{% block body %}
-    <h1>O projekcie Wolne Lektury</h1>
-    <form action="{% url search %}" method="GET" accept-charset="utf-8" id="search-form">
-        <p>{{ form.q }} <input type="submit" value="Szukaj" /> <strong>lub</strong> <a href="{% url main_page %}">wróć do strony głównej</a></p>
-    </form>
-
-    <div class="column-left">
-        <h2>Wolne Lektury</h2>
-    
-        <p>Biblioteka internetowa z lekturami szkolnymi „Wolne Lektury” (www.wolnelektury.pl) to projekt realizowany
-        przez Fundację Nowoczesna Polska. Działa od 2007 roku i udostępnia w swoich zbiorach lektury szkolne, które są
-        zalecane do użytku przez Ministerstwo Edukacji Narodowej i które trafiły już do domeny publicznej. Są one
-        opracowane, opatrzone komentarzem i udostępnione w kilku formatach (html, odt, txt i pdf). Można je zgodnie z
-        prawem, bezpłatnie przeglądać, ściągać na swój komputer, a także udostępniać innym i cytować.</p>
-        
-         <p>Zespół projektu Wolne Lektury składa się z doświadczonych redaktorek i nauczycielek, co zapewnia rzetelność
-        naszego portalu. W tworzeniu go współpracujemy z Biblioteką Narodową, która dostarcza nam najlepszych dostępnych
-        wydań i opracowań krytycznych lektur szkolnych, opublikowanych w Cyfrowej Bibliotece Narodowej Polona. Wspólnie
-        staramy się, aby teksty lektur – nasze dziedzictwo kulturowe – były dostępne dla wszystkich, niezależnie od
-        miejsca zamieszkania, zasobności portfela, sprawności lub jej braku. Jest to możliwe dzięki istnieniu domeny
-        publicznej, czyli zbioru dzieł nieobjętych restrykcjami prawa autorskiego, oraz dzięki nowoczesnym technologiom
-        – narzędziom, które pozwalają zwielokrotnić dostępność treści upublicznianych w Internecie.</p>
-        
-         <p>Projekt Wolne Lektury jest całkowicie niekomercyjny i realizowany pro publico bono. Dlatego tak ważne jest
-        dla nas poparcie udzielone przez wybitne osobistości kultury i nauki. Patronat honorowy nad projektem Wolne 
-        Lektury sprawuje Ministerstwo Kultury i Dziedzictwa Narodowego, Ministerstwo Edukacji Narodowej oraz
-        Stowarzyszenie Pisarzy Polskich.. W Komitecie Honorowym Wolnych Lektur zgodzili się uczestniczyć prof. Maria
-        Janion, prof. Grażyna Borkowska, prof. Przemysław
-        Czapliński, prof. Mieczysław Dąbrowski, prof. Ewa Kraskowska, prof. Małgorzata Czermińska, prof. Jerzy Jarzębski
-        i prof. Piotr Śliwiński.</p>
-        
-         <p>Digitalizacją i korektą tekstów zajmuje się Biblioteka Narodowa. Serwis internetowy został zaprojektowany
-        przez 2ia. Autorem języka składu tekstów Wolnych Lektur opartego na języku XML jest Dariusz Gałecki. Obsługę
-        prawną Wolnych Lektur zapewnia Kancelaria Grynhoff,
-        Woźny, Maliński. Hosting serwisu zapewnia
-        firma EO Networks. W opracowaniu technicznym tekstów pomaga wydawnictwo Korporacja Ha!Art. Logo Wolne Lektury
-        jest dziełem agencji PZL. Projekt objęli patronatem medialnym: Dziennik, Elle, Tok.fm, Biblioteka Analiz,
-        Tygodnik Powszechny, Przekrój i TVP Kultura.</p>
-        
-        <h2>Jak korzystać z Wolnych Lektur?</h2>
-        
-         <p>Najważniejszą innowacją Wolnych Lektur, odróżniającą ten projekt od innych bibliotek internetowych, jest
-        możliwość przeszukiwania tekstów z zastosowaniem różnych kryteriów: tradycyjnych, takich jak tytuł, autor,
-        epoka, rodzaj, gatunek literacki, ale i niespotykanych nigdzie indziej, to jest odnoszących się do treści wielu
-        utworów naraz – motywów i tematów literackich. Takie przeszukiwanie jest możliwe dzięki specjalnemu opracowaniu
-        tekstów lektur szkolnych, to znaczy opisaniu ich za pomocą wymienionych kryteriów. Tym właśnie Wolne Lektury
-        różnią się od licznych stron z opracowaniami lektur szkolnych – dostarczają narzędzi do twórczej pracy z
-        tekstem, a nie gotowych ściąg. Jeśli np. uczeń dostanie temat pracy domowej: „Motyw dziecka w romantyzmie na
-        podstawie wybranych utworów“, to trzy kliknięcia na naszej stronie sprawią, że na ekranie komputera pojawi mu
-        się komplet tekstów do analizy. Dzięki takim narzędziom czytanie lektur staje się fascynującą podróżą po świecie
-        kultury.</p>
-        
-         <p>Kolejną użyteczną funkcjonalnością Wolnych Lektur, przydatną w pracy w szkole, jest możliwość układania
-        całych zestawów tekstów przerabianych na przykład w ciągu roku przez daną klasę. Takie półki z lekturami są
-        tworzone przez nauczycielkę/la, która/y może następnie wysłać swoim uczniom odnośnik (link) do tego zbioru, a
-        oni jednym kliknięciem ściągną cały zestaw na swój komputer.</p>
-        
-        <p>Wszystkie teksty książek ze stron Wolne Lektury (w postaci plików html, pdf, txt) dostępne są poza restrykcjami prawa autorskiego i można je swobodnie wykorzystywać bez żadnych warunków.</p>
-
-        <p>Jeśli teksty te są opatrzone dodatkowymi materiałami (przypisy, motywy literackie etc.) które podlegają prawu
-        autorskiemu, to te dodatkowe materiały udostępnione są na licencji Creative Commons Uznanie Autorstwa - Na Tych
-        Samych Warunkach 3.0 PL (<a href="http://creativecommons.org/licenses/by-sa/3.0/">http://creativecommons.org/licenses/by-sa/3.0/</a>).</p>
-    </div>
-    
-    <div class="column-right">
-        <h2>O Fundacji</h2>
-
-        <p>Fundacja Nowoczesna Polska powstała, ponieważ kształcenie dzieci jest kluczem do przyszłości Polski. Jednym z
-        najważniejszych zadań, jakie stoją przed polską edukacją, jest walka z cyfrowym wykluczeniem. Umiejętność
-        korzystania z komputera i internetu w czasach społeczeństwa informacyjnego jest rodzajem elementarza. Ci, którzy
-        go nie znają, skazani są na wegetację na obrzeżach nowoczesnego świata. </p>
-        
-         <p>Dlatego od siedmiu lat pomagamy dzieciom zrozumieć i wykorzystywać zaawansowane technologie. Fundacja
-        Nowoczesna Polska tysiącom dzieci chce dać to, co najcenniejsze: wiedzę i umiejętności pozwalające rozumieć
-        współczesny świat i wykorzystywać możliwości, jakie on oferuje.</p>
-        
-         <p>Fundacja Nowoczesna Polska – poza projektem Wolne Lektury – koordynuje także projekt Wolne Podręczniki,
-        tworzony przez ruch społeczny nauczycieli wolontariuszy, którzy korzystając z Internetu piszą nowe podręczniki
-        dla polskich uczniów. Wolne Podręczniki są publikowane na wolnych licencjach – czyli takich, które zezwalają
-        każdemu na bezpłatne kopiowanie, rozpowszechnianie i aktualizowanie ich bez konieczności pytania o zgodę zespołu
-        autorów. Każdy nauczyciel będzie mógł te podręczniki uzupełniać, rozszerzać i poprawiać zgodnie z własnymi
-        potrzebami i doświadczeniem. Dzięki wolnym licencjom można poważnie obniżyć koszt podręczników wydawanych w
-        tradycyjnej postaci książek drukowanych na papierze, a podręczniki rozpowszechniane w formie elektronicznej będą
-        dostępne za darmo.</p>
-        
-        <h2>O domenie publicznej</h2>
-        
-        <p>W serwisie Wolne Lektury możemy zgodnie z prawem publikować tylko te książki, które należą do domeny
-        publicznej, a więc te, które wyszły już spod działania prawa autorskiego. Domena publiczna to rodzaj skarbca
-        kultury, wspólnego dobra, z którego wszyscy mogą korzystać na równych prawach, bez ograniczeń i opłat. Istnienie
-        domeny publicznej jest gwarantem dostępu do dóbr kultury, ten zaś jest naszym obywatelskim prawem zapisanym w
-        konstytucji.</p>
-        
-         <p>Choć zasadą jest, że po jakimś czasie wszystkie dzieła mają zasilić domenę publiczną, to czas działania
-        polskiego prawa autorskiego został w ciągu ostatnich kilkunastu lat znacznie wydłużony. Jeszcze na początku lat
-        90. było to 25 lat od śmierci autora, potem ten czas wydłużono na 50 lat, dziś jest to już lat 70. To oznacza,
-        że wielu pozycji z ministerialnych list lektur nie będziemy mogli udostępnić jeszcze przez wiele lat. Dopiero w
-        2020 roku opublikujemy utwory Marka Hłaski i Witolda Gombrowicza. Powieści Kuncewiczowej zasilą domenę publiczną
-        w roku 2060, a poezje Miłosza w 2075 roku.</p>
-        
-         <p>Ograniczenia prawa autorskiego odnoszą się także do wydań krytycznych i tłumaczeń. Do 1 stycznia 2012 roku
-        będziemy czekać na "Wielki Testament" Villona i inne utwory tłumaczone przez Boya-Żeleńskiego, a do 2068 roku na
-        „Kubusia Puchatka” Milne'a i inne przekłady Ireny Tuwim. Nie mamy także prawa upubliczniać wstępów i przedmów
-        napisanych przez autorów, którzy zmarli mniej niż 70 lat temu. Z tego właśnie powodu zdarza się czasem, że jakiś
-        utwór znajduje się na Wolnych Lekturach, ale link do odpowiadającej mu pozycji w Cyfrowej Bibliotece Narodowej
-        Polona odsyła do strony, która mówi, że utwór objęty jest ochroną prawa autorskiego. Znaczy to, że choć sam
-        tekst należy do domeny publicznej i dlatego umieszczamy go w Wolnych Lekturach, to jego wydanie krytyczne,
-        którym dysponuje CBN Polona (ze wszystkimi wstępami, przedmowami i komentarzami redaktorów), wciąż jest objęte
-        działaniem prawa autorskiego.</p>
-        
-         <p>O domenę publiczną należy dbać i otaczać ją ochroną. Kultura to misterny gmach, w którym kolejne piętra mogą
-        być budowane tylko na solidnych podstawach wypracowanych przez poprzedników. Kochanowski bezpośrednio czerpał z
-        tradycji antycznej. Mickiewicz twórczość ludową wykorzystał do stworzenia najpiękniejszych polskich wierszy.
-        Każde kolejne pokolenie może sięgać wzrokiem dalej, wypracowywać własny literacki język i trwale wpisywać się w
-        historię literatury tylko dzięki osiągnięciom poprzedników. Dlatego tak ważna jest wolność w udostępnianiu i
-        wykorzystywaniu najważniejszych dzieł polskiej i światowej literatury. Bez domeny publicznej zbudowanie tego
-        wspaniałego gmachu, jakim jest kultura, byłoby niemożliwe.</p>
-    </div>
-{% endblock %}
-
diff --git a/wolnelektury/templates/info/base.html b/wolnelektury/templates/info/base.html
new file mode 100644 (file)
index 0000000..528e296
--- /dev/null
@@ -0,0 +1,21 @@
+{% extends "base.html" %}
+{% load i18n %}
+{% load chunks %}
+
+{% block title %}{{ object.page_title }}{% endblock %}
+
+{% block body %}
+    <h1>{{ object.title }}</h1>
+    <form action="{% url search %}" method="get" accept-charset="utf-8" id="search-form">
+        <p>{{ form.q }} <input type="submit" value="{% trans "Search" %}" /> <strong>{%trans "or" %}</strong> <a href="{% url main_page %}">{% trans "return to the main page" %}</a></p>
+    </form>
+
+    {% autoescape off %}
+    <div class="column-left">
+       {{ object.left_column }}
+    </div>
+    <div class="column-right">
+       {{ object.right_column }}
+    </div>
+       {% endautoescape %}
+{% endblock %}
diff --git a/wolnelektury/templates/info/help_us.html b/wolnelektury/templates/info/help_us.html
deleted file mode 100644 (file)
index edb229a..0000000
+++ /dev/null
@@ -1,101 +0,0 @@
-{% extends "base.html" %}
-
-{% block title %}Możesz nam pomóc w WolneLektury.pl{% endblock %}
-
-{% block body %}
-    <h1>Możesz nam pomóc</h1>
-    <form action="{% url search %}" method="get" accept-charset="utf-8" id="search-form">
-        <p>{{ form.q }} <input type="submit" value="Szukaj" /> <strong>lub</strong> <a href="{% url main_page %}">wróć do strony głównej</a></p>
-    </form>
-
-    <div class="column-left">
-        <h2>Wolontariat</h2>
-
-        <p>Utwory włączane sukcesywnie do naszej biblioteki staramy się opracowywać jak najdokładniej. Jest to możliwe
-        tylko dzięki współpracującym z nami wolontariuszom.</p>
-        
-        <p>Zapraszamy wszystkie osoby, które chcą współtworzyć szkolną bibliotekę internetową Wolne Lektury.</p>
-        
-        <p>Wszystkim wolontariuszom oferujemy szkolenia i praktykę w zakresie edycji tekstów: redakcji technicznej i
-        merytorycznej. Wolontariusze mogą poznać problemy, ale i możliwości, jakie wiążą się z publikacjami internetowymi.
-        Współorganizują z nami szkolenia i konferencje, pomagają w przygotowaniu wersji tekstów do słuchania (tzw.
-        audiobooków). Wystawiamy umowy i zaświadczenia o tym, kiedy i jakie prace wykonywał wolontariusz na rzecz naszej
-        fundacji. Szkolenia, praktyka edytorska i potwierdzające je zaświadczenia mogą się okazać istotne w procesie
-        podnoszenia kwalifikacji i awansu zawodowego.</p>
-        
-        <h2>Co jest do zrobienia?</h2>
-        
-        <p>Najwięcej pracy mamy przy przygotowaniu lektur do publikacji. Z tekstu, który otrzymujemy z Biblioteki
-        Narodowej, należy usunąć literówki i inne mechaniczne błędy, a następnie opatrzyć tekst przypisami, pamiętając o
-        tym, że nasza oferta skierowana jest przede wszystkim do uczniów, dla których wiele słów i zwrotów będzie brzmiało
-        anachronicznie. Wydania dawniejsze (rygor wyznacza tu prawo autorskie) poddawane są koniecznym uwspółcześnieniom
-        językowym, np. w zakresie ortografii lub fleksji, przy czym pilnujemy, aby nie naruszać artystycznej swoistości
-        tekstu. Ostatnim etapem jest wyszukiwanie motywów i tematów literackich, mające pomóc przejrzeć literaturę "na
-        wskroś". We wszystkich tych pracach wspomagają nas wolontariusze – nauczyciele i studenci – często służąc również
-        radami i uwagami przy podejmowaniu ważnych decyzji.</p>
-        
-        <h2>Jak się do nas zgłosić?</h2>
-        
-        <p>Wszystkie zainteresowane osoby prosimy o przysłanie maila na adres <a href="mail:fundacja@nowoczesnapolska.org.pl">fundacja@nowoczesnapolska.org.pl</a>.</p>
-
-        <p>Zapraszamy także na <a href="http://redmine.nowoczesnapolska.org.pl/projects/wl-publikacje">stronę redakcji Wolnych Lektur</a>, na której znajdują się wszystkie niezbędne informacje o tym, jak włączyć się w prace redakcyjne.</p>
-    </div>
-    <div class="column-right">
-        <h2>Najbardziej zasłużeni wolontariusze</h2>
-
-       <h3>Agatapaszkowska (współpracuje z nami od 15 marca 2008)</h3>
-
-        <p>m.in. opracowywała „W pustyni i w puszczy” Sienkiewicza ; zob. też na naszej stronie „wkład użytkownika”: <a href="http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Agatapaszkowska">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Agatapaszkowska</a></p>
-
-
-       <h3>AgnieszkaKappa (współpracuje z nami od 16 marca 2008)</h3>
-
-        <p>m.in. brała udział w tworzeniu listy i opisie użycia motywów i tematów literackich; opracowywała teksty Sienkiewicza (Latarnik, Janko Muzykant, Quo vadis); zob. też na naszej stronie „wkład użytkownika”: <a href="http://wiki.wolnepodreczniki.pl/index.php?title=Specjalna:Wk%C5%82ad&amp;limit=500&amp;target=AgnieszkaKappa">http://wiki.wolnepodreczniki.pl/index.php?title=Specjalna:Wk%C5%82ad&amp;limit=500&amp;target=AgnieszkaKappa</a></p>
-
-
-        <h3>Anerys (współpracuje z nami od 5 lipca 2007)</h3>
-
-        <p>m.in. brała udział w tworzeniu listy motywów i tematów literackich, dyskusji o gatunkach literackich, opracowywała Bogurodzicę, „Fraszki” i „Treny” Kochanowskiego; wiersze Słowackiego (Grób Agamemnona), „Świętoszka” Moliere'a, czy poezje Kasprowicza (w tym hymn „Dies Irae”); zob. też na naszej stronie „wkład użytkownika”: <a href="http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Anerys">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Anerys</a></p>
-
-
-       <h3>EmiliaZdankiewicz (współpracuje z nami od 17 marca 2008)</h3>
-
-        <p>m.in. motywy literackie dyskusja i opisywanie, Słowacki, Kordian; Konopnicka, Nasza szkapa; Mickiewicz, Dziady cz. III; zob. też na naszej stronie „wkład użytkownika”: <a href="http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/EmiliaZdankiewicz">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/EmiliaZdankiewicz</a></p>
-
-
-       <h3>Ewa_Serafin (współpracuje z nami od 15 marca 2008)</h3>
-
-        <p>m.in. brała udział w tworzeniu listy i opisie użycia motywów i tematów literackich, opracowywała poezje Kasprowicza („Z wichrów i hal”, „Nad przepaściami”, „W ciemności schodzi moja dusza” oraz „Nad Niemnem” Orzeszkowej; zob. też na naszej stronie „wkład użytkownika”: <a href="http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Ewa_Serafi">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Ewa_Serafi</a>n</p>
-
-
-       <h3>Hanna_Golab (współpracuje z nami od 15 marca 2008)</h3>
-
-        <p>opracowywała „Króla Edypa” Sofoklesa oraz „Dusiołka” Leśmiana; zob. też na naszej stronie „wkład użytkownika”: <a href="http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Hanna_Golab">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Hanna_Golab</a></p>
-
-
-       <h3>Ingene (współpracuje z nami od 16 lipca 2008)</h3>
-
-        <p>m.in. opracowywała „Siłaczkę” Żeromskiego, „Quo vadis” Sienkiewicza oraz „Treny” Kochanowskiego; zob. też na naszej stronie „wkład użytkownika”: <a href="http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Ingene">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Ingene</a></p>
-    
-       <h3>Jmyszkowska (współpracuje z nami od 26 marca 2008)</h3>
-
-        <p>m. in. opracowywała „Giaura” Byrona oraz „Quo vadis” Sienkiewicza; zob. też na naszej stronie „wkład użytkownika”: <a href="http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Jmyszkowska">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Jmyszkowska</a></p>
-
-
-        <h3>Marysiabailey (współpracuje z nami od 1 października 2007)</h3>
-
-        <p>m.in. brała udział w tworzeniu listy motywów i tematów literackich oraz opisywaniu ich użycia; opracowywała „Chłopów” Reymonta, „Lalkę” Prusa, „Nie-Boską komedię” Krasińskiego, „Bajki” i „Satyry” Krasickiego, „Antygonę” Sofoklesa oraz utwory Kochanowskiego, Morsztyna, Mickiewicza, Kasprowicza, Goethego, Oppmana, Kasprowicza; zob. też na naszej stronie „wkład użytkownika”: <a href="http://wiki.wolnepodreczniki.pl/index.php?title=Specjalna:Wk%C5%82ad&amp;limit=500&amp;target=Marysiabailey">http://wiki.wolnepodreczniki.pl/index.php?title=Specjalna:Wk%C5%82ad&amp;limit=500&amp;target=Marysiabailey</a>; ponadto przygotowywała i prowadziła szkolenie dla wolontariuszy 15 marca 2008; zajmowała się proofreadingiem, a obecnie kieruje pracami nad audiobookami.</p>
-
-
-        <h3>Olga_Wojtczak (współpracuje z nami od 21 października 2008)</h3>
-
-        <p>m.in. opracowywała powieści Sienkiewicza (Trylogia), Reymonta, Żeromskiego, dramaty Shakespeare'a; zob. też na naszej stronie „wkład użytkownika”: <a href="http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Olga_Wojtczak">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Olga_Wojtczak</a></p>
-
-
-        <h3>Renataml (współpracuje z nami od 30 czerwca 2007)</h3>
-
-        <p>brała udział w dyskusji na temat listy motywów, wspomagała nas radami jako doświadczona nauczycielka, edytowała „Lalkę” Prusa, „Balladynę” Słowackiego, „Siłaczkę” Żeromskiego.
-
-        <a href="http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Renataml">http://wiki.wolnepodreczniki.pl/Specjalna:Wk%C5%82ad/Renataml</a></p>
-    </div>
-{% endblock %}
diff --git a/wolnelektury/templates/info/join_us.html b/wolnelektury/templates/info/join_us.html
new file mode 100644 (file)
index 0000000..fd4ea7d
--- /dev/null
@@ -0,0 +1,10 @@
+{% load i18n %}
+<p>{% blocktrans %}We have over 1000 works published in Wolne Lektury!
+Help us expand the library and set new readings free by
+making a donation or transferring 1% of your income tax.{% endblocktrans %}
+{% comment %}<a href='{}'>{% trans "More..." %}</a>{% endcomment %}</p>
+
+<p>{% blocktrans %}Become an editor of Wolne Lektury! Find out if
+we're currently working on a reading you're looking for and prepare
+a publication by yourself by logging into the Editorial Platform.{% endblocktrans %}
+<a href='{% url help_us %}'>{% trans "More..." %}</a></p>
diff --git a/wolnelektury/templates/info/voluntary_services.html b/wolnelektury/templates/info/voluntary_services.html
deleted file mode 100644 (file)
index b835671..0000000
+++ /dev/null
@@ -1,185 +0,0 @@
-{% extends "base.html" %}
-
-{% block title %}Wolontariat dla wiedzy w WolneLektury.pl{% endblock %}
-
-{% block body %}
-    <h1>Wolontariat dla wiedzy</h1>
-    <form action="{% url search %}" method="GET" accept-charset="utf-8" id="search-form">
-        <p>{{ form.q }} <input type="submit" value="Szukaj" /> <strong>lub</strong> <a href="{% url main_page %}">wróć do strony głównej</a></p>
-    </form>
-
-    <div id="volontariat" class="column-left">
-    <h2>Wolontariat</h2>
-       <p>
-               Biogramy pisarzy oraz definicje epok i gatunków literackich w
-               bibliotece internetowej Wolne Lektury napisali uczniowie
-               czterech szkół podczas warsztatów „Wolontariat dla wiedzy”.
-       </p>
-
-       <p>
-               Uczniowie pracowali wspólnie pod merytorycznym nadzorem
-               nauczycieli i specjalistów – literaturoznawców na
-               <a href="http://wolnepodreczniki.pl/wolontariat/">
-                       platformie internetowej wiki</a>
-               przygotowanej przez zespół
-               <a href="http://2ia.pl/">2ia</a>. Praca nad notami była jednocześnie nauką wykorzystywania
-               komputerów i internetu do wyszukiwania informacji, a także
-               weryfikowania ich wiarygodności.
-       </p>
-
-       <p>
-               Projekt "Wolontariat dla wiedzy" został zrealizowany dzięki
-               wsparciu
-               <a href="http://www.menis.gov.pl/">
-                       Ministerstwa Edukacji Narodowej</a>. Nagrody dla uczniów ufundowali
-               <a href="http://www.nk.com.pl/engine/index.php?page=glowna">
-                       Wydawnictwo Nasza Księgarnia</a>
-               i
-               <a href="http://helion.pl/">Wydawnictwo Helion</a>. Noty zweryfikowano w serwisie
-               <a href="http://www.plagiat.pl/webplagiat/main.action">
-                       Plagiat.pl</a>.
-       </p>
-
-       <p>
-               <a href="/static/wolontariat.pdf">Raport z realizacji projektu „Wolontariat dla wiedzy"</a>.
-       </p>
-       <p>
-       <img src="/static/img/wolontariat/okladka.jpg" style='margin: 10px' />
-       <img src="/static/img/wolontariat/01.jpg" style='margin: 10px' />
-       <img src="/static/img/wolontariat/02.jpg" style='margin: 10px' />
-    <img src="/static/img/wolontariat/03.jpg" style='margin: 10px' />
-    <img src="/static/img/wolontariat/04.jpg" style='margin: 10px' />
-       </p>
-       
-    </div>
-    
-    
-    <div class="column-right">
-       <h2>Autorzy</h2>
-
-       <ol>
-               <li>
-                       <p>
-                               Gimnazjum nr 40 z Oddziałami Integracyjnymi w Zespole
-                               Szkół nr 69 im. Armii Krajowej Grupy Bojowej „KRYBAR”,
-                               ul. Drewniana 8, 00-345 Warszawa; klasa druga pod opieką
-                               Anny Budziarek-Friedrich:
-                       </p>
-
-                       <ul>
-                               <li>Burdon Filip;</li>
-                               <li>Dębski Bartek;</li>
-                               <li>Jackowicz Kamil;</li>
-                               <li>Kurek Paweł;</li>
-                               <li>Makles Bartosz;</li>
-                               <li>Markiewicz Jeremiasz;</li>
-                               <li>Migdał Katarzyna;</li>
-                               <li>Mioduszewski Michał;</li>
-                               <li>Pfeiffer Ida;</li>
-                               <li>Płaskowicka Karolina;</li>
-                               <li>Sailer Ewa.</li>
-                       </ul>
-               </li>
-
-               <li>
-                       <p>
-                               XXXIII Liceum Ogólnokształcące im. Mikołaja Kopernika,
-                               ul. Bema 76, 01-225 Warszawa; klasa pierwsza o profilu
-                               biologiczno-chemicznym pod opieką Elżbiety Konkowskiej:
-                       </p>
-
-                       <ul>
-                               <li>Chwil Bartłomiej;</li>
-                               <li>Czarnecka Natalia;</li>
-                               <li>Gawrońska Iga;</li>
-                               <li>Grabarczyk Marta;</li>
-                               <li>Jastrząb Katarzyna;</li>
-                               <li>Krawczak Olga;</li>
-                               <li>Krawczyk Marianna;</li>
-                               <li>Kur Natalia;</li>
-                               <li>Kwiatek Marta;</li>
-                               <li>Laśkiewicz Joanna;</li>
-                               <li>Machczyńska Daria;</li>
-                               <li>Miecznikowska Izabela;</li>
-                               <li>Moczulska Karolina;</li>
-                               <li>Mościcka Aneta;</li>
-                               <li>Narloch Sabina;</li>
-                               <li>Przybysz Paweł;</li>
-                               <li>Puchta Marek;</li>
-                               <li>Ryska Cezary;</li>
-                               <li>Sandomierski Bartłomiej;</li>
-                               <li>Sławiński Tomasz;</li>
-                               <li>Słowik Olga;</li>
-                               <li>Starzycka Katarzyna;</li>
-                               <li>Strzelczak Karolina;</li>
-                               <li>Szafran Danuta;</li>
-                               <li>Szmigielska Magdalena;</li>
-                               <li>Szulkowska Alicja;</li>
-                               <li>Ślusarczyk Anna;</li>
-                               <li>Tytkowska Anna.</li>
-                       </ul>
-                       <li>
-                               <p>
-                                       Autorskie Niepubliczne Liceum Ogólnokształcące nr
-                                       42, ul. Iwicka 47 B, 00-735 Warszawa; klasa pierwsza
-                                       o profilu ogólnym pod opieką Michała Friedricha:
-                               </p>
-
-                               <ul>
-                                       <li>Baraniecka Marta;</li>
-                                       <li>Gołaszewska Ewa;</li>
-                                       <li>Kwiatkowski Michał;</li>
-                                       <li>Machnikowska Monika;</li>
-                                       <li>Pietrzak Bartosz;</li>
-                                       <li>Przespolewski Przemysław;</li>
-                                       <li>Rosińska Zuzanna;</li>
-                                       <li>Sibiga Magdalena.</li>
-                               </ul>
-                       </li>
-                       <li>
-                               <p>
-                                       LXIV Liceum Ogólnokształcące im. St. I. Witkiewicza,
-                                       ul. Elbląska 51, 01-737 Warszawa; klasa pierwsza o
-                                       profilu ogólnym pod opieką Daniela Zycha:
-                               </p>
-
-                               <ul>
-                                       <li>Andrzejczak Kamil;</li>
-                                       <li>Czubaj Konrad;</li>
-                                       <li>Drągowska Katarzyna;</li>
-                                       <li>Gajewska Magdalena;</li>
-                                       <li>Głowacki Jan;</li>
-                                       <li>Grad Paweł;</li>
-                                       <li>Hnatowski Bartek;</li>
-                                       <li>Karwowski Marcin;</li>
-                                       <li>Kłos Aneta;</li>
-                                       <li>Kozieł Barbara;</li>
-                                       <li>Kozłowska Anna;</li>
-                                       <li>Krug Pamela;</li>
-                                       <li>Krzosek Jakub;</li>
-                                       <li>Lubaś Michał;</li>
-                                       <li>Masewicz Natalia;</li>
-                                       <li>Mastalerz Agnieszka;</li>
-                                       <li>Modelska Marta;</li>
-                                       <li>Nowak Aleksandra;</li>
-                                       <li>Pabian Agnieszka;</li>
-                                       <li>Paszkowska Aleksandra;</li>
-                                       <li>Pielat Zofia;</li>
-                                       <li>Poniecka Agnieszka;</li>
-                                       <li>Pytlak Urszula;</li>
-                                       <li>Rosa Karolina;</li>
-                                       <li>Smyczyńska Kamila;</li>
-                                       <li>Stolińska Barbara;</li>
-                                       <li>Szymańska Katarzyna;</li>
-                                       <li>Ścibior Ewa;</li>
-                                       <li>Witczak Magda;</li>
-                                       <li>Witkowska Justyna;</li>
-                                       <li>Wyrzykowska Jowita;</li>
-                                       <li>Ziółkowska Adrianna.</li>
-                               </ul>
-                       </li>
-         </li>
-         </ol>
-         </div>
-{% endblock %}
-
index 93bccb3..699b50f 100644 (file)
@@ -1,5 +1,6 @@
+{% load i18n %}
 <div>
-    <p class="download"><a href="{{ object.file.url }}">Pobierz</a> {% if object.author %}(autor: {{ object.author }}){% endif %}</p>
+    <p class="download"><a href="{{ object.file.url }}">{% trans "Download" %}</a> {% if object.author %}({% trans "author" %}: {{ object.author }}){% endif %}</p>
     <h2>{{ object.title }}</h2>
     {% if object.slideshare_id %}
     <object style="margin:0px" width="480" height="400">
index 9ee604e..d0186ae 100644 (file)
@@ -1,15 +1,16 @@
 {% extends 'base.html' %}
+{% load i18n %}
 
 {% block title %}{{ object.title }} w WolneLektury.pl{% endblock %}
 
 {% block body %}
     <h1>{{ object.title }}</h1>
     <form action="{% url search %}" method="GET" accept-charset="utf-8" id="search-form">
-        <p>{{ form.q }} <input type="submit" value="Szukaj" /> <strong>lub</strong> <a href="{% url lessons_document_list %}">wróć do listy materiałów</a></p>
+        <p>{{ form.q }} <input type="submit" value="{% trans "Search" %}" /> <strong>{% trans "or" %}</strong> <a href="{% url lessons_document_list %}">{% trans "return to list of materials" %}</a></p>
     </form>
-    
+
     <div id="document-detail">
-        <p class="download"><a href="{{ object.file.url }}">Pobierz</a> {% if object.author %}(autor: {{ object.author }}){% endif %}</p>
+        <p class="download"><a href="{{ object.file.url }}">{% trans "Download" %}</a> {% if object.author %}({% trans "author" %}: {{ object.author }}){% endif %}</p>
         {% if object.slideshare_id %}
         <object style="margin:0px" width="480" height="400">
             <param name="movie" value="http://static.slidesharecdn.com/swf/{{ object.slideshare_player }}?doc={{ object.slideshare_id }}&rel=0&stripped_title={{ object.name|slugify }}" /><param name="allowFullScreen" value="true"/><param name="allowScriptAccess" value="always"/><embed src="http://static.slidesharecdn.com/swf/{{ object.slideshare_player }}?doc={{ object.slideshare_id }}&rel=0&stripped_title={{ object.name|slugify }}" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="480" height="400"></embed></object>
index 1a5ab01..2f1c848 100644 (file)
@@ -1,24 +1,25 @@
 {% extends "base.html" %}
+{% load i18n %}
 {% load catalogue_tags chunks %}
 
 {% block bodyid %}document-list-body{% endblock %}
 
-{% block title %}Materiały pomocnicze dla nauczycieli w WolneLektury.pl{% endblock %}
+{% block title %}{% trans "Hand-outs for teachers on " %}WolneLektury.pl{% endblock %}
 
 {% block extrahead %}
     <script type="text/javascript" charset="utf-8">
         $(function() {
-            $('#document-list a').click(function() {
+            $('#document-list a[data-hash]').click(function() {
                 if (!$(this).hasClass('active')) {
-                    $('#document-list a').removeClass('active');
+                    $('#document-list a[data-hash]').removeClass('active');
                     $(this).addClass('active');
                     document.location.hash = $(this).attr('data-hash');
                 }
                 return false;
             });
-            
+
             var lastHash = null;
-            
+
             function checkHash() {
                 if (document.location.hash != lastHash) {
                     lastHash = document.location.hash;
@@ -27,7 +28,7 @@
                         $('#document-list a').removeClass('active');
                         documentLink.addClass('active');
                     };
-                    
+
                     if ($('#document-detail').attr('data-hash') != lastHash) {
                         $('#document-detail')
                             .attr('data-hash', lastHash)
                 } else if (!document.location.hash) {
                     $('#document-list a:first').click();
                 }
-                
+
                 setTimeout(checkHash, 500);
             };
-            
+
             checkHash();
         });
     </script>
 {% endblock extrahead %}
 {% block body %}
-    <h1>Materiały pomocnicze dla nauczycieli</h1>
+    <h1>{% trans "Hand-outs for teachers" %}</h1>
     <form action="{% url search %}" method="GET" accept-charset="utf-8" id="search-form">
-        <p>{{ form.q }} <input type="submit" value="Szukaj" /> <strong>lub</strong> <a href="{% url main_page %}">wróć do strony głównej</a></p>
+        <p>{{ form.q }} <input type="submit" value="{% trans "Search" %}" /> <strong>{% trans "or" %}</strong> <a href="{% url main_page %}">{% trans "return to main page" %}</a></p>
     </form>
-    
+
     <div id="document-list">
-        <ol>
-        {% for object in object_list %}
-            <li><a href="{{ object.get_absolute_url }}" data-hash="#{{ object.slug }}">{{ object }}</a></li>
-        {% endfor %}
-        </ol>
+        {% chunk "document-list" %}
     </div>
     <div id="document-detail">
     </div>
 {% endblock %}
-            
\ No newline at end of file
index 36c297b..7489d4a 100644 (file)
@@ -1,9 +1,10 @@
+{% load i18n %}
 {% if is_paginated %}
 <div class="pagination">
     {% if page_obj.has_previous %}
-        <a href="?page={{ page_obj.previous_page_number }}{{ getvars }}" class="prev">&lsaquo;&lsaquo; poprzedni</a>
+        <a href="?page={{ page_obj.previous_page_number }}{{ getvars }}" class="prev">&lsaquo;&lsaquo; {% trans "previous" %}</a>
     {% else %}
-        <span class="disabled prev">&lsaquo;&lsaquo; poprzedni</span>
+        <span class="disabled prev">&lsaquo;&lsaquo; {% trans "previous" %}</span>
     {% endif %}
     {% for page in pages %}
         {% if page %}
@@ -17,9 +18,9 @@
         {% endif %}
     {% endfor %}
     {% if page_obj.has_next %}
-        <a href="?page={{ page_obj.next_page_number }}{{ getvars }}" class="next">następny &rsaquo;&rsaquo;</a>
+        <a href="?page={{ page_obj.next_page_number }}{{ getvars }}" class="next">{% trans "next" %} &rsaquo;&rsaquo;</a>
     {% else %}
-        <span class="disabled next">następny &rsaquo;&rsaquo;</span>
+        <span class="disabled next">{% trans "next" %} &rsaquo;&rsaquo;</span>
     {% endif %}
 </div>
 {% endif %}
diff --git a/wolnelektury/translation.py b/wolnelektury/translation.py
new file mode 100644 (file)
index 0000000..3b10a96
--- /dev/null
@@ -0,0 +1,24 @@
+# -*- coding: utf-8 -*-
+# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
+
+from modeltranslation.translator import translator, TranslationOptions
+from infopages.models import InfoPage
+from catalogue.models import Book, Fragment
+
+class InfoPageTranslationOptions(TranslationOptions):
+    fields = ('page_title', 'title', 'left_column', 'right_column')
+
+translator.register(InfoPage, InfoPageTranslationOptions)
+
+class BookTranslationOptions(TranslationOptions):
+    fields = ('_short_html', )
+
+translator.register(Book, BookTranslationOptions)
+
+class FragmentTranslationOptions(TranslationOptions):
+    fields = ('_short_html', )
+
+translator.register(Fragment, FragmentTranslationOptions)
+
index 4f9d4ed..8b05298 100644 (file)
@@ -7,45 +7,49 @@ from django.contrib import admin
 
 from catalogue.forms import SearchForm
 
+from infopages.models import InfoPage
 
-admin.autodiscover()
 
+admin.autodiscover()
 
 urlpatterns = patterns('',
     url(r'^katalog/', include('catalogue.urls')),
     url(r'^materialy/', include('lessons.urls')),
-    
+    url(r'^sugestia/', include('suggest.urls')),
+
     # Static pages
-    url(r'^wolontariat/$', 'django.views.generic.simple.direct_to_template', 
-        {'template': 'info/voluntary_services.html', 'extra_context': {'form': SearchForm()}},
-        name='voluntary_services'),
-    url(r'^mozesz-nam-pomoc/$', 'django.views.generic.simple.direct_to_template',
-        {'template': 'info/help_us.html', 'extra_context': {'form': SearchForm()}},
-        name='help_us'),
-    url(r'^o-projekcie/$', 'django.views.generic.simple.direct_to_template', 
-        {'template': 'info/about_us.html', 'extra_context': {'form': SearchForm()}},
-        name='about_us'),
+    url(r'^wolontariat/$', 'infopages.views.infopage', {'slug': 'voluntary_services'}, name='voluntary_services'),
+    url(r'^mozesz-nam-pomoc/$', 'infopages.views.infopage', {'slug': 'help_us'}, name='help_us'),
+    url(r'^o-projekcie/$', 'infopages.views.infopage', {'slug': 'about_us'}, name='about_us'),
+    url(r'^widget/$', 'infopages.views.infopage', {'slug': 'widget'}, name='widget'),
+    
     url(r'^1procent/$', 'django.views.generic.simple.direct_to_template', {
         'template': '1percent.html'
     }, name='1percent'),
-    
+
     # Admin panel
     url(r'^admin/catalogue/book/import$', 'catalogue.views.import_book', name='import_book'),
     url(r'^admin/doc/', include('django.contrib.admindocs.urls')),
     url(r'^admin/(.*)$', admin.site.root),
-    
+
     # Authentication
     url(r'^uzytkownicy/zaloguj/$', 'catalogue.views.login', name='login'),
     url(r'^uzytkownicy/wyloguj/$', 'catalogue.views.logout_then_redirect', name='logout'),
     url(r'^uzytkownicy/utworz/$', 'catalogue.views.register', name='register'),
-    
+
     # API
     (r'^api/', include('api.urls')),
-    
+
     # Static files
-    url(r'^%s(?P<path>.*)$' % settings.MEDIA_URL[1:], 'django.views.static.serve', 
+    url(r'^%s(?P<path>.*)$' % settings.MEDIA_URL[1:], 'django.views.static.serve',
         {'document_root': settings.MEDIA_ROOT, 'show_indexes': True}),
     url(r'^%s(?P<path>.*)$' % settings.STATIC_URL[1:], 'django.views.static.serve',
         {'document_root': settings.STATIC_ROOT, 'show_indexes': True}),
     url(r'^$', 'django.views.generic.simple.redirect_to', {'url': 'katalog/'}),
+    url(r'^i18n/', include('django.conf.urls.i18n')),
 )
+
+if 'rosetta' in settings.INSTALLED_APPS:
+    urlpatterns += patterns('',
+        url(r'^rosetta/', include('rosetta.urls')),
+    )
diff --git a/wolnelektury/wolnelektury.fcgi b/wolnelektury/wolnelektury.fcgi
deleted file mode 100644 (file)
index 5115758..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-#!/usr/bin/env python
-import os
-from os.path import abspath, dirname, join
-import sys
-
-# Redirect sys.stdout to sys.stderr for bad libraries like geopy that use
-# print statements for optional import exceptions.
-sys.stdout = sys.stderr
-
-# Add apps and lib directories to PYTHONPATH
-sys.path.insert(0, abspath(join(dirname(__file__), '../apps')))
-sys.path.insert(0, abspath(join(dirname(__file__), '../lib')))
-
-# Emulate manage.py path hacking.
-sys.path.insert(0, abspath(join(dirname(__file__), "../")))
-sys.path.insert(0, abspath(join(dirname(__file__), ".")))
-
-# Run Django
-os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'
-
-from django.core.servers.fastcgi import runfastcgi
-runfastcgi(method='threaded', daemonize='false')
-
diff --git a/wolnelektury/wolnelektury.wsgi b/wolnelektury/wolnelektury.wsgi
deleted file mode 100644 (file)
index acafede..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-#!/usr/bin/env python
-import os
-from os.path import abspath, dirname, join
-import sys
-
-# Redirect sys.stdout to sys.stderr for bad libraries like geopy that use
-# print statements for optional import exceptions.
-sys.stdout = sys.stderr
-
-# Add apps and lib directories to PYTHONPATH
-sys.path.insert(0, abspath(join(dirname(__file__), '../apps')))
-sys.path.insert(0, abspath(join(dirname(__file__), '../lib')))
-
-# Emulate manage.py path hacking.
-sys.path.insert(0, abspath(join(dirname(__file__), "../")))
-sys.path.insert(0, abspath(join(dirname(__file__), ".")))
-
-# Run Django
-os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'
-
-from django.core.handlers.wsgi import WSGIHandler
-application = WSGIHandler()
-