From d1d765455fbc9274bd4f92bc87493f352622bb4a Mon Sep 17 00:00:00 2001 From: niphlod Date: Wed, 31 Aug 2016 02:04:45 +0200 Subject: [PATCH 01/49] fixes #1439 --- gluon/admin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gluon/admin.py b/gluon/admin.py index 3eb3bc54..90b50c27 100644 --- a/gluon/admin.py +++ b/gluon/admin.py @@ -449,7 +449,7 @@ def create_missing_folders(): """ paths = (global_settings.gluon_parent, abspath( 'site-packages', gluon=True), '') - [add_path_first(path) for p in paths] + [add_path_first(p) for p in paths] def create_missing_app_folders(request): From 38f1e318cf21e6aaff77d788df731ebc6d3dd345 Mon Sep 17 00:00:00 2001 From: Vinyl Darkscratch Date: Fri, 9 Sep 2016 00:17:40 -0700 Subject: [PATCH 02/49] Update translations --- applications/admin/languages/af.py | 0 applications/admin/languages/bg.py | 0 applications/admin/languages/cs.py | 445 ++++---------- applications/admin/languages/de.py | 0 applications/admin/languages/default.py | 0 applications/admin/languages/es.py | 226 ++++++- applications/admin/languages/fr.py | 629 ++++++++++++++++---- applications/admin/languages/he.py | 0 applications/admin/languages/it.py | 0 applications/admin/languages/ja.py | 0 applications/admin/languages/my-mm.py | 0 applications/admin/languages/pl.py | 0 applications/admin/languages/plural-en.py | 0 applications/admin/languages/plural-ru.py | 0 applications/admin/languages/plural-uk.py | 0 applications/admin/languages/pt-br.py | 0 applications/admin/languages/pt.py | 0 applications/admin/languages/ro.py | 0 applications/admin/languages/ru.py | 0 applications/admin/languages/sr-cr.py | 0 applications/admin/languages/sr-lt.py | 0 applications/admin/languages/tr.py | 0 applications/admin/languages/uk.py | 0 applications/admin/languages/zh-tw.py | 0 applications/admin/languages/zh.py | 0 applications/welcome/languages/ar.py | 90 ++- applications/welcome/languages/ca.py | 9 + applications/welcome/languages/cs.py | 196 +++--- applications/welcome/languages/de.py | 41 +- applications/welcome/languages/default.py | 0 applications/welcome/languages/es.py | 74 ++- applications/welcome/languages/fr-ca.py | 28 +- applications/welcome/languages/fr.py | 41 +- applications/welcome/languages/hi.py | 29 +- applications/welcome/languages/hu.py | 28 +- applications/welcome/languages/id.py | 82 ++- applications/welcome/languages/it.py | 23 +- applications/welcome/languages/my-mm.py | 10 + applications/welcome/languages/my.py | 89 ++- applications/welcome/languages/nl.py | 28 +- applications/welcome/languages/pl.py | 28 +- applications/welcome/languages/plural-cs.py | 0 applications/welcome/languages/plural-en.py | 0 applications/welcome/languages/plural-es.py | 0 applications/welcome/languages/plural-ru.py | 0 applications/welcome/languages/plural-uk.py | 0 applications/welcome/languages/pt-br.py | 59 +- applications/welcome/languages/pt.py | 93 ++- applications/welcome/languages/ro.py | 28 +- applications/welcome/languages/ru.py | 28 +- applications/welcome/languages/sk.py | 158 +++-- applications/welcome/languages/tr.py | 61 +- applications/welcome/languages/uk.py | 24 +- applications/welcome/languages/zh-cn.py | 28 +- applications/welcome/languages/zh-tw.py | 28 +- applications/welcome/languages/zh.py | 28 +- 56 files changed, 1904 insertions(+), 727 deletions(-) mode change 100644 => 100755 applications/admin/languages/af.py mode change 100644 => 100755 applications/admin/languages/bg.py mode change 100644 => 100755 applications/admin/languages/cs.py mode change 100644 => 100755 applications/admin/languages/de.py mode change 100644 => 100755 applications/admin/languages/default.py mode change 100644 => 100755 applications/admin/languages/es.py mode change 100644 => 100755 applications/admin/languages/fr.py mode change 100644 => 100755 applications/admin/languages/he.py mode change 100644 => 100755 applications/admin/languages/it.py mode change 100644 => 100755 applications/admin/languages/ja.py mode change 100644 => 100755 applications/admin/languages/my-mm.py mode change 100644 => 100755 applications/admin/languages/pl.py mode change 100644 => 100755 applications/admin/languages/plural-en.py mode change 100644 => 100755 applications/admin/languages/plural-ru.py mode change 100644 => 100755 applications/admin/languages/plural-uk.py mode change 100644 => 100755 applications/admin/languages/pt-br.py mode change 100644 => 100755 applications/admin/languages/pt.py mode change 100644 => 100755 applications/admin/languages/ro.py mode change 100644 => 100755 applications/admin/languages/ru.py mode change 100644 => 100755 applications/admin/languages/sr-cr.py mode change 100644 => 100755 applications/admin/languages/sr-lt.py mode change 100644 => 100755 applications/admin/languages/tr.py mode change 100644 => 100755 applications/admin/languages/uk.py mode change 100644 => 100755 applications/admin/languages/zh-tw.py mode change 100644 => 100755 applications/admin/languages/zh.py mode change 100644 => 100755 applications/welcome/languages/ar.py mode change 100644 => 100755 applications/welcome/languages/ca.py mode change 100644 => 100755 applications/welcome/languages/cs.py mode change 100644 => 100755 applications/welcome/languages/de.py mode change 100644 => 100755 applications/welcome/languages/default.py mode change 100644 => 100755 applications/welcome/languages/es.py mode change 100644 => 100755 applications/welcome/languages/fr-ca.py mode change 100644 => 100755 applications/welcome/languages/fr.py mode change 100644 => 100755 applications/welcome/languages/hi.py mode change 100644 => 100755 applications/welcome/languages/hu.py mode change 100644 => 100755 applications/welcome/languages/it.py mode change 100644 => 100755 applications/welcome/languages/my-mm.py mode change 100644 => 100755 applications/welcome/languages/nl.py mode change 100644 => 100755 applications/welcome/languages/pl.py mode change 100644 => 100755 applications/welcome/languages/plural-cs.py mode change 100644 => 100755 applications/welcome/languages/plural-en.py mode change 100644 => 100755 applications/welcome/languages/plural-es.py mode change 100644 => 100755 applications/welcome/languages/plural-ru.py mode change 100644 => 100755 applications/welcome/languages/plural-uk.py mode change 100644 => 100755 applications/welcome/languages/pt-br.py mode change 100644 => 100755 applications/welcome/languages/pt.py mode change 100644 => 100755 applications/welcome/languages/ro.py mode change 100644 => 100755 applications/welcome/languages/ru.py mode change 100644 => 100755 applications/welcome/languages/sk.py mode change 100644 => 100755 applications/welcome/languages/tr.py mode change 100644 => 100755 applications/welcome/languages/uk.py mode change 100644 => 100755 applications/welcome/languages/zh-cn.py mode change 100644 => 100755 applications/welcome/languages/zh-tw.py mode change 100644 => 100755 applications/welcome/languages/zh.py diff --git a/applications/admin/languages/af.py b/applications/admin/languages/af.py old mode 100644 new mode 100755 diff --git a/applications/admin/languages/bg.py b/applications/admin/languages/bg.py old mode 100644 new mode 100755 diff --git a/applications/admin/languages/cs.py b/applications/admin/languages/cs.py old mode 100644 new mode 100755 index 0edeb8e2..1b9481ef --- a/applications/admin/languages/cs.py +++ b/applications/admin/languages/cs.py @@ -2,131 +2,89 @@ { '!langcode!': 'cs-cz', '!langname!': 'čeština', -'"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN': 'Kolonka "Upravit" je nepovinný výraz, například "pole1=\'nováhodnota\'". (Avšak výsledky databázového JOINu nelze mazat ani upravovat.)', -'"User Exception" debug mode. ': '"Uživatelská výjimka", Debug mód.', -'"User Exception" debug mode. An error ticket could be issued!': '"Uživatelská výjimka", Debug mód. Může být vystaven chybový tiket.', +'"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN': 'Kolonka "Upravit" je nepovinný výraz, například "pole1=\'nováhodnota\'". Výsledky databázového JOINu nemůžete mazat ani upravovat.', +'"User Exception" debug mode. An error ticket could be issued!': '"User Exception" debug mode. An error ticket could be issued!', '%%{Row} in Table': '%%{řádek} v tabulce', '%%{Row} selected': 'označených %%{řádek}', -'%s': '%s', '%s %%{row} deleted': '%s smazaných %%{záznam}', '%s %%{row} updated': '%s upravených %%{záznam}', '%s selected': '%s označených', -'%s students registered': '%s studentů registrováno', '%Y-%m-%d': '%d.%m.%Y', '%Y-%m-%d %H:%M:%S': '%d.%m.%Y %H:%M:%S', '(requires internet access)': '(vyžaduje připojení k internetu)', -'(requires internet access, experimental)': '(vyžaduje internetové připojení, experimentální)', +'(requires internet access, experimental)': '(requires internet access, experimental)', '(something like "it-it")': '(například "cs-cs")', -'(version %s)': '(verze %s)', -'?': '?', '@markmin\x01(file **gluon/contrib/plural_rules/%s.py** is not found)': '(soubor **gluon/contrib/plural_rules/%s.py** nenalezen)', -'@markmin\x01An error occured, please [[reload %s]] the page': 'An error occured, please [[reload %s]] the page', '@markmin\x01Searching: **%s** %%{file}': 'Hledání: **%s** %%{soubor}', -'Abort': 'Ukončit', 'About': 'O programu', 'About application': 'O aplikaci', -'Accept Terms': 'Souhlasit s podmínkami', 'Access Control': 'Řízení přístupu', 'Add breakpoint': 'Přidat bod přerušení', -'Additional code for your application': 'Další kód pro Vaši aplikaci (pro příkaz import). Neběží ve specifickém režimu ani ve vláknech jako model/kontrolér/šablona, ale jako standardní python moduly. Ty tedy můžete umístit sem (pouze pro tuto aplikaci) nebo používat systémově dostupné.', -'Admin design page': 'Admin design stránka', -'admin disabled because no admin password': 'admin je zakázán, protože chybí heslo administrátora', -'admin disabled because not supported on google app engine': 'admin je zakázán kvůli chybějící podpoře na Google App Engine', -'admin disabled because too many invalid login attempts': 'Admin je zakázán po příliš mnoha nesprávných pokusech o přihlášení', -'admin disabled because unable to access password file': 'Admin je zakázán, protože nelze číst soubor s heslem', -'Admin is disabled because insecure channel': 'Admin je zakázán na nezabezpečeném připojení', +'Additional code for your application': 'Další kód pro Vaši aplikaci', +'Admin design page': 'Admin design page', 'Admin language': 'jazyk rozhraní', -'Admin versioning page': 'Admin verzovací stránka', 'Administrative interface': 'pro administrátorské rozhraní klikněte sem', 'Administrative Interface': 'Administrátorské rozhraní', 'administrative interface': 'rozhraní pro správu', 'Administrator Password:': 'Administrátorské heslo:', 'Ajax Recipes': 'Recepty s ajaxem', -'An error occured, please %s the page': 'Došlo k chybě, prosím %s stránku', +'An error occured, please %s the page': 'An error occured, please %s the page', 'and rename it:': 'a přejmenovat na:', -'App does not exist or you are not authorized': 'Aplikace neexistuje nebo vám chybí oprávnění', 'appadmin': 'appadmin', 'appadmin is disabled because insecure channel': 'appadmin je zakázaná bez zabezpečeného spojení', -'Application': 'Aplikace', +'Application': 'Application', 'application "%s" uninstalled': 'application "%s" odinstalována', -'Application cannot be generated in demo mode': 'Aplikace nemůže být vytvořena v demo módu', 'application compiled': 'aplikace zkompilována', -'Application exists already': 'Aplikace již existuje', -'application is compiled and cannot be designed': 'aplikace je přeložena a nelze ji editovat', 'Application name:': 'Název aplikace:', -'Application updated via git pull': 'Aplikace byla aktualizována pomocí git pull', 'are not used': 'nepoužita', 'are not used yet': 'ještě nepoužita', -'Are you sure you want to delete file "%s"?': 'Skutečně chcete smazat soubor "%s"?', -'Are you sure you want to delete plugin "%s"?': 'Skutečně chcete smazat plugin "%s"?', 'Are you sure you want to delete this object?': 'Opravdu chcete odstranit tento objekt?', 'Are you sure you want to uninstall application "%s"?': 'Opravdu chcete odinstalovat aplikaci "%s"?', -'Are you sure?': 'Jste si jist(a)?', -'arguments': 'argumenty', -'at char %s': 'na pozici znaku %s', -'at line %s': 'na řádku %s', -'ATTENTION:': 'POZOR:', -'ATTENTION: Login requires a secure (HTTPS) connection or running on localhost.': 'POZOR: Přihlášení vyžaduje zabezpečené (HTTPS) připojení nebo spouštění na localhost.', -'ATTENTION: TESTING IS NOT THREAD SAFE SO DO NOT PERFORM MULTIPLE TESTS CONCURRENTLY.': 'POZOR: TESTOVÁNÍ NENÍ BEZPEČNÉ PŘI SOUBĚŽNÝCH VLÁKNECH. NESPOUŠTĚJ VÍCE TESTŮ SOUBĚŽNĚ.', -'ATTENTION: you cannot edit the running application!': 'POZOR: Nelze editovat spuštěnou aplikaci.', -'Autocomplete Python Code': 'Autocomplete Python kód', +'arguments': 'arguments', +'at char %s': 'at char %s', +'at line %s': 'at line %s', +'ATTENTION:': 'ATTENTION:', +'ATTENTION: TESTING IS NOT THREAD SAFE SO DO NOT PERFORM MULTIPLE TESTS CONCURRENTLY.': 'ATTENTION: TESTING IS NOT THREAD SAFE SO DO NOT PERFORM MULTIPLE TESTS CONCURRENTLY.', 'Available Databases and Tables': 'Dostupné databáze a tabulky', 'back': 'zpět', -'Back to the plugins list': 'Zpět do seznamu pluginů', -'Back to wizard': 'Zpátky do průvodce', -'Basics': 'Základy', +'Back to wizard': 'Back to wizard', +'Basics': 'Basics', 'Begin': 'Začít', 'breakpoint': 'bod přerušení', 'Breakpoints': 'Body přerušení', 'breakpoints': 'body přerušení', -'Bulk Register': 'Hromadná registrace', -'Bulk Student Registration': 'Hromadná registrace studentů', 'Buy this book': 'Koupit web2py knihu', 'Cache': 'Cache', 'cache': 'cache', -'Cache Cleared': 'Cache byla vymazána', 'Cache Keys': 'Klíče cache', 'cache, errors and sessions cleaned': 'cache, chyby a relace byly pročištěny', 'can be a git repo': 'může to být git repo', 'Cancel': 'Storno', 'Cannot be empty': 'Nemůže být prázdné', -'Cannot compile: there are errors in your app:': 'Nelze zkompilovat: ve vaší aplikaci jsou chyby:', -'cannot create file': 'nelze vytvořit soubor', -'cannot upload file "%(filename)s"': 'nelze nahrát soubor "%(filename)s"', 'Change Admin Password': 'Změnit heslo pro správu', 'Change admin password': 'Změnit heslo pro správu aplikací', -'change editor settings': 'změnit nastavení editoru', 'Change password': 'Změna hesla', -'Changelog': 'Žurnál změn', 'check all': 'vše označit', 'Check for upgrades': 'Zkusit aktualizovat', 'Check to delete': 'Označit ke smazání', 'Check to delete:': 'Označit ke smazání:', 'Checking for upgrades...': 'Zjišťuji, zda jsou k dispozici aktualizace...', 'Clean': 'Pročistit', -'Clear': 'Inicializovat', 'Clear CACHE?': 'Vymazat CACHE?', 'Clear DISK': 'Vymazat DISK', 'Clear RAM': 'Vymazat RAM', 'Click row to expand traceback': 'Pro rozbalení stopy, klikněte na řádek', 'Click row to view a ticket': 'Pro zobrazení chyby (ticketu), klikněte na řádku...', 'Client IP': 'IP adresa klienta', -'code': 'kód', -'Code listing': 'Výpis kódu', +'code': 'code', +'Code listing': 'Code listing', 'collapse/expand all': 'vše sbalit/rozbalit', -'Command': 'Příkaz', -'Comment:': 'Komentář:', -'Commit': 'Potvrdit', -'Commit form': 'Potvrdit formulář', -'Committed files': 'Potvrzené soubory', 'Community': 'Komunita', 'Compile': 'Zkompilovat', -'Compile (all or nothing)': 'Přeložit (vše nebo nic)', -'Compile (skip failed views)': 'Přeložit (přeskočit chybné šablony)', 'compiled application removed': 'zkompilovaná aplikace smazána', 'Components and Plugins': 'Komponenty a zásuvné moduly', 'Condition': 'Podmínka', -'continue': 'pokračovat', +'continue': 'continue', 'Controller': 'Kontrolér (Controller)', 'Controllers': 'Kontroléry', 'controllers': 'kontroléry', @@ -134,12 +92,9 @@ 'Count': 'Počet', 'Create': 'Vytvořit', 'create file with filename:': 'vytvořit soubor s názvem:', -'Create/Upload': 'Vytvořit/Nahrát', 'created by': 'vytvořil', 'Created By': 'Vytvořeno - kým', -'Created by:': 'Vytvořil:', 'Created On': 'Vytvořeno - kdy', -'Created on:': 'Vytvořeno:', 'crontab': 'crontab', 'Current request': 'Aktuální požadavek', 'Current response': 'Aktuální odpověď', @@ -150,19 +105,18 @@ 'data uploaded': 'data nahrána', 'Database': 'Rozhraní databáze', 'Database %s select': 'databáze %s výběr', -'Database administration': 'Administrace databáze', +'Database administration': 'Database administration', 'database administration': 'správa databáze', -'Database Administration (appadmin)': 'Administrace databáze (appadmin)', 'Date and Time': 'Datum a čas', 'day': 'den', 'db': 'db', 'DB Model': 'Databázový model', 'Debug': 'Ladění', -'defines tables': 'definuje tabulky', +'defines tables': 'defines tables', 'Delete': 'Smazat', 'delete': 'smazat', 'delete all checked': 'smazat vše označené', -'delete plugin': 'zrušit plugin', +'delete plugin': 'delete plugin', 'Delete this file (you will be asked to confirm deletion)': 'Smazat tento soubor (budete požádán o potvrzení mazání)', 'Delete:': 'Smazat:', 'deleted after first hit': 'smazat po prvním dosažení', @@ -170,265 +124,166 @@ 'Deploy': 'Nahrát', 'Deploy on Google App Engine': 'Nahrát na Google App Engine', 'Deploy to OpenShift': 'Nahrát na OpenShift', -'Deploy to pythonanywhere': 'Nahrát na PythonAnywhere', -'Deploy to PythonAnywhere': 'Nahrát na PythonAnywhere', -'Deployment form': 'Forumlář pro deployment (nasazení)', -'Deployment Interface': 'Rozhraní pro deployment (nasazení)', 'Deployment Recipes': 'Postupy pro deployment', 'Description': 'Popis', -'Description:': 'Popis:', 'design': 'návrh', 'Detailed traceback description': 'Podrobný výpis prostředí', 'details': 'podrobnosti', 'direction: ltr': 'směr: ltr', -'directory not found': 'adresář nebyl nalezen', 'Disable': 'Zablokovat', -'Disabled': 'Blokováno', -'disabled in demo mode': 'zakázáno v demo módu', -'disabled in GAE mode': 'zakázáno v GAE módu', -'disabled in multi user mode': 'zakázáno ve víceuživatelském módu', 'DISK': 'DISK', 'Disk Cache Keys': 'Klíče diskové cache', 'Disk Cleared': 'Disk smazán', -'Display line numbers': 'Zobrazit čísla řádků', -'DO NOT use the "Pack compiled" feature.': 'NEPOUŽÍVEJ vlastnost "Zabalit zkompilované".', 'docs': 'dokumentace', -'Docs': 'Dokumentace', 'Documentation': 'Dokumentace', "Don't know what to do?": 'Nevíte kudy kam?', 'done!': 'hotovo!', -'Downgrade': 'Downgrade (vrácení verze)', 'Download': 'Stáhnout', -'Download .w2p': 'Stažení .w2p', -'Download as .exe': 'Stáhnout jako .exe', 'download layouts': 'stáhnout moduly rozvržení stránky', -'Download layouts from repository': 'Stáhnout moduly rozvržení z repozitáře', 'download plugins': 'stáhnout zásuvné moduly', -'Download plugins from repository': 'Stáhnout pluginy z repozitáře', 'E-mail': 'E-mail', 'Edit': 'Upravit', -'edit all': 'editovat vše', +'edit all': 'edit all', 'Edit application': 'Správa aplikace', -'edit controller': 'editovat controller', -'edit controller:': 'editovat kontrolér:', +'edit controller': 'edit controller', 'Edit current record': 'Upravit aktuální záznam', 'Edit Profile': 'Upravit profil', -'edit views:': 'upravit šablonu (view):', -'Editing %s': 'Editace %s', +'edit views:': 'upravit pohled:', 'Editing file "%s"': 'Úprava souboru "%s"', 'Editing Language file': 'Úprava jazykového souboru', -'Editing Plural Forms File': 'Editování souboru množných čísel', -'Editor': 'Editor', -'Email Address': 'Emailová adresa', +'Editing Plural Forms File': 'Editing Plural Forms File', 'Email and SMS': 'Email a SMS', 'Enable': 'Odblokovat', -'Enable Close-Tag': 'Povolit Close-Tag', -'Enable Code Folding': 'Povolit sdružování kódu', 'enter a number between %(min)g and %(max)g': 'zadejte číslo mezi %(min)g a %(max)g', 'enter an integer between %(min)g and %(max)g': 'zadejte celé číslo mezi %(min)g a %(max)g', 'Error': 'Chyba', 'Error logs for "%(app)s"': 'Seznam výskytu chyb pro aplikaci "%(app)s"', 'Error snapshot': 'Snapshot chyby', -'Error ticket': 'Tiket chyby', +'Error ticket': 'Ticket chyby', 'Errors': 'Chyby', -'Exception %(extype)s: %(exvalue)s': 'Výjimka %(extype)s: %(exvalue)s', -'Exception %s': 'Výjimka %s', +'Exception %(extype)s: %(exvalue)s': 'Exception %(extype)s: %(exvalue)s', +'Exception %s': 'Exception %s', 'Exception instance attributes': 'Prvky instance výjimky', -'Exit Fullscreen': 'Ukončit režim celé obrazovky', -'Expand Abbreviation': 'Rozvinout zkratku', -'Expand Abbreviation (html files only)': 'Rozvinout zkratku (pouze html soubory)', +'Expand Abbreviation': 'Expand Abbreviation', 'export as csv file': 'exportovat do .csv souboru', -'Exports:': 'Exporty:', 'exposes': 'vystavuje', 'exposes:': 'vystavuje funkce:', 'extends': 'rozšiřuje', 'failed to compile file because:': 'soubor se nepodařilo zkompilovat, protože:', -'failed to reload module because:': 'nepodařilo se restartovat modul, protože:', 'FAQ': 'Často kladené dotazy', 'File': 'Soubor', 'file': 'soubor', -'file "%(filename)s" created': 'soubor "%(filename)s" byl vytvořen', -'file "%(filename)s" deleted': 'soubor "%(filename)s" byl zrušen', -'file "%(filename)s" uploaded': 'soubor "%(filename)s" byl nahrán', -'file "%s" of %s restored': 'soubor "%s" z %s byl obnoven', -'file changed on disk': 'soubor se na disku změnil', -'file does not exist': 'soubor neexistuje', -'file not found': 'soubor nebyl nalezen', +'file "%(filename)s" created': 'file "%(filename)s" created', 'file saved on %(time)s': 'soubor uložen %(time)s', 'file saved on %s': 'soubor uložen %s', -'filename': 'jméno souboru', 'Filename': 'Název souboru', -'Files added': 'Soubory byly přidány', 'filter': 'filtr', 'Find Next': 'Najít další', 'Find Previous': 'Najít předchozí', 'First name': 'Křestní jméno', 'Forgot username?': 'Zapomněl jste svoje přihlašovací jméno?', 'forgot username?': 'zapomněl jste svoje přihlašovací jméno?', -'Form has errors': 'Ve formuláři jsou chyby', 'Forms and Validators': 'Formuláře a validátory', -'Frames': 'Framy', +'Frames': 'Frames', 'Free Applications': 'Aplikace zdarma', -'Functions with no doctests will result in [passed] tests.': 'Funkce bez doctestů se projeví jako [úspěšný] test.', -'GAE Email': 'GAE e-mail', -'GAE Output': 'GAE výstup', -'GAE Password': 'GAE heslo', +'Functions with no doctests will result in [passed] tests.': 'Functions with no doctests will result in [passed] tests.', 'Generate': 'Vytvořit', 'Get from URL:': 'Stáhnout z internetu:', 'Git Pull': 'Git Pull', 'Git Push': 'Git Push', 'Globals##debug': 'Globální proměnné', 'go!': 'OK!', -'Google App Engine Deployment Interface': 'Google App Engine - rozhraní pro nasazení', -'Google Application Id': 'ID Google Aplikace', -'Goto': 'Přejít na', -'graph model': 'grafický model', -'Graph Model': 'Grafický model', +'Goto': 'Goto', +'graph model': 'graph model', 'Group %(group_id)s created': 'Skupina %(group_id)s vytvořena', 'Group ID': 'ID skupiny', 'Groups': 'Skupiny', 'Hello World': 'Ahoj světe', 'Help': 'Nápověda', -'here': 'zde', 'Hide/Show Translated strings': 'Skrýt/Zobrazit přeložené texty', -'Highlight current line': 'Zvýraznit aktuální řádek', 'Hits': 'Kolikrát dosaženo', 'Home': 'Domovská stránka', 'honored only if the expression evaluates to true': 'brát v potaz jen když se tato podmínka vyhodnotí kladně', 'How did you get here?': 'Jak jste se sem vlastně dostal?', -'If start the downgrade, be patient, it may take a while to rollback': 'Spustíte-li downgrade verze, vyčkejte, protože vrácení změn může trvat dlouho', -'If start the upgrade, be patient, it may take a while to download': 'Spustíte-li upgrade, vyčkejte, protože stahování může trvat dlouho', -'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\n\t\tA green title indicates that all tests (if defined) passed. In this case test results are not shown.': 'Jestliže přehled výše obsahuje číslo chybového tiketu, znamená to chybu v kontroléru, ještě před pokusem vykonat doctesty. (Často je to způsobeno chybou odsazení nebo chybou mimo kód funkce.) Zelený nadpis označuje, že žádný test nehavaroval. (V tom případě dílčí výsledky nejsou uvedeny.)', -'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\nA green title indicates that all tests (if defined) passed. In this case test results are not shown.': 'Jestliže přehled výše obsahuje číslo chybového tiketu, znamená to chybu v kontroléru, ještě před pokusem vykonat doctesty. (Často je to způsobeno chybou odsazení nebo chybou mimo kód funkce.) Zelený nadpis označuje, že žádný test nehavaroval. (V tom případě dílčí výsledky nejsou uvedeny.)', -'if your application uses a database other than sqlite you will then have to configure its DAL in pythonanywhere.': 'Jestliže vaše aplikace používá jinou databázi než SQLite, budete muset na PythonAnywhere konfigurovat její DAL() připojení.', +'If start the upgrade, be patient, it may take a while to download': 'If start the upgrade, be patient, it may take a while to download', +'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\nA green title indicates that all tests (if defined) passed. In this case test results are not shown.': 'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\nA green title indicates that all tests (if defined) passed. In this case test results are not shown.', 'import': 'import', 'Import/Export': 'Import/Export', -'In development, use the default Rocket webserver that is currently supported by this debugger.': 'Při vývoji je doporučeno použít předvolený webserver Rocket, se kterým tento debugger spolupracuje.', 'includes': 'zahrnuje', -'Indent with tabs': 'Odsazení tabelátory', 'Index': 'Index', 'insert new': 'vložit nový záznam ', 'insert new %s': 'vložit nový záznam %s', -'inspect attributes': 'prohlédnout atributy', +'inspect attributes': 'inspect attributes', 'Install': 'Instalovat', -'Installation of %(plugin)s for %(app)s': 'Instalace %(plugin)s pro %(app)s', 'Installed applications': 'Nainstalované aplikace', 'Interaction at %s line %s': 'Interakce v %s, na řádce %s', 'Interactive console': 'Interaktivní příkazová řádka', -'internal error': 'vnitřní chyba', -'internal error: %s': 'vnitřní chyba: %s', 'Internal State': 'Vnitřní stav', 'Introduction': 'Úvod', -'Invalid action': 'Chybná akce', -'Invalid application name': 'Nesprávné jméno aplikace', -'invalid circular reference': 'nepovolený kruhový odkaz', 'Invalid email': 'Neplatný email', -'Invalid git repository specified.': 'Byl zadán nesprávný git repozitář.', 'Invalid password': 'Nesprávné heslo', -'invalid password': 'nesprávné heslo', 'invalid password.': 'neplatné heslo', 'Invalid Query': 'Neplatný dotaz', 'invalid request': 'Neplatný požadavek', -'Invalid request': 'Nesprávný požadavek (request)', -'invalid table names (auth_* tables already defined)': 'chybná jména tabulek (auth_* tabulky už byly definovány)', -'invalid ticket': 'chybný tiket', 'Is Active': 'Je aktivní', 'It is %s %%{day} today.': 'Dnes je to %s %%{den}.', 'Key': 'Klíč', -'Key bindings': 'Vazby kláves', -'Key bindings for ZenCoding Plugin': 'Vazby kláves pro ZenCoding Plugin', -'Keyboard shortcuts': 'Klávesové zkratky', -'kill process': 'likvidovat proces', -'language file "%(filename)s" created/updated': 'jazykový soubor "%(filename)s" byl vytvořen/aktualizován', -'Language files (static strings) updated': 'Jazykové soubory (statické řetězce) byly aktualizovány', +'Key bindings': 'Vazby klíčů', +'Key bindings for ZenCoding Plugin': 'Key bindings for ZenCoding Plugin', 'languages': 'jazyky', 'Languages': 'Jazyky', 'Last name': 'Příjmení', -'Last Revision': 'Minulá verze', 'Last saved on:': 'Naposledy uloženo:', 'Layout': 'Rozvržení stránky (layout)', 'Layout Plugins': 'Moduly rozvržení stránky (Layout Plugins)', 'Layouts': 'Rozvržení stránek', 'License for': 'Licence pro', -'License:': 'Licence:', -'Line Nr': 'Č.řádku', 'Line number': 'Číslo řádku', 'LineNo': 'Č.řádku', -'lists by exception': 'výpis podle výjimky', -'lists by ticket': 'výpis podle tiketu', -'Live Chat': 'Online chat', -'Loading...': 'Nahrávám...', +'Live Chat': 'Online pokec', 'loading...': 'nahrávám...', -'Local Apps': 'Lokální aplikace', -'locals': 'lokální proměnné', +'locals': 'locals', 'Locals##debug': 'Lokální proměnné', 'Logged in': 'Přihlášení proběhlo úspěšně', 'Logged out': 'Odhlášení proběhlo úspěšně', -'login': 'přihlásit se', 'Login': 'Přihlásit se', -'Login successful': 'Přihlášení bylo úspěšné', +'login': 'přihlásit se', 'Login to the Administrative Interface': 'Přihlásit se do Správce aplikací', -'Login/Register': 'Přihlásit se / Registrovat', 'logout': 'odhlásit se', 'Logout': 'Odhlásit se', -'lost password': 'ztracené heslo', 'Lost Password': 'Zapomněl jste heslo', 'Lost password?': 'Zapomněl jste heslo?', 'lost password?': 'zapomněl jste heslo?', -'Main Menu': 'Hlavní nabídka', -'Manage': 'Spravovat', -'Manage %(action)s': 'Spravovat %(action)s', -'Manage Access Control': 'Spravovat řízení přístupu', -'Manage Admin Users/Students': 'Spravovat Admin uživatele / Studenty', -'Manage Cache': 'Spravovat cache', -'Manage Students': 'Spravovat studenty', -'Memberships': 'Členství ve skupinách', +'Manage': 'Manage', +'Manage Cache': 'Manage Cache', 'Menu Model': 'Model rozbalovací nabídky', -'merge': 'sloučit', 'Models': 'Modely', 'models': 'modely', 'Modified By': 'Změněno - kým', 'Modified On': 'Změněno - kdy', 'Modules': 'Moduly', 'modules': 'moduly', -'Multi User Mode': 'Víceuživatelský mód', 'My Sites': 'Správa aplikací', 'Name': 'Jméno', 'new application "%s" created': 'nová aplikace "%s" vytvořena', -'new application "%s" imported': 'nová aplikace "%s" byla importována', 'New Application Wizard': 'Nový průvodce aplikací', 'New application wizard': 'Nový průvodce aplikací', 'New password': 'Nové heslo', -'new plugin installed': 'nový plugin byl instalován', -'New plugin installed: %s': 'Nový plugin byl instalován: %s', 'New Record': 'Nový záznam', 'new record inserted': 'nový záznam byl založen', -'New simple application': 'Vytvořit novou aplikaci', -'next': 'další', -'next %s rows': 'dalších %s řádků', +'New simple application': 'Vytvořit primitivní aplikaci', +'next': 'next', 'next 100 rows': 'dalších 100 řádků', -'NO': 'NE', -'no changes': 'beze změn', 'No databases in this application': 'V této aplikaci nejsou žádné databáze', 'No Interaction yet': 'Ještě žádná interakce nenastala', -'no match': 'nenalezena shoda', -'no package selected': 'nebyla vybrána žádná package', -'no permission to uninstall "%s"': 'chybí oprávnění odinstalovat "%s"', 'No ticket_storage.txt found under /private folder': 'Soubor ticket_storage.txt v adresáři /private nenalezen', -'Node:': 'Uzel (node):', -'Not Authorized': 'Chybí autorizace', -'Not supported': 'Není podporováno', -'Note: If you receive an error with github status code of 128, ensure the system and account you are deploying from has a cooresponding ssh key configured in the openshift account.': 'Poznámka: Dostanete-li chybu s github status code = 128, ujistěte se, že systém a účet z něhož provádíte nasazení má odpovídající ssh klíč, konfigurovaný v OpenShift účtu.', 'Object or table name': 'Objekt či tabulka', 'Old password': 'Původní heslo', -"On production, you'll have to configure your webserver to use one process and multiple threads to use this debugger.": 'Pro použití tohoto debuggeru na produkci je potřeba konfigurovat webserver, aby používal jeden proces a více vláken.', 'online designer': 'online návrhář', 'Online examples': 'Příklady online', -'Open new app in new window': 'Otevřít novou aplikaci v novém okně', -'OpenShift Deployment Interface': 'OpenShift rozhraní pro nasazení aplikace', -'OpenShift Output': 'OpenShift výstup', -'or alternatively': 'nebo případně', -'Or Get from URL:': 'Nebo získat z URL adresy:', +'Open new app in new window': 'Open new app in new window', +'or alternatively': 'or alternatively', +'Or Get from URL:': 'Or Get from URL:', 'or import from csv file': 'nebo importovat z .csv souboru', 'Origin': 'Původ', 'Original/Translation': 'Originál/Překlad', @@ -438,53 +293,30 @@ 'Overwrite installed app': 'Přepsat instalovanou aplikaci', 'Pack all': 'Zabalit', 'Pack compiled': 'Zabalit zkompilované', -'Pack custom': 'Zabalit volitelně (custom)', -'pack plugin': 'zabalit plugin', -'Password': 'Heslo', +'pack plugin': 'pack plugin', 'password': 'heslo', -'password changed': 'heslo bylo změněno', +'Password': 'Heslo', "Password fields don't match": 'Hesla se neshodují', -'Past revisions': 'Minulá verze', -'Path to appcfg.py': 'Cesta ke appcfg.py', -'Path to local openshift repo root.': 'Cesta ke kořenu (rootu) lokálního OpenShift repozitáře.', -'Peeking at file': 'Sledování souboru', -'Permission': 'Oprávnění', -'Permissions': 'Oprávnění', +'Peeking at file': 'Peeking at file', 'Please': 'Prosím', -'Please wait, giving pythonanywhere a moment...': 'Prosím, čekejte na dokončení činnosti PythonAnywhere...', -'plugin "%(plugin)s" deleted': 'plugin "%(plugin)s" byl odstraněn', -'Plugin "%s" in application': 'Plugin "%s" v aplikaci', -'plugin not specified': 'plugin nebyl určen', -'Plugin page': 'Stránka pluginů', +'Plugin "%s" in application': 'Plugin "%s" in application', 'plugins': 'zásuvné moduly', 'Plugins': 'Zásuvné moduly', -'Plural Form #%s': 'Množné číslo #%s', +'Plural Form #%s': 'Plural Form #%s', 'Plural-Forms:': 'Množná čísla:', -'Powered by': 'používá technologii', +'Powered by': 'Poháněno', 'Preface': 'Předmluva', -'Preferences saved correctly': 'Nastavení byla úspěšně uložena', -'Preferences saved on session only': 'Nastavení byla uložena pouze pro toto sezení', -'previous %s rows': 'předchozích %s řádků', 'previous 100 rows': 'předchozích 100 řádků', 'Private files': 'Soukromé soubory', 'private files': 'soukromé soubory', 'profile': 'profil', 'Project Progress': 'Vývoj projektu', -'Pull': 'Pull', -'Pull failed, certain files could not be checked out. Check logs for details.': 'Pull selhal, některé soubory nelze zkopírovat. Pro podrobnosti zkontrolujte logy.', -'Pull is not possible because you have unmerged files. Fix them up in the work tree, and then try again.': 'Pull nelze provést, protože máte nesloučené soubory. Vyřešte tyto konflikty a pak akci opakujte.', -'Push': 'Push', -'Push failed, there are unmerged entries in the cache. Resolve merge issues manually and try again.': 'Push selhal, protože máte nesloučené soubory. Vyřešte tyto konflikty a pak akci opakujte.', -'pygraphviz library not found': 'pygraphviz knihovna nebyla nalezena', 'Python': 'Python', -'PythonAnywhere Apps': 'PythonAnywhere aplikace', -'PythonAnywhere Password': 'PythonAnywhere heslo', 'Query:': 'Dotaz:', 'Quick Examples': 'Krátké příklady', 'RAM': 'RAM', 'RAM Cache Keys': 'Klíče RAM Cache', 'Ram Cleared': 'RAM smazána', -'Rapid Search': 'Rychlé hledání', 'Readme': 'Nápověda', 'Recipes': 'Postupy jak na to', 'Record': 'Záznam', @@ -503,167 +335,114 @@ 'Removed Breakpoint on %s at line %s': 'Bod přerušení smazán - soubor %s na řádce %s', 'Replace': 'Zaměnit', 'Replace All': 'Zaměnit vše', -'Repository (%s)': 'Repozitář (%s)', -'request': 'požadavek (request)', -'requires distutils, but not installed': 'vyžaduje distutils, jenže ty nejsou instalovány', -'requires python-git, but not installed': 'vyžaduje python-git, který ale není nainstalován', +'request': 'request', 'Reset Password key': 'Reset registračního klíče', -'Resolve Conflict file': 'Vyřešit konflikty', -'response': 'odpověď (response)', +'response': 'response', 'restart': 'restart', 'restore': 'obnovit', 'Retrieve username': 'Získat přihlašovací jméno', 'return': 'return', -'Revert': 'Vrátit se k původnímu', 'revert': 'vrátit se k původnímu', -'reverted to revision %s': 'vráceno k verzi %s', -'Revision %s': 'Verze %s', -'Revision:': 'Verze:', 'Role': 'Role', -'Roles': 'Role', 'Rows in Table': 'Záznamy v tabulce', 'Rows selected': 'Záznamů zobrazeno', 'rules are not defined': 'pravidla nejsou definována', -'Run tests': 'Spustit testy', -'Run tests in this file': 'Spustit testy v souboru', "Run tests in this file (to run all files, you may also use the button labelled 'test')": "Spustí testy v tomto souboru (ke spuštění všech testů, použijte tlačítko 'test')", 'Running on %s': 'Běží na %s', 'Save': 'Uložit', -'Save file:': 'Uložit soubor:', -'Save file: %s': 'Uložit soubor: %s', -'Save model as...': 'Uložit model jako...', +'Save file:': 'Save file:', 'Save via Ajax': 'Uložit pomocí Ajaxu', 'Saved file hash:': 'hash uloženého souboru:', -'Screenshot %s': 'Screenshot %s', -'Search': 'Hledání', -'Select Files to Package': 'Vybrat soubory pro package', 'Semantic': 'Modul semantic', 'Services': 'Služby', -'session': 'session (sezení)', -'session expired': 'vypršela session', -'Session saved correctly': 'Session byla úspěšně uložena', -'Session saved on session only': 'Session byla uložena jen pro toto sezení', +'session': 'session', +'session expired': 'session expired', 'Set Breakpoint on %s at line %s: %s': 'Bod přerušení nastaven v souboru %s na řádce %s: %s', 'shell': 'příkazová řádka', -'Showing %s to %s of %s %s found': 'Zobrazuji %s až %s z %s %s nalezených', -'Singular Form': 'Jednotné číslo', +'Singular Form': 'Singular Form', 'Site': 'Správa aplikací', 'Size of cache:': 'Velikost cache:', -'skip to generate': 'přeskočit pro vytvoření', -'some files could not be removed': 'některé soubory nelze odstranit', -'Something went wrong please wait a few minutes before retrying': 'Něco se nepodařilo. Vyčkejte několik minut a pak zkuste znova', +'skip to generate': 'skip to generate', 'Sorry, could not find mercurial installed': 'Bohužel mercurial není nainstalován.', -'source : db': 'zdroj : db', -'source : filesystem': 'zdroj : souborový systém', 'Start a new app': 'Vytvořit novou aplikaci', 'Start searching': 'Začít hledání', 'Start wizard': 'Spustit průvodce', 'state': 'stav', -'Static': 'Statické soubory', +'Static': 'Static', 'static': 'statické soubory', 'Static files': 'Statické soubory', 'Statistics': 'Statistika', -'Step': 'Krok', -'step': 'krok', -'stop': 'zastavit', +'Step': 'Step', +'step': 'step', +'stop': 'stop', 'Stylesheet': 'CSS styly', 'submit': 'odeslat', 'Submit': 'Odeslat', 'successful': 'úspěšně', 'Support': 'Podpora', 'Sure you want to delete this object?': 'Opravdu chcete smazat tento objekt?', -'switch to : db': 'přepnout na : db', -'switch to : filesystem': 'přepnout na : souborový systém', -'Tab width (# characters)': 'Šířka tabelátoru (# znaků)', 'Table': 'tabulka', 'Table name': 'Název tabulky', 'Temporary': 'Dočasný', 'test': 'test', -'Testing application': 'Zkušební aplikace', -'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.': '"Dotaz" je například "db.tabulka1.pole1==\'hodnota\'". Dotaz se dvěma tabulkami "db.tabulka1.pole1==db.tabulka2.pole2" vytvoří SQL JOIN.', -'The app exists, was created by wizard, continue to overwrite!': 'Aplikace existuje, byla vytvořena průvodcem. Pokračováním ji přepíšete !', -'The app exists, was NOT created by wizard, continue to overwrite!': 'Aplikace existuje, a NEBYLA vytvořena průvodcem. Pokračováním ji přepíšete !', +'Testing application': 'Testing application', +'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.': '"Dotaz" je podmínka, například "db.tabulka1.pole1==\'hodnota\'". Podmínka "db.tabulka1.pole1==db.tabulka2.pole2" pak vytvoří SQL JOIN.', 'The application logic, each URL path is mapped in one exposed function in the controller': 'Logika aplikace: každá URL je mapována na funkci vystavovanou kontrolérem.', 'The Core': 'Jádro (The Core)', -'The data representation, define database tables and sets': 'Modely se vykonají při každém přístupu. Zde se obvykle definuje především reprezentace dat: Připojení k databázi a struktura tabulek databáze', -'The output of the file is a dictionary that was rendered by the view %s': 'Výstup ze souboru je dictionary (slovník), který se zobrazil pomocí šablony (view) %s.', -'The presentations layer, views are also known as templates': 'Prezentační vrstva: šablony (neboli pohledy, templaty, view). Mixuje Html, Python kód a Python data.', +'The data representation, define database tables and sets': 'Reprezentace dat: definovat tabulky databáze a záznamy', +'The output of the file is a dictionary that was rendered by the view %s': 'Výstup ze souboru je slovník, který se zobrazil v pohledu %s.', +'The presentations layer, views are also known as templates': 'Prezentační vrstva: pohledy či templaty (šablony)', 'The Views': 'Pohledy (The Views)', -'Theme': 'Téma', -'There are no controllers': 'Nejsou vytvořeny žádné controllery', -'There are no models': 'Není vytvořen žádný model', -'There are no modules': 'Nejsou přidány žádné moduly', +'There are no controllers': 'There are no controllers', +'There are no modules': 'There are no modules', 'There are no plugins': 'Žádné moduly nejsou instalovány.', 'There are no private files': 'Žádné soukromé soubory neexistují.', -'There are no static files': 'Nejsou přidány žádné statické soubory', -'There are no translators': 'Není vytvořen žádný překlad', -'There are no translators, only default language is supported': 'Není vytvořen žádný překlad, je podporován jen defaultní jazyk', -'There are no views': 'Nejsou vytvořeny žádné šablony (views)', -'These files are not served, they are only available from within your app': 'Tyto soubory jsou přístupné jen běžící aplikaci. Nejsou dostupné uživatelům, ani se nekopírují do případného vývojového repozitáře. Hesla a citlivá nastavení nedávejte nikam jinam.', -'These files are served without processing, your images go here': 'Tyto soubory jsou stahovány přímo, bez jakékoli přídavné logiky, sem patří např. obrázky.', +'There are no static files': 'There are no static files', +'There are no translators, only default language is supported': 'There are no translators, only default language is supported', +'There are no views': 'There are no views', +'These files are not served, they are only available from within your app': 'Tyto soubory jsou klientům nepřístupné. K dispozici jsou pouze v rámci aplikace.', +'These files are served without processing, your images go here': 'Tyto soubory jsou servírovány bez přídavné logiky, sem patří např. obrázky.', 'This App': 'Tato aplikace', -"This debugger may not work properly if you don't have a threaded webserver or you're using multiple daemon processes.": 'Tento debugger nebude pracovat správně, jestliže váš webový server nepracuje pomocí vláken nebo když používáte více procesů démonů.', -'This is a copy of the scaffolding application': 'Toto je kopie vzorové aplikace.', -'This is an experimental feature and it needs more testing. If you decide to downgrade you do it at your own risk': 'Toto je experimentální vlastnost, která vyžaduje další testování. Návrat verze jen na vlastní riziko.', -'This is an experimental feature and it needs more testing. If you decide to upgrade you do it at your own risk': 'Toto je experimentální vlastnost, která vyžaduje další testování. Upgrade verze jen na vlastní riziko.', -'This is the %(filename)s template': 'Toto je šablona %(filename)s', -"This page can commit your changes to an openshift app repo and push them to your cloud instance. This assumes that you've already created the application instance using the web2py skeleton and have that repo somewhere on a filesystem that this web2py instance can access. This functionality requires GitPython installed and on the python path of the runtime that web2py is operating in.": 'Tato stránka umožňuje potvrdit vaše změny do OpenShift aplikačního repozitáře a odeslat je do vaší cloud instance. Předpokladem je, že jste už vytvořili aplikační instanci pomocí Web2py předlohy a že tento repozitář máte někde na disku tak, aby k němu Web2py mělo přístup. Tato funkcionalita vyžaduje, aby byl instalován GitPython a aby mohl být nalezen pomocí cesty, se kterou Web2py pracuje.', -'This page can upload your application to the Google App Engine computing cloud. Mind that you must first create indexes locally and this is done by installing the Google appserver and running the app locally with it once, or there will be errors when selecting records. Attention: deployment may take long time, depending on the network speed. Attention: it will overwrite your app.yaml. DO NOT SUBMIT TWICE.': 'Tato stránka umožňuje zkopírovat vaši aplikaci do Google App Engine cloudu. Pamatujte, že nejprve je třeba vytvořit indexy lokálně, čehož dosáhnete instalací Google appserver a jedním lokálním spuštěním aplikace. V opačném případě bude docházet k chybám vyhledávání. Pozor: v závislosti na rychlosti sítě může nasazení trvat dlouhou dobu. Pozor: bude přepsán váš soubor app.yaml. BĚHEM SPUŠTĚNÍ NESPOUŠTĚJTE PODRUHÉ.', +'This is a copy of the scaffolding application': 'Toto je kopie aplikace skelet.', +'This is an experimental feature and it needs more testing. If you decide to upgrade you do it at your own risk': 'This is an experimental feature and it needs more testing. If you decide to upgrade you do it at your own risk', +'This is the %(filename)s template': 'This is the %(filename)s template', 'this page to see if a breakpoint was hit and debug interaction is required.': 'tuto stránku, abyste uviděli, zda se dosáhlo bodu přerušení.', -'This will pull changes from the remote repo for application "%s"?': 'Toto stáhne (pull) změny ze vzdáleného repozitáře pro aplikaci "%s"?', -'This will push changes to the remote repo for application "%s".': 'Toto nahraje (push) změny do vzdáleného repozitáře pro aplikaci "%s".', -'Ticket': 'Tiket', -'Ticket ID': 'ID tiketu', -'Ticket Missing': 'Chybový tiket chybí', +'Ticket': 'Ticket', +'Ticket ID': 'Ticket ID', 'Time in Cache (h:m:s)': 'Čas v Cache (h:m:s)', 'Timestamp': 'Časové razítko', 'to previous version.': 'k předchozí verzi.', -'To create a plugin, name a file/folder plugin_[name]': 'Zásuvný modul vytvoříte tak, že pojmenujete skupinu souborů nebo adresář(e) plugin_[jméno modulu]', +'To create a plugin, name a file/folder plugin_[name]': 'Zásuvný modul vytvoříte tak, že pojmenujete soubor/adresář plugin_[jméno modulu]', 'To emulate a breakpoint programatically, write:': 'K nastavení bodu přerušení v kódu programu, napište:', 'to use the debugger!': ', abyste mohli ladící program používat!', 'toggle breakpoint': 'vyp./zap. bod přerušení', -'Toggle comment': 'Přepnout komentář', 'Toggle Fullscreen': 'Na celou obrazovku a zpět', 'too short': 'Příliš krátké', -'Traceback': 'Hierarchie volání', +'Traceback': 'Traceback', 'Translation strings for the application': 'Překlad textů pro aplikaci', -'try something like': 'zkuste něco jako', +'try something like': 'try something like', 'Try the mobile interface': 'Zkuste rozhraní pro mobilní zařízení', -'try view': 'vyzkoušet šablonu (view)', +'try view': 'try view', 'Twitter': 'Twitter', -'Type PDB debugger command in here and hit Return (Enter) to execute it.': 'Zapište příkaz PDB debuggeru a stiskněte Return (Enter) pro jeho provedení.', -'Type python statement in here and hit Return (Enter) to execute it.': 'Zapište příkaz pythonu a stiskněte Return (Enter) pro jeho provedení.', -'Type some Python code in here and hit Return (Enter) to execute it.': 'Zapište kód v jazyce python a stiskněte Return (Enter) pro jeho provedení.', -'Unable to check for upgrades': 'Nelze zjistit informaci o aktualizacích', -'unable to create application "%s"': 'nelze vytvořit aplikaci "%s"', -'unable to delete file "%(filename)s"': 'nelze zrušit soubor "%(filename)s"', -'unable to delete file plugin "%(plugin)s"': 'nelze zrušit plugin "%(plugin)s"', -'Unable to determine the line number!': 'Nelze určit číslo řádky!', -'Unable to download app because:': 'Nelze stáhnout aplikaci, protože:', -'unable to download layout': 'nelze stáhnout šablonu (layout)', -'unable to download plugin: %s': 'nelze stáhnout plugin: %s', -'Unable to download the list of plugins': 'Nelze stáhnout seznam pluginů', -'unable to install plugin "%s"': 'nelze instalovat plugin "%s"', +'Type python statement in here and hit Return (Enter) to execute it.': 'Type python statement in here and hit Return (Enter) to execute it.', +'Type some Python code in here and hit Return (Enter) to execute it.': 'Type some Python code in here and hit Return (Enter) to execute it.', +'Unable to check for upgrades': 'Unable to check for upgrades', 'unable to parse csv file': 'csv soubor nedá sa zpracovat', -'unable to uninstall "%s"': 'nelze instalovat "%s"', -'unable to upgrade because "%s"': 'nelze upgradovat, protože "%s"', 'uncheck all': 'vše odznačit', 'Uninstall': 'Odinstalovat', -'Unsupported webserver working mode: %s': 'Nepodporovaný mód webového serveru: %s', 'update': 'aktualizovat', -'update all languages': 'aktualizovat všechny jazyky o nové texty ze zdrojových souborů', +'update all languages': 'aktualizovat všechny jazyky', 'Update:': 'Upravit:', 'Upgrade': 'Upgrade', -'upgrade now': 'upgradovat nyní', -'upgrade now to %s': 'upgradovat nyní na %s', +'upgrade now': 'upgrade now', +'upgrade now to %s': 'upgrade now to %s', 'upload': 'nahrát', -'Upload': 'Upload (nahrát)', +'Upload': 'Upload', 'Upload a package:': 'Nahrát balík:', 'Upload and install packed application': 'Nahrát a instalovat zabalenou aplikaci', 'upload file:': 'nahrát soubor:', 'upload plugin file:': 'nahrát soubor modulu:', 'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Použijte (...)&(...) pro AND, (...)|(...) pro OR a ~(...) pro NOT pro sestavení složitějších dotazů.', -'User': 'Uživatel', 'User %(id)s Logged-in': 'Uživatel %(id)s přihlášen', 'User %(id)s Logged-out': 'Uživatel %(id)s odhlášen', 'User %(id)s Password changed': 'Uživatel %(id)s změnil heslo', @@ -672,46 +451,30 @@ 'User %(id)s Username retrieved': 'Uživatel %(id)s si nachal zaslat přihlašovací jméno', 'User ID': 'ID uživatele', 'Username': 'Přihlašovací jméno', -'Users': 'Uživatelé', -'Using the shell may lock the database to other users of this app.': 'Použití příkazového shellu může uzamknout databázi ostatním uživatelům této aplikace.', -'variables': 'proměnné', +'variables': 'variables', 'Verify Password': 'Zopakujte heslo', 'Version': 'Verze', 'Version %s.%s.%s (%s) %s': 'Verze %s.%s.%s (%s) %s', 'Versioning': 'Verzování', 'Videos': 'Videa', -'View': 'Šablona (View)', -'Views': 'Šablony (Views)', -'views': 'šablony (views)', -'Warning!': 'Pozor!', -'WARNING:': 'POZOR:', -'WARNING: The following views could not be compiled:': 'POZOR: Následující šablony se nepodařilo zkompilovat:', -'Web Framework': 'Webový framework', -'web2py Admin Password': 'web2py Heslo administrátora', -'web2py apps to deploy': 'web2py aplikace k nasazení', -'web2py Debugger': 'web2py Debugger', -'web2py downgrade': 'web2py downgrade', +'View': 'Pohled (View)', +'Views': 'Pohledy', +'views': 'pohledy', +'Web Framework': 'Web Framework', 'web2py is up to date': 'Máte aktuální verzi web2py.', 'web2py online debugger': 'Ladící online web2py program', -'web2py Recent Tweets': 'Nedávné tweety na Twitteru o web2py', -'web2py upgrade': 'aktualizace Web2py', -'web2py upgraded; please restart it': 'Web2py bylo aktualizováno; prosím restarujte jej', +'web2py Recent Tweets': 'Štěbetání na Twitteru o web2py', +'web2py upgrade': 'web2py upgrade', +'web2py upgraded; please restart it': 'web2py upgraded; please restart it', 'Welcome': 'Vítejte', -'Welcome to web2py': 'Vitejte ve Web2py aplikaci.', -'Welcome to web2py!': 'Vítejte ve Web2py aplikaci.', +'Welcome to web2py': 'Vitejte ve web2py', +'Welcome to web2py!': 'Vítejte ve web2py!', 'Which called the function %s located in the file %s': 'která zavolala funkci %s v souboru (kontroléru) %s.', -'Working...': 'Pracuji...', -'WSGI reference name': 'jméno WSGI reference', -'YES': 'ANO', -'Yes': 'Ano', 'You are successfully running web2py': 'Úspěšně jste spustili web2py.', 'You can also set and remove breakpoint in the edit window, using the Toggle Breakpoint button': 'Nastavovat a mazat body přerušení je též možno v rámci editování zdrojového souboru přes tlačítko Vyp./Zap. bod přerušení', -'You can inspect variables using the console bellow': 'Níže pomocí příkazové řádky si můžete prohlédnout proměnné', -'You can inspect variables using the console below': 'You can inspect variables using the console below', 'You can modify this application and adapt it to your needs': 'Tuto aplikaci si můžete upravit a přizpůsobit ji svým potřebám.', -'You have one more login attempt before you are locked out': 'Máte jen jeden další pokus k přihlášení před zablokováním', 'You need to set up and reach a': 'Je třeba nejprve nastavit a dojít až na', -'You only need these if you have already registered': 'Toto potřebujete jen tehdy, jestliže jste se už registroval(a)', 'You visited the url %s': 'Navštívili jste stránku %s,', 'Your application will be blocked until you click an action button (next, step, continue, etc.)': 'Aplikace bude blokována než se klikne na jedno z tlačítek (další, krok, pokračovat, atd.)', +'You can inspect variables using the console bellow': 'Níže pomocí příkazové řádky si můžete prohlédnout proměnné', } diff --git a/applications/admin/languages/de.py b/applications/admin/languages/de.py old mode 100644 new mode 100755 diff --git a/applications/admin/languages/default.py b/applications/admin/languages/default.py old mode 100644 new mode 100755 diff --git a/applications/admin/languages/es.py b/applications/admin/languages/es.py old mode 100644 new mode 100755 index c4501c12..a1db7b4e --- a/applications/admin/languages/es.py +++ b/applications/admin/languages/es.py @@ -3,29 +3,40 @@ '!langcode!': 'es', '!langname!': 'Español', '"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN': '"actualice" es una expresión opcional como "campo1=\'nuevo_valor\'". No se puede actualizar o eliminar resultados de un JOIN', +'"User Exception" debug mode. ': '"User Exception" debug mode. ', +'%s': '%s', '%s %%{row} deleted': '%s filas eliminadas', '%s %%{row} updated': '%s filas actualizadas', +'%s selected': '%s selected', +'%s students registered': '%s students registered', '%Y-%m-%d': '%Y-%m-%d', '%Y-%m-%d %H:%M:%S': '%Y-%m-%d %H:%M:%S', '(requires internet access, experimental)': '(requiere acceso a internet, experimental)', '(something like "it-it")': '(algo como "it-it")', '(version %s)': '(version %s)', +'?': '?', '@markmin\x01(file **gluon/contrib/plural_rules/%s.py** is not found)': '(archivo **gluon/contrib/plural_rules/%s.py** no se ha encontrado)', '@markmin\x01An error occured, please [[reload %s]] the page': 'Ocurrió un error, por favor [[recargue %s]] la página', '@markmin\x01Number of entries: **%s**': 'Número de entradas: **%s**', '@markmin\x01Searching: **%s** %%{file}': 'Buscando: **%s** archivos', 'A new version of web2py is available': 'Hay una nueva versión de web2py disponible', 'A new version of web2py is available: %s': 'Hay una nueva versión de web2py disponible: %s', +'Abort': 'Abort', 'About': 'Acerca de', 'About application': 'Acerca de la aplicación', +'Accept Terms': 'Accept Terms', +'Add breakpoint': 'Add breakpoint', 'additional code for your application': 'código adicional para su aplicación', 'Additional code for your application': 'Código adicional para su aplicación', +'Admin design page': 'Admin design page', 'admin disabled because no admin password': 'admin deshabilitado por falta de contraseña', 'admin disabled because not supported on google app engine': 'admin deshabilitado, no es soportado en GAE', +'admin disabled because too many invalid login attempts': 'admin disabled because too many invalid login attempts', 'admin disabled because unable to access password file': 'admin deshabilitado, imposible acceder al archivo con la contraseña', 'Admin is disabled because insecure channel': 'Admin deshabilitado, el canal no es seguro', 'Admin is disabled because unsecure channel': 'Admin deshabilitado, el canal no es seguro', 'Admin language': 'Lenguaje de administración', +'Admin versioning page': 'Admin versioning page', 'administrative interface': 'interfaz administrativa', 'Administrator Password:': 'Contraseña del Administrador:', 'An error occured, please %s the page': 'Ha ocurrido un error, por favor %s la página', @@ -34,12 +45,15 @@ 'App does not exist or you are not authorized': 'App does not exist or you are not authorized', 'appadmin': 'appadmin', 'appadmin is disabled because insecure channel': 'admin deshabilitado, el canal no es seguro', +'Application': 'Application', 'application "%s" uninstalled': 'aplicación "%s" desinstalada', 'application %(appname)s installed with md5sum: %(digest)s': 'application %(appname)s installed with md5sum: %(digest)s', +'Application cannot be generated in demo mode': 'Application cannot be generated in demo mode', 'application compiled': 'aplicación compilada', 'Application exists already': 'Application exists already', 'application is compiled and cannot be designed': 'la aplicación está compilada y no puede ser modificada', 'Application name:': 'Nombre de la aplicación:', +'Application updated via git pull': 'Application updated via git pull', 'are not used': 'are not used', 'are not used yet': 'are not used yet', 'Are you sure you want to delete file "%s"?': '¿Está seguro que desea eliminar el archivo "%s"?', @@ -52,6 +66,7 @@ 'arguments': 'argumentos', 'at char %s': 'en el carácter %s', 'at line %s': 'en la línea %s', +'ATTENTION:': 'ATTENTION:', 'ATTENTION: Login requires a secure (HTTPS) connection or running on localhost.': 'ATENCIÓN: Inicio de sesión requiere una conexión segura (HTTPS) o localhost.', 'ATTENTION: TESTING IS NOT THREAD SAFE SO DO NOT PERFORM MULTIPLE TESTS CONCURRENTLY.': 'ATENCIÓN: NO EJECUTE VARIAS PRUEBAS SIMULTANEAMENTE, NO SON THREAD SAFE.', 'ATTENTION: you cannot edit the running application!': 'ATENCIÓN: ¡no puede modificar la aplicación que se ejecuta!', @@ -61,11 +76,19 @@ 'Available Databases and Tables': 'Bases de Datos y Tablas Disponibles', 'back': 'atrás', 'Back to the plugins list': 'Regresar a la lista de plugins', +'Back to wizard': 'Back to wizard', +'Basics': 'Basics', +'Begin': 'Begin', 'breakpoint': 'punto de ruptura', +'Breakpoints': 'Breakpoints', 'breakpoints': 'puntos de ruptura', 'browse': 'navegar', +'Bulk Register': 'Bulk Register', +'Bulk Student Registration': 'Bulk Student Registration', 'Cache': 'Caché', 'cache': 'caché', +'Cache Cleared': 'Cache Cleared', +'Cache Keys': 'Cache Keys', 'cache, errors and sessions cleaned': 'caché, errores y sesiones eliminados', 'can be a git repo': 'puede ser un repositorio git', 'Cancel': 'Cancelar', @@ -74,29 +97,41 @@ 'Cannot compile: there are errors in your app:': 'No se puede compilar: hay errores en su aplicación:', 'cannot create file': 'no es posible crear archivo', 'cannot upload file "%(filename)s"': 'no es posible subir archivo "%(filename)s"', +'Change Admin Password': 'Change Admin Password', 'Change admin password': 'cambie contraseña admin', 'change editor settings': 'cambiar la configuración del editor', 'Change Password': 'Cambie Contraseña', +'Changelog': 'Changelog', 'check all': 'marcar todos', 'Check for upgrades': 'buscar actualizaciones', 'Check to delete': 'Marque para eliminar', 'Checking for upgrades...': 'Buscando actualizaciones...', 'Clean': 'Limpiar', +'Clear': 'Clear', 'Clear CACHE?': '¿Limpiar CACHÉ?', 'Clear DISK': 'Limpiar DISCO', 'Clear RAM': 'Limpiar RAM', 'click here for online examples': 'haga click aquí para ver ejemplos en línea', 'click here for the administrative interface': 'haga click aquí para usar la interfaz administrativa', 'Click row to expand traceback': 'Click en la fila para expandir el rastreo', +'Click row to view a ticket': 'Click row to view a ticket', 'click to check for upgrades': 'haga clic para buscar actualizaciones', 'click to open': 'click para abrir', 'Client IP': 'IP del Cliente', 'code': 'código', 'Code listing': 'Listado de código', 'collapse/expand all': 'contraer/expandir todo', +'Command': 'Command', +'Comment:': 'Comment:', +'Commit': 'Commit', 'commit (mercurial)': 'confirmar (mercurial)', +'Commit form': 'Commit form', +'Committed files': 'Committed files', 'Compile': 'Compilar', +'Compile (all or nothing)': 'Compile (all or nothing)', +'Compile (skip failed views)': 'Compile (skip failed views)', 'compiled application removed': 'aplicación compilada removida', +'Condition': 'Condition', 'continue': 'continuar', 'Controllers': 'Controladores', 'controllers': 'controladores', @@ -108,6 +143,9 @@ 'Create new simple application': 'Cree una nueva aplicación', 'Create/Upload': 'Crear/Subir', 'created by': 'creado por', +'Created by:': 'Created by:', +'Created On': 'Created On', +'Created on:': 'Created on:', 'crontab': 'crontab', 'Current request': 'Solicitud en curso', 'Current response': 'Respuesta en curso', @@ -117,7 +155,10 @@ 'customize me!': 'Adáptame!', 'data uploaded': 'datos subidos', 'database': 'base de datos', +'Database': 'Database', +'Database %s select': 'Database %s select', 'database %s select': 'selección en base de datos %s', +'Database administration': 'Database administration', 'database administration': 'administración base de datos', 'Database Administration (appadmin)': 'Administración de Base de Datos (appadmin)', 'Date and Time': 'Fecha y Hora', @@ -130,30 +171,51 @@ 'delete plugin': 'eliminar plugin', 'Delete this file (you will be asked to confirm deletion)': 'Elimine este fichero (se le pedirá confirmación)', 'Delete:': 'Eliminar:', +'deleted after first hit': 'deleted after first hit', 'Demo': 'Demo', 'Deploy': 'Deploy', 'Deploy on Google App Engine': 'Instale en Google App Engine', 'Deploy to OpenShift': 'Instale en OpenShift', +'Deploy to pythonanywhere': 'Deploy to pythonanywhere', +'Deploy to PythonAnywhere': 'Deploy to PythonAnywhere', +'Deployment form': 'Deployment form', +'Deployment Interface': 'Deployment Interface', 'Description': 'Descripción', +'Description:': 'Description:', 'design': 'modificar', 'DESIGN': 'DISEÑO', 'Design for': 'Diseño para', 'Detailed traceback description': 'Descripción detallada del rastreo', 'details': 'detalles', 'direction: ltr': 'dirección: ltr', +'directory not found': 'directory not found', 'Disable': 'Deshabilitar', +'Disabled': 'Disabled', +'disabled in demo mode': 'disabled in demo mode', +'disabled in GAE mode': 'disabled in GAE mode', +'disabled in multi user mode': 'disabled in multi user mode', 'DISK': 'DISCO', +'Disk Cache Keys': 'Disk Cache Keys', +'Disk Cleared': 'Disk Cleared', +'Display line numbers': 'Display line numbers', +'DO NOT use the "Pack compiled" feature.': 'DO NOT use the "Pack compiled" feature.', 'docs': 'documentos', 'Docs': 'Documentos', 'Done!': 'Listo!', 'done!': 'listo!', +'Downgrade': 'Downgrade', 'Download': 'Descargar', +'Download .w2p': 'Download .w2p', +'Download as .exe': 'Download as .exe', 'download files via http:': 'descargar archivos via http:', 'download layouts': 'descargar layouts', +'Download layouts from repository': 'Download layouts from repository', 'download plugins': 'descargar plugins', +'Download plugins from repository': 'Download plugins from repository', 'E-mail': 'Correo electrónico', 'EDIT': 'EDITAR', 'Edit': 'editar', +'edit all': 'edit all', 'Edit application': 'Editar aplicación', 'edit controller': 'editar controlador', 'edit controller:': 'editar controlador:', @@ -166,9 +228,14 @@ 'Editing Language file': 'Editando archivo de lenguaje', 'Editing myclientapi': 'Editando myclientapi', 'Editing myemail': 'Editando myemail', +'Editing Plural Forms File': 'Editing Plural Forms File', 'Editing rbare': 'Editando rbare', 'Editing ul': 'Editando ul', +'Editor': 'Editor', +'Email Address': 'Email Address', 'Enable': 'Habilitar', +'Enable Close-Tag': 'Enable Close-Tag', +'Enable Code Folding': 'Enable Code Folding', 'Enterprise Web Framework': 'Framework Web Empresarial', 'Error': 'Error', 'Error logs for "%(app)s"': 'Bitácora de errores en "%(app)s"', @@ -176,11 +243,14 @@ 'Error ticket': 'Error ticket', 'Errors': 'errores', 'Errors in form, please check it out.': 'Errores en el formulario, verifique por favor.', +'Exception %(extype)s: %(exvalue)s': 'Exception %(extype)s: %(exvalue)s', +'Exception %s': 'Exception %s', 'Exception instance attributes': 'Atributos de la instancia de Excepción', 'Exit Fullscreen': 'Salir de pantalla completa', 'Expand Abbreviation': 'Expandir abreviación', 'Expand Abbreviation (html files only)': 'Expandir Abreviación (sólo archivos html)', 'export as csv file': 'exportar como archivo CSV', +'Exports:': 'Exports:', 'exposes': 'expone', 'exposes:': 'expone:', 'extends': 'extiende', @@ -195,27 +265,53 @@ 'file "%s" of %s restored': 'archivo "%s" de %s restaurado', 'file changed on disk': 'archivo modificado en el disco', 'file does not exist': 'archivo no existe', +'file not found': 'file not found', 'file saved on %(time)s': 'archivo guardado %(time)s', 'file saved on %s': 'archivo guardado %s', +'filename': 'filename', +'Filename': 'Filename', +'Files added': 'Files added', 'filter': 'filter', 'Find Next': 'Buscar próximo', 'Find Previous': 'Bucar anterior', 'First name': 'Nombre', +'Form has errors': 'Form has errors', 'Frames': 'Frames', 'Functions with no doctests will result in [passed] tests.': 'Funciones sin doctests equivalen a pruebas [aceptadas].', +'GAE Email': 'GAE Email', +'GAE Output': 'GAE Output', +'GAE Password': 'GAE Password', +'Generate': 'Generate', 'Git Pull': 'Git Pull', 'Git Push': 'Git Push', 'Globals##debug': 'Globals', +'go!': 'go!', +'Google App Engine Deployment Interface': 'Google App Engine Deployment Interface', +'Google Application Id': 'Google Application Id', +'Goto': 'Goto', 'graph model': 'graficación del modelo', +'Graph Model': 'Graph Model', 'Group ID': 'ID de Grupo', 'Hello World': 'Hola Mundo', 'Help': 'ayuda', 'here': 'aquí', +'Hide/Show Translated strings': 'Hide/Show Translated strings', +'Highlight current line': 'Highlight current line', +'Hits': 'Hits', +'Home': 'Home', +'honored only if the expression evaluates to true': 'honored only if the expression evaluates to true', 'htmledit': 'htmledit', +'If start the downgrade, be patient, it may take a while to rollback': 'If start the downgrade, be patient, it may take a while to rollback', +'If start the upgrade, be patient, it may take a while to download': 'If start the upgrade, be patient, it may take a while to download', +'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\n\t\tA green title indicates that all tests (if defined) passed. In this case test results are not shown.': 'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\n\t\tA green title indicates that all tests (if defined) passed. In this case test results are not shown.', 'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\nA green title indicates that all tests (if defined) passed. In this case test results are not shown.': 'Si el reporte anterior contiene un número de tiquete este indica un falla en la ejecución del controlador, antes de cualquier intento de ejecutat doctests. Esto generalmente se debe a un error en la indentación o un error por fuera del código de la función.\r\nUn titulo verde indica que todas las pruebas pasaron (si existen). En dicho caso los resultados no se muestran.', +'if your application uses a database other than sqlite you will then have to configure its DAL in pythonanywhere.': 'if your application uses a database other than sqlite you will then have to configure its DAL in pythonanywhere.', 'Image': 'Imagen', +'import': 'import', 'Import/Export': 'Importar/Exportar', +'In development, use the default Rocket webserver that is currently supported by this debugger.': 'In development, use the default Rocket webserver that is currently supported by this debugger.', 'includes': 'incluye', +'Indent with tabs': 'Indent with tabs', 'insert new': 'inserte nuevo', 'insert new %s': 'inserte nuevo %s', 'inspect attributes': 'inspeccionar atributos', @@ -226,47 +322,72 @@ 'Interaction at %s line %s': 'Interacción en %s línea %s', 'Interactive console': 'Terminal interactiva', 'internal error': 'error interno', +'internal error: %s': 'internal error: %s', 'Internal State': 'Estado Interno', 'Invalid action': 'Acción inválida', 'Invalid application name': 'Nombre de aplicación no válido', +'invalid circular reference': 'invalid circular reference', 'Invalid email': 'Correo inválido', +'Invalid git repository specified.': 'Invalid git repository specified.', 'invalid password': 'contraseña inválida', 'invalid password.': 'contraseña inválida.', 'Invalid Query': 'Consulta inválida', 'invalid request': 'solicitud inválida', 'Invalid request': 'Petición inválida', +'invalid table names (auth_* tables already defined)': 'invalid table names (auth_* tables already defined)', 'invalid ticket': 'tiquete inválido', +'Key': 'Key', 'Key bindings': 'Key bindings', 'Key bindings for ZenCoding Plugin': 'Key bindings para el Plugin ZenCoding', 'Keyboard shortcuts': 'Atajos de teclado', +'kill process': 'kill process', 'language file "%(filename)s" created/updated': 'archivo de lenguaje "%(filename)s" creado/actualizado', 'Language files (static strings) updated': 'Archivos de lenguaje (cadenas estáticas) actualizados', 'languages': 'lenguajes', 'Languages': 'Lenguajes', 'languages updated': 'lenguajes actualizados', 'Last name': 'Apellido', +'Last Revision': 'Last Revision', 'Last saved on:': 'Guardado en:', 'License for': 'Licencia para', 'License:': 'Licencia:', +'Line Nr': 'Line Nr', +'Line number': 'Line number', +'lists by exception': 'lists by exception', 'lists by ticket': 'listas por ticket', +'Loading...': 'Loading...', 'loading...': 'cargando...', +'Local Apps': 'Local Apps', 'locals': 'locals', 'Locals##debug': 'Locals', 'Login': 'Inicio de sesión', 'login': 'inicio de sesión', +'Login successful': 'Login successful', 'Login to the Administrative Interface': 'Inicio de sesión para la Interfaz Administrativa', +'Login/Register': 'Login/Register', 'Logout': 'fin de sesión', 'Lost Password': 'Contraseña perdida', +'lost password': 'lost password', +'Main Menu': 'Main Menu', 'manage': 'gestionar', 'Manage': 'Gestionar', +'Manage %(action)s': 'Manage %(action)s', +'Manage Access Control': 'Manage Access Control', +'Manage Admin Users/Students': 'Manage Admin Users/Students', 'Manage Cache': 'Administrar Caché', +'Manage Students': 'Manage Students', +'Memberships': 'Memberships', 'merge': 'combinar', 'Models': 'Modelos', 'models': 'modelos', +'Modified On': 'Modified On', 'Modules': 'Módulos', 'modules': 'módulos', +'Multi User Mode': 'Multi User Mode', 'Name': 'Nombre', 'new application "%s" created': 'nueva aplicación "%s" creada', +'new application "%s" imported': 'new application "%s" imported', +'New Application Wizard': 'New Application Wizard', 'New application wizard': 'Asistente para nueva aplicación', 'new plugin installed': 'nuevo plugin instalado', 'New plugin installed: %s': 'Nuevo plugin instalado: %s', @@ -278,14 +399,25 @@ 'new record inserted': 'nuevo registro insertado', 'New simple application': 'Nueva aplicación', 'next': 'siguiente', +'next %s rows': 'next %s rows', 'next 100 rows': '100 filas siguientes', 'NO': 'NO', +'no changes': 'no changes', 'No databases in this application': 'No hay bases de datos en esta aplicación', 'No Interaction yet': 'No hay interacción', 'no match': 'no encontrado', 'no package selected': 'ningún paquete seleccionado', +'no permission to uninstall "%s"': 'no permission to uninstall "%s"', 'No ticket_storage.txt found under /private folder': 'No se encontró ticket_storage.txt en la carpeta /private', +'Node:': 'Node:', +'Not Authorized': 'Not Authorized', +'Not supported': 'Not supported', +'Note: If you receive an error with github status code of 128, ensure the system and account you are deploying from has a cooresponding ssh key configured in the openshift account.': 'Note: If you receive an error with github status code of 128, ensure the system and account you are deploying from has a cooresponding ssh key configured in the openshift account.', +"On production, you'll have to configure your webserver to use one process and multiple threads to use this debugger.": "On production, you'll have to configure your webserver to use one process and multiple threads to use this debugger.", 'online designer': 'diseñador en línea', +'Open new app in new window': 'Open new app in new window', +'OpenShift Deployment Interface': 'OpenShift Deployment Interface', +'OpenShift Output': 'OpenShift Output', 'or alternatively': 'o alternativamente', 'Or Get from URL:': 'O obtener desde una URL:', 'or import from csv file': 'o importar desde archivo CSV', @@ -302,28 +434,52 @@ 'PAM authenticated user, cannot change password here': 'usuario autenticado por PAM, no puede cambiar la contraseña aquí', 'Password': 'Contraseña', 'password changed': 'contraseña cambiada', +'Past revisions': 'Past revisions', +'Path to appcfg.py': 'Path to appcfg.py', +'Path to local openshift repo root.': 'Path to local openshift repo root.', 'Peeking at file': 'Visualizando archivo', +'Permission': 'Permission', +'Permissions': 'Permissions', 'Please': 'Por favor', +'Please wait, giving pythonanywhere a moment...': 'Please wait, giving pythonanywhere a moment...', 'Plugin': 'Plugin', 'plugin "%(plugin)s" deleted': 'plugin "%(plugin)s" eliminado', 'Plugin "%s" in application': 'Plugin "%s" en aplicación', +'plugin not specified': 'plugin not specified', 'Plugin page': 'Página del plugin', 'plugins': 'plugins', 'Plugins': 'Plugins', +'Plural Form #%s': 'Plural Form #%s', 'Plural-Forms:': 'Plural-Forms:', 'Powered by': 'Este sitio usa', +'Preferences saved correctly': 'Preferences saved correctly', +'Preferences saved on session only': 'Preferences saved on session only', +'previous %s rows': 'previous %s rows', 'previous 100 rows': '100 filas anteriores', 'Private files': 'Archivos privados', 'private files': 'archivos privados', 'Project Progress': 'Progreso del Proyecto', +'Pull': 'Pull', +'Pull failed, certain files could not be checked out. Check logs for details.': 'Pull failed, certain files could not be checked out. Check logs for details.', +'Pull is not possible because you have unmerged files. Fix them up in the work tree, and then try again.': 'Pull is not possible because you have unmerged files. Fix them up in the work tree, and then try again.', +'Push': 'Push', +'Push failed, there are unmerged entries in the cache. Resolve merge issues manually and try again.': 'Push failed, there are unmerged entries in the cache. Resolve merge issues manually and try again.', +'pygraphviz library not found': 'pygraphviz library not found', +'PythonAnywhere Apps': 'PythonAnywhere Apps', +'PythonAnywhere Password': 'PythonAnywhere Password', 'Query:': 'Consulta:', 'RAM': 'RAM', +'RAM Cache Keys': 'RAM Cache Keys', +'Ram Cleared': 'Ram Cleared', 'Rapid Search': 'Búsqueda rápida', +'Record': 'Record', 'record': 'registro', 'record does not exist': 'el registro no existe', 'record id': 'id de registro', 'Record ID': 'ID de Registro', +'Record id': 'Record id', 'refresh': 'recargar', +'register': 'register', 'Register': 'Regístrese', 'Registration key': 'Contraseña de Registro', 'reload': 'recargar', @@ -335,15 +491,25 @@ 'Repository (%s)': 'Repositorio (%s)', 'Repository: %s': 'Repositorio: %s', 'request': 'petición', +'requires distutils, but not installed': 'requires distutils, but not installed', +'requires python-git, but not installed': 'requires python-git, but not installed', 'Resolve Conflict file': 'archivo Resolución de Conflicto', 'response': 'respuesta', +'restart': 'restart', 'restore': 'restaurar', 'return': 'return', 'revert': 'revertir', +'Revert': 'Revert', +'reverted to revision %s': 'reverted to revision %s', +'Revision %s': 'Revision %s', +'Revision:': 'Revision:', 'Role': 'Rol', +'Roles': 'Roles', 'Rows in table': 'Filas en la tabla', +'Rows in Table': 'Rows in Table', 'Rows selected': 'Filas seleccionadas', 'rules are not defined': 'reglas no están definidas', +'Run tests': 'Run tests', 'Run tests in this file': 'Ejecute tests en este archivo', "Run tests in this file (to run all files, you may also use the button labelled 'test')": "Ejecute tests en este archivo (para ejecutarlo en todos los archivos, podrías usar el botón etiquetado como 'test')", 'Running on %s': 'Ejecutando en %s', @@ -351,18 +517,31 @@ 'save': 'guardar', 'Save file:': 'Guardar archivo:', 'Save file: %s': 'Guardar archivo: %s', +'Save model as...': 'Save model as...', 'Save via Ajax': 'Guardar vía Ajax', 'Saved file hash:': 'Hash del archivo guardado:', 'Screenshot %s': 'Screenshot %s', 'Screenshots': 'Screenshots', +'Search': 'Search', +'Select Files to Package': 'Select Files to Package', 'selected': 'seleccionado(s)', 'session': 'sesión', 'session expired': 'sesión expirada', +'Session saved correctly': 'Session saved correctly', +'Session saved on session only': 'Session saved on session only', 'Set Breakpoint on %s at line %s: %s': 'Establecer punto de ruptura en %s en la línea %s: %s', 'shell': 'shell', +'Showing %s to %s of %s %s found': 'Showing %s to %s of %s %s found', +'Singular Form': 'Singular Form', 'Site': 'sitio', +'Size of cache:': 'Size of cache:', +'skip to generate': 'skip to generate', 'some files could not be removed': 'algunos archivos no pudieron ser removidos', +'Something went wrong please wait a few minutes before retrying': 'Something went wrong please wait a few minutes before retrying', +'Sorry, could not find mercurial installed': 'Sorry, could not find mercurial installed', +'source : db': 'source : db', 'source : filesystem': 'fuente : sistema de archivos', +'Start a new app': 'Start a new app', 'Start searching': 'Iniciar búsqueda', 'Start wizard': 'Iniciar asistente', 'state': 'estado', @@ -370,6 +549,7 @@ 'static': 'estáticos', 'Static files': 'Archivos estáticos', 'Statistics': 'Estadísticas', +'Step': 'Step', 'step': 'paso', 'stop': 'parar', 'submit': 'enviar', @@ -378,32 +558,49 @@ 'successful': 'exitoso', 'Sure you want to delete this object?': '¿Está seguro que desea eliminar este objeto?', 'switch to : db': 'cambiar a : db', +'switch to : filesystem': 'switch to : filesystem', +'Tab width (# characters)': 'Tab width (# characters)', 'table': 'tabla', +'Table': 'Table', 'Table name': 'Nombre de la tabla', +'Temporary': 'Temporary', 'test': 'probar', 'Testing application': 'Probando aplicación', 'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.': 'La "consulta" es una condición como "db.tabla1.campo1==\'valor\'". Algo como "db.tabla1.campo1==db.tabla2.campo2" resulta en un JOIN SQL.', +'The app exists, was created by wizard, continue to overwrite!': 'The app exists, was created by wizard, continue to overwrite!', +'The app exists, was NOT created by wizard, continue to overwrite!': 'The app exists, was NOT created by wizard, continue to overwrite!', 'The application logic, each URL path is mapped in one exposed function in the controller': 'La lógica de la aplicación, cada ruta URL se mapea en una función expuesta en el controlador', 'the application logic, each URL path is mapped in one exposed function in the controller': 'la lógica de la aplicación, cada ruta URL se mapea en una función expuesta en el controlador', 'the data representation, define database tables and sets': 'la representación de datos, define tablas y conjuntos de base de datos', 'The data representation, define database tables and sets': 'La representación de datos, define tablas y conjuntos de base de datos', 'The presentations layer, views are also known as templates': 'La capa de presentación, las vistas también son llamadas plantillas', 'the presentations layer, views are also known as templates': 'la capa de presentación, las vistas también son llamadas plantillas', +'Theme': 'Theme', 'There are no controllers': 'No hay controladores', 'There are no models': 'No hay modelos', 'There are no modules': 'No hay módulos', 'There are no plugins': 'No hay plugins', 'There are no private files': 'No hay archivos privados', 'There are no static files': 'No hay archivos estáticos', +'There are no translators': 'There are no translators', 'There are no translators, only default language is supported': 'No hay traductores, sólo el lenguaje por defecto es soportado', 'There are no views': 'No hay vistas', 'These files are not served, they are only available from within your app': 'Estos archivos no se proveen, ellos sólo están disponibles para su aplicación', 'These files are served without processing, your images go here': 'Estos archivos se proveen sin procesar, sus imágenes van aquí', 'these files are served without processing, your images go here': 'estos archivos se proveen sin procesar, sus imágenes van aquí', +"This debugger may not work properly if you don't have a threaded webserver or you're using multiple daemon processes.": "This debugger may not work properly if you don't have a threaded webserver or you're using multiple daemon processes.", +'This is an experimental feature and it needs more testing. If you decide to downgrade you do it at your own risk': 'This is an experimental feature and it needs more testing. If you decide to downgrade you do it at your own risk', +'This is an experimental feature and it needs more testing. If you decide to upgrade you do it at your own risk': 'This is an experimental feature and it needs more testing. If you decide to upgrade you do it at your own risk', 'This is the %(filename)s template': 'Está es la plantilla %(filename)s', +"This page can commit your changes to an openshift app repo and push them to your cloud instance. This assumes that you've already created the application instance using the web2py skeleton and have that repo somewhere on a filesystem that this web2py instance can access. This functionality requires GitPython installed and on the python path of the runtime that web2py is operating in.": "This page can commit your changes to an openshift app repo and push them to your cloud instance. This assumes that you've already created the application instance using the web2py skeleton and have that repo somewhere on a filesystem that this web2py instance can access. This functionality requires GitPython installed and on the python path of the runtime that web2py is operating in.", +'This page can upload your application to the Google App Engine computing cloud. Mind that you must first create indexes locally and this is done by installing the Google appserver and running the app locally with it once, or there will be errors when selecting records. Attention: deployment may take long time, depending on the network speed. Attention: it will overwrite your app.yaml. DO NOT SUBMIT TWICE.': 'This page can upload your application to the Google App Engine computing cloud. Mind that you must first create indexes locally and this is done by installing the Google appserver and running the app locally with it once, or there will be errors when selecting records. Attention: deployment may take long time, depending on the network speed. Attention: it will overwrite your app.yaml. DO NOT SUBMIT TWICE.', 'this page to see if a breakpoint was hit and debug interaction is required.': 'esta página para ver si un punto de ruptura fue configurado y la depuración es requerida.', +'This will pull changes from the remote repo for application "%s"?': 'This will pull changes from the remote repo for application "%s"?', +'This will push changes to the remote repo for application "%s".': 'This will push changes to the remote repo for application "%s".', 'Ticket': 'Ticket', 'Ticket ID': 'Ticket ID', +'Ticket Missing': 'Ticket Missing', +'Time in Cache (h:m:s)': 'Time in Cache (h:m:s)', 'Timestamp': 'Timestamp', 'TM': 'MR', 'to previous version.': 'a la versión previa.', @@ -420,25 +617,34 @@ 'try something like': 'intente algo como', 'Try the mobile interface': 'Pruebe la interfaz móvil', 'try view': 'Pruebe la vista', +'Type PDB debugger command in here and hit Return (Enter) to execute it.': 'Type PDB debugger command in here and hit Return (Enter) to execute it.', 'Type some Python code in here and hit Return (Enter) to execute it.': 'Escriba algún código Python aquí y teclee la tecla Enter para ejecutarlo', 'Unable to check for upgrades': 'No es posible verificar la existencia de actualizaciones', 'unable to create application "%s"': 'no es posible crear la aplicación "%s"', 'unable to delete file "%(filename)s"': 'no es posible eliminar el archivo "%(filename)s"', 'unable to delete file plugin "%(plugin)s"': 'no es posible eliminar plugin "%(plugin)s"', +'Unable to determine the line number!': 'Unable to determine the line number!', 'Unable to download': 'No es posible la descarga', 'Unable to download app': 'No es posible descargar la aplicación', 'Unable to download app because:': 'No es posible descargar la aplicación porque:', 'Unable to download because': 'No es posible descargar porque', +'unable to download layout': 'unable to download layout', +'unable to download plugin: %s': 'unable to download plugin: %s', +'Unable to download the list of plugins': 'Unable to download the list of plugins', +'unable to install plugin "%s"': 'unable to install plugin "%s"', 'unable to parse csv file': 'no es posible analizar el archivo CSV', 'unable to uninstall "%s"': 'no es posible instalar "%s"', 'unable to upgrade because "%s"': 'no es posible actualizar porque "%s"', 'uncheck all': 'desmarcar todos', 'Uninstall': 'desinstalar', +'Unsupported webserver working mode: %s': 'Unsupported webserver working mode: %s', 'update': 'actualizar', 'update all languages': 'actualizar todos los lenguajes', 'Update:': 'Actualice:', +'Upgrade': 'Upgrade', 'upgrade now to %s': 'upgrade now to %s', 'upgrade web2py now': 'actualize web2py ahora', +'upload': 'upload', 'Upload': 'Subir', 'Upload & install packed application': 'Suba e instale aplicación empaquetada', 'Upload a package:': 'Subir un paquete:', @@ -448,7 +654,11 @@ 'upload file:': 'suba un archivo:', 'upload plugin file:': 'suba un archivo de plugin:', 'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Use (...)&(...) para AND, (...)|(...) para OR, y ~(...) para NOT, para crear consultas más complejas.', +'User': 'User', 'User ID': 'ID de Usuario', +'Username': 'Username', +'Users': 'Users', +'Using the shell may lock the database to other users of this app.': 'Using the shell may lock the database to other users of this app.', 'variables': 'variables', 'Version': 'Versión', 'versioning': 'versiones', @@ -456,16 +666,28 @@ 'view': 'vista', 'Views': 'Vistas', 'views': 'vistas', +'Warning!': 'Warning!', +'WARNING:': 'WARNING:', +'WARNING: The following views could not be compiled:': 'WARNING: The following views could not be compiled:', 'Web Framework': 'Web Framework', +'web2py Admin Password': 'web2py Admin Password', +'web2py apps to deploy': 'web2py apps to deploy', +'web2py Debugger': 'web2py Debugger', +'web2py downgrade': 'web2py downgrade', 'web2py is up to date': 'web2py está actualizado', 'web2py online debugger': 'web2py debugger en línea', 'web2py Recent Tweets': 'Tweets Recientes de web2py', +'web2py upgrade': 'web2py upgrade', 'web2py upgraded; please restart it': 'web2py actualizado; favor reiniciar', 'Welcome to web2py': 'Bienvenido a web2py', +'WSGI reference name': 'WSGI reference name', 'YES': 'SÍ', 'Yes': 'Sí', 'You are going to install': 'Vas a instalar', -'You need to set up and reach a': 'Necesitas configurar y obtener un', -'Your application will be blocked until you click an action button (next, step, continue, etc.)': 'Tu aplicación será bloqueada hasta que des click en un botón de acción (siguiente, paso, continuar, etc.)', +'You can also set and remove breakpoint in the edit window, using the Toggle Breakpoint button': 'You can also set and remove breakpoint in the edit window, using the Toggle Breakpoint button', 'You can inspect variables using the console below': 'Puedes inspeccionar las variables utilizando la terminal de abajo', +'You have one more login attempt before you are locked out': 'You have one more login attempt before you are locked out', +'You need to set up and reach a': 'Necesitas configurar y obtener un', +'You only need these if you have already registered': 'You only need these if you have already registered', +'Your application will be blocked until you click an action button (next, step, continue, etc.)': 'Tu aplicación será bloqueada hasta que des click en un botón de acción (siguiente, paso, continuar, etc.)', } diff --git a/applications/admin/languages/fr.py b/applications/admin/languages/fr.py old mode 100644 new mode 100755 index 66326765..c8a180b1 --- a/applications/admin/languages/fr.py +++ b/applications/admin/languages/fr.py @@ -3,277 +3,646 @@ '!langcode!': 'fr', '!langname!': 'Français', '"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN': '"update" est une expression en option tels que "field1 = \'newvalue\'". Vous ne pouvez pas mettre à jour ou supprimer les résultats d\'une jointure "a JOIN"', -'%Y-%m-%d': '%d-%m-%Y', -'%Y-%m-%d %H:%M:%S': '%d-%m-%Y %H:%M:%S', +'"User Exception" debug mode. ': '"User Exception" debug mode. ', +'%s': '%s', '%s %%{row} deleted': 'lignes %s supprimées', '%s %%{row} updated': 'lignes %s mises à jour', +'%s selected': '%s selected', +'%s students registered': '%s students registered', +'%Y-%m-%d': '%d-%m-%Y', +'%Y-%m-%d %H:%M:%S': '%d-%m-%Y %H:%M:%S', +'(**%.0d MB**)': '(**%.0d MB**)', +'(file **gluon/contrib/plural_rules/%s.py** is not found)': '(file **gluon/contrib/plural_rules/%s.py** is not found)', '(requires internet access)': '(nécessite un accès Internet)', +'(requires internet access, experimental)': '(nécessite un accès Internet, expérimentale)', '(something like "it-it")': '(quelque chose comme "it-it") ', +'(version %s)': '(version %s)', +'**%(items)s** %%{item(items)}, **%(bytes)s** %%{byte(bytes)}': '**%(items)s** %%{item(items)}, **%(bytes)s** %%{byte(bytes)}', +'**%(items)s** items, **%(bytes)s** %%{byte(bytes)}': '**%(items)s** items, **%(bytes)s** %%{byte(bytes)}', +'**not available** (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)': '**not available** (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)', +'?': '?', '@markmin\x01Searching: **%s** %%{file}': 'Cherche: **%s** fichiers', +'``**not available**``:red (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)': '``**not available**``:red (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)', 'A new version of web2py is available: %s': 'Une nouvelle version de web2py est disponible: %s ', 'A new version of web2py is available: Version 1.68.2 (2009-10-21 09:59:29)\n': 'Une nouvelle version de web2py est disponible: Version 1.68.2 (2009-10-21 09:59:29)\r\n', -'ATTENTION: Login requires a secure (HTTPS) connection or running on localhost.': 'ATTENTION: nécessite une connexion sécurisée (HTTPS) ou être en localhost. ', -'ATTENTION: TESTING IS NOT THREAD SAFE SO DO NOT PERFORM MULTIPLE TESTS CONCURRENTLY.': 'ATTENTION: les tests ne sont pas thread-safe DONC NE PAS EFFECTUER DES TESTS MULTIPLES SIMULTANÉMENT.', -'ATTENTION: you cannot edit the running application!': "ATTENTION: vous ne pouvez pas modifier l'application qui tourne!", +'Abort': 'Abort', 'About': 'à propos', 'About application': "A propos de l'application", +'Accept Terms': 'Termes acceptés', +'Add breakpoint': 'Ajouter une interruption', 'Additional code for your application': 'Code additionnel pour votre application', +'additional code for your application': 'code supplémentaire pour votre application', +'Admin design page': 'Admin design page', +'admin disabled because no admin password': 'admin désactivée car aucun mot de passe admin', +'admin disabled because not supported on google app engine': 'admin désactivée car non prise en charge sur Google Apps engine', +'admin disabled because too many invalid login attempts': 'admin disabled because too many invalid login attempts', +'admin disabled because unable to access password file': "admin désactivée car incapable d'accéder au fichier mot de passe", 'Admin is disabled because insecure channel': 'Admin est désactivé parce que canal non sécurisé', 'Admin language': "Language de l'admin", +'Admin versioning page': 'Admin versioning page', +'administrative interface': "interface d'administration", 'Administrator Password:': 'Mot de passe Administrateur:', +'An error occured, please [[reload %s]] the page': 'Une erreur c’est produite, s’il vous plait [[reload %s]] la page', +'and rename it (required):': 'et renommez-la (obligatoire):', +'and rename it:': 'et renommez-le:', +'App does not exist or you are not authorized': 'App does not exist or you are not authorized', +'appadmin': 'appadmin', +'appadmin is disabled because insecure channel': 'appadmin est désactivé parce que canal non sécurisé', +'Application': 'Application', +'application "%s" uninstalled': 'application "%s" désinstallée', +'application %(appname)s installed with md5sum: %(digest)s': 'application %(appname)s installée avec md5sum: %(digest)s', +'Application cannot be generated in demo mode': 'Application cannot be generated in demo mode', +'application compiled': 'application compilée', +'Application exists already': 'Application exists already', +'application is compiled and cannot be designed': "l'application est compilée et ne peut être modifiée", 'Application name:': "Nom de l'application:", +'Application updated via git pull': 'Application updated via git pull', +'are not used': 'are not used', +'are not used yet': 'are not used yet', 'Are you sure you want to delete file "%s"?': 'Êtes-vous sûr de vouloir supprimer le fichier «%s»?', 'Are you sure you want to delete plugin "%s"?': 'Êtes-vous sûr de vouloir supprimer le plugin "%s"?', 'Are you sure you want to delete this object?': 'Êtes-vous sûr de vouloir supprimer cet objet?', 'Are you sure you want to uninstall application "%s"?': "Êtes-vous sûr de vouloir désinstaller l'application «%s»?", 'Are you sure you want to upgrade web2py now?': 'Êtes-vous sûr de vouloir mettre à jour web2py maintenant?', +'Are you sure?': 'Etes vous sûr?', +'arguments': 'arguments', +'at char %s': 'at char %s', +'at line %s': 'at line %s', +'ATTENTION:': 'ATTENTION:', +'ATTENTION: Login requires a secure (HTTPS) connection or running on localhost.': 'ATTENTION: nécessite une connexion sécurisée (HTTPS) ou être en localhost. ', +'ATTENTION: TESTING IS NOT THREAD SAFE SO DO NOT PERFORM MULTIPLE TESTS CONCURRENTLY.': 'ATTENTION: les tests ne sont pas thread-safe DONC NE PAS EFFECTUER DES TESTS MULTIPLES SIMULTANÉMENT.', +'ATTENTION: you cannot edit the running application!': "ATTENTION: vous ne pouvez pas modifier l'application qui tourne!", +'Autocomplete Python Code': 'Autocomplete Python Code', 'Available databases and tables': 'Bases de données et tables disponible', +'Available Databases and Tables': 'Available Databases and Tables', +'back': 'retour', +'Back to the plugins list': 'Retour à la liste de plugins', +'Back to wizard': 'Back to wizard', +'Basics': 'Basics', +'Begin': 'Begin', +'breakpoint': 'breakpoint', +'Breakpoints': 'Breakpoints', +'breakpoints': 'breakpoints', +'Bulk Register': 'Bulk Register', +'Bulk Student Registration': 'Bulk Student Registration', +'Cache': 'Cache', +'cache': 'cache', +'Cache Cleared': 'Cache Cleared', +'Cache contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.': 'Cache contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.', +'Cache Keys': 'Cache Keys', +'cache, errors and sessions cleaned': 'cache, erreurs et sessions nettoyés', +'can be a git repo': 'can be a git repo', +'Cancel': 'Retour', 'Cannot be empty': 'Ne peut pas être vide', 'Cannot compile: there are errors in your app. Debug it, correct errors and try again.': 'Ne peut pas compiler: il y a des erreurs dans votre application. corriger les erreurs et essayez à nouveau.', 'Cannot compile: there are errors in your app:': 'Ne peut pas compiler: il y a des erreurs dans votre application:', +'cannot create file': 'ne peut pas créer de fichier', +'cannot upload file "%(filename)s"': 'ne peut pas charger le fichier "%(filename)s"', +'Change Admin Password': 'Change Admin Password', 'Change admin password': 'Changer le mot de passe admin', +'change editor settings': 'change editor settings', +'Changelog': 'Changelog', +'check all': 'tout vérifier ', 'Check for upgrades': 'Vérifier les mises à jour', 'Check to delete': 'Cocher pour supprimer', 'Checking for upgrades...': 'Vérification des mises à jour ... ', 'Clean': 'nettoyer', +'Clear': 'Clear', +'Clear CACHE?': 'Clear CACHE?', +'Clear DISK': 'Clear DISK', +'Clear RAM': 'Clear RAM', +'Click row to expand traceback': 'Click row to expand traceback', +'Click row to view a ticket': 'Click row to view a ticket', +'click to check for upgrades': 'Cliquez pour vérifier les mises jour', +'code': 'code', +'Code listing': 'Code listing', +'collapse/expand all': 'tout réduire/agrandir', +'Command': 'Command', +'Comment:': 'Comment:', +'Commit': 'Commit', +'Commit form': 'Commit form', +'Committed files': 'Committed files', 'Compile': 'compiler', +'Compile (all or nothing)': 'Compile (all or nothing)', +'Compile (skip failed views)': 'Compile (skip failed views)', +'compiled application removed': 'application compilée enlevée', +'Condition': 'Condition', +'continue': 'continue', 'Controllers': 'Contrôleurs', +'controllers': 'contrôleurs', +'Count': 'Count', 'Create': 'Créer', +'create file with filename:': 'créer un fichier avec nom de fichier:', +'create new application:': 'créer une nouvelle application:', 'Create new simple application': 'Créer une nouvelle application', +'Create/Upload': 'Create/Upload', +'created by': 'créé par', +'Created by:': 'Created by:', +'Created On': 'Created On', +'Created on:': 'Created on:', +'crontab': 'crontab', 'Current request': 'Requête actuelle', 'Current response': 'Réponse actuelle', 'Current session': 'Session en cours', -'Date and Time': 'Date et heure', -'Delete': 'Supprimer', -'Delete this file (you will be asked to confirm deletion)': 'Supprimer ce fichier (on vous demandera de confirmer la suppression)', -'Delete:': 'Supprimer:', -'Deploy': 'Déployer', -'Deploy on Google App Engine': 'Déployer sur Google App Engine', -'EDIT': 'MODIFIER', -'Edit': 'modifier', -'Edit application': "Modifier l'application", -'Edit current record': 'Modifier cette entrée', -'Editing Language file': 'Modifier le fichier de langue', -'Editing file': 'Modifier le fichier', -'Editing file "%s"': 'Modifier le fichier "% s" ', -'Enterprise Web Framework': 'Enterprise Web Framework', -'Error logs for "%(app)s"': 'Journal d\'erreurs pour "%(app)s"', -'Errors': 'erreurs', -'Exception instance attributes': "Attributs d'instance Exception", -'Functions with no doctests will result in [passed] tests.': 'Des fonctions sans doctests entraîneront des tests [passed] .', -'Help': 'aide', -'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\nA green title indicates that all tests (if defined) passed. In this case test results are not shown.': "Si le rapport ci-dessus contient un numéro de ticket, cela indique une défaillance dans l'exécution du contrôleur, avant toute tentative d'exécuter les doctests. Cela est généralement dû à une erreur d'indentation ou une erreur à l'extérieur du code de la fonction.\r\nUn titre vert indique que tous les tests (si définis) sont passés. Dans ce cas, les résultats des essais ne sont pas affichées.", -'Import/Export': 'Importer/Exporter', -'Install': 'Installer', -'Installed applications': 'Applications installées', -'Internal State': 'État Interne', -'Invalid Query': 'Requête non valide', -'Invalid action': 'Action non valide', -'Language files (static strings) updated': 'Fichiers de langue (chaînes statiques) mis à jour ', -'Languages': 'Langues', -'Last saved on:': 'Dernière sauvegarde le:', -'License for': 'Licence pour', -'Login': 'Connexion', -'Login to the Administrative Interface': "Se connecter à l'interface d'administration", -'Logout': 'déconnexion', -'Models': 'Modèles', -'Modules': 'Modules', -'NO': 'NON', -'New Record': 'Nouvelle Entrée', -'New application wizard': 'Assistant nouvelle application', -'New simple application': 'Nouvelle application simple', -'No databases in this application': 'Aucune base de données dans cette application', -'Original/Translation': 'Original / Traduction', -'Overwrite installed app': "Écraser l'application installée", -'PAM authenticated user, cannot change password here': 'Utilisateur authentifié par PAM, vous ne pouvez pas changer le mot de passe ici', -'Pack all': 'tout empaqueter', -'Pack compiled': 'paquet compilé', -'Peeking at file': 'Jeter un oeil au fichier', -'Plugin "%s" in application': 'Plugin "%s" dans l\'application', -'Plugins': 'Plugins', -'Powered by': 'Propulsé par', -'Query:': 'Requête: ', -'Remove compiled': 'retirer compilé', -'Resolve Conflict file': 'Résoudre les conflits de fichiers', -'Rows in table': 'Lignes de la table', -'Rows selected': 'Lignes sélectionnées', -"Run tests in this file (to run all files, you may also use the button labelled 'test')": "Lancer les tests dans ce fichier (pour lancer tous les fichiers, vous pouvez également utiliser le bouton nommé 'test')", -'Save': 'Enregistrer', -'Saved file hash:': 'Hash du Fichier enregistré:', -'Site': 'Site', -'Start wizard': "Démarrer l'assistant", -'Static files': 'Fichiers statiques', -'Sure you want to delete this object?': 'Vous êtes sûr de vouloir supprimer cet objet? ', -'TM': 'MD', -'Testing application': "Test de l'application", -'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.': 'La "requête" est une condition comme "db.table1.field1==\'value\'". Quelque chose comme "db.table1.field1==db.table2.field2" aboutit à un JOIN SQL.', -'The application logic, each URL path is mapped in one exposed function in the controller': "La logique de l'application, chaque chemin d'URL est mappé avec une fonction exposée dans le contrôleur", -'The data representation, define database tables and sets': 'La représentation des données, définir les tables et ensembles de la base de données', -'The presentations layer, views are also known as templates': "Les couches de présentation, les vues sont également appelées modples", -'There are no controllers': "Il n'y a pas de contrôleurs", -'There are no models': "Il n'y a pas de modèles", -'There are no modules': "Il n'y a pas de modules", -'There are no plugins': "Il n'y a pas de plugins", -'There are no static files': "Il n'y a pas de fichiers statiques", -'There are no translators, only default language is supported': "Il n'y a pas de traducteurs, seule la langue par défaut est prise en charge", -'There are no views': "Il n'y a pas de vues", -'These files are served without processing, your images go here': 'Ces fichiers sont renvoyés sans traitement, vos images viennent ici', -'This is the %(filename)s template': 'Ceci est le modèle %(filename)s ', -'Ticket': 'Ticket', -'To create a plugin, name a file/folder plugin_[name]': 'Pour créer un plugin, créer un fichier /dossier plugin_[nom]', -'Translation strings for the application': "Chaînes de traduction pour l'application", -'Unable to check for upgrades': 'Impossible de vérifier les mises à jour', -'Unable to download': 'Impossible de télécharger', -'Unable to download app': "Impossible de télécharger l'app", -'Unable to download app because:': "Impossible de télécharger l'app car:", -'Unable to download because': 'Impossible de télécharger car', -'Uninstall': 'désinstaller', -'Update:': 'Mise à jour:', -'Upload & install packed application': "Charger & installer l'application empaquetée", -'Upload a package:': 'Charger un paquet:', -'Upload existing application': 'Charger une application existante', -'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Utilisez (...)&(...) pour AND, (...)|(...) pour OR, et ~(...) pour NOT afin de construire des requêtes plus complexes. ', -'Use an url:': 'Utiliser une url:', -'Version': 'Version', -'Views': 'Vues', -'Web Framework': 'Framework Web', -'YES': 'OUI', -'additional code for your application': 'code supplémentaire pour votre application', -'admin disabled because no admin password': 'admin désactivée car aucun mot de passe admin', -'admin disabled because not supported on google app engine': 'admin désactivée car non prise en charge sur Google Apps engine', -'admin disabled because unable to access password file': "admin désactivée car incapable d'accéder au fichier mot de passe", -'administrative interface': "interface d'administration", -'and rename it (required):': 'et renommez-la (obligatoire):', -'and rename it:': 'et renommez-le:', -'appadmin': 'appadmin', -'appadmin is disabled because insecure channel': 'appadmin est désactivé parce que canal non sécurisé', -'application "%s" uninstalled': 'application "%s" désinstallée', -'application %(appname)s installed with md5sum: %(digest)s': 'application %(appname)s installée avec md5sum: %(digest)s', -'application compiled': 'application compilée', -'application is compiled and cannot be designed': "l'application est compilée et ne peut être modifiée", -'arguments': 'arguments', -'back': 'retour', -'cache': 'cache', -'cache, errors and sessions cleaned': 'cache, erreurs et sessions nettoyés', -'cannot create file': 'ne peut pas créer de fichier', -'cannot upload file "%(filename)s"': 'ne peut pas charger le fichier "%(filename)s"', -'check all': 'tout vérifier ', -'click to check for upgrades': 'Cliquez pour vérifier les mises jour', -'code': 'code', -'collapse/expand all': 'tout réduire/agrandir', -'compiled application removed': 'application compilée enlevée', -'controllers': 'contrôleurs', -'create file with filename:': 'créer un fichier avec nom de fichier:', -'create new application:': 'créer une nouvelle application:', -'created by': 'créé par', -'crontab': 'crontab', 'currently running': 'tourne actuellement', 'currently saved or': 'actuellement enregistré ou', 'data uploaded': 'données chargées', +'Database': 'Database', 'database': 'base de données', +'Database %s select': 'Database %s select', 'database %s select': 'base de données %s sélectionner', +'Database administration': 'Database administration', 'database administration': 'administration base de données', +'Database Administration (appadmin)': 'Database Administration (appadmin)', +'Date and Time': 'Date et heure', 'db': 'bdd', +'Debug': 'Debug', 'defines tables': 'définit les tables', +'Delete': 'Supprimer', 'delete': 'supprimer', 'delete all checked': 'supprimer tout ce qui est coché', 'delete plugin': ' supprimer le plugin', +'Delete this file (you will be asked to confirm deletion)': 'Supprimer ce fichier (on vous demandera de confirmer la suppression)', +'Delete:': 'Supprimer:', +'deleted after first hit': 'deleted after first hit', +'Demo': 'Demo', +'Deploy': 'Déployer', +'Deploy on Google App Engine': 'Déployer sur Google App Engine', +'Deploy to OpenShift': 'Deploy to OpenShift', +'Deploy to pythonanywhere': 'Deploy to pythonanywhere', +'Deploy to PythonAnywhere': 'Deploy to PythonAnywhere', +'Deployment form': 'Deployment form', +'Deployment Interface': 'Deployment Interface', +'Description:': 'Description:', 'design': 'conception', +'Detailed traceback description': 'Detailed traceback description', +'details': 'details', 'direction: ltr': 'direction: ltr', +'directory not found': 'directory not found', +'Disable': 'Disable', +'Disabled': 'Disabled', +'disabled in demo mode': 'disabled in demo mode', +'disabled in GAE mode': 'disabled in GAE mode', +'disabled in multi user mode': 'disabled in multi user mode', +'DISK': 'DISK', +'Disk Cache Keys': 'Disk Cache Keys', +'Disk Cleared': 'Disk Cleared', +'DISK contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.': 'DISK contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.', +'Display line numbers': 'Display line numbers', +'DO NOT use the "Pack compiled" feature.': 'DO NOT use the "Pack compiled" feature.', 'docs': 'docs', +'Docs': 'Docs', 'done!': 'fait!', +'Downgrade': 'Downgrade', +'Download .w2p': 'Download .w2p', +'Download as .exe': 'Download as .exe', 'download layouts': 'télécharger layouts', +'Download layouts from repository': 'Download layouts from repository', 'download plugins': 'télécharger plugins', +'Download plugins from repository': 'Download plugins from repository', +'EDIT': 'MODIFIER', +'Edit': 'modifier', +'edit all': 'edit all', +'Edit application': "Modifier l'application", 'edit controller': 'modifier contrôleur', +'edit controller:': 'edit controller:', +'Edit current record': 'Modifier cette entrée', 'edit views:': 'modifier vues:', +'Editing %s': 'Editing %s', +'Editing file': 'Modifier le fichier', +'Editing file "%s"': 'Modifier le fichier "% s" ', +'Editing Language file': 'Modifier le fichier de langue', +'Editing Plural Forms File': 'Editing Plural Forms File', +'Editor': 'Editor', +'Email Address': 'Email Address', +'Enable': 'Enable', +'Enable Close-Tag': 'Enable Close-Tag', +'Enable Code Folding': 'Enable Code Folding', +'Enterprise Web Framework': 'Enterprise Web Framework', +'Error': 'Error', +'Error logs for "%(app)s"': 'Journal d\'erreurs pour "%(app)s"', +'Error snapshot': 'Error snapshot', +'Error ticket': 'Error ticket', +'Errors': 'erreurs', +'Exception %(extype)s: %(exvalue)s': 'Exception %(extype)s: %(exvalue)s', +'Exception %s': 'Exception %s', +'Exception instance attributes': "Attributs d'instance Exception", +'Exit Fullscreen': 'Exit Fullscreen', +'Expand Abbreviation (html files only)': 'Expand Abbreviation (html files only)', 'export as csv file': 'export au format CSV', +'Exports:': 'Exports:', 'exposes': 'expose', 'exposes:': 'expose:', 'extends': 'étend', +'failed to compile file because:': 'failed to compile file because:', 'failed to reload module': 'impossible de recharger le module', 'failed to reload module because:': 'impossible de recharger le module car:', +'File': 'File', 'file "%(filename)s" created': 'fichier "%(filename)s" créé', 'file "%(filename)s" deleted': 'fichier "%(filename)s" supprimé', 'file "%(filename)s" uploaded': 'fichier "%(filename)s" chargé', 'file "%s" of %s restored': 'fichier "%s" de %s restauré', 'file changed on disk': 'fichier modifié sur le disque', 'file does not exist': "fichier n'existe pas", +'file not found': 'file not found', 'file saved on %(time)s': 'fichier enregistré le %(time)s', 'file saved on %s': 'fichier enregistré le %s', +'filename': 'filename', +'Filename': 'Filename', +'Files added': 'Files added', 'filter': 'filtre', +'Find Next': 'Find Next', +'Find Previous': 'Find Previous', +'Form has errors': 'Form has errors', +'Frames': 'Frames', +'Functions with no doctests will result in [passed] tests.': 'Des fonctions sans doctests entraîneront des tests [passed] .', +'GAE Email': 'GAE Email', +'GAE Output': 'GAE Output', +'GAE Password': 'GAE Password', +'Generate': 'Generate', +'Git Pull': 'Git Pull', +'Git Push': 'Git Push', +'Globals##debug': 'Globals##debug', +'go!': 'go!', +'Google App Engine Deployment Interface': 'Google App Engine Deployment Interface', +'Google Application Id': 'Google Application Id', +'Goto': 'Goto', +'Graph Model': 'Graph Model', +'graph model': 'graph model', +'Help': 'aide', +'here': 'here', +'Hide/Show Translated strings': 'Hide/Show Translated strings', +'Highlight current line': 'Highlight current line', +'Hit Ratio: **%(ratio)s%%** (**%(hits)s** %%{hit(hits)} and **%(misses)s** %%{miss(misses)})': 'Hit Ratio: **%(ratio)s%%** (**%(hits)s** %%{hit(hits)} and **%(misses)s** %%{miss(misses)})', +'Hits': 'Hits', +'Home': 'Home', +'honored only if the expression evaluates to true': 'honored only if the expression evaluates to true', 'htmledit': 'edition html', +'If start the downgrade, be patient, it may take a while to rollback': 'If start the downgrade, be patient, it may take a while to rollback', +'If start the upgrade, be patient, it may take a while to download': 'If start the upgrade, be patient, it may take a while to download', +'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\n\t\tA green title indicates that all tests (if defined) passed. In this case test results are not shown.': 'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\n\t\tA green title indicates that all tests (if defined) passed. In this case test results are not shown.', +'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\nA green title indicates that all tests (if defined) passed. In this case test results are not shown.': "Si le rapport ci-dessus contient un numéro de ticket, cela indique une défaillance dans l'exécution du contrôleur, avant toute tentative d'exécuter les doctests. Cela est généralement dû à une erreur d'indentation ou une erreur à l'extérieur du code de la fonction.\r\nUn titre vert indique que tous les tests (si définis) sont passés. Dans ce cas, les résultats des essais ne sont pas affichées.", +'if your application uses a database other than sqlite you will then have to configure its DAL in pythonanywhere.': 'if your application uses a database other than sqlite you will then have to configure its DAL in pythonanywhere.', +'import': 'import', +'Import/Export': 'Importer/Exporter', +'In development, use the default Rocket webserver that is currently supported by this debugger.': 'In development, use the default Rocket webserver that is currently supported by this debugger.', 'includes': 'inclus', +'Indent with tabs': 'Indent with tabs', 'index': 'index', 'insert new': 'insérer nouveau', 'insert new %s': 'insérer nouveau %s', +'inspect attributes': 'inspect attributes', +'Install': 'Installer', +'Installation of %(plugin)s for %(app)s': 'Installation of %(plugin)s for %(app)s', +'Installed applications': 'Applications installées', +'Interaction at %s line %s': 'Interaction at %s line %s', +'Interactive console': 'Interactive console', 'internal error': 'erreur interne', +'internal error: %s': 'internal error: %s', +'Internal State': 'État Interne', +'Invalid action': 'Action non valide', +'Invalid application name': 'Invalid application name', +'invalid circular reference': 'invalid circular reference', +'Invalid git repository specified.': 'Invalid git repository specified.', 'invalid password': 'mot de passe invalide', +'invalid password.': 'invalid password.', +'Invalid Query': 'Requête non valide', 'invalid request': 'Demande incorrecte', +'Invalid request': 'Invalid request', +'invalid table names (auth_* tables already defined)': 'invalid table names (auth_* tables already defined)', 'invalid ticket': 'ticket non valide', +'Key': 'Key', +'Keyboard shortcuts': 'Keyboard shortcuts', +'kill process': 'kill process', 'language file "%(filename)s" created/updated': 'fichier de langue "%(filename)s" créé/mis à jour', +'Language files (static strings) updated': 'Fichiers de langue (chaînes statiques) mis à jour ', 'languages': 'langues', +'Languages': 'Langues', +'Last Revision': 'Last Revision', +'Last saved on:': 'Dernière sauvegarde le:', +'License for': 'Licence pour', +'License:': 'License:', +'Line Nr': 'Line Nr', +'Line number': 'Line number', +'lists by exception': 'lists by exception', +'lists by ticket': 'lists by ticket', +'Loading...': 'Loading...', 'loading...': 'Chargement ...', +'Local Apps': 'Local Apps', +'locals': 'locals', +'Locals##debug': 'Locals##debug', +'Login': 'Connexion', 'login': 'connexion', +'Login successful': 'Login successful', +'Login to the Administrative Interface': "Se connecter à l'interface d'administration", +'Login/Register': 'Login/Register', +'Logout': 'déconnexion', +'lost password': 'lost password', +'Main Menu': 'Main Menu', +'Manage': 'Manage', +'Manage %(action)s': 'Manage %(action)s', +'Manage Access Control': 'Manage Access Control', +'Manage Admin Users/Students': 'Manage Admin Users/Students', +'Manage Cache': 'Manage Cache', +'Manage Students': 'Manage Students', +'Memberships': 'Memberships', +"Mercurial Version Control System Interface[[NEWLINE]]for application '%s'": "Mercurial Version Control System Interface[[NEWLINE]]for application '%s'", 'merge': 'fusionner', +'Models': 'Modèles', 'models': 'modèles', +'Modified On': 'Modified On', +'Modules': 'Modules', 'modules': 'modules', +'Multi User Mode': 'Multi User Mode', 'new application "%s" created': 'nouvelle application "%s" créée', +'new application "%s" imported': 'new application "%s" imported', +'New Application Wizard': 'New Application Wizard', +'New application wizard': 'Assistant nouvelle application', 'new plugin installed': 'nouveau plugin installé', +'New plugin installed: %s': 'New plugin installed: %s', +'New Record': 'Nouvelle Entrée', 'new record inserted': 'nouvelle entrée insérée', +'New simple application': 'Nouvelle application simple', +'next': 'next', +'next %s rows': 'next %s rows', 'next 100 rows': '100 lignes suivantes', +'NO': 'NON', +'no changes': 'no changes', +'No databases in this application': 'Aucune base de données dans cette application', +'No Interaction yet': 'No Interaction yet', 'no match': 'aucune correspondance', +'no package selected': 'no package selected', +'no permission to uninstall "%s"': 'no permission to uninstall "%s"', +'Node:': 'Node:', +'Not Authorized': 'Not Authorized', +'Not supported': 'Not supported', +'Note: If you receive an error with github status code of 128, ensure the system and account you are deploying from has a cooresponding ssh key configured in the openshift account.': 'Note: If you receive an error with github status code of 128, ensure the system and account you are deploying from has a cooresponding ssh key configured in the openshift account.', +'Number of entries: **%s**': 'Number of entries: **%s**', +"On production, you'll have to configure your webserver to use one process and multiple threads to use this debugger.": "On production, you'll have to configure your webserver to use one process and multiple threads to use this debugger.", +'Open new app in new window': 'Open new app in new window', +'OpenShift Deployment Interface': 'OpenShift Deployment Interface', +'OpenShift Output': 'OpenShift Output', +'or alternatively': 'or alternatively', +'Or Get from URL:': 'Or Get from URL:', 'or import from csv file': 'ou importer depuis un fichier CSV ', 'or provide app url:': "ou fournir l'URL de l'app:", 'or provide application url:': "ou fournir l'URL de l'application:", +'Original/Translation': 'Original / Traduction', +'Overview': 'Overview', +'Overwrite installed app': "Écraser l'application installée", +'Pack all': 'tout empaqueter', +'Pack compiled': 'paquet compilé', +'Pack custom': 'Pack custom', 'pack plugin': 'paquet plugin', +'PAM authenticated user, cannot change password here': 'Utilisateur authentifié par PAM, vous ne pouvez pas changer le mot de passe ici', 'password changed': 'mot de passe modifié', +'Past revisions': 'Past revisions', +'Path to appcfg.py': 'Path to appcfg.py', +'Path to local openshift repo root.': 'Path to local openshift repo root.', +'Peeking at file': 'Jeter un oeil au fichier', +'Permission': 'Permission', +'Permissions': 'Permissions', +'Please': 'Please', +'Please wait, giving pythonanywhere a moment...': 'Please wait, giving pythonanywhere a moment...', 'plugin "%(plugin)s" deleted': 'plugin "%(plugin)s" supprimé', +'Plugin "%s" in application': 'Plugin "%s" dans l\'application', +'plugin not specified': 'plugin not specified', +'Plugin page': 'Plugin page', 'plugins': 'plugins', +'Plugins': 'Plugins', +'Plural Form #%s': 'Plural Form #%s', +'Plural-Forms:': 'Plural-Forms:', +'Powered by': 'Propulsé par', +'Preferences saved correctly': 'Preferences saved correctly', +'Preferences saved on session only': 'Preferences saved on session only', +'previous %s rows': 'previous %s rows', 'previous 100 rows': '100 lignes précédentes', +'Private files': 'Private files', +'private files': 'private files', +'Project Progress': 'Project Progress', +'Pull': 'Pull', +'Pull failed, certain files could not be checked out. Check logs for details.': 'Pull failed, certain files could not be checked out. Check logs for details.', +'Pull is not possible because you have unmerged files. Fix them up in the work tree, and then try again.': 'Pull is not possible because you have unmerged files. Fix them up in the work tree, and then try again.', +'Push': 'Push', +'Push failed, there are unmerged entries in the cache. Resolve merge issues manually and try again.': 'Push failed, there are unmerged entries in the cache. Resolve merge issues manually and try again.', +'pygraphviz library not found': 'pygraphviz library not found', +'PythonAnywhere Apps': 'PythonAnywhere Apps', +'PythonAnywhere Password': 'PythonAnywhere Password', +'Query:': 'Requête: ', +'RAM': 'RAM', +'RAM Cache Keys': 'RAM Cache Keys', +'Ram Cleared': 'Ram Cleared', +'RAM contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.': 'RAM contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.', +'Rapid Search': 'Rapid Search', +'Record': 'Record', 'record': 'entrée', 'record does not exist': "l'entrée n'existe pas", 'record id': 'id entrée', +'Record id': 'Record id', +'refresh': 'refresh', +'register': 'register', +'Reload routes': 'Reload routes', +'Remove compiled': 'retirer compilé', +'Removed Breakpoint on %s at line %s': 'Removed Breakpoint on %s at line %s', +'Replace': 'Replace', +'Replace All': 'Replace All', +'Repository (%s)': 'Repository (%s)', +'request': 'request', +'requires distutils, but not installed': 'requires distutils, but not installed', +'requires python-git, but not installed': 'requires python-git, but not installed', +'Resolve Conflict file': 'Résoudre les conflits de fichiers', +'response': 'response', +'restart': 'restart', 'restore': 'restaurer', +'return': 'return', +'Revert': 'Revert', 'revert': 'revenir', +'reverted to revision %s': 'reverted to revision %s', +'Revision %s': 'Revision %s', +'Revision:': 'Revision:', +'Role': 'Role', +'Roles': 'Roles', +'Rows in Table': 'Rows in Table', +'Rows in table': 'Lignes de la table', +'Rows selected': 'Lignes sélectionnées', +'rules are not defined': 'rules are not defined', +'Run tests': 'Run tests', +'Run tests in this file': 'Run tests in this file', +"Run tests in this file (to run all files, you may also use the button labelled 'test')": "Lancer les tests dans ce fichier (pour lancer tous les fichiers, vous pouvez également utiliser le bouton nommé 'test')", +'Running on %s': 'Running on %s', +'Save': 'Enregistrer', 'save': 'sauver', +'Save file:': 'Save file:', +'Save file: %s': 'Save file: %s', +'Save model as...': 'Save model as...', +'Save via Ajax': 'Save via Ajax', +'Saved file hash:': 'Hash du Fichier enregistré:', +'Screenshot %s': 'Screenshot %s', +'Search': 'Search', +'Searching: **%s** %%{file}': 'Searching: **%s** %%{file}', +'Select Files to Package': 'Select Files to Package', 'selected': 'sélectionnés', +'session': 'session', 'session expired': 'la session a expiré ', +'Session saved correctly': 'Session saved correctly', +'Session saved on session only': 'Session saved on session only', +'Set Breakpoint on %s at line %s: %s': 'Set Breakpoint on %s at line %s: %s', 'shell': 'shell', +'Showing %s to %s of %s %s found': 'Showing %s to %s of %s %s found', +'Singular Form': 'Singular Form', +'Site': 'Site', +'Size of cache:': 'Size of cache:', +'skip to generate': 'skip to generate', 'some files could not be removed': 'certains fichiers ne peuvent pas être supprimés', +'Something went wrong please wait a few minutes before retrying': 'Something went wrong please wait a few minutes before retrying', +'Sorry, could not find mercurial installed': 'Sorry, could not find mercurial installed', +'source : db': 'source : db', +'source : filesystem': 'source : filesystem', +'Start a new app': 'Start a new app', +'Start searching': 'Start searching', +'Start wizard': "Démarrer l'assistant", 'state': 'état', 'static': 'statiques', +'Static': 'Static', +'Static files': 'Fichiers statiques', +'Statistics': 'Statistics', +'Step': 'Step', +'step': 'step', +'stop': 'stop', 'submit': 'envoyer', +'Submit': 'Submit', +'successful': 'successful', +'Sure you want to delete this object?': 'Vous êtes sûr de vouloir supprimer cet objet? ', +'switch to : db': 'switch to : db', +'switch to : filesystem': 'switch to : filesystem', +'Tab width (# characters)': 'Tab width (# characters)', 'table': 'table', +'Table': 'Table', +'Temporary': 'Temporary', 'test': 'tester', +'Testing application': "Test de l'application", +'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.': 'La "requête" est une condition comme "db.table1.field1==\'value\'". Quelque chose comme "db.table1.field1==db.table2.field2" aboutit à un JOIN SQL.', +'The app exists, was created by wizard, continue to overwrite!': 'The app exists, was created by wizard, continue to overwrite!', +'The app exists, was NOT created by wizard, continue to overwrite!': 'The app exists, was NOT created by wizard, continue to overwrite!', 'the application logic, each URL path is mapped in one exposed function in the controller': "la logique de l'application, chaque chemin d'URL est mappé dans une fonction exposée dans le contrôleur", +'The application logic, each URL path is mapped in one exposed function in the controller': "La logique de l'application, chaque chemin d'URL est mappé avec une fonction exposée dans le contrôleur", 'the data representation, define database tables and sets': 'La représentation des données, définir les tables et ensembles de la base de données', +'The data representation, define database tables and sets': 'La représentation des données, définir les tables et ensembles de la base de données', +'The presentations layer, views are also known as templates': 'Les couches de présentation, les vues sont également appelées modples', 'the presentations layer, views are also known as templates': 'la couche de présentation, les vues sont également appelées modèles', +'Theme': 'Theme', +'There are no controllers': "Il n'y a pas de contrôleurs", +'There are no models': "Il n'y a pas de modèles", +'There are no modules': "Il n'y a pas de modules", +'There are no plugins': "Il n'y a pas de plugins", +'There are no private files': 'There are no private files', +'There are no static files': "Il n'y a pas de fichiers statiques", +'There are no translators': 'There are no translators', +'There are no translators, only default language is supported': "Il n'y a pas de traducteurs, seule la langue par défaut est prise en charge", +'There are no views': "Il n'y a pas de vues", +'These files are not served, they are only available from within your app': 'These files are not served, they are only available from within your app', +'These files are served without processing, your images go here': 'Ces fichiers sont renvoyés sans traitement, vos images viennent ici', 'these files are served without processing, your images go here': 'ces fichiers sont servis sans transformation, vos images vont ici', +"This debugger may not work properly if you don't have a threaded webserver or you're using multiple daemon processes.": "This debugger may not work properly if you don't have a threaded webserver or you're using multiple daemon processes.", +'This is an experimental feature and it needs more testing. If you decide to downgrade you do it at your own risk': 'This is an experimental feature and it needs more testing. If you decide to downgrade you do it at your own risk', +'This is an experimental feature and it needs more testing. If you decide to upgrade you do it at your own risk': 'This is an experimental feature and it needs more testing. If you decide to upgrade you do it at your own risk', +'This is the %(filename)s template': 'Ceci est le modèle %(filename)s ', +"This page can commit your changes to an openshift app repo and push them to your cloud instance. This assumes that you've already created the application instance using the web2py skeleton and have that repo somewhere on a filesystem that this web2py instance can access. This functionality requires GitPython installed and on the python path of the runtime that web2py is operating in.": "This page can commit your changes to an openshift app repo and push them to your cloud instance. This assumes that you've already created the application instance using the web2py skeleton and have that repo somewhere on a filesystem that this web2py instance can access. This functionality requires GitPython installed and on the python path of the runtime that web2py is operating in.", +'This page can upload your application to the Google App Engine computing cloud. Mind that you must first create indexes locally and this is done by installing the Google appserver and running the app locally with it once, or there will be errors when selecting records. Attention: deployment may take long time, depending on the network speed. Attention: it will overwrite your app.yaml. DO NOT SUBMIT TWICE.': 'This page can upload your application to the Google App Engine computing cloud. Mind that you must first create indexes locally and this is done by installing the Google appserver and running the app locally with it once, or there will be errors when selecting records. Attention: deployment may take long time, depending on the network speed. Attention: it will overwrite your app.yaml. DO NOT SUBMIT TWICE.', +'this page to see if a breakpoint was hit and debug interaction is required.': 'this page to see if a breakpoint was hit and debug interaction is required.', +'This will pull changes from the remote repo for application "%s"?': 'This will pull changes from the remote repo for application "%s"?', +'This will push changes to the remote repo for application "%s".': 'This will push changes to the remote repo for application "%s".', +'Ticket': 'Ticket', +'Ticket ID': 'Ticket ID', +'Ticket Missing': 'Ticket Missing', +'Time in Cache (h:m:s)': 'Time in Cache (h:m:s)', +'TM': 'MD', 'to previous version.': 'à la version précédente.', +'To create a plugin, name a file/folder plugin_[name]': 'Pour créer un plugin, créer un fichier /dossier plugin_[nom]', +'To emulate a breakpoint programatically, write:': 'To emulate a breakpoint programatically, write:', +'to use the debugger!': 'to use the debugger!', +'toggle breakpoint': 'toggle breakpoint', +'Toggle comment': 'Toggle comment', +'Toggle Fullscreen': 'Toggle Fullscreen', +'Traceback': 'Traceback', 'translation strings for the application': "chaînes de traduction de l'application", +'Translation strings for the application': "Chaînes de traduction pour l'application", 'try': 'essayer', 'try something like': 'essayez quelque chose comme', +'Try the mobile interface': 'Try the mobile interface', +'try view': 'try view', +'Type PDB debugger command in here and hit Return (Enter) to execute it.': 'Type PDB debugger command in here and hit Return (Enter) to execute it.', +'Type some Python code in here and hit Return (Enter) to execute it.': 'Type some Python code in here and hit Return (Enter) to execute it.', +'Unable to check for upgrades': 'Impossible de vérifier les mises à jour', 'unable to create application "%s"': 'impossible de créer l\'application "%s"', 'unable to delete file "%(filename)s"': 'impossible de supprimer le fichier "%(filename)s"', 'unable to delete file plugin "%(plugin)s"': 'impossible de supprimer le plugin "%(plugin)s"', +'Unable to determine the line number!': 'Unable to determine the line number!', +'Unable to download': 'Impossible de télécharger', +'Unable to download app': "Impossible de télécharger l'app", +'Unable to download app because:': "Impossible de télécharger l'app car:", +'Unable to download because': 'Impossible de télécharger car', +'unable to download layout': 'unable to download layout', +'unable to download plugin: %s': 'unable to download plugin: %s', +'Unable to download the list of plugins': 'Unable to download the list of plugins', +'unable to install plugin "%s"': 'unable to install plugin "%s"', 'unable to parse csv file': "impossible d'analyser les fichiers CSV", 'unable to uninstall "%s"': 'impossible de désinstaller "%s"', 'unable to upgrade because "%s"': 'impossible de mettre à jour car "%s"', 'uncheck all': 'tout décocher', +'Uninstall': 'désinstaller', +'Unsupported webserver working mode: %s': 'Unsupported webserver working mode: %s', 'update': 'mettre à jour', 'update all languages': 'mettre à jour toutes les langues', +'Update:': 'Mise à jour:', +'Upgrade': 'Upgrade', 'upgrade now': 'mettre à jour maintenant', +'upgrade now to %s': 'upgrade now to %s', 'upgrade web2py now': 'mettre à jour web2py maintenant', 'upload': 'charger', +'Upload': 'Upload', +'Upload & install packed application': "Charger & installer l'application empaquetée", +'Upload a package:': 'Charger un paquet:', +'Upload and install packed application': 'Upload and install packed application', 'upload application:': "charger l'application:", +'Upload existing application': 'Charger une application existante', 'upload file:': 'charger le fichier:', 'upload plugin file:': 'charger fichier plugin:', +'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Utilisez (...)&(...) pour AND, (...)|(...) pour OR, et ~(...) pour NOT afin de construire des requêtes plus complexes. ', +'Use an url:': 'Utiliser une url:', 'user': 'utilisateur', +'User': 'User', +'Username': 'Username', +'Users': 'Users', +'Using the shell may lock the database to other users of this app.': 'Using the shell may lock the database to other users of this app.', 'variables': 'variables', +'Version': 'Version', 'versioning': 'versioning', +'Versioning': 'Versioning', 'view': 'vue', +'Views': 'Vues', 'views': 'vues', -'web2py Recent Tweets': 'Tweets récents sur web2py ', +'Warning!': 'Warning!', +'WARNING:': 'WARNING:', +'WARNING: The following views could not be compiled:': 'WARNING: The following views could not be compiled:', +'Web Framework': 'Framework Web', +'web2py Admin Password': 'web2py Admin Password', +'web2py apps to deploy': 'web2py apps to deploy', +'web2py Debugger': 'web2py Debugger', +'web2py downgrade': 'web2py downgrade', 'web2py is up to date': 'web2py est à jour', +'web2py online debugger': 'web2py online debugger', +'web2py Recent Tweets': 'Tweets récents sur web2py ', +'web2py upgrade': 'web2py upgrade', 'web2py upgraded; please restart it': 'web2py mis à jour; veuillez le redémarrer', +'Working...': 'Working...', +'WSGI reference name': 'WSGI reference name', +'YES': 'OUI', +'Yes': 'Yes', +'You can also set and remove breakpoint in the edit window, using the Toggle Breakpoint button': 'You can also set and remove breakpoint in the edit window, using the Toggle Breakpoint button', +'You can inspect variables using the console below': 'You can inspect variables using the console below', +'You have one more login attempt before you are locked out': 'You have one more login attempt before you are locked out', +'You need to set up and reach a': 'You need to set up and reach a', +'You only need these if you have already registered': 'You only need these if you have already registered', +'Your application will be blocked until you click an action button (next, step, continue, etc.)': 'Your application will be blocked until you click an action button (next, step, continue, etc.)', } diff --git a/applications/admin/languages/he.py b/applications/admin/languages/he.py old mode 100644 new mode 100755 diff --git a/applications/admin/languages/it.py b/applications/admin/languages/it.py old mode 100644 new mode 100755 diff --git a/applications/admin/languages/ja.py b/applications/admin/languages/ja.py old mode 100644 new mode 100755 diff --git a/applications/admin/languages/my-mm.py b/applications/admin/languages/my-mm.py old mode 100644 new mode 100755 diff --git a/applications/admin/languages/pl.py b/applications/admin/languages/pl.py old mode 100644 new mode 100755 diff --git a/applications/admin/languages/plural-en.py b/applications/admin/languages/plural-en.py old mode 100644 new mode 100755 diff --git a/applications/admin/languages/plural-ru.py b/applications/admin/languages/plural-ru.py old mode 100644 new mode 100755 diff --git a/applications/admin/languages/plural-uk.py b/applications/admin/languages/plural-uk.py old mode 100644 new mode 100755 diff --git a/applications/admin/languages/pt-br.py b/applications/admin/languages/pt-br.py old mode 100644 new mode 100755 diff --git a/applications/admin/languages/pt.py b/applications/admin/languages/pt.py old mode 100644 new mode 100755 diff --git a/applications/admin/languages/ro.py b/applications/admin/languages/ro.py old mode 100644 new mode 100755 diff --git a/applications/admin/languages/ru.py b/applications/admin/languages/ru.py old mode 100644 new mode 100755 diff --git a/applications/admin/languages/sr-cr.py b/applications/admin/languages/sr-cr.py old mode 100644 new mode 100755 diff --git a/applications/admin/languages/sr-lt.py b/applications/admin/languages/sr-lt.py old mode 100644 new mode 100755 diff --git a/applications/admin/languages/tr.py b/applications/admin/languages/tr.py old mode 100644 new mode 100755 diff --git a/applications/admin/languages/uk.py b/applications/admin/languages/uk.py old mode 100644 new mode 100755 diff --git a/applications/admin/languages/zh-tw.py b/applications/admin/languages/zh-tw.py old mode 100644 new mode 100755 diff --git a/applications/admin/languages/zh.py b/applications/admin/languages/zh.py old mode 100644 new mode 100755 diff --git a/applications/welcome/languages/ar.py b/applications/welcome/languages/ar.py old mode 100644 new mode 100755 index a9e06cf2..c3908eba --- a/applications/welcome/languages/ar.py +++ b/applications/welcome/languages/ar.py @@ -1,48 +1,82 @@ -# coding: utf8 +# -*- coding: utf-8 -*- { '!langcode!': 'ar', '!langname!': 'Arabic', +'"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN': '"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN', '%s %%(shop)': '%s %%(shop)', '%s %%(shop[0])': '%s %%(shop[0])', '%s %%{quark[0]}': '%s %%{quark[0]}', +'%s %%{row} deleted': '%s %%{row} deleted', +'%s %%{row} updated': '%s %%{row} updated', '%s %%{shop[0]}': '%s %%{shop[0]}', '%s %%{shop}': '%s %%{shop}', +'%s selected': '%s selected', '%Y-%m-%d': '%Y-%m-%d', '%Y-%m-%d %H:%M:%S': '%Y-%m-%d %H:%M:%S', +'?': '?', '@markmin\x01**Hello World**': '**مرحباً بالعالم**', 'About': 'نبذة', 'Access Control': 'متحكمات الوصول', +'admin': 'admin', 'Administrative Interface': 'واجهة التحكم', 'Ajax Recipes': 'وصفات أجاكس', +'appadmin is disabled because insecure channel': 'appadmin is disabled because insecure channel', 'Are you sure you want to delete this object?': 'هل أنت متأكد بحذف هذا الكائن ؟', +'Available Databases and Tables': 'Available Databases and Tables', 'Buy this book': 'أشتري هذا الكتاب', +"Buy web2py's book": "Buy web2py's book", +'cache': 'cache', +'Cache': 'Cache', +'Cache Cleared': 'Cache Cleared', +'Cache Keys': 'Cache Keys', 'Cannot be empty': 'لا يمكن بأن يكون خالي', 'Check to delete': 'أختر للحذف', +'Clear CACHE?': 'Clear CACHE?', +'Clear DISK': 'Clear DISK', +'Clear RAM': 'Clear RAM', 'Client IP': 'IP المستخدم', 'Community': 'المجتمع', 'Components and Plugins': 'العناصر والإضافات', +'Config.ini': 'Config.ini', 'Controller': 'متحكم', 'Copyright': 'الحقوق', 'Created By': 'أنشئ بواسطة', 'Created On': 'أنشئ في', +'Current request': 'Current request', +'Current response': 'Current response', +'Current session': 'Current session', 'customize me!': 'التخصيص', +'data uploaded': 'data uploaded', 'Database': 'قاعدة البيانات', +'Database %s select': 'Database %s select', +'Database Administration (appadmin)': 'Database Administration (appadmin)', +'db': 'db', 'DB Model': 'نموذج قاعدة البيانات', +'Delete:': 'Delete:', 'Demo': 'تجربة', 'Deployment Recipes': 'الوصفات المنشورة', 'Description': 'الوصف', +'design': 'design', +'Design': 'Design', +'DISK': 'DISK', +'Disk Cache Keys': 'Disk Cache Keys', +'Disk Cleared': 'Disk Cleared', 'Documentation': 'المستندات', -"Don't know what to do?": "لا تعلم ماذا ستفعل ؟", +"Don't know what to do?": 'لا تعلم ماذا ستفعل ؟', +'done!': 'done!', 'Download': 'تحميل', 'E-mail': 'البريد الإلكتروني', +'Edit current record': 'Edit current record', 'Email and SMS': 'البريد الإلكتروني والرسالة النصية', 'enter an integer between %(min)g and %(max)g': 'أدخل عدد صحيح بين %(min)g و %(man)g', 'enter date and time as %(format)s': 'أدخل التاريخ والوقت كالنمط %(format)', 'Errors': 'الأخطاء', +'export as csv file': 'export as csv file', 'FAQ': 'الأسئلة الشائعة', 'First name': 'الأسم الأول', 'Forms and Validators': 'الإستمارات والمدققات', 'Free Applications': 'تطبيقات مجانية', +'Graph Model': 'Graph Model', 'Group %(group_id)s created': 'المجموعة %(group_id)s قد أنشئت', 'Group ID': 'هوية المجموعة', 'Group uniquely assigned to user %(id)s': 'المجموعة مخصصة للمستخدم %(id)s', @@ -50,44 +84,73 @@ 'Hello World': 'مرحباً بالعالم', 'Hello World ## comment': ' مرحباً بالعالم', 'Hello World## comment': 'مرحباً بالعالم', +'Helping web2py': 'Helping web2py', 'Home': 'الرئيسية', 'How did you get here?': 'كيف أستطعت الوصول إلى هنا ؟', +'import': 'import', +'Import/Export': 'Import/Export', +'Internal State': 'Internal State', 'Introduction': 'مقدمة', 'Invalid email': 'بريد إلكتروني غير صالح', +'Invalid Query': 'Invalid Query', +'invalid request': 'invalid request', 'Is Active': 'نشط', +'Key': 'Key', 'Last name': 'أسم العائلة', 'Layout': 'النسق', 'Layout Plugins': 'نسّق الإضافات', 'Layouts': 'لأنساق', 'Live Chat': 'المحادثة الحيّة', +'Log In': 'Log In', 'Logged in': 'تم تسجيل الدخول', 'Logged out': 'تم تسجيل الخروج', 'Login': 'تسجيل الدخول', 'Logout': 'تسجيل الخروج', 'Lost Password': 'فقدت كلمة المرور', 'Lost password?': 'هل فقدت كلمة المرور ؟', +'Manage %(action)s': 'Manage %(action)s', +'Manage Access Control': 'Manage Access Control', +'Manage Cache': 'Manage Cache', +'Memberships': 'Memberships', 'Menu Model': 'قالب القوائم', 'Modified By': 'عًدلت بواسطة', 'Modified On': 'عُدلت في', 'My Sites': 'موقعي', 'Name': 'الأسم', +'New Record': 'New Record', +'new record inserted': 'new record inserted', +'next %s rows': 'next %s rows', +'No databases in this application': 'No databases in this application', 'Object or table name': 'أسم الكائن أو الجدول', +'Online book': 'Online book', 'Online examples': 'أمثلة على الأنترنت', +'or import from csv file': 'or import from csv file', 'Origin': 'أصل', 'Other Plugins': 'إضافات أخرى', 'Other Recipes': 'وصفات أخرى', 'Overview': 'نظرة عامة', 'Password': 'كلمة المرور', -"Password fields don't match": "حقول كلمة المرور لا تتطابق", +"Password fields don't match": 'حقول كلمة المرور لا تتطابق', +'Permission': 'Permission', +'Permissions': 'Permissions', 'please input your password again': 'الرجاء إعادة إدخال كلمة المرور', 'Plugins': 'الإضافات', 'Powered by': 'مدعوم بواسطة', 'Preface': 'المدخل', +'previous %s rows': 'previous %s rows', 'Profile': 'الملف الشخصي', +'pygraphviz library not found': 'pygraphviz library not found', 'Python': 'بايثون', +'Query:': 'Query:', 'Quick Examples': 'أمثلة سريعة', +'RAM': 'RAM', +'RAM Cache Keys': 'RAM Cache Keys', +'Ram Cleared': 'Ram Cleared', 'Recipes': 'وصفات', +'Record': 'Record', +'record does not exist': 'record does not exist', 'Record ID': 'هوية السجل ', +'Record id': 'Record id', 'Register': 'التسجيل', 'Registration identifier': 'مُعرف التسجيل', 'Registration key': 'رمز التسجيل', @@ -95,20 +158,38 @@ 'Remember me (for 30 days)': 'تذكرني ( إلى 30 يوم)', 'Reset Password key': 'إعادة ظبط مفتاح كلمة المرور', 'Role': 'دور', +'Roles': 'Roles', +'Rows in Table': 'Rows in Table', +'Rows selected': 'Rows selected', +'Save model as...': 'Save model as...', 'Semantic': 'دليل لفظي', 'Services': 'خدمات', +'Sign Up': 'Sign Up', +'Size of cache:': 'Size of cache:', +'state': 'state', +'Statistics': 'Statistics', 'Stylesheet': 'أسلوب النمط', +'submit': 'submit', 'Support': 'الدعم', +'Table': 'Table', +'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.': 'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.', 'The Core': 'النواة', -'The output of the file is a dictionary that was rendered by the view %s': 'نتاج هذا الملف هو قاموس قًدم بواسطة العارض %s', +'The output of the file is a dictionary that was rendered by the view %s': 'نتاج هذا الملف هو قاموس قًدم بواسطة العارض %s', 'The Views': 'المشاهدات', 'This App': 'هذا التطبيق', +'Time in Cache (h:m:s)': 'Time in Cache (h:m:s)', 'Timestamp': 'البصمة الزمنية', +'Traceback': 'Traceback', 'Twitter': 'تويتر', +'unable to parse csv file': 'unable to parse csv file', +'Update:': 'Update:', +'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.', +'User': 'User', 'User %(id)s Logged-in': 'المستخدم %(id)s قد سجل دخوله', 'User %(id)s Logged-out': 'المستخدم %(id)s قد سجل خروجه', 'User %(id)s Registered': 'المستخدم %(id)s مسجل', 'User ID': 'هوية المستخدم', +'Users': 'Users', 'value already in database or empty': 'القيمة موجودة مسبقاً أو فارغة', 'Verify Password': 'تأكيد كلمة المرور', 'Videos': 'الفيديوهات', @@ -116,6 +197,7 @@ 'Welcome': 'مرحباً', 'Welcome to web2py!': 'مرحباً بكم في ويب2 باي !', 'Which called the function %s located in the file %s': 'الدالة المسماة %s موجودة في ملف %s', +'Working...': 'Working...', 'You are successfully running web2py': 'أستطعت تثبيت web2py بنجاح !', 'You can modify this application and adapt it to your needs': 'تستطيع تعديل هذا التطبيق لما يناسب إحتياجك', 'You visited the url %s': ' ملقد زرت الرابط %s', diff --git a/applications/welcome/languages/ca.py b/applications/welcome/languages/ca.py old mode 100644 new mode 100755 index e0f3109e..2fb827f1 --- a/applications/welcome/languages/ca.py +++ b/applications/welcome/languages/ca.py @@ -11,6 +11,7 @@ '%Y-%m-%d': '%d/%m/%Y', '%Y-%m-%d %H:%M:%S': '%d/%m/%Y %H:%M:%S', '(something like "it-it")': '(similar a "això-això")', +'?': '?', '@markmin\x01An error occured, please [[reload %s]] the page': 'Hi ha hagut un error, si us plau [[recarregui %s]] la pàgina', '@markmin\x01Number of entries: **%s**': "Nombre d'entrades: **%s**", 'A new version of web2py is available': 'Hi ha una nova versió de wep2py disponible', @@ -22,6 +23,7 @@ 'Add': 'Afegir', 'Add Record': 'Afegeix registre', 'additional code for your application': '`codi addicional per a la seva aplicació', +'admin': 'admin', 'admin disabled because no admin password': 'admin inhabilitat per falta de contrasenya', 'admin disabled because not supported on google app engine': 'admin inhabilitat, no és suportat en GAE', 'admin disabled because unable to access password file': 'admin inhabilitat, impossible accedir al fitxer con la contrasenya', @@ -57,6 +59,7 @@ 'Available Databases and Tables': 'Bases de dades i taules disponibles', 'Back': 'Endarrera', 'Buy this book': 'Compra aquest lllibre', +"Buy web2py's book": "Buy web2py's book", 'Cache': 'Caché', 'cache': 'caché', 'Cache Cleared': 'Caché Netejada', @@ -88,6 +91,7 @@ 'compile': 'compilar', 'compiled application removed': 'aplicació compilada eliminada', 'Components and Plugins': 'Components i Plugins', +'Config.ini': 'Config.ini', 'contains': 'conté', 'Controller': 'Controlador', 'Controllers': 'Controladors', @@ -128,6 +132,7 @@ 'Description': 'Descripció', 'design': 'diseny', 'DESIGN': 'DISENY', +'Design': 'Design', 'Design for': 'Diseny per a', 'detecting': 'detectant', 'DISK': 'DISC', @@ -193,6 +198,7 @@ 'Forms and Validators': 'Formularis i validadors', 'Free Applications': 'Aplicacions Lliures', 'Functions with no doctests will result in [passed] tests.': 'Funcions sense doctests equivalen a pruebas [aceptades].', +'Graph Model': 'Graph Model', 'Group %(group_id)s created': 'Grupo %(group_id)s creat', 'Group ID': 'ID de Grup', 'Group uniquely assigned to user %(id)s': 'Grup assignat únicament al usuari %(id)s', @@ -200,6 +206,7 @@ 'Hello': 'Hola', 'Hello World': 'Hola Món', 'help': 'ajuda', +'Helping web2py': 'Helping web2py', 'Home': 'Inici', 'Hosted by': 'Hosted by', 'How did you get here?': 'Com has arribat aquí?', @@ -260,6 +267,7 @@ 'Manage %(action)s': 'Manage %(action)s', 'Manage Access Control': 'Manage Access Control', 'Manage Cache': 'Gestionar la Caché', +'Memberships': 'Memberships', 'Menu Model': 'Model "menu"', 'merge': 'combinar', 'Models': 'Models', @@ -288,6 +296,7 @@ 'not in': 'no a', 'Object or table name': 'Nom del objecte o taula', 'Old password': 'Contrasenya anterior', +'Online book': 'Online book', 'Online examples': 'Ejemples en línia', 'Or': 'O', 'or import from csv file': 'o importar desde fitxer CSV', diff --git a/applications/welcome/languages/cs.py b/applications/welcome/languages/cs.py old mode 100644 new mode 100755 index c2169745..11d980db --- a/applications/welcome/languages/cs.py +++ b/applications/welcome/languages/cs.py @@ -12,10 +12,10 @@ '%Y-%m-%d': '%d.%m.%Y', '%Y-%m-%d %H:%M:%S': '%d.%m.%Y %H:%M:%S', '(requires internet access)': '(vyžaduje připojení k internetu)', -'(requires internet access, experimental)': '(vyžaduje internetové připojení, experimentální)', -'(something like "it-it")': '(například "cs-cz")', +'(requires internet access, experimental)': '(requires internet access, experimental)', +'(something like "it-it")': '(například "cs-cs")', +'?': '?', '@markmin\x01(file **gluon/contrib/plural_rules/%s.py** is not found)': '(soubor **gluon/contrib/plural_rules/%s.py** nenalezen)', -'@markmin\x01An error occured, please [[reload %s]] the page': 'Došlo k chybě, prosím [[obnovte stránku %s]]', '@markmin\x01Searching: **%s** %%{file}': 'Hledání: **%s** %%{soubor}', 'About': 'O programu', 'About application': 'O aplikaci', @@ -30,11 +30,11 @@ 'administrative interface': 'rozhraní pro správu', 'Administrator Password:': 'Administrátorské heslo:', 'Ajax Recipes': 'Recepty s ajaxem', -'An error occured, please %s the page': 'Došlo k chybě, prosím %s stránku', +'An error occured, please %s the page': 'An error occured, please %s the page', 'and rename it:': 'a přejmenovat na:', 'appadmin': 'appadmin', 'appadmin is disabled because insecure channel': 'appadmin je zakázaná bez zabezpečeného spojení', -'Application': 'Aplikace', +'Application': 'Application', 'application "%s" uninstalled': 'application "%s" odinstalována', 'application compiled': 'aplikace zkompilována', 'Application name:': 'Název aplikace:', @@ -42,23 +42,24 @@ 'are not used yet': 'ještě nepoužita', 'Are you sure you want to delete this object?': 'Opravdu chcete odstranit tento objekt?', 'Are you sure you want to uninstall application "%s"?': 'Opravdu chcete odinstalovat aplikaci "%s"?', -'arguments': 'argumenty', -'at char %s': 'na pozici znaku %s', -'at line %s': 'na řádku %s', -'ATTENTION:': 'POZOR:', +'arguments': 'arguments', +'at char %s': 'at char %s', +'at line %s': 'at line %s', +'ATTENTION:': 'ATTENTION:', 'ATTENTION: TESTING IS NOT THREAD SAFE SO DO NOT PERFORM MULTIPLE TESTS CONCURRENTLY.': 'ATTENTION: TESTING IS NOT THREAD SAFE SO DO NOT PERFORM MULTIPLE TESTS CONCURRENTLY.', 'Available Databases and Tables': 'Dostupné databáze a tabulky', 'back': 'zpět', -'Back to wizard': 'Zpátky do průvodce', -'Basics': 'Základy', +'Back to wizard': 'Back to wizard', +'Basics': 'Basics', 'Begin': 'Začít', 'breakpoint': 'bod přerušení', 'Breakpoints': 'Body přerušení', 'breakpoints': 'body přerušení', -'Buy this book': 'Koupit Web2py knihu', -"Buy web2py's book": 'Koupit Web2py knihu', +'Buy this book': 'Koupit web2py knihu', +"Buy web2py's book": "Buy web2py's book", 'Cache': 'Cache', 'cache': 'cache', +'Cache Cleared': 'Cache Cleared', 'Cache Keys': 'Klíče cache', 'cache, errors and sessions cleaned': 'cache, chyby a relace byly pročištěny', 'can be a git repo': 'může to být git repo', @@ -79,8 +80,8 @@ 'Click row to expand traceback': 'Pro rozbalení stopy, klikněte na řádek', 'Click row to view a ticket': 'Pro zobrazení chyby (ticketu), klikněte na řádku...', 'Client IP': 'IP adresa klienta', -'code': 'kód', -'Code listing': 'Výpis kódu', +'code': 'code', +'Code listing': 'Code listing', 'collapse/expand all': 'vše sbalit/rozbalit', 'Community': 'Komunita', 'Compile': 'Zkompilovat', @@ -88,7 +89,7 @@ 'Components and Plugins': 'Komponenty a zásuvné moduly', 'Condition': 'Podmínka', 'Config.ini': 'Config.ini', -'continue': 'pokračovat', +'continue': 'continue', 'Controller': 'Kontrolér (Controller)', 'Controllers': 'Kontroléry', 'controllers': 'kontroléry', @@ -109,18 +110,19 @@ 'data uploaded': 'data nahrána', 'Database': 'Rozhraní databáze', 'Database %s select': 'databáze %s výběr', -'Database administration': 'Administrace databáze', +'Database administration': 'Database administration', 'database administration': 'správa databáze', +'Database Administration (appadmin)': 'Database Administration (appadmin)', 'Date and Time': 'Datum a čas', 'day': 'den', 'db': 'db', 'DB Model': 'Databázový model', 'Debug': 'Ladění', -'defines tables': 'definuje tabulky', +'defines tables': 'defines tables', 'Delete': 'Smazat', 'delete': 'smazat', 'delete all checked': 'smazat vše označené', -'delete plugin': 'zrušit plugin', +'delete plugin': 'delete plugin', 'Delete this file (you will be asked to confirm deletion)': 'Smazat tento soubor (budete požádán o potvrzení mazání)', 'Delete:': 'Smazat:', 'deleted after first hit': 'smazat po prvním dosažení', @@ -141,36 +143,35 @@ 'Disk Cleared': 'Disk smazán', 'docs': 'dokumentace', 'Documentation': 'Dokumentace', -"Don't know what to do?": 'Kde najdu další informace ?', +"Don't know what to do?": 'Nevíte kudy kam?', 'done!': 'hotovo!', 'Download': 'Stáhnout', 'download layouts': 'stáhnout moduly rozvržení stránky', 'download plugins': 'stáhnout zásuvné moduly', 'E-mail': 'E-mail', 'Edit': 'Upravit', -'edit all': 'editovat vše', +'edit all': 'edit all', 'Edit application': 'Správa aplikace', -'edit controller': 'editovat controller', +'edit controller': 'edit controller', 'Edit current record': 'Upravit aktuální záznam', 'Edit Profile': 'Upravit profil', 'edit views:': 'upravit pohled:', 'Editing file "%s"': 'Úprava souboru "%s"', 'Editing Language file': 'Úprava jazykového souboru', -'Editing Plural Forms File': 'Editování souboru množných čísel', +'Editing Plural Forms File': 'Editing Plural Forms File', 'Email and SMS': 'Email a SMS', 'Enable': 'Odblokovat', 'enter a number between %(min)g and %(max)g': 'zadejte číslo mezi %(min)g a %(max)g', -'Enter an integer between %(min)g and %(max)g': 'Enter an integer between %(min)g and %(max)g', 'enter an integer between %(min)g and %(max)g': 'zadejte celé číslo mezi %(min)g a %(max)g', 'Error': 'Chyba', 'Error logs for "%(app)s"': 'Seznam výskytu chyb pro aplikaci "%(app)s"', 'Error snapshot': 'Snapshot chyby', 'Error ticket': 'Ticket chyby', 'Errors': 'Chyby', -'Exception %(extype)s: %(exvalue)s': 'Výjimka %(extype)s: %(exvalue)s', -'Exception %s': 'Výjimka %s', +'Exception %(extype)s: %(exvalue)s': 'Exception %(extype)s: %(exvalue)s', +'Exception %s': 'Exception %s', 'Exception instance attributes': 'Prvky instance výjimky', -'Expand Abbreviation': 'Expandovat zkratku', +'Expand Abbreviation': 'Expand Abbreviation', 'export as csv file': 'exportovat do .csv souboru', 'exposes': 'vystavuje', 'exposes:': 'vystavuje funkce:', @@ -179,7 +180,7 @@ 'FAQ': 'Často kladené dotazy', 'File': 'Soubor', 'file': 'soubor', -'file "%(filename)s" created': 'soubor "%(filename)s" byl vytvořen', +'file "%(filename)s" created': 'file "%(filename)s" created', 'file saved on %(time)s': 'soubor uložen %(time)s', 'file saved on %s': 'soubor uložen %s', 'Filename': 'Název souboru', @@ -190,7 +191,7 @@ 'Forgot username?': 'Zapomněl jste svoje přihlašovací jméno?', 'forgot username?': 'zapomněl jste svoje přihlašovací jméno?', 'Forms and Validators': 'Formuláře a validátory', -'Frames': 'Framy', +'Frames': 'Frames', 'Free Applications': 'Aplikace zdarma', 'Functions with no doctests will result in [passed] tests.': 'Functions with no doctests will result in [passed] tests.', 'Generate': 'Vytvořit', @@ -199,28 +200,29 @@ 'Git Push': 'Git Push', 'Globals##debug': 'Globální proměnné', 'go!': 'OK!', -'Goto': 'Přejít na', -'graph model': 'grafický model', +'Goto': 'Goto', +'graph model': 'graph model', +'Graph Model': 'Graph Model', 'Group %(group_id)s created': 'Skupina %(group_id)s vytvořena', 'Group ID': 'ID skupiny', 'Groups': 'Skupiny', -'Hello World': 'Ahoj všichni', +'Hello World': 'Ahoj světe', 'Help': 'Nápověda', -'Helping web2py': 'Podpořte Web2py', +'Helping web2py': 'Helping web2py', 'Hide/Show Translated strings': 'Skrýt/Zobrazit přeložené texty', 'Hits': 'Kolikrát dosaženo', 'Home': 'Domovská stránka', 'honored only if the expression evaluates to true': 'brát v potaz jen když se tato podmínka vyhodnotí kladně', -'How did you get here?': 'Jak se Ti tato stránka vlastně zobrazila?', +'How did you get here?': 'Jak jste se sem vlastně dostal?', 'If start the upgrade, be patient, it may take a while to download': 'If start the upgrade, be patient, it may take a while to download', -'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\nA green title indicates that all tests (if defined) passed. In this case test results are not shown.': 'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\r\nA green title indicates that all tests (if defined) passed. In this case test results are not shown.', +'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\nA green title indicates that all tests (if defined) passed. In this case test results are not shown.': 'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\nA green title indicates that all tests (if defined) passed. In this case test results are not shown.', 'import': 'import', 'Import/Export': 'Import/Export', 'includes': 'zahrnuje', 'Index': 'Index', 'insert new': 'vložit nový záznam ', 'insert new %s': 'vložit nový záznam %s', -'inspect attributes': 'prohlédnout atributy', +'inspect attributes': 'inspect attributes', 'Install': 'Instalovat', 'Installed applications': 'Nainstalované aplikace', 'Interaction at %s line %s': 'Interakce v %s, na řádce %s', @@ -236,7 +238,7 @@ 'It is %s %%{day} today.': 'Dnes je to %s %%{den}.', 'Key': 'Klíč', 'Key bindings': 'Vazby klíčů', -'Key bindings for ZenCoding Plugin': 'Key bindings pro ZenCoding Plugin', +'Key bindings for ZenCoding Plugin': 'Key bindings for ZenCoding Plugin', 'languages': 'jazyky', 'Languages': 'Jazyky', 'Last name': 'Příjmení', @@ -247,11 +249,11 @@ 'License for': 'Licence pro', 'Line number': 'Číslo řádku', 'LineNo': 'Č.řádku', -'Live Chat': 'Online chat', +'Live Chat': 'Online pokec', 'loading...': 'nahrávám...', 'locals': 'locals', 'Locals##debug': 'Lokální proměnné', -'Log In': 'Přihlásit se', +'Log In': 'Log In', 'Logged in': 'Přihlášení proběhlo úspěšně', 'Logged out': 'Odhlášení proběhlo úspěšně', 'Login': 'Přihlásit se', @@ -262,8 +264,11 @@ 'Lost Password': 'Zapomněl jste heslo', 'Lost password?': 'Zapomněl jste heslo?', 'lost password?': 'zapomněl jste heslo?', -'Manage': 'Spravovat', -'Manage Cache': 'Spravovat cache', +'Manage': 'Manage', +'Manage %(action)s': 'Manage %(action)s', +'Manage Access Control': 'Manage Access Control', +'Manage Cache': 'Manage Cache', +'Memberships': 'Memberships', 'Menu Model': 'Model rozbalovací nabídky', 'Models': 'Modely', 'models': 'modely', @@ -274,25 +279,26 @@ 'My Sites': 'Správa aplikací', 'Name': 'Jméno', 'new application "%s" created': 'nová aplikace "%s" vytvořena', -'New application wizard': 'Nový průvodce aplikací', 'New Application Wizard': 'Nový průvodce aplikací', +'New application wizard': 'Nový průvodce aplikací', 'New password': 'Nové heslo', 'New Record': 'Nový záznam', 'new record inserted': 'nový záznam byl založen', -'New simple application': 'Vytvořit novou aplikaci', -'next': 'další', +'New simple application': 'Vytvořit primitivní aplikaci', +'next': 'next', +'next %s rows': 'next %s rows', 'next 100 rows': 'dalších 100 řádků', 'No databases in this application': 'V této aplikaci nejsou žádné databáze', 'No Interaction yet': 'Ještě žádná interakce nenastala', 'No ticket_storage.txt found under /private folder': 'Soubor ticket_storage.txt v adresáři /private nenalezen', 'Object or table name': 'Objekt či tabulka', 'Old password': 'Původní heslo', -'Online book': 'Online kniha', +'Online book': 'Online book', 'online designer': 'online návrhář', -'Online examples': 'Ukázka aplikace: web2py stránky', -'Open new app in new window': 'Otevřít novou aplikaci v novém okně', -'or alternatively': 'nebo případně', -'Or Get from URL:': 'Nebo získat z URL adresy:', +'Online examples': 'Příklady online', +'Open new app in new window': 'Open new app in new window', +'or alternatively': 'or alternatively', +'Or Get from URL:': 'Or Get from URL:', 'or import from csv file': 'nebo importovat z .csv souboru', 'Origin': 'Původ', 'Original/Translation': 'Originál/Překlad', @@ -302,24 +308,28 @@ 'Overwrite installed app': 'Přepsat instalovanou aplikaci', 'Pack all': 'Zabalit', 'Pack compiled': 'Zabalit zkompilované', -'pack plugin': 'pack (zabalit) plugin', +'pack plugin': 'pack plugin', 'password': 'heslo', 'Password': 'Heslo', "Password fields don't match": 'Hesla se neshodují', -'Peeking at file': 'Sledování souboru', +'Peeking at file': 'Peeking at file', +'Permission': 'Permission', +'Permissions': 'Permissions', 'Please': 'Prosím', -'Plugin "%s" in application': 'Plugin "%s" v aplikaci', +'Plugin "%s" in application': 'Plugin "%s" in application', 'plugins': 'zásuvné moduly', 'Plugins': 'Zásuvné moduly', -'Plural Form #%s': 'Množné číslo #%s', +'Plural Form #%s': 'Plural Form #%s', 'Plural-Forms:': 'Množná čísla:', -'Powered by': 'Používá technologii', +'Powered by': 'Poháněno', 'Preface': 'Předmluva', +'previous %s rows': 'previous %s rows', 'previous 100 rows': 'předchozích 100 řádků', 'Private files': 'Soukromé soubory', 'private files': 'soukromé soubory', 'profile': 'profil', 'Project Progress': 'Vývoj projektu', +'pygraphviz library not found': 'pygraphviz library not found', 'Python': 'Python', 'Query:': 'Dotaz:', 'Quick Examples': 'Krátké příklady', @@ -353,38 +363,40 @@ 'return': 'return', 'revert': 'vrátit se k původnímu', 'Role': 'Role', +'Roles': 'Roles', 'Rows in Table': 'Záznamy v tabulce', 'Rows selected': 'Záznamů zobrazeno', 'rules are not defined': 'pravidla nejsou definována', "Run tests in this file (to run all files, you may also use the button labelled 'test')": "Spustí testy v tomto souboru (ke spuštění všech testů, použijte tlačítko 'test')", 'Running on %s': 'Běží na %s', 'Save': 'Uložit', -'Save file:': 'Uložit soubor:', +'Save file:': 'Save file:', +'Save model as...': 'Save model as...', 'Save via Ajax': 'Uložit pomocí Ajaxu', 'Saved file hash:': 'hash uloženého souboru:', 'Semantic': 'Modul semantic', 'Services': 'Služby', 'session': 'session', -'session expired': 'vypršela session', +'session expired': 'session expired', 'Set Breakpoint on %s at line %s: %s': 'Bod přerušení nastaven v souboru %s na řádce %s: %s', 'shell': 'příkazová řádka', -'Sign Up': 'Registrovat se', -'Singular Form': 'Jednotné číslo', +'Sign Up': 'Sign Up', +'Singular Form': 'Singular Form', 'Site': 'Správa aplikací', 'Size of cache:': 'Velikost cache:', -'skip to generate': 'přeskočit pro vytvoření', +'skip to generate': 'skip to generate', 'Sorry, could not find mercurial installed': 'Bohužel mercurial není nainstalován.', 'Start a new app': 'Vytvořit novou aplikaci', 'Start searching': 'Začít hledání', 'Start wizard': 'Spustit průvodce', 'state': 'stav', -'Static': 'Statické soubory', +'Static': 'Static', 'static': 'statické soubory', 'Static files': 'Statické soubory', 'Statistics': 'Statistika', -'Step': 'Krok', -'step': 'krok', -'stop': 'zastavit', +'Step': 'Step', +'step': 'step', +'stop': 'stop', 'Stylesheet': 'CSS styly', 'submit': 'odeslat', 'Submit': 'Odeslat', @@ -395,30 +407,30 @@ 'Table name': 'Název tabulky', 'Temporary': 'Dočasný', 'test': 'test', -'Testing application': 'Zkušební aplikace', +'Testing application': 'Testing application', 'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.': '"Dotaz" je podmínka, například "db.tabulka1.pole1==\'hodnota\'". Podmínka "db.tabulka1.pole1==db.tabulka2.pole2" pak vytvoří SQL JOIN.', 'The application logic, each URL path is mapped in one exposed function in the controller': 'Logika aplikace: každá URL je mapována na funkci vystavovanou kontrolérem.', 'The Core': 'Jádro (The Core)', 'The data representation, define database tables and sets': 'Reprezentace dat: definovat tabulky databáze a záznamy', -'The output of the file is a dictionary that was rendered by the view %s': 'Funkce vrátila dictionary (slovník) hodnot, a ty se vypsaly pomocí šablony %s.', +'The output of the file is a dictionary that was rendered by the view %s': 'Výstup ze souboru je slovník, který se zobrazil v pohledu %s.', 'The presentations layer, views are also known as templates': 'Prezentační vrstva: pohledy či templaty (šablony)', 'The Views': 'Pohledy (The Views)', -'There are no controllers': 'Nejsou vytvořeny žádné controllery', -'There are no modules': 'Nejsou přidány žádné moduly', -'There are no plugins': 'Žádné pluginy nejsou instalovány.', +'There are no controllers': 'There are no controllers', +'There are no modules': 'There are no modules', +'There are no plugins': 'Žádné moduly nejsou instalovány.', 'There are no private files': 'Žádné soukromé soubory neexistují.', -'There are no static files': 'Nejsou přidány žádné statické soubory', +'There are no static files': 'There are no static files', 'There are no translators, only default language is supported': 'There are no translators, only default language is supported', -'There are no views': 'Nejsou vytvořeny žádné šablony (views)', +'There are no views': 'There are no views', 'These files are not served, they are only available from within your app': 'Tyto soubory jsou klientům nepřístupné. K dispozici jsou pouze v rámci aplikace.', 'These files are served without processing, your images go here': 'Tyto soubory jsou servírovány bez přídavné logiky, sem patří např. obrázky.', 'This App': 'Tato aplikace', 'This is a copy of the scaffolding application': 'Toto je kopie aplikace skelet.', 'This is an experimental feature and it needs more testing. If you decide to upgrade you do it at your own risk': 'This is an experimental feature and it needs more testing. If you decide to upgrade you do it at your own risk', -'This is the %(filename)s template': 'Toto je šablona %(filename)s', +'This is the %(filename)s template': 'This is the %(filename)s template', 'this page to see if a breakpoint was hit and debug interaction is required.': 'tuto stránku, abyste uviděli, zda se dosáhlo bodu přerušení.', -'Ticket': 'Tiket', -'Ticket ID': 'ID tiketu', +'Ticket': 'Ticket', +'Ticket ID': 'Ticket ID', 'Time in Cache (h:m:s)': 'Čas v Cache (h:m:s)', 'Timestamp': 'Časové razítko', 'to previous version.': 'k předchozí verzi.', @@ -428,15 +440,15 @@ 'toggle breakpoint': 'vyp./zap. bod přerušení', 'Toggle Fullscreen': 'Na celou obrazovku a zpět', 'too short': 'Příliš krátké', -'Traceback': 'Hierarchie volání', +'Traceback': 'Traceback', 'Translation strings for the application': 'Překlad textů pro aplikaci', -'try something like': 'zkuste něco jako', +'try something like': 'try something like', 'Try the mobile interface': 'Zkuste rozhraní pro mobilní zařízení', -'try view': 'vyzkoušet šablonu (view)', +'try view': 'try view', 'Twitter': 'Twitter', 'Type python statement in here and hit Return (Enter) to execute it.': 'Type python statement in here and hit Return (Enter) to execute it.', 'Type some Python code in here and hit Return (Enter) to execute it.': 'Type some Python code in here and hit Return (Enter) to execute it.', -'Unable to check for upgrades': 'Nelze zjistit informaci o aktualizacích', +'Unable to check for upgrades': 'Unable to check for upgrades', 'unable to parse csv file': 'csv soubor nedá sa zpracovat', 'uncheck all': 'vše odznačit', 'Uninstall': 'Odinstalovat', @@ -444,15 +456,16 @@ 'update all languages': 'aktualizovat všechny jazyky', 'Update:': 'Upravit:', 'Upgrade': 'Upgrade', -'upgrade now': 'upgradovat nyní', -'upgrade now to %s': 'upgradovat nyní na %s', +'upgrade now': 'upgrade now', +'upgrade now to %s': 'upgrade now to %s', 'upload': 'nahrát', -'Upload': 'Upload (nahrát)', +'Upload': 'Upload', 'Upload a package:': 'Nahrát balík:', 'Upload and install packed application': 'Nahrát a instalovat zabalenou aplikaci', 'upload file:': 'nahrát soubor:', 'upload plugin file:': 'nahrát soubor modulu:', 'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Použijte (...)&(...) pro AND, (...)|(...) pro OR a ~(...) pro NOT pro sestavení složitějších dotazů.', +'User': 'User', 'User %(id)s Logged-in': 'Uživatel %(id)s přihlášen', 'User %(id)s Logged-out': 'Uživatel %(id)s odhlášen', 'User %(id)s Password changed': 'Uživatel %(id)s změnil heslo', @@ -461,7 +474,8 @@ 'User %(id)s Username retrieved': 'Uživatel %(id)s si nachal zaslat přihlašovací jméno', 'User ID': 'ID uživatele', 'Username': 'Přihlašovací jméno', -'variables': 'proměnné', +'Users': 'Users', +'variables': 'variables', 'Verify Password': 'Zopakujte heslo', 'Version': 'Verze', 'Version %s.%s.%s (%s) %s': 'Verze %s.%s.%s (%s) %s', @@ -470,22 +484,22 @@ 'View': 'Pohled (View)', 'Views': 'Pohledy', 'views': 'pohledy', -'Web Framework': 'Webový framework', +'Web Framework': 'Web Framework', 'web2py is up to date': 'Máte aktuální verzi web2py.', 'web2py online debugger': 'Ladící online web2py program', 'web2py Recent Tweets': 'Štěbetání na Twitteru o web2py', -'web2py upgrade': 'aktualizace Web2py', -'web2py upgraded; please restart it': 'Web2py bylo aktualizováno; prosím restarujte jej', +'web2py upgrade': 'web2py upgrade', +'web2py upgraded; please restart it': 'web2py upgraded; please restart it', 'Welcome': 'Vítejte', -'Welcome to web2py': 'Vitejte ve Web2py aplikaci', -'Welcome to web2py!': 'Vítejte ve Web2py aplikaci.', -'Which called the function %s located in the file %s': 'Tím byla zavolána funkce %s ze souboru (kontroléru) %s.', -'Working...': 'Pracuji...', -'You are successfully running web2py': 'Spustil(a) jsi webový server a Web2py.', +'Welcome to web2py': 'Vitejte ve web2py', +'Welcome to web2py!': 'Vítejte ve web2py!', +'Which called the function %s located in the file %s': 'která zavolala funkci %s v souboru (kontroléru) %s.', +'Working...': 'Working...', +'You are successfully running web2py': 'Úspěšně jste spustili web2py.', 'You can also set and remove breakpoint in the edit window, using the Toggle Breakpoint button': 'Nastavovat a mazat body přerušení je též možno v rámci editování zdrojového souboru přes tlačítko Vyp./Zap. bod přerušení', 'You can inspect variables using the console bellow': 'Níže pomocí příkazové řádky si můžete prohlédnout proměnné', -'You can modify this application and adapt it to your needs': 'V ADMIN rozhraní můžeš Vytvořit novou aplikaci jako kopii ukázkové Welcome aplikace. A začít upravovat: modely, kontroléry, šablony pro URL adresy, které požaduješ.', +'You can modify this application and adapt it to your needs': 'Tuto aplikaci si můžete upravit a přizpůsobit ji svým potřebám.', 'You need to set up and reach a': 'Je třeba nejprve nastavit a dojít až na', -'You visited the url %s': 'Zadal jsi URL adresu %s.', +'You visited the url %s': 'Navštívili jste stránku %s,', 'Your application will be blocked until you click an action button (next, step, continue, etc.)': 'Aplikace bude blokována než se klikne na jedno z tlačítek (další, krok, pokračovat, atd.)', } diff --git a/applications/welcome/languages/de.py b/applications/welcome/languages/de.py old mode 100644 new mode 100755 index 91264a42..2e40b349 --- a/applications/welcome/languages/de.py +++ b/applications/welcome/languages/de.py @@ -1,32 +1,41 @@ -# coding: utf8 +# -*- coding: utf-8 -*- { '!langcode!': 'de', '!langname!': 'Deutsch (DE)', -'"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN': '""Update" ist ein optionaler Ausdruck wie "Feld1 = \'newvalue". JOIN Ergebnisse können nicht aktualisiert oder gelöscht werden', +'"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN': '"Update" ist ein optionaler Ausdruck wie "feld1=\'newvalue\'". JOIN Ergebnisse können nicht aktualisiert oder gelöscht werden', '%s %%(shop)': '%s %%(shop)', '%s %%(shop[0])': '%s %%(shop[0])', '%s %%{quark[0]}': '%s %%{quark[0]}', -'%s %%{row} deleted': '%s %%{row} deleted', -'%s %%{row} updated': '%s %%{row} updated', +'%s %%{row} deleted': '%s %%{row} gelöscht', +'%s %%{row} updated': '%s %%{row} aktualisiert', '%s %%{shop[0]}': '%s %%{shop[0]}', '%s %%{shop}': '%s %%{shop}', -'%s selected': '%s selected', +'%s selected': '%s ausgewählt', '%Y-%m-%d': '%Y-%m-%d', '%Y-%m-%d %H:%M:%S': '%Y-%m-%d %H:%M:%S', +'(**%.0d MB**)': '(**%.0d MB**)', +'**%(items)s** %%{item(items)}, **%(bytes)s** %%{byte(bytes)}': '**%(items)s** %%{item(items)}, **%(bytes)s** %%{byte(bytes)}', +'**%(items)s** items, **%(bytes)s** %%{byte(bytes)}': '**%(items)s** items, **%(bytes)s** %%{byte(bytes)}', +'**not available** (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)': '**nicht verfügbar** (benötigt die Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] Bibliothek)', '?': '?', '@markmin\x01**Hello World**': '**Hallo Welt**', '@markmin\x01An error occured, please [[reload %s]] the page': 'Ein Fehler ist aufgetreten, bitte [[laden %s]] Sie die Seite neu', +'``**not available**``:red (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)': '``**nicht verfügbar**``:rot (benötigt die Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] Bibliothek)', 'About': 'Über', 'Access Control': 'Zugangskontrolle', +'admin': 'admin', 'Administrative Interface': 'Administrationsoberfläche', 'Ajax Recipes': 'Ajax Rezepte', +'An error occured, please [[reload %s]] the page': 'Ein Fehler ist aufgetreten, bitte [[laden %s]] Sie die Seite neu', 'appadmin is disabled because insecure channel': 'Appadmin ist deaktiviert, wegen der Benutzung eines unsicheren Kanals', 'Are you sure you want to delete this object?': 'Sind Sie sich sicher, dass Sie dieses Objekt löschen wollen?', 'Available Databases and Tables': 'Verfügbare Datenbanken und Tabellen', 'Buy this book': 'Dieses Buch kaufen', +"Buy web2py's book": "web2py's Buch kaufen", 'cache': 'cache', 'Cache': 'Cache', 'Cache Cleared': 'Cache geleert', +'Cache contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.': 'Cache enthält items die bis zu **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} alt sind.', 'Cache Keys': 'Cache Schlüssel', 'Cannot be empty': 'Darf nicht leer sein', 'Check to delete': 'Auswählen um zu löschen', @@ -36,6 +45,7 @@ 'Client IP': 'Client IP', 'Community': 'Community', 'Components and Plugins': 'Komponenten und Plugins', +'Config.ini': 'Config.ini', 'Controller': 'Controller', 'Copyright': 'Copyright', 'Created By': 'Erstellt von', @@ -55,9 +65,11 @@ 'Deployment Recipes': 'Entwicklungsrezepte', 'Description': 'Beschreibung', 'design': 'Design', +'Design': 'Design', 'DISK': 'DISK', 'Disk Cache Keys': 'Disk Cache Keys', 'Disk Cleared': 'Disk gelöscht', +'DISK contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.': 'DISK enthält items die bis zu **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} alt sind.', 'Documentation': 'Dokumentation', "Don't know what to do?": 'Wissen Sie nicht weiter?', 'done!': 'Fertig!', @@ -82,6 +94,8 @@ 'Hello World': 'Hallo Welt', 'Hello World ## Kommentar': 'Hallo Welt ', 'Hello World## Kommentar': 'Hallo Welt', +'Helping web2py': 'Helping web2py', +'Hit Ratio: **%(ratio)s%%** (**%(hits)s** %%{hit(hits)} and **%(misses)s** %%{miss(misses)})': 'Trefferquote: **%(ratio)s%%** (**%(hits)s** %%{hit(hits)} und **%(misses)s** %%{miss(misses)})', 'Home': 'Startseite', 'How did you get here?': 'Wie sind Sie hier her gelangt?', 'import': 'Importieren', @@ -98,6 +112,7 @@ 'Layout Plugins': 'Layout Plugins', 'Layouts': 'Layouts', 'Live Chat': 'Live Chat', +'Log In': 'Log In', 'Logged in': 'Eingeloggt', 'Logged out': 'Ausgeloggt', 'Login': 'Einloggen', @@ -117,7 +132,9 @@ 'new record inserted': 'neuer Eintrag hinzugefügt', 'next %s rows': 'nächste %s Reihen', 'No databases in this application': 'Keine Datenbank in dieser Anwendung', +'Number of entries: **%s**': 'Nummer der Einträge: **%s**', 'Object or table name': 'Objekt- oder Tabellenname', +'Online book': 'Online Buch', 'Online examples': 'Online Beispiele', 'or import from csv file': 'oder von csv Datei importieren', 'Origin': 'Ursprung', @@ -126,8 +143,8 @@ 'Overview': 'Überblick', 'Password': 'Passwort', "Password fields don't match": 'Passwortfelder sind nicht gleich', -'Permission': 'Permission', -'Permissions': 'Permissions', +'Permission': 'Erlaubnis', +'Permissions': 'Erlaubnisse', 'please input your password again': 'Bitte geben Sie ihr Passwort erneut ein', 'Plugins': 'Plugins', 'Powered by': 'Unterstützt von', @@ -140,7 +157,8 @@ 'Quick Examples': 'Kurze Beispiele', 'RAM': 'RAM', 'RAM Cache Keys': 'RAM Cache Keys', -'Ram Cleared': 'Ram Cleared', +'Ram Cleared': 'Ram gelöscht', +'RAM contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.': 'RAM enthält items die bis zu **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} alt sind.', 'Recipes': 'Rezepte', 'Record': 'Eintrag', 'record does not exist': 'Eintrag existiert nicht', @@ -159,6 +177,7 @@ 'Save model as...': 'Speichere Vorlage als...', 'Semantic': 'Semantik', 'Services': 'Dienste', +'Sign Up': 'Registrieren', 'Size of cache:': 'Cachegröße:', 'state': 'Status', 'Statistics': 'Statistik', @@ -171,10 +190,10 @@ 'The output of the file is a dictionary that was rendered by the view %s': 'Die Ausgabe der Datei ist ein "dictionary", welches vom "view" %s gerendert wurde', 'The Views': 'Die Views', 'This App': 'Diese App', -'This email already has an account': 'This email already has an account', +'This email already has an account': 'Diese email besitzt bereits ein Konto', 'Time in Cache (h:m:s)': 'Zeit im Cache (h:m:s)', 'Timestamp': 'Zeitstempel', -'Traceback': 'Traceback', +'Traceback': 'Zurückverfolgen', 'Twitter': 'Twitter', 'unable to parse csv file': 'csv Datei konnte nicht geparst werden', 'Update:': 'Update:', @@ -196,4 +215,4 @@ 'You are successfully running web2py': 'web2py wird erfolgreich ausgeführt', 'You can modify this application and adapt it to your needs': 'Sie können diese Anwendung verändern und Ihren Bedürfnissen anpassen', 'You visited the url %s': 'Sie haben die URL %s besucht', -} +} \ No newline at end of file diff --git a/applications/welcome/languages/default.py b/applications/welcome/languages/default.py old mode 100644 new mode 100755 diff --git a/applications/welcome/languages/es.py b/applications/welcome/languages/es.py old mode 100644 new mode 100755 index 7579cc37..c2154767 --- a/applications/welcome/languages/es.py +++ b/applications/welcome/languages/es.py @@ -8,11 +8,17 @@ '%s %%{row} deleted': '%s %%{fila} %%{eliminada}', '%s %%{row} updated': '%s %%{fila} %%{actualizada}', '%s selected': '%s %%{seleccionado}', -'%Y-%m-%d': '%d/%m/%Y', -'%Y-%m-%d %H:%M:%S': '%d/%m/%Y %H:%M:%S', -'(something like "it-it")': '(algo como "eso-eso")', +'%Y-%m-%d': '%d/%m/%A', +'%Y-%m-%d %H:%M:%S': '%d/%m/%A %H:%M:%S', +'(**%.0d MB**)': '(**%.0d MB**)', +'(something like "it-it")': '(algo como "it-it")', +'**%(items)s** %%{item(items)}, **%(bytes)s** %%{byte(bytes)}': '**%(items)s** %%{item(items)}, **%(bytes)s** %%{byte(bytes)}', +'**%(items)s** items, **%(bytes)s** %%{byte(bytes)}': '**%(items)s** items, **%(bytes)s** %%{byte(bytes)}', +'**not available** (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)': '**no disponible** (requiere la libreria [[guppy http://pypi.python.org/pypi/guppy/ popup]] de Python)', +'?': '?', '@markmin\x01An error occured, please [[reload %s]] the page': 'Ha ocurrido un error, por favor [[recargar %s]] la página', '@markmin\x01Number of entries: **%s**': 'Número de entradas: **%s**', +'``**not available**``:red (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)': '``**not available**``:red (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)', 'A new version of web2py is available': 'Hay una nueva versión de web2py disponible', 'A new version of web2py is available: %s': 'Hay una nueva versión de web2py disponible: %s', 'About': 'Acerca de', @@ -21,6 +27,7 @@ 'Access Control': 'Control de Acceso', 'Add': 'Añadir', 'additional code for your application': 'código adicional para su aplicación', +'admin': 'admin', 'admin disabled because no admin password': 'admin deshabilitado por falta de contraseña', 'admin disabled because not supported on google app engine': 'admin deshabilitado, no es soportado en GAE', 'admin disabled because unable to access password file': 'admin deshabilitado, imposible acceder al archivo con la contraseña', @@ -31,11 +38,12 @@ 'Administrator Password:': 'Contraseña del Administrador:', 'Ajax Recipes': 'Recetas AJAX', 'An error occured, please %s the page': 'Ha ocurrido un error, por favor %s la página', +'An error occured, please [[reload %s]] the page': 'Ha ocurrido un error, por favor [[reload %s]] la pagina', 'And': 'Y', 'and rename it (required):': 'y renómbrela (requerido):', 'and rename it:': ' y renómbrelo:', 'appadmin': 'appadmin', -'appadmin is disabled because insecure channel': 'admin deshabilitado, el canal no es seguro', +'appadmin is disabled because insecure channel': 'appadmin deshabilitado, el canal no es seguro', 'application "%s" uninstalled': 'aplicación "%s" desinstalada', 'application compiled': 'aplicación compilada', 'application is compiled and cannot be designed': 'la aplicación está compilada y no puede ser modificada', @@ -46,7 +54,7 @@ 'Are you sure you want to uninstall application "%s"': '¿Está seguro que desea desinstalar la aplicación "%s"', 'Are you sure you want to uninstall application "%s"?': '¿Está seguro que desea desinstalar la aplicación "%s"?', 'at': 'en', -'ATTENTION: Login requires a secure (HTTPS) connection or running on localhost.': 'ATENCION: Inicio de sesión requiere una conexión segura (HTTPS) o localhost.', +'ATTENTION: Login requires a secure (HTTPS) connection or running on localhost.': 'ATENCION: Inicio de sesión requiere una conexión segura (HTTPS) o corriendo en localhost.', 'ATTENTION: TESTING IS NOT THREAD SAFE SO DO NOT PERFORM MULTIPLE TESTS CONCURRENTLY.': 'ATENCION: NO EJECUTE VARIAS PRUEBAS SIMULTANEAMENTE, NO SON THREAD SAFE.', 'ATTENTION: you cannot edit the running application!': 'ATENCION: no puede modificar la aplicación que está ejecutandose!', 'Authentication': 'Autenticación', @@ -55,8 +63,11 @@ 'Available Databases and Tables': 'Bases de datos y tablas disponibles', 'Back': 'Atrás', 'Buy this book': 'Compra este libro', +"Buy web2py's book": "Compra el libro de web2py", 'Cache': 'Caché', 'cache': 'caché', +'Cache Cleared': 'Cache Limpiada', +'Cache contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.': 'La Cache contiene items con **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} de antiguedad.', 'Cache Keys': 'Llaves de la Caché', 'cache, errors and sessions cleaned': 'caché, errores y sesiones eliminados', 'Cannot be empty': 'No puede estar vacío', @@ -83,6 +94,7 @@ 'compile': 'compilar', 'compiled application removed': 'aplicación compilada eliminada', 'Components and Plugins': 'Componentes y Plugins', +'Config.ini': 'Config.ini', 'contains': 'contiene', 'Controller': 'Controlador', 'Controllers': 'Controladores', @@ -90,7 +102,7 @@ 'Copyright': 'Copyright', 'create file with filename:': 'cree archivo con nombre:', 'Create new application': 'Cree una nueva aplicación', -'create new application:': 'nombre de la nueva aplicación:', +'create new application:': 'cree una nueva aplicación:', 'Created By': 'Creado Por', 'Created On': 'Creado En', 'CSV (hidden cols)': 'CSV (columnas ocultas)', @@ -98,7 +110,7 @@ 'Current response': 'Respuesta en curso', 'Current session': 'Sesión en curso', 'currently saved or': 'actualmente guardado o', -'customize me!': '¡Adáptame!', +'customize me!': '¡Personalizame!', 'data uploaded': 'datos subidos', 'Database': 'Base de datos', 'Database %s select': 'selección en base de datos %s', @@ -119,11 +131,13 @@ 'Description': 'Descripción', 'design': 'diseño', 'DESIGN': 'DISEÑO', +'Design': 'Diseño', 'Design for': 'Diseño por', 'detecting': 'detectando', 'DISK': 'DISCO', 'Disk Cache Keys': 'Llaves de Caché en Disco', 'Disk Cleared': 'Disco limpiado', +'DISK contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.': 'El DISCO contiene items con **%(hours)02d** %%{hora(hours)} **%(min)02d** %%{minuto(min)} **%(sec)02d** %%{segundo(sec)} de antiguedad.', 'Documentation': 'Documentación', "Don't know what to do?": '¿No sabe que hacer?', 'done!': '¡hecho!', @@ -143,14 +157,14 @@ 'Email and SMS': 'Correo electrónico y SMS', 'Email sent': 'Correo electrónico enviado', 'End of impersonation': 'Fin de suplantación', -'enter a number between %(min)g and %(max)g': 'introduzca un número entre %(min)g y %(max)g', +'enter a number between %(min)g and %(max)g': 'introduzca un numero entre %(min)g y %(max)g', 'enter a value': 'introduzca un valor', -'enter an integer between %(min)g and %(max)g': 'introduzca un entero entre %(min)g y %(max)g', +'enter an integer between %(min)g and %(max)g': 'introduzca un número entero entre %(min)g y %(max)g', 'enter date and time as %(format)s': 'introduzca fecha y hora como %(format)s', -'Error logs for "%(app)s"': 'Bitácora de errores en "%(app)s"', +'Error logs for "%(app)s"': 'Bitácora de errores para "%(app)s"', 'errors': 'errores', 'Errors': 'Errores', -'Errors in form, please check it out.': 'Hay errores en el formulario, por favor comprúebelo.', +'Errors in form, please check it out.': 'Hay errores en el formulario, por favor compruébelo.', 'export as csv file': 'exportar como archivo CSV', 'Export:': 'Exportar:', 'exposes': 'expone', @@ -171,12 +185,15 @@ 'Forms and Validators': 'Formularios y validadores', 'Free Applications': 'Aplicaciones Libres', 'Functions with no doctests will result in [passed] tests.': 'Funciones sin doctests equivalen a pruebas [aceptadas].', +'Graph Model': 'Modelo en Grafo', 'Group %(group_id)s created': 'Grupo %(group_id)s creado', 'Group ID': 'ID de Grupo', 'Group uniquely assigned to user %(id)s': 'Grupo asignado únicamente al usuario %(id)s', 'Groups': 'Grupos', 'Hello World': 'Hola Mundo', 'help': 'ayuda', +'Helping web2py': 'Ayudando a web2py', +'Hit Ratio: **%(ratio)s%%** (**%(hits)s** %%{hit(hits)} and **%(misses)s** %%{miss(misses)})': 'Hit Ratio: **%(ratio)s%%** (**%(hits)s** %%{hit(hits)} and **%(misses)s** %%{miss(misses)})', 'Home': 'Inicio', 'How did you get here?': '¿Cómo llegaste aquí?', 'htmledit': 'htmledit', @@ -199,9 +216,9 @@ 'Invalid login': 'Inicio de sesión inválido', 'invalid password': 'contraseña inválida', 'Invalid Query': 'Consulta inválida', -'invalid request': 'solicitud inválida', +'invalid request': 'Solicitud inválida', 'Invalid reset password': 'Reinicio de contraseña inválido', -'invalid ticket': 'tiquete inválido', +'invalid ticket': 'Tiquete inválido', 'Is Active': 'Está Activo', 'Key': 'Llave', 'language file "%(filename)s" created/updated': 'archivo de lenguaje "%(filename)s" creado/actualizado', @@ -217,6 +234,7 @@ 'License for': 'Licencia para', 'Live Chat': 'Chat en vivo', 'loading...': 'cargando...', +'Log In': 'Log In', 'Logged in': 'Sesión iniciada', 'Logged out': 'Sesión finalizada', 'Login': 'Inicio de sesión', @@ -229,9 +247,12 @@ 'Lost password?': '¿Olvidó la contraseña?', 'lost password?': '¿olvidó la contraseña?', 'Main Menu': 'Menú principal', +'Manage %(action)s': 'Gestionar %(action)s', +'Manage Access Control': 'Gestionar control de acceso', 'Manage Cache': 'Gestionar la Caché', +'Memberships': 'Membresias', 'Menu Model': 'Modelo "menu"', -'merge': 'combinar', +'merge': 'Combinar', 'Models': 'Modelos', 'models': 'modelos', 'Modified By': 'Modificado Por', @@ -248,14 +269,17 @@ 'New password': 'Contraseña nueva', 'New Record': 'Registro nuevo', 'new record inserted': 'nuevo registro insertado', +'next %s rows': 'siguiente %s filas', 'next 100 rows': '100 filas siguientes', 'NO': 'NO', 'No databases in this application': 'No hay bases de datos en esta aplicación', 'No records found': 'No se han encontrado registros', 'Not authorized': 'No autorizado', 'not in': 'no en', +'Number of entries: **%s**': 'Numero de entradas: **%s**', 'Object or table name': 'Nombre del objeto o tabla', 'Old password': 'Contraseña vieja', +'Online book': 'Libro Online', 'Online examples': 'Ejemplos en línea', 'Or': 'O', 'or import from csv file': 'o importar desde archivo CSV', @@ -272,14 +296,18 @@ "Password fields don't match": 'Los campos de contraseña no coinciden', 'Password reset': 'Reinicio de contraseña', 'Peeking at file': 'Visualizando archivo', +'Permission': 'Permiso', +'Permissions': 'Permisos', 'Phone': 'Teléfono', 'please input your password again': 'por favor introduzca su contraseña otra vez', 'Plugins': 'Plugins', 'Powered by': 'Este sitio usa', 'Preface': 'Prefacio', +'previous %s rows': 'fila %s anterior', 'previous 100 rows': '100 filas anteriores', 'Profile': 'Perfil', 'Profile updated': 'Perfil actualizado', +'pygraphviz library not found': 'Libreria pygraphviz no encontrada', 'Python': 'Python', 'Query Not Supported: %s': 'Consulta No Soportada: %s', 'Query:': 'Consulta:', @@ -287,6 +315,7 @@ 'RAM': 'RAM', 'RAM Cache Keys': 'Llaves de la Caché en RAM', 'Ram Cleared': 'Ram Limpiada', +'RAM contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.': 'La RAM contiene items con **%(hours)02d** %%{hora(hours)} **%(min)02d** %%{minuto(min)} **%(sec)02d** %%{segundo(sec)} de antiguedad.', 'Recipes': 'Recetas', 'Record': 'Registro', 'Record %(id)s created': 'Registro %(id)s creado', @@ -310,22 +339,25 @@ 'Retrieve username': 'Recuperar nombre de usuario', 'revert': 'revertir', 'Role': 'Rol', +'Roles': 'Roles', 'Rows in Table': 'Filas en la tabla', 'Rows selected': 'Filas seleccionadas', 'save': 'guardar', +'Save model as...': 'Guardar modelo como...', 'Saved file hash:': 'Hash del archivo guardado:', 'Search': 'Buscar', 'Semantic': 'Semántica', 'Services': 'Servicios', 'session expired': 'sesión expirada', 'shell': 'terminal', +'Sign Up': 'Registrarse', 'site': 'sitio', 'Size of cache:': 'Tamaño de la Caché:', 'some files could not be removed': 'algunos archivos no pudieron ser removidos', 'start': 'inicio', 'starts with': 'comienza por', 'state': 'estado', -'static': 'estáticos', +'static': 'estático', 'Static files': 'Archivos estáticos', 'Statistics': 'Estadísticas', 'Stylesheet': 'Hoja de estilo', @@ -366,17 +398,18 @@ 'Toggle comment': 'Alternar comentario', 'Toggle Fullscreen': 'Alternar pantalla completa', 'too short': 'demasiado corto', +'Traceback': 'Rastrear', 'translation strings for the application': 'cadenas de caracteres de traducción para la aplicación', 'try': 'intente', 'try something like': 'intente algo como', -'TSV (Excel compatible)': 'TSV (compatible Excel)', -'TSV (Excel compatible, hidden cols)': 'TSV (compatible Excel, columnas ocultas)', +'TSV (Excel compatible)': 'TSV (compatible con Excel)', +'TSV (Excel compatible, hidden cols)': 'TSV (compatible con Excel, columnas ocultas)', 'Twitter': 'Twitter', 'Unable to check for upgrades': 'No es posible verificar la existencia de actualizaciones', 'unable to create application "%s"': 'no es posible crear la aplicación "%s"', 'unable to delete file "%(filename)s"': 'no es posible eliminar el archivo "%(filename)s"', 'Unable to download': 'No es posible la descarga', -'Unable to download app': 'No es posible descarga la aplicación', +'Unable to download app': 'No es posible descargar la aplicación', 'unable to parse csv file': 'no es posible analizar el archivo CSV', 'unable to uninstall "%s"': 'no es posible instalar "%s"', 'uncheck all': 'desmarcar todos', @@ -389,6 +422,7 @@ 'Upload existing application': 'Suba esta aplicación', 'upload file:': 'suba archivo:', 'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Use (...)&(...) para AND, (...)|(...) para OR, y ~(...) para NOT, para crear consultas más complejas.', +'User': 'Usuario', 'User %(id)s is impersonating %(other_id)s': 'El usuario %(id)s está suplantando %(other_id)s', 'User %(id)s Logged-in': 'El usuario %(id)s inició la sesión', 'User %(id)s Logged-out': 'El usuario %(id)s finalizó la sesión', @@ -405,12 +439,13 @@ 'User Logged-out': 'El usuario finalizó la sesión', 'Username': 'Nombre de usuario', 'Username retrieve': 'Recuperar nombre de usuario', +'Users': 'Usuarios', 'value already in database or empty': 'el valor ya existe en la base de datos o está vacío', 'value not allowed': 'valor no permitido', 'value not in database': 'el valor no está en la base de datos', 'Verify Password': 'Verificar Contraseña', 'Version': 'Versión', -'versioning': 'versiones', +'versioning': 'versionado', 'Videos': 'Vídeos', 'View': 'Vista', 'view': 'vista', @@ -431,3 +466,4 @@ 'You visited the url %s': 'Usted visitó la url %s', 'Your username is: %(username)s': 'Su nombre de usuario es: %(username)s', } + diff --git a/applications/welcome/languages/fr-ca.py b/applications/welcome/languages/fr-ca.py old mode 100644 new mode 100755 index 7693d5b4..310afadc --- a/applications/welcome/languages/fr-ca.py +++ b/applications/welcome/languages/fr-ca.py @@ -1,4 +1,4 @@ -# coding: utf8 +# -*- coding: utf-8 -*- { '!langcode!': 'fr-ca', '!langname!': 'Français (Canadien)', @@ -8,9 +8,11 @@ '%s selected': '%s sélectionné', '%Y-%m-%d': '%Y-%m-%d', '%Y-%m-%d %H:%M:%S': '%Y-%m-%d %H:%M:%S', +'?': '?', 'about': 'à propos', 'About': 'À propos', 'Access Control': "Contrôle d'accès", +'admin': 'admin', 'Administrative Interface': 'Administrative Interface', 'Administrative interface': "Interface d'administration", 'Ajax Recipes': 'Recettes Ajax', @@ -19,8 +21,10 @@ 'Authentication': 'Authentification', 'Available Databases and Tables': 'Bases de données et tables disponibles', 'Buy this book': 'Acheter ce livre', +"Buy web2py's book": "Buy web2py's book", 'cache': 'cache', 'Cache': 'Cache', +'Cache Cleared': 'Cache Cleared', 'Cache Keys': 'Cache Keys', 'Cannot be empty': 'Ne peut pas être vide', 'change password': 'changer le mot de passe', @@ -32,6 +36,7 @@ 'Client IP': 'IP client', 'Community': 'Communauté', 'Components and Plugins': 'Components and Plugins', +'Config.ini': 'Config.ini', 'Controller': 'Contrôleur', 'Copyright': "Droit d'auteur", 'Current request': 'Demande actuelle', @@ -41,6 +46,7 @@ 'data uploaded': 'données téléchargées', 'Database': 'base de données', 'Database %s select': 'base de données %s select', +'Database Administration (appadmin)': 'Database Administration (appadmin)', 'db': 'db', 'DB Model': 'Modèle DB', 'Delete:': 'Supprimer:', @@ -48,6 +54,7 @@ 'Deployment Recipes': 'Recettes de déploiement ', 'Description': 'Descriptif', 'design': 'design', +'Design': 'Design', 'DISK': 'DISK', 'Disk Cache Keys': 'Disk Cache Keys', 'Disk Cleared': 'Disk Cleared', @@ -69,11 +76,13 @@ 'Forms and Validators': 'Formulaires et Validateurs', 'Free Applications': 'Applications gratuites', 'Function disabled': 'Fonction désactivée', +'Graph Model': 'Graph Model', 'Group %(group_id)s created': '%(group_id)s groupe créé', 'Group ID': 'Groupe ID', 'Group uniquely assigned to user %(id)s': "Groupe unique attribué à l'utilisateur %(id)s", 'Groups': 'Groupes', 'Hello World': 'Bonjour le monde', +'Helping web2py': 'Helping web2py', 'Home': 'Accueil', 'How did you get here?': 'How did you get here?', 'import': 'import', @@ -93,6 +102,7 @@ 'Layouts': 'layouts', 'Live chat': 'Clavardage en direct', 'Live Chat': 'Live Chat', +'Log In': 'Log In', 'Logged in': 'Connecté', 'login': 'connectez-vous', 'Login': 'Connectez-vous', @@ -101,14 +111,19 @@ 'Lost Password': 'Mot de passe perdu', 'lost password?': 'mot de passe perdu?', 'Main Menu': 'Menu principal', +'Manage %(action)s': 'Manage %(action)s', +'Manage Access Control': 'Manage Access Control', 'Manage Cache': 'Manage Cache', +'Memberships': 'Memberships', 'Menu Model': 'Menu modèle', 'My Sites': 'My Sites', 'Name': 'Nom', 'New Record': 'Nouvel enregistrement', 'new record inserted': 'nouvel enregistrement inséré', +'next %s rows': 'next %s rows', 'next 100 rows': '100 prochaines lignes', 'No databases in this application': "Cette application n'a pas de bases de données", +'Online book': 'Online book', 'Online examples': 'Exemples en ligne', 'or import from csv file': "ou importer d'un fichier CSV", 'Origin': 'Origine', @@ -118,12 +133,16 @@ 'password': 'mot de passe', 'Password': 'Mot de passe', "Password fields don't match": 'Les mots de passe ne correspondent pas', +'Permission': 'Permission', +'Permissions': 'Permissions', 'please input your password again': "S'il vous plaît entrer votre mot de passe", 'Plugins': 'Plugiciels', 'Powered by': 'Alimenté par', 'Preface': 'Préface', +'previous %s rows': 'previous %s rows', 'previous 100 rows': '100 lignes précédentes', 'profile': 'profile', +'pygraphviz library not found': 'pygraphviz library not found', 'Python': 'Python', 'Query:': 'Requête:', 'Quick Examples': 'Examples Rapides', @@ -149,10 +168,13 @@ 'Reset Password key': 'Réinitialiser le mot clé', 'Resources': 'Ressources', 'Role': 'Rôle', +'Roles': 'Roles', 'Rows in Table': 'Lignes du tableau', 'Rows selected': 'Lignes sélectionnées', +'Save model as...': 'Save model as...', 'Semantic': 'Sémantique', 'Services': 'Services', +'Sign Up': 'Sign Up', 'Size of cache:': 'Size of cache:', 'state': 'état', 'Statistics': 'Statistics', @@ -171,14 +193,17 @@ 'This is a copy of the scaffolding application': "Ceci est une copie de l'application échafaudage", 'Time in Cache (h:m:s)': 'Time in Cache (h:m:s)', 'Timestamp': 'Horodatage', +'Traceback': 'Traceback', 'Twitter': 'Twitter', 'unable to parse csv file': "incapable d'analyser le fichier cvs", 'Update:': 'Mise à jour:', 'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Employez (...)&(...) pour AND, (...)|(...) pour OR, and ~(...) pour NOT pour construire des requêtes plus complexes.', +'User': 'User', 'User %(id)s Logged-in': 'Utilisateur %(id)s connecté', 'User %(id)s Registered': 'Utilisateur %(id)s enregistré', 'User ID': 'ID utilisateur', 'User Voice': 'User Voice', +'Users': 'Users', 'value already in database or empty': 'valeur déjà dans la base ou vide', 'Verify Password': 'Vérifiez le mot de passe', 'Videos': 'Vidéos', @@ -189,6 +214,7 @@ 'Welcome to web2py': 'Bienvenue à web2py', 'Welcome to web2py!': 'Welcome to web2py!', 'Which called the function %s located in the file %s': 'Qui a appelé la fonction %s se trouvant dans le fichier %s', +'Working...': 'Working...', 'You are successfully running web2py': 'Vous roulez avec succès web2py', 'You can modify this application and adapt it to your needs': "Vous pouvez modifier cette application et l'adapter à vos besoins", 'You visited the url %s': "Vous avez visité l'URL %s", diff --git a/applications/welcome/languages/fr.py b/applications/welcome/languages/fr.py old mode 100644 new mode 100755 index c3922ad3..08701bae --- a/applications/welcome/languages/fr.py +++ b/applications/welcome/languages/fr.py @@ -1,4 +1,4 @@ -# coding: utf8 +# -*- coding: utf-8 -*- { '!langcode!': 'fr', '!langname!': 'Français', @@ -8,18 +8,29 @@ '%s selected': '%s sélectionné', '%Y-%m-%d': '%Y-%m-%d', '%Y-%m-%d %H:%M:%S': '%Y-%m-%d %H:%M:%S', +'(**%.0d MB**)': '(**%.0d MB**)', +'**%(items)s** %%{item(items)}, **%(bytes)s** %%{byte(bytes)}': '**%(items)s** %%{item(items)}, **%(bytes)s** %%{byte(bytes)}', +'**%(items)s** items, **%(bytes)s** %%{byte(bytes)}': '**%(items)s** items, **%(bytes)s** %%{byte(bytes)}', +'**not available** (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)': '**not available** (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)', +'?': '?', +'``**not available**``:red (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)': '``**not available**``:red (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)', 'About': 'À propos', 'Access Control': "Contrôle d'accès", +'admin': 'admin', 'Administrative Interface': "Interface d'administration", 'Administrative interface': "Interface d'administration", 'Ajax Recipes': 'Recettes Ajax', +'An error occured, please [[reload %s]] the page': 'An error occured, please [[reload %s]] the page', 'appadmin is disabled because insecure channel': "appadmin est désactivée parce que le canal n'est pas sécurisé", 'Are you sure you want to delete this object?': 'Êtes-vous sûr de vouloir supprimer cet objet?', 'Authentication': 'Authentification', 'Available Databases and Tables': 'Bases de données et tables disponibles', 'Buy this book': 'Acheter ce livre', +"Buy web2py's book": "Buy web2py's book", 'cache': 'cache', 'Cache': 'Cache', +'Cache Cleared': 'Cache Cleared', +'Cache contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.': 'Cache contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.', 'Cache Keys': 'Clés de cache', 'Cannot be empty': 'Ne peut pas être vide', 'change password': 'changer le mot de passe', @@ -31,6 +42,7 @@ 'Client IP': 'IP client', 'Community': 'Communauté', 'Components and Plugins': 'Composants et Plugins', +'Config.ini': 'Config.ini', 'Controller': 'Contrôleur', 'Copyright': 'Copyright', 'Created By': 'Créé par', @@ -42,6 +54,7 @@ 'data uploaded': 'données téléchargées', 'Database': 'base de données', 'Database %s select': 'base de données %s selectionnée', +'Database Administration (appadmin)': 'Database Administration (appadmin)', 'db': 'bdd', 'DB Model': 'Modèle BDD', 'Delete:': 'Supprimer:', @@ -49,9 +62,11 @@ 'Deployment Recipes': 'Recettes de déploiement', 'Description': 'Description', 'design': 'design', +'Design': 'Design', 'DISK': 'DISQUE', 'Disk Cache Keys': 'Clés de cache du disque', 'Disk Cleared': 'Disque vidé', +'DISK contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.': 'DISK contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.', 'Documentation': 'Documentation', "Don't know what to do?": 'Vous ne savez pas quoi faire?', 'done!': 'fait!', @@ -70,12 +85,15 @@ 'Forms and Validators': 'Formulaires et Validateurs', 'Free Applications': 'Applications gratuites', 'Function disabled': 'Fonction désactivée', +'Graph Model': 'Graph Model', 'Group ID': 'Groupe ID', 'Groups': 'Groupes', 'Hello World': 'Bonjour le monde', +'Helping web2py': 'En train d’aider web2py', +'Hit Ratio: **%(ratio)s%%** (**%(hits)s** %%{hit(hits)} and **%(misses)s** %%{miss(misses)})': 'Hit Ratio: **%(ratio)s%%** (**%(hits)s** %%{hit(hits)} and **%(misses)s** %%{miss(misses)})', 'Home': 'Accueil', 'How did you get here?': 'Comment êtes-vous arrivé ici?', -'import': 'import', +'import': 'Importer', 'Import/Export': 'Importer/Exporter', 'Index': 'Index', 'insert new': 'insérer un nouveau', @@ -93,6 +111,7 @@ 'Layouts': 'Mises en page', 'Live chat': 'Chat en direct', 'Live Chat': 'Chat en direct', +'Log In': 'Log In', 'login': 'connectez-vous', 'Login': 'Connectez-vous', 'logout': 'déconnectez-vous', @@ -101,7 +120,10 @@ 'Lost password?': 'Mot de passe perdu?', 'lost password?': 'mot de passe perdu?', 'Main Menu': 'Menu principal', +'Manage %(action)s': 'Manage %(action)s', +'Manage Access Control': 'Manage Access Control', 'Manage Cache': 'Gérer le Cache', +'Memberships': 'Memberships', 'Menu Model': 'Menu modèle', 'Modified By': 'Modifié par', 'Modified On': 'Modifié le', @@ -109,9 +131,12 @@ 'Name': 'Nom', 'New Record': 'Nouvel enregistrement', 'new record inserted': 'nouvel enregistrement inséré', +'next %s rows': 'next %s rows', 'next 100 rows': '100 prochaines lignes', 'No databases in this application': "Cette application n'a pas de bases de données", +'Number of entries: **%s**': 'Number of entries: **%s**', 'Object or table name': 'Objet ou nom de table', +'Online book': 'Online book', 'Online examples': 'Exemples en ligne', 'or import from csv file': "ou importer d'un fichier CSV", 'Origin': 'Origine', @@ -120,16 +145,21 @@ 'Overview': 'Présentation', 'Password': 'Mot de passe', "Password fields don't match": 'Les mots de passe ne correspondent pas', +'Permission': 'Permission', +'Permissions': 'Permissions', 'Plugins': 'Plugins', 'Powered by': 'Alimenté par', 'Preface': 'Préface', +'previous %s rows': 'previous %s rows', 'previous 100 rows': '100 lignes précédentes', +'pygraphviz library not found': 'Bibliothèque pygraphviz introuvable', 'Python': 'Python', 'Query:': 'Requête:', 'Quick Examples': 'Exemples Rapides', 'RAM': 'RAM', 'RAM Cache Keys': 'Clés de cache de la RAM', 'Ram Cleared': 'Ram vidée', +'RAM contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.': 'RAM contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.', 'Readme': 'Lisez-moi', 'Recipes': 'Recettes', 'Record': 'enregistrement', @@ -145,10 +175,13 @@ 'Reset Password key': 'Réinitialiser le mot clé', 'Resources': 'Ressources', 'Role': 'Rôle', +'Roles': 'Roles', 'Rows in Table': 'Lignes du tableau', 'Rows selected': 'Lignes sélectionnées', +'Save model as...': 'Enregistrer le modèle sous...', 'Semantic': 'Sémantique', 'Services': 'Services', +'Sign Up': 'Sign Up', 'Size of cache:': 'Taille du cache:', 'state': 'état', 'Statistics': 'Statistiques', @@ -167,14 +200,17 @@ 'This is a copy of the scaffolding application': "Ceci est une copie de l'application échafaudage", 'Time in Cache (h:m:s)': 'Temps en Cache (h:m:s)', 'Timestamp': 'Horodatage', +'Traceback': 'Traceback', 'Twitter': 'Twitter', 'unable to parse csv file': "incapable d'analyser le fichier cvs", 'Update:': 'Mise à jour:', 'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Employez (...)&(...) pour AND, (...)|(...) pour OR, and ~(...) pour NOT afin de construire des requêtes plus complexes.', +'User': 'User', 'User %(id)s Logged-in': 'Utilisateur %(id)s connecté', 'User %(id)s Registered': 'Utilisateur %(id)s enregistré', 'User ID': 'ID utilisateur', 'User Voice': "Voix de l'utilisateur", +'Users': 'Users', 'Verify Password': 'Vérifiez le mot de passe', 'Videos': 'Vidéos', 'View': 'Présentation', @@ -184,6 +220,7 @@ 'Welcome to web2py': 'Bienvenue à web2py', 'Welcome to web2py!': 'Bienvenue à web2py!', 'Which called the function %s located in the file %s': 'Qui a appelé la fonction %s se trouvant dans le fichier %s', +'Working...': 'Working...', 'You are successfully running web2py': 'Vous exécutez avec succès web2py', 'You can modify this application and adapt it to your needs': "Vous pouvez modifier cette application et l'adapter à vos besoins", 'You visited the url %s': "Vous avez visité l'URL %s", diff --git a/applications/welcome/languages/hi.py b/applications/welcome/languages/hi.py old mode 100644 new mode 100755 index 46a47e86..19fe70fd --- a/applications/welcome/languages/hi.py +++ b/applications/welcome/languages/hi.py @@ -1,4 +1,4 @@ -# coding: utf8 +# -*- coding: utf-8 -*- { '!langcode!': 'hi-in', '!langname!': 'हिन्दी', @@ -8,8 +8,10 @@ '%s selected': '%s चुना हुआ', '%Y-%m-%d': '%Y-%m-%d', '%Y-%m-%d %H:%M:%S': '%Y-%m-%d %H:%M:%S', +'?': '?', 'About': 'About', 'Access Control': 'Access Control', +'admin': 'admin', 'Administrative Interface': 'Administrative Interface', 'Administrative interface': 'प्रशासनिक इंटरफेस के लिए यहाँ क्लिक करें', 'Ajax Recipes': 'Ajax Recipes', @@ -17,8 +19,10 @@ 'Are you sure you want to delete this object?': 'Are you sure you want to delete this object?', 'Available Databases and Tables': 'उपलब्ध डेटाबेस और तालिका', 'Buy this book': 'Buy this book', +"Buy web2py's book": "Buy web2py's book", 'cache': 'cache', 'Cache': 'Cache', +'Cache Cleared': 'Cache Cleared', 'Cache Keys': 'Cache Keys', 'Cannot be empty': 'खाली नहीं हो सकता', 'Change Password': 'पासवर्ड बदलें', @@ -29,6 +33,7 @@ 'Clear RAM': 'Clear RAM', 'Community': 'Community', 'Components and Plugins': 'Components and Plugins', +'Config.ini': 'Config.ini', 'Controller': 'Controller', 'Copyright': 'Copyright', 'Current request': 'वर्तमान अनुरोध', @@ -38,12 +43,14 @@ 'data uploaded': 'डाटा अपलोड सम्पन्न ', 'Database': 'डेटाबेस', 'Database %s select': 'डेटाबेस %s चुनी हुई', +'Database Administration (appadmin)': 'Database Administration (appadmin)', 'db': 'db', 'DB Model': 'DB Model', 'Delete:': 'मिटाना:', 'Demo': 'Demo', 'Deployment Recipes': 'Deployment Recipes', 'design': 'रचना करें', +'Design': 'Design', 'DISK': 'DISK', 'Disk Cache Keys': 'Disk Cache Keys', 'Disk Cleared': 'Disk Cleared', @@ -62,9 +69,11 @@ 'FAQ': 'FAQ', 'Forms and Validators': 'Forms and Validators', 'Free Applications': 'Free Applications', +'Graph Model': 'Graph Model', 'Groups': 'Groups', 'Hello from MyApp': 'Hello from MyApp', 'Hello World': 'Hello World', +'Helping web2py': 'Helping web2py', 'Home': 'Home', 'How did you get here?': 'How did you get here?', 'import': 'import', @@ -81,28 +90,38 @@ 'Layout Plugins': 'Layout Plugins', 'Layouts': 'Layouts', 'Live Chat': 'Live Chat', +'Log In': 'Log In', 'login': 'login', 'Login': 'लॉग इन', 'logout': 'logout', 'Logout': 'लॉग आउट', 'Lost Password': 'पासवर्ड खो गया', 'Main Menu': 'Main Menu', +'Manage %(action)s': 'Manage %(action)s', +'Manage Access Control': 'Manage Access Control', 'Manage Cache': 'Manage Cache', +'Memberships': 'Memberships', 'Menu Model': 'Menu Model', 'My Sites': 'My Sites', 'New Record': 'नया रेकॉर्ड', 'new record inserted': 'नया रेकॉर्ड डाला', +'next %s rows': 'next %s rows', 'next 100 rows': 'अगले 100 पंक्तियाँ', 'No databases in this application': 'इस अनुप्रयोग में कोई डेटाबेस नहीं हैं', +'Online book': 'Online book', 'Online examples': 'ऑनलाइन उदाहरण के लिए यहाँ क्लिक करें', 'or import from csv file': 'या csv फ़ाइल से आयात', 'Other Plugins': 'Other Plugins', 'Other Recipes': 'Other Recipes', 'Overview': 'Overview', +'Permission': 'Permission', +'Permissions': 'Permissions', 'Plugins': 'Plugins', 'Powered by': 'Powered by', 'Preface': 'Preface', +'previous %s rows': 'previous %s rows', 'previous 100 rows': 'पिछले 100 पंक्तियाँ', +'pygraphviz library not found': 'pygraphviz library not found', 'Python': 'Python', 'Query:': 'प्रश्न:', 'Quick Examples': 'Quick Examples', @@ -115,10 +134,14 @@ 'Record id': 'रिकॉर्ड पहचानकर्ता (आईडी)', 'Register': 'पंजीकृत (रजिस्टर) करना ', 'register': 'register', +'Role': 'Role', +'Roles': 'Roles', 'Rows in Table': 'तालिका में पंक्तियाँ ', 'Rows selected': 'चयनित (चुने गये) पंक्तियाँ ', +'Save model as...': 'Save model as...', 'Semantic': 'Semantic', 'Services': 'Services', +'Sign Up': 'Sign Up', 'Size of cache:': 'Size of cache:', 'state': 'स्थिति', 'Statistics': 'Statistics', @@ -133,16 +156,20 @@ 'The Views': 'The Views', 'This App': 'This App', 'Time in Cache (h:m:s)': 'Time in Cache (h:m:s)', +'Traceback': 'Traceback', 'Twitter': 'Twitter', 'unable to parse csv file': 'csv फ़ाइल पार्स करने में असमर्थ', 'Update:': 'अद्यतन करना:', 'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.', +'User': 'User', +'Users': 'Users', 'Videos': 'Videos', 'View': 'View', 'Welcome %s': 'Welcome %s', 'Welcome to web2py': 'वेब२पाइ (web2py) में आपका स्वागत है', 'Welcome to web2py!': 'Welcome to web2py!', 'Which called the function %s located in the file %s': 'Which called the function %s located in the file %s', +'Working...': 'Working...', 'You are successfully running web2py': 'You are successfully running web2py', 'You can modify this application and adapt it to your needs': 'You can modify this application and adapt it to your needs', 'You visited the url %s': 'You visited the url %s', diff --git a/applications/welcome/languages/hu.py b/applications/welcome/languages/hu.py old mode 100644 new mode 100755 index bc32c8dd..c020c409 --- a/applications/welcome/languages/hu.py +++ b/applications/welcome/languages/hu.py @@ -1,4 +1,4 @@ -# coding: utf8 +# -*- coding: utf-8 -*- { '!langcode!': 'hu', '!langname!': 'Magyar', @@ -8,8 +8,10 @@ '%s selected': '%s kiválasztott', '%Y-%m-%d': '%Y.%m.%d.', '%Y-%m-%d %H:%M:%S': '%Y.%m.%d. %H:%M:%S', +'?': '?', 'About': 'About', 'Access Control': 'Access Control', +'admin': 'admin', 'Administrative Interface': 'Administrative Interface', 'Administrative interface': 'az adminisztrációs felületért kattints ide', 'Ajax Recipes': 'Ajax Recipes', @@ -17,8 +19,10 @@ 'Are you sure you want to delete this object?': 'Are you sure you want to delete this object?', 'Available Databases and Tables': 'Elérhető adatbázisok és táblák', 'Buy this book': 'Buy this book', +"Buy web2py's book": "Buy web2py's book", 'cache': 'gyorsítótár', 'Cache': 'Cache', +'Cache Cleared': 'Cache Cleared', 'Cache Keys': 'Cache Keys', 'Cannot be empty': 'Nem lehet üres', 'change password': 'jelszó megváltoztatása', @@ -29,6 +33,7 @@ 'Client IP': 'Client IP', 'Community': 'Community', 'Components and Plugins': 'Components and Plugins', +'Config.ini': 'Config.ini', 'Controller': 'Controller', 'Copyright': 'Copyright', 'Current request': 'Jelenlegi lekérdezés', @@ -38,6 +43,7 @@ 'data uploaded': 'adat feltöltve', 'Database': 'adatbázis', 'Database %s select': 'adatbázis %s kiválasztás', +'Database Administration (appadmin)': 'Database Administration (appadmin)', 'db': 'db', 'DB Model': 'DB Model', 'Delete:': 'Töröl:', @@ -45,6 +51,7 @@ 'Deployment Recipes': 'Deployment Recipes', 'Description': 'Description', 'design': 'design', +'Design': 'Design', 'DISK': 'DISK', 'Disk Cache Keys': 'Disk Cache Keys', 'Disk Cleared': 'Disk Cleared', @@ -64,9 +71,11 @@ 'First name': 'First name', 'Forms and Validators': 'Forms and Validators', 'Free Applications': 'Free Applications', +'Graph Model': 'Graph Model', 'Group ID': 'Group ID', 'Groups': 'Groups', 'Hello World': 'Hello Világ', +'Helping web2py': 'Helping web2py', 'Home': 'Home', 'How did you get here?': 'How did you get here?', 'import': 'import', @@ -85,19 +94,25 @@ 'Layout Plugins': 'Layout Plugins', 'Layouts': 'Layouts', 'Live Chat': 'Live Chat', +'Log In': 'Log In', 'login': 'belép', 'logout': 'kilép', 'lost password': 'elveszett jelszó', 'Lost Password': 'Lost Password', 'Main Menu': 'Főmenü', +'Manage %(action)s': 'Manage %(action)s', +'Manage Access Control': 'Manage Access Control', 'Manage Cache': 'Manage Cache', +'Memberships': 'Memberships', 'Menu Model': 'Menü model', 'My Sites': 'My Sites', 'Name': 'Name', 'New Record': 'Új bejegyzés', 'new record inserted': 'új bejegyzés felvéve', +'next %s rows': 'next %s rows', 'next 100 rows': 'következő 100 sor', 'No databases in this application': 'Nincs adatbázis ebben az alkalmazásban', +'Online book': 'Online book', 'Online examples': 'online példákért kattints ide', 'or import from csv file': 'vagy betöltés csv fájlból', 'Origin': 'Origin', @@ -105,10 +120,14 @@ 'Other Recipes': 'Other Recipes', 'Overview': 'Overview', 'Password': 'Password', +'Permission': 'Permission', +'Permissions': 'Permissions', 'Plugins': 'Plugins', 'Powered by': 'Powered by', 'Preface': 'Preface', +'previous %s rows': 'previous %s rows', 'previous 100 rows': 'előző 100 sor', +'pygraphviz library not found': 'pygraphviz library not found', 'Python': 'Python', 'Query:': 'Lekérdezés:', 'Quick Examples': 'Quick Examples', @@ -125,10 +144,13 @@ 'Registration key': 'Registration key', 'Reset Password key': 'Reset Password key', 'Role': 'Role', +'Roles': 'Roles', 'Rows in Table': 'Sorok a táblában', 'Rows selected': 'Kiválasztott sorok', +'Save model as...': 'Save model as...', 'Semantic': 'Semantic', 'Services': 'Services', +'Sign Up': 'Sign Up', 'Size of cache:': 'Size of cache:', 'state': 'állapot', 'Statistics': 'Statistics', @@ -145,17 +167,21 @@ 'This App': 'This App', 'Time in Cache (h:m:s)': 'Time in Cache (h:m:s)', 'Timestamp': 'Timestamp', +'Traceback': 'Traceback', 'Twitter': 'Twitter', 'unable to parse csv file': 'nem lehet a csv fájlt beolvasni', 'Update:': 'Frissít:', 'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.', +'User': 'User', 'User ID': 'User ID', +'Users': 'Users', 'Videos': 'Videos', 'View': 'Nézet', 'Welcome %s': 'Welcome %s', 'Welcome to web2py': 'Isten hozott a web2py-ban', 'Welcome to web2py!': 'Welcome to web2py!', 'Which called the function %s located in the file %s': 'Which called the function %s located in the file %s', +'Working...': 'Working...', 'You are successfully running web2py': 'You are successfully running web2py', 'You can modify this application and adapt it to your needs': 'You can modify this application and adapt it to your needs', 'You visited the url %s': 'You visited the url %s', diff --git a/applications/welcome/languages/id.py b/applications/welcome/languages/id.py index 0bb837dc..e34864ed 100755 --- a/applications/welcome/languages/id.py +++ b/applications/welcome/languages/id.py @@ -1,7 +1,8 @@ -# coding: utf8 +# -*- coding: utf-8 -*- { '!langcode!': 'id', '!langname!': 'Indonesian', +'"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN': '"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN', '%d days ago': '%d hari yang lalu', '%d hours ago': '%d jam yang lalu', '%d minutes ago': '%d menit yang lalu', @@ -25,11 +26,14 @@ '1 week ago': '1 minggu yang lalu', '1 year ago': '1 tahun yang lalu', '< Previous': '< Sebelumnya', +'?': '?', 'About': 'Tentang', 'About application': 'Tentang Aplikasi', +'Access Control': 'Access Control', 'Add': 'Tambah', 'Additional code for your application': 'Tambahan kode untuk aplikasi Anda', 'Address': 'Alamat', +'admin': 'admin', 'Admin language': 'Bahasa Admin', 'administrative interface': 'antarmuka administrative', 'Administrator Password:': 'Administrator Kata Sandi:', @@ -48,6 +52,11 @@ 'Available Databases and Tables': 'Database dan Tabel yang tersedia', 'Back': 'Kembali', 'Buy this book': 'Beli buku ini', +"Buy web2py's book": "Buy web2py's book", +'Cache': 'Cache', +'cache': 'cache', +'Cache Cleared': 'Cache Cleared', +'Cache Keys': 'Cache Keys', 'cache, errors and sessions cleaned': 'cache, kesalahan dan sesi dibersihkan', 'can be a git repo': 'bisa menjadi repo git', 'Cancel': 'Batalkan', @@ -69,7 +78,9 @@ 'Compile': 'Kompilasi', 'compiled application removed': 'aplikasi yang dikompilasi dihapus', 'Components and Plugins': 'Komponen dan Plugin', +'Config.ini': 'Config.ini', 'contains': 'mengandung', +'Controller': 'Controller', 'Controllers': 'Kontrolir', 'controllers': 'kontrolir', 'Copyright': 'Hak Cipta', @@ -78,18 +89,30 @@ 'create file with filename:': 'buat file dengan nama:', 'created by': 'dibuat oleh', 'CSV (hidden cols)': 'CSV (kolom tersembunyi)', +'Current request': 'Current request', +'Current response': 'Current response', +'Current session': 'Current session', 'currently running': 'sedang berjalan', 'data uploaded': 'data diunggah', +'Database': 'Database', 'Database %s select': 'Memilih Database %s', 'database administration': 'administrasi database', +'Database Administration (appadmin)': 'Database Administration (appadmin)', +'db': 'db', +'DB Model': 'DB Model', 'defines tables': 'mendefinisikan tabel', 'Delete': 'Hapus', 'delete all checked': 'menghapus semua yang di centang', 'Delete this file (you will be asked to confirm deletion)': 'Hapus file ini (Anda akan diminta untuk mengkonfirmasi penghapusan)', 'Delete:': 'Hapus:', +'Demo': 'Demo', +'Deployment Recipes': 'Deployment Recipes', 'Description': 'Keterangan', 'design': 'disain', +'Design': 'Design', 'direction: ltr': 'petunjuk: ltr', +'DISK': 'DISK', +'Disk Cache Keys': 'Disk Cache Keys', 'Disk Cleared': 'Disk Dihapus', 'Documentation': 'Dokumentasi', "Don't know what to do?": 'Tidak tahu apa yang harus dilakukan?', @@ -101,6 +124,8 @@ 'Duration': 'Durasi', 'Edit': 'Mengedit', 'Edit application': 'Mengedit Aplikasi', +'Edit current record': 'Edit current record', +'Email and SMS': 'Email and SMS', 'Email sent': 'Email dikirim', 'enter a valid email address': 'masukkan alamat email yang benar', 'enter a valid URL': 'masukkan URL yang benar', @@ -112,17 +137,21 @@ 'Export:': 'Ekspor:', 'exposes': 'menghadapkan', 'extends': 'meluaskan', +'FAQ': 'FAQ', 'filter': 'menyaring', 'First Name': 'Nama Depan', 'Forgot username?': 'Lupa nama pengguna?', +'Forms and Validators': 'Forms and Validators', 'Free Applications': 'Aplikasi Gratis', 'Gender': 'Jenis Kelamin', +'Graph Model': 'Graph Model', 'Group %(group_id)s created': 'Grup %(group_id)s dibuat', 'Group uniquely assigned to user %(id)s': 'Grup unik yang diberikan kepada pengguna %(id)s', 'Groups': 'Grup', 'Guest': 'Tamu', 'Hello World': 'Halo Dunia', 'Help': 'Bantuan', +'Helping web2py': 'Helping web2py', 'Home': 'Halaman Utama', 'How did you get here?': 'Bagaimana kamu bisa di sini?', 'Image': 'Gambar', @@ -132,14 +161,21 @@ 'Install': 'Memasang', 'Installation': 'Instalasi', 'Installed applications': 'Aplikasi yang diinstal', +'Internal State': 'Internal State', 'Introduction': 'Pengenalan', 'Invalid email': 'Email tidak benar', +'Invalid Query': 'Invalid Query', +'invalid request': 'invalid request', +'Key': 'Key', 'Language': 'Bahasa', 'languages': 'bahasa', 'Languages': 'Bahasa', 'Last Name': 'Nama Belakang', +'Layout': 'Layout', 'License for': 'Lisensi untuk', +'Live Chat': 'Live Chat', 'loading...': 'sedang memuat...', +'Log In': 'Log In', 'Logged in': 'Masuk', 'Logged out': 'Keluar', 'Login': 'Masuk', @@ -149,17 +185,24 @@ 'Lost password?': 'Lupa kata sandi?', 'Maintenance': 'Pemeliharaan', 'Manage': 'Mengelola', +'Manage %(action)s': 'Manage %(action)s', +'Manage Access Control': 'Manage Access Control', 'Manage Cache': 'Mengelola Cache', -'models': 'model', +'Memberships': 'Memberships', +'Menu Model': 'Menu Model', 'Models': 'Model', +'models': 'model', 'Modules': 'Modul', 'modules': 'modul', 'My Sites': 'Situs Saya', 'New': 'Baru', 'new application "%s" created': 'aplikasi baru "%s" dibuat', 'New password': 'Kata sandi baru', +'New Record': 'New Record', +'new record inserted': 'new record inserted', 'New simple application': 'Aplikasi baru sederhana', 'News': 'Berita', +'next %s rows': 'next %s rows', 'next 100 rows': '100 baris berikutnya', 'Next >': 'Berikutnya >', 'Next Page': 'Halaman Berikutnya', @@ -168,6 +211,7 @@ 'not a Zip Code': 'bukan Kode Pos', 'Note': 'Catatan', 'Old password': 'Kata sandi lama', +'Online book': 'Online book', 'Online examples': 'Contoh Online', 'Or': 'Atau', 'or alternatively': 'atau alternatif', @@ -183,22 +227,33 @@ 'Password': 'Kata sandi', 'Password changed': 'Kata sandi berubah', "Password fields don't match": 'Kata sandi tidak sama', +'Permission': 'Permission', +'Permissions': 'Permissions', 'please input your password again': 'silahkan masukan kata sandi anda lagi', 'plugins': 'plugin', 'Plugins': 'Plugin', 'Plural-Forms:': 'Bentuk-Jamak:', 'Powered by': 'Didukung oleh', 'Preface': 'Pendahuluan', +'previous %s rows': 'previous %s rows', 'previous 100 rows': '100 baris sebelumnya', 'Previous Page': 'Halaman Sebelumnya', -'private files': 'file pribadi', 'Private files': 'File pribadi', +'private files': 'file pribadi', 'Profile': 'Profil', 'Profile updated': 'Profil diperbarui', 'Project Progress': 'Perkembangan Proyek', +'pygraphviz library not found': 'pygraphviz library not found', +'Python': 'Python', +'Query:': 'Query:', 'Quick Examples': 'Contoh Cepat', +'RAM': 'RAM', +'RAM Cache Keys': 'RAM Cache Keys', 'Ram Cleared': 'Ram Dihapus', 'Recipes': 'Resep', +'Record': 'Record', +'record does not exist': 'record does not exist', +'Record id': 'Record id', 'Register': 'Daftar', 'Registration successful': 'Pendaftaran berhasil', 'reload': 'memuat kembali', @@ -206,6 +261,8 @@ 'Remember me (for 30 days)': 'Ingat saya (selama 30 hari)', 'Remove compiled': 'Hapus Kompilasi', 'Request reset password': 'Meminta reset kata sandi', +'Role': 'Role', +'Roles': 'Roles', 'Rows in Table': 'Baris dalam Tabel', 'Rows selected': 'Baris dipilih', "Run tests in this file (to run all files, you may also use the button labelled 'test')": "Jalankan tes di file ini (untuk menjalankan semua file, Anda juga dapat menggunakan tombol berlabel 'test')", @@ -216,17 +273,26 @@ 'Select Files to Package': 'Pilih Berkas untuk Paket', 'Send Email': 'Kirim Email', 'Service': 'Layanan', +'Services': 'Services', +'Sign Up': 'Sign Up', 'Site': 'Situs', 'Size of cache:': 'Ukuran cache:', 'starts with': 'dimulai dengan', -'static': 'statis', +'state': 'state', 'Static': 'Statis', +'static': 'statis', 'Statistics': 'Statistik', +'Stylesheet': 'Stylesheet', +'submit': 'submit', 'Support': 'Mendukung', 'Table': 'Tabel', 'test': 'tes', +'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.': 'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.', 'The application logic, each URL path is mapped in one exposed function in the controller': 'Logika aplikasi, setiap jalur URL dipetakan dalam satu fungsi terpapar di kontrolir', +'The Core': 'The Core', 'The data representation, define database tables and sets': 'Representasi data, mendefinisikan tabel database dan set', +'The output of the file is a dictionary that was rendered by the view %s': 'The output of the file is a dictionary that was rendered by the view %s', +'The Views': 'The Views', 'There are no plugins': 'Tidak ada plugin', 'There are no private files': 'Tidak ada file pribadi', 'These files are not served, they are only available from within your app': 'File-file ini tidak dilayani, mereka hanya tersedia dari dalam aplikasi Anda', @@ -235,8 +301,10 @@ 'Time in Cache (h:m:s)': 'Waktu di Cache (h: m: s)', 'To create a plugin, name a file/folder plugin_[name]': 'Untuk membuat sebuah plugin, nama file / folder plugin_ [nama]', 'too short': 'terlalu pendek', +'Traceback': 'Traceback', 'Translation strings for the application': 'Terjemahan string untuk aplikasi', 'Try the mobile interface': 'Coba antarmuka ponsel', +'Twitter': 'Twitter', 'Unable to download because:': 'Tidak dapat mengunduh karena:', 'unable to parse csv file': 'tidak mampu mengurai file csv', 'update all languages': 'memperbarui semua bahasa', @@ -246,17 +314,21 @@ 'Upload and install packed application': 'Upload dan pasang aplikasi yang dikemas', 'upload file:': 'unggah file:', 'upload plugin file:': 'unggah file plugin:', +'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.', +'User': 'User', 'User %(id)s Logged-in': 'Pengguna %(id)s Masuk', 'User %(id)s Logged-out': 'Pengguna %(id)s Keluar', 'User %(id)s Password changed': 'Pengguna %(id)s Kata Sandi berubah', 'User %(id)s Password reset': 'Pengguna %(id)s Kata Sandi telah direset', 'User %(id)s Profile updated': 'Pengguna %(id)s Profil diperbarui', 'User %(id)s Registered': 'Pengguna %(id)s Terdaftar', +'Users': 'Users', 'value already in database or empty': 'data sudah ada dalam database atau kosong', 'value not allowed': 'data tidak benar', 'value not in database': 'data tidak ada dalam database', 'Verify Password': 'Verifikasi Kata Sandi', 'Version': 'Versi', +'Videos': 'Videos', 'View': 'Lihat', 'Views': 'Lihat', 'views': 'lihat', @@ -266,6 +338,8 @@ 'Website': 'Situs Web', 'Welcome': 'Selamat Datang', 'Welcome to web2py!': 'Selamat Datang di web2py!', +'Which called the function %s located in the file %s': 'Which called the function %s located in the file %s', +'Working...': 'Working...', 'You are successfully running web2py': 'Anda berhasil menjalankan web2py', 'You can modify this application and adapt it to your needs': 'Anda dapat memodifikasi aplikasi ini dan menyesuaikan dengan kebutuhan Anda', 'You visited the url %s': 'Anda mengunjungi url %s', diff --git a/applications/welcome/languages/it.py b/applications/welcome/languages/it.py old mode 100644 new mode 100755 index 77a706be..1f779c13 --- a/applications/welcome/languages/it.py +++ b/applications/welcome/languages/it.py @@ -1,4 +1,4 @@ -# coding: utf8 +# -*- coding: utf-8 -*- { '!=': '!=', '!langcode!': 'it', @@ -16,11 +16,13 @@ '=': '=', '>': '>', '>=': '>=', +'?': '?', '@markmin\x01An error occured, please [[reload %s]] the page': 'An error occured, please [[reload %s]] the page', '@markmin\x01Number of entries: **%s**': 'Numero di entità: **%s**', 'About': 'About', 'Access Control': 'Controllo Accessi', 'Add': 'Aggiungi', +'admin': 'admin', 'Administrative Interface': 'Interfaccia Amministrativa', 'Administrative interface': 'Interfaccia amministrativa', 'Ajax Recipes': 'Ajax Recipes', @@ -31,8 +33,10 @@ 'Available Databases and Tables': 'Database e tabelle disponibili', 'Back': 'Indietro', 'Buy this book': 'Compra questo libro', +"Buy web2py's book": "Buy web2py's book", 'cache': 'cache', 'Cache': 'Cache', +'Cache Cleared': 'Cache Cleared', 'Cache Keys': 'Cache Keys', 'Cannot be empty': 'Non può essere vuoto', 'Change password': 'Cambia Password', @@ -47,6 +51,7 @@ 'Cognome': 'Cognome', 'Community': 'Community', 'Components and Plugins': 'Componenti and Plugin', +'Config.ini': 'Config.ini', 'contains': 'contiene', 'Controller': 'Controller', 'Copyright': 'Copyright', @@ -61,6 +66,7 @@ 'data uploaded': 'dati caricati', 'Database': 'Database', 'Database %s select': 'Database %s select', +'Database Administration (appadmin)': 'Database Administration (appadmin)', 'db': 'db', 'DB Model': 'Modello di DB', 'Delete': 'Cancella', @@ -69,6 +75,7 @@ 'Deployment Recipes': 'Deployment Recipes', 'Description': 'Descrizione', 'design': 'progetta', +'Design': 'Design', 'DISK': 'DISK', 'Disk Cache Keys': 'Disk Cache Keys', 'Disk Cleared': 'Disk Cleared', @@ -103,6 +110,7 @@ 'hello world': 'salve mondo', 'Hello World': 'Salve Mondo', 'Hello World in a flash!': 'Salve Mondo in un flash!', +'Helping web2py': 'Helping web2py', 'Home': 'Home', 'How did you get here?': 'Come sei arrivato qui?', 'HTML': 'HTML', @@ -124,6 +132,7 @@ 'Layout Plugins': 'Layout Plugins', 'Layouts': 'Layouts', 'Live Chat': 'Live Chat', +'Log In': 'Log In', 'Logged in': 'Loggato', 'Logged out': 'Disconnesso', 'login': 'accesso', @@ -134,7 +143,10 @@ 'Lost password?': 'Password smarrita?', 'lost password?': 'dimenticato la password?', 'Main Menu': 'Menu principale', +'Manage %(action)s': 'Manage %(action)s', +'Manage Access Control': 'Manage Access Control', 'Manage Cache': 'Manage Cache', +'Memberships': 'Memberships', 'Menu Model': 'Menu Modelli', 'Modified By': 'Modificato da', 'Modified On': 'Modificato il', @@ -144,6 +156,7 @@ 'New password': 'Nuova password', 'New Record': 'Nuovo elemento (record)', 'new record inserted': 'nuovo record inserito', +'next %s rows': 'next %s rows', 'next 100 rows': 'prossime 100 righe', 'No databases in this application': 'Nessun database presente in questa applicazione', 'No records found': 'Nessun record trovato', @@ -152,6 +165,7 @@ 'not authorized': 'non autorizzato', 'Object or table name': 'Oggeto o nome tabella', 'Old password': 'Vecchia password', +'Online book': 'Online book', 'Online examples': 'Vedere gli esempi', 'Or': 'O', 'or import from csv file': 'oppure importa da file CSV', @@ -161,10 +175,13 @@ 'Overview': 'Overview', 'Password': 'Password', "Password fields don't match": 'I campi password non sono uguali', +'Permission': 'Permission', +'Permissions': 'Permissions', 'please input your password again': 'perfavore reimmeti la tua password', 'Plugins': 'Plugins', 'Powered by': 'Powered by', 'Preface': 'Preface', +'previous %s rows': 'previous %s rows', 'previous 100 rows': '100 righe precedenti', 'Profile': 'Profilo', 'pygraphviz library not found': 'pygraphviz library not found', @@ -189,6 +206,7 @@ 'Request reset password': 'Richiedi il reset della password', 'Reset Password key': 'Resetta chiave Password ', 'Role': 'Ruolo', +'Roles': 'Roles', 'Rows in Table': 'Righe nella tabella', 'Rows selected': 'Righe selezionate', 'Save model as...': 'Salva modello come...', @@ -196,6 +214,7 @@ 'Search': 'Ricerca', 'Semantic': 'Semantic', 'Services': 'Servizi', +'Sign Up': 'Sign Up', 'Size of cache:': 'Size of cache:', 'starts with': 'comincia con', 'state': 'stato', @@ -225,6 +244,7 @@ 'Update': 'Aggiorna', 'Update:': 'Aggiorna:', 'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Per costruire richieste (query) più complesse si usano (...)&(...) come "e" (AND), (...)|(...) come "o" (OR), e ~(...) come negazione (NOT).', +'User': 'User', 'User %(id)s Logged-in': 'User %(id)s Logged-in', 'User %(id)s Logged-out': 'User %(id)s Logged-out', 'User %(id)s Password changed': 'User %(id)s Password changed', @@ -232,6 +252,7 @@ 'User %(id)s Profile updated': 'User %(id)s Profile updated', 'User %(id)s Registered': 'User %(id)s Registered', 'User ID': 'ID Utente', +'Users': 'Users', 'value already in database or empty': 'valore già presente nel database o vuoto', 'Verify Password': 'Verifica Password', 'Videos': 'Videos', diff --git a/applications/welcome/languages/my-mm.py b/applications/welcome/languages/my-mm.py old mode 100644 new mode 100755 index 36a03029..97e39ffe --- a/applications/welcome/languages/my-mm.py +++ b/applications/welcome/languages/my-mm.py @@ -10,10 +10,12 @@ '%Y-%m-%d %H:%M:%S': '%Y-%m-%d %H:%M:%S', '(requires internet access, experimental)': '(requires internet access, experimental)', '(something like "it-it")': '(something like "it-it")', +'?': '?', '@markmin\x01An error occured, please [[reload %s]] the page': 'An error occured, please [[reload %s]] the page', 'About': 'အကြောင်း', 'Access Control': 'အသုံးပြု ခြင်းဆိုင်ရာ ထိန်းချုပ်ရန်', 'Additional code for your application': 'Additional code for your application', +'admin': 'admin', 'Admin language': 'Admin language', 'administrative interface': 'administrative interface', 'Administrative Interface': 'စီမံခန့်ခွဲရာ အင်တာဖေ့စ်', @@ -27,8 +29,10 @@ 'Are you sure you want to delete this object?': 'သင် ဒီအရာ ဖျက်ရန် သေချာပါသလား။', 'Available Databases and Tables': 'အသုံးပြုနိုင်သော ဒေတာဘေစ့်များနှင့် ဇယားများ', 'Buy this book': 'ဒီစာအုပ်ကို ဝယ်ပါ', +"Buy web2py's book": "Buy web2py's book", 'cache': 'cache', 'Cache': 'Cache', +'Cache Cleared': 'Cache Cleared', 'Cache Keys': 'Cache Keys', 'can be a git repo': 'can be a git repo', 'Cannot be empty': 'အလွတ် မဖြစ်ရပါ', @@ -44,6 +48,7 @@ 'Community': 'အသိုင်းအဝိုင်း', 'Compile': 'Compile', 'Components and Plugins': 'Components and Plugins', +'Config.ini': 'Config.ini', 'Controller': 'ကွန်ထရိုလာ', 'Controllers': 'ကွန်ထရိုလာများ', 'controllers': 'controllers', @@ -76,6 +81,7 @@ 'Deployment Recipes': 'Deployment Recipes', 'Description': 'ဖော်ပြချက်', 'design': 'design', +'Design': 'Design', 'direction: ltr': 'direction: ltr', 'Disable': 'ပိတ်ရန်', 'DISK': 'DISK', @@ -109,6 +115,7 @@ 'Groups': 'အဖွဲ့များ', 'Hello World': 'မင်္ဂလာပါ ကမ္ဘာကြီး။', 'Help': 'အကူအညီ', +'Helping web2py': 'Helping web2py', 'Home': 'မူလသို့', 'How did you get here?': 'သင် ဘယ်လို ရောက်လာခဲ့သလဲ။', 'import': 'သွင်းယူရန်', @@ -131,6 +138,7 @@ 'Layout Plugins': 'Layout Plugins', 'Layouts': 'အပြင်အဆင်များ', 'Live Chat': 'တိုက်ရိုက် ဆက်သွယ် ပြောကြားရန်', +'Log In': 'Log In', 'Login': 'ဝင်ရောက်အသုံးပြုရန်', 'Login to the Administrative Interface': 'Login to the Administrative Interface', 'Logout': 'ထွက်ရန်', @@ -158,6 +166,7 @@ 'No databases in this application': 'ဒီ application တွင် မည်သည့် ဒေတာဘေစ့်မှ မရှိပါ', 'no package selected': 'no package selected', 'Object or table name': 'Object or table name', +'Online book': 'Online book', 'Online examples': 'အွန်လိုင်း နမူနာများ', 'or alternatively': 'or alternatively', 'Or Get from URL:': 'Or Get from URL:', @@ -211,6 +220,7 @@ 'Semantic': 'Semantic', 'Services': 'Services', 'shell': 'shell', +'Sign Up': 'Sign Up', 'Site': 'Site', 'Size of cache:': 'Size of cache:', 'Start wizard': 'Start wizard', diff --git a/applications/welcome/languages/my.py b/applications/welcome/languages/my.py index d5b85f95..cf9589b6 100755 --- a/applications/welcome/languages/my.py +++ b/applications/welcome/languages/my.py @@ -1,7 +1,8 @@ -# coding: utf8 +# -*- coding: utf-8 -*- { '!langcode!': 'my', '!langname!': 'Malay', +'"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN': '"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN', '%d days ago': '%d hari yang lalu', '%d hours ago': '%d jam yang lalu', '%d minutes ago': '%d minit yang lalu', @@ -25,23 +26,34 @@ '1 week ago': '1 minggu yang lalu', '1 year ago': '1 tahun yang lalu', '< Previous': '< Sebelumnya', +'?': '?', 'About': 'Mengenai', +'Access Control': 'Access Control', 'Add': 'Tambah', +'admin': 'admin', 'Admin language': 'Bahasa admin', 'Administrator Password:': 'Kata laluan Administrator:', 'Ajax Recipes': 'Resipi Ajax', 'An error occured, please %s the page': 'Kesilapan telah berlaku, sila %s laman', 'And': 'Dan', 'and rename it:': 'dan menamakan itu:', +'appadmin is disabled because insecure channel': 'appadmin is disabled because insecure channel', 'are not used yet': 'tidak digunakan lagi', 'Are you sure you want to delete this object?': 'Apakah anda yakin anda mahu memadam ini?', +'Available Databases and Tables': 'Available Databases and Tables', 'Back': 'Kembali', 'Buy this book': 'Beli buku ini', +"Buy web2py's book": "Buy web2py's book", +'cache': 'cache', +'Cache': 'Cache', +'Cache Cleared': 'Cache Cleared', +'Cache Keys': 'Cache Keys', 'cache, errors and sessions cleaned': 'cache, kesilapan dan sesi dibersihkan', 'Cancel': 'Batal', 'Cannot be empty': 'Tidak boleh kosong', 'Change admin password': 'Tukar kata laluan admin', 'Change password': 'Tukar kata laluan', +'Check to delete': 'Check to delete', 'Clean': 'Bersihkan', 'Clear': 'Hapus', 'Clear CACHE?': 'Hapus CACHE?', @@ -51,25 +63,42 @@ 'Close': 'Tutup', 'Community': 'Komuniti', 'Components and Plugins': 'Komponen dan Plugin', +'Config.ini': 'Config.ini', 'contains': 'mengandung', +'Controller': 'Controller', 'Copyright': 'Hak Cipta', 'Create': 'Buat', 'create file with filename:': 'mencipta fail dengan nama:', 'created by': 'dicipta oleh', +'Current request': 'Current request', +'Current response': 'Current response', +'Current session': 'Current session', 'currently running': 'sedang berjalan', 'data uploaded': 'data diunggah', +'Database': 'Database', +'Database %s select': 'Database %s select', +'Database Administration (appadmin)': 'Database Administration (appadmin)', +'db': 'db', +'DB Model': 'DB Model', 'Delete': 'Hapus', 'Delete this file (you will be asked to confirm deletion)': 'Padam fail ini (anda akan diminta untuk mengesahkan pemadaman)', 'Delete:': 'Hapus:', +'Demo': 'Demo', +'Deployment Recipes': 'Deployment Recipes', 'design': 'disain', +'Design': 'Design', 'direction: ltr': 'arah: ltr', +'DISK': 'DISK', +'Disk Cache Keys': 'Disk Cache Keys', 'Disk Cleared': 'Disk Dihapuskan', 'Documentation': 'Dokumentasi', "Don't know what to do?": 'Tidak tahu apa yang perlu dilakukan?', 'done!': 'selesai!', 'Download': 'Unduh', 'Duration': 'Tempoh', +'Edit current record': 'Edit current record', 'Email : ': 'Emel : ', +'Email and SMS': 'Email and SMS', 'Email sent': 'Emel dihantar', 'enter a valid email address': 'masukkan alamat emel yang benar', 'enter a valid URL': 'masukkan URL yang benar', @@ -78,17 +107,21 @@ 'Errors': 'Kesalahan', 'export as csv file': 'eksport sebagai file csv', 'Export:': 'Eksport:', +'FAQ': 'FAQ', 'File': 'Fail', 'filter': 'menapis', 'First Name': 'Nama Depan', 'Forgot username?': 'Lupa nama pengguna?', +'Forms and Validators': 'Forms and Validators', 'Free Applications': 'Aplikasi Percuma', 'Gender': 'Jenis Kelamin', +'Graph Model': 'Graph Model', 'Group %(group_id)s created': 'Kumpulan %(group_id)s dicipta', 'Group uniquely assigned to user %(id)s': 'Kumpulan unik yang diberikan kepada pengguna %(id)s', 'Groups': 'Kumpulan', 'Hello World': 'Halo Dunia', 'Help': 'Bantuan', +'Helping web2py': 'Helping web2py', 'Home': 'Laman Utama', 'How did you get here?': 'Bagaimana kamu boleh di sini?', 'Image': 'Gambar', @@ -97,14 +130,21 @@ 'includes': 'termasuk', 'Install': 'Pasang', 'Installation': 'Pemasangan', +'Internal State': 'Internal State', 'Introduction': 'Pengenalan', 'Invalid email': 'Emel tidak benar', +'Invalid Query': 'Invalid Query', +'invalid request': 'invalid request', +'Key': 'Key', 'Language': 'Bahasa', 'languages': 'bahasa', 'Languages': 'Bahasa', 'Last Name': 'Nama Belakang', +'Layout': 'Layout', 'License for': 'lesen untuk', +'Live Chat': 'Live Chat', 'loading...': 'sedang memuat...', +'Log In': 'Log In', 'Logged in': 'Masuk', 'Logged out': 'Keluar', 'Login': 'Masuk', @@ -113,20 +153,29 @@ 'Lost password?': 'Lupa kata laluan?', 'Maintenance': 'Penyelenggaraan', 'Manage': 'Menguruskan', +'Manage %(action)s': 'Manage %(action)s', +'Manage Access Control': 'Manage Access Control', 'Manage Cache': 'Menguruskan Cache', -'models': 'model', +'Memberships': 'Memberships', +'Menu Model': 'Menu Model', 'Models': 'Model', +'models': 'model', 'Modules': 'Modul', 'modules': 'modul', 'My Sites': 'Laman Saya', 'New': 'Baru', 'New password': 'Kata laluan baru', +'New Record': 'New Record', +'new record inserted': 'new record inserted', +'next %s rows': 'next %s rows', 'next 100 rows': '100 baris seterusnya', 'Next >': 'Seterusnya >', 'Next Page': 'Laman Seterusnya', +'No databases in this application': 'No databases in this application', 'No ticket_storage.txt found under /private folder': 'Ticket_storage.txt tidak dijumpai di bawah folder /private', 'not a Zip Code': 'bukan Pos', 'Old password': 'Kata laluan lama', +'Online book': 'Online book', 'Online examples': 'Contoh Online', 'Or': 'Atau', 'or alternatively': 'atau sebagai alternatif', @@ -139,27 +188,41 @@ 'Password': 'Kata laluan', 'Password changed': 'Kata laluan berubah', "Password fields don't match": 'Kata laluan tidak sama', +'Permission': 'Permission', +'Permissions': 'Permissions', 'please input your password again': 'sila masukan kata laluan anda lagi', 'plugins': 'plugin', 'Plugins': 'Plugin', 'Powered by': 'Disokong oleh', 'Preface': 'Pendahuluan', +'previous %s rows': 'previous %s rows', 'previous 100 rows': '100 baris sebelumnya', 'Previous Page': 'Laman Sebelumnya', -'private files': 'fail peribadi', 'Private files': 'Fail peribadi', +'private files': 'fail peribadi', 'Profile': 'Profil', 'Profile updated': 'Profil dikemaskini', 'Project Progress': 'Kemajuan Projek', +'pygraphviz library not found': 'pygraphviz library not found', +'Python': 'Python', +'Query:': 'Query:', 'Quick Examples': 'Contoh Cepat', +'RAM': 'RAM', +'RAM Cache Keys': 'RAM Cache Keys', 'Ram Cleared': 'Ram Dihapuskan', 'Recipes': 'Resipi', +'Record': 'Record', +'record does not exist': 'record does not exist', +'Record id': 'Record id', 'Register': 'Daftar', 'Registration successful': 'Pendaftaran berjaya', 'reload': 'memuat kembali', 'Reload routes': 'Memuat laluan kembali', 'Remember me (for 30 days)': 'Ingat saya (selama 30 hari)', 'Request reset password': 'Meminta reset kata laluan', +'Role': 'Role', +'Roles': 'Roles', +'Rows in Table': 'Rows in Table', 'Rows selected': 'Baris dipilih', 'Running on %s': 'Berjalan pada %s', 'Save model as...': 'Simpan model sebagai ...', @@ -167,14 +230,24 @@ 'Search': 'Cari', 'Select Files to Package': 'Pilih Fail untuk Pakej', 'Send Email': 'Kirim Emel', +'Services': 'Services', +'Sign Up': 'Sign Up', 'Size of cache:': 'Saiz cache:', 'Solution': 'Penyelesaian', 'starts with': 'bermula dengan', +'state': 'state', 'static': 'statik', 'Static': 'Statik', 'Statistics': 'Statistik', +'Stylesheet': 'Stylesheet', +'submit': 'submit', 'Support': 'Menyokong', +'Table': 'Table', 'test': 'ujian', +'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.': 'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.', +'The Core': 'The Core', +'The output of the file is a dictionary that was rendered by the view %s': 'The output of the file is a dictionary that was rendered by the view %s', +'The Views': 'The Views', 'There are no plugins': 'Tiada plugin', 'There are no private files': 'Tiada fail peribadi', 'These files are not served, they are only available from within your app': 'Fail-fail ini tidak disampaikan, mereka hanya boleh didapati dari dalam aplikasi anda', @@ -184,6 +257,8 @@ 'Title': 'Judul', 'To create a plugin, name a file/folder plugin_[name]': 'Untuk mencipta plugin, nama fail/folder plugin_ [nama]', 'too short': 'terlalu pendek', +'Traceback': 'Traceback', +'Twitter': 'Twitter', 'Unable to download because:': 'Tidak dapat memuat turun kerana:', 'unable to parse csv file': 'tidak mampu mengurai file csv', 'update all languages': 'mengemaskini semua bahasa', @@ -193,24 +268,30 @@ 'Upload a package:': 'Unggah pakej:', 'upload file:': 'unggah fail:', 'upload plugin file:': 'unggah fail plugin:', +'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.', +'User': 'User', 'User %(id)s Logged-in': 'Pengguna %(id)s Masuk', 'User %(id)s Logged-out': 'Pengguna %(id)s Keluar', 'User %(id)s Password changed': 'Pengguna %(id)s Kata Laluan berubah', 'User %(id)s Password reset': 'Pengguna %(id)s Kata Laluan telah direset', 'User %(id)s Profile updated': 'Pengguna %(id)s Profil dikemaskini', 'User %(id)s Registered': 'Pengguna %(id)s Didaftarkan', +'Users': 'Users', 'value not allowed': 'data tidak benar', 'Verify Password': 'Pengesahan Kata Laluan', 'Version': 'Versi', 'Versioning': 'Pembuatan Sejarah', +'Videos': 'Videos', 'View': 'Lihat', -'Views': 'Lihat', 'views': 'Lihat', +'Views': 'Lihat', 'Web Framework': 'Rangka Kerja Web', 'web2py Recent Tweets': 'Tweet terbaru web2py', 'Website': 'Laman Web', 'Welcome': 'Selamat Datang', 'Welcome to web2py!': 'Selamat Datang di web2py!', +'Which called the function %s located in the file %s': 'Which called the function %s located in the file %s', +'Working...': 'Working...', 'You are successfully running web2py': 'Anda berjaya menjalankan web2py', 'You can modify this application and adapt it to your needs': 'Anda boleh mengubah suai aplikasi ini dan menyesuaikan dengan keperluan anda', 'You visited the url %s': 'Anda melawat url %s', diff --git a/applications/welcome/languages/nl.py b/applications/welcome/languages/nl.py old mode 100644 new mode 100755 index 39892e52..1000587e --- a/applications/welcome/languages/nl.py +++ b/applications/welcome/languages/nl.py @@ -1,4 +1,4 @@ -# coding: utf8 +# -*- coding: utf-8 -*- { '!langcode!': 'nl', '!langname!': 'Nederlands', @@ -19,6 +19,7 @@ '=': '=', '>': '>', '>=': '>=', +'?': '?', 'A new version of web2py is available': 'Een nieuwe versie van web2py is beschikbaar', 'A new version of web2py is available: %s': 'Een nieuwe versie van web2py is beschikbaar: %s', 'About': 'Over', @@ -27,6 +28,7 @@ 'Access Control': 'Toegangscontrole', 'Add': 'Toevoegen', 'additional code for your application': 'additionele code voor je applicatie', +'admin': 'admin', 'admin disabled because no admin password': 'admin is uitgezet omdat er geen admin wachtwoord is', 'admin disabled because not supported on google app engine': 'admin is uitgezet omdat dit niet ondersteund wordt op google app engine', 'admin disabled because unable to access password file': 'admin is uitgezet omdat het wachtwoordbestand niet geopend kan worden', @@ -54,8 +56,10 @@ 'Available Databases and Tables': 'Beschikbare databases en tabellen', 'Back': 'Terug', 'Buy this book': 'Koop dit boek', +"Buy web2py's book": "Buy web2py's book", 'Cache': 'Cache', 'cache': 'cache', +'Cache Cleared': 'Cache Cleared', 'Cache Keys': 'Cache Keys', 'cache, errors and sessions cleaned': 'cache, errors en sessies geleegd', 'Cannot be empty': 'Mag niet leeg zijn', @@ -78,6 +82,7 @@ 'compile': 'compileren', 'compiled application removed': 'gecompileerde applicatie verwijderd', 'Components and Plugins': 'Components en Plugins', +'Config.ini': 'Config.ini', 'contains': 'bevat', 'Controller': 'Controller', 'Controllers': 'Controllers', @@ -98,6 +103,7 @@ 'Database': 'Database', 'Database %s select': 'Database %s select', 'database administration': 'database administratie', +'Database Administration (appadmin)': 'Database Administration (appadmin)', 'Date and Time': 'Datum en Tijd', 'db': 'db', 'DB Model': 'DB Model', @@ -112,6 +118,7 @@ 'Description': 'Beschrijving', 'design': 'design', 'DESIGN': 'DESIGN', +'Design': 'Design', 'Design for': 'Design voor', 'DISK': 'DISK', 'Disk Cache Keys': 'Disk Cache Keys', @@ -160,12 +167,14 @@ 'Forms and Validators': 'Formulieren en Validators', 'Free Applications': 'Gratis Applicaties', 'Functions with no doctests will result in [passed] tests.': 'Functies zonder doctests zullen resulteren in [passed] tests.', +'Graph Model': 'Graph Model', 'Group %(group_id)s created': 'Groep %(group_id)s gemaakt', 'Group ID': 'Groep ID', 'Group uniquely assigned to user %(id)s': 'Groep is uniek toegekend aan gebruiker %(id)s', 'Groups': 'Groepen', 'Hello World': 'Hallo Wereld', 'help': 'help', +'Helping web2py': 'Helping web2py', 'Home': 'Home', 'How did you get here?': 'Hoe ben je hier gekomen?', 'htmledit': 'Bewerk HTML', @@ -201,6 +210,7 @@ 'License for': 'Licentie voor', 'Live Chat': 'Live Chat', 'loading...': 'laden...', +'Log In': 'Log In', 'Logged in': 'Ingelogd', 'Logged out': 'Uitgelogd', 'Login': 'Login', @@ -211,7 +221,10 @@ 'Lost Password': 'Wachtwoord Kwijt', 'Lost password?': 'Wachtwoord kwijt?', 'Main Menu': 'Hoofdmenu', +'Manage %(action)s': 'Manage %(action)s', +'Manage Access Control': 'Manage Access Control', 'Manage Cache': 'Beheer Cache', +'Memberships': 'Memberships', 'Menu Model': 'Menu Model', 'merge': 'samenvoegen', 'Models': 'Modellen', @@ -227,11 +240,13 @@ 'New password': 'Nieuw wachtwoord', 'New Record': 'Nieuw Record', 'new record inserted': 'nieuw record ingevoegd', +'next %s rows': 'next %s rows', 'next 100 rows': 'volgende 100 rijen', 'NO': 'NEE', 'No databases in this application': 'Geen database in deze applicatie', 'Object or table name': 'Object of tabelnaam', 'Old password': 'Oude wachtwoord', +'Online book': 'Online book', 'Online examples': 'Online voorbeelden', 'Or': 'Of', 'or import from csv file': 'of importeer van csv-bestand', @@ -246,12 +261,16 @@ 'Password': 'Wachtwoord', "Password fields don't match": 'Wachtwoordvelden komen niet overeen', 'Peeking at file': 'Naar bestand aan het gluren', +'Permission': 'Permission', +'Permissions': 'Permissions', 'please input your password again': 'geef alstublieft nogmaals uw wachtwoord', 'Plugins': 'Plugins', 'Powered by': 'Powered by', 'Preface': 'Inleiding', +'previous %s rows': 'previous %s rows', 'previous 100 rows': 'vorige 100 rijen', 'Profile': 'Profiel', +'pygraphviz library not found': 'pygraphviz library not found', 'Python': 'Python', 'Query': 'Query', 'Query:': 'Query:', @@ -277,9 +296,11 @@ 'restore': 'herstel', 'revert': 'herstel', 'Role': 'Rol', +'Roles': 'Roles', 'Rows in Table': 'Rijen in tabel', 'Rows selected': 'Rijen geselecteerd', 'save': 'bewaar', +'Save model as...': 'Save model as...', 'Save profile': 'Bewaar profiel', 'Saved file hash:': 'Opgeslagen file hash:', 'Search': 'Zoek', @@ -287,6 +308,7 @@ 'Services': 'Services', 'session expired': 'sessie verlopen', 'shell': 'shell', +'Sign Up': 'Sign Up', 'site': 'site', 'Size of cache:': 'Grootte van cache:', 'some files could not be removed': 'sommige bestanden konden niet worden verwijderd', @@ -326,6 +348,7 @@ 'Timestamp': 'Timestamp (timestamp)', 'to previous version.': 'naar vorige versie.', 'too short': 'te kort', +'Traceback': 'Traceback', 'translation strings for the application': 'vertaalstrings voor de applicatie', 'True': 'Waar', 'try': 'probeer', @@ -347,6 +370,7 @@ 'Upload existing application': 'Upload bestaande applicatie', 'upload file:': 'upload bestand', 'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Gebruik (...)&(...) voor AND, (...)|(...) voor OR, en ~(...) voor NOT om meer complexe queries te maken.', +'User': 'User', 'User %(id)s Logged-in': 'Gebruiker %(id)s Logged-in', 'User %(id)s Logged-out': 'Gebruiker %(id)s Logged-out', 'User %(id)s Password changed': 'Wachtwoord van gebruiker %(id)s is veranderd', @@ -354,6 +378,7 @@ 'User %(id)s Profile updated': 'Profiel van Gebruiker %(id)s geupdate', 'User %(id)s Registered': 'Gebruiker %(id)s Geregistreerd', 'User ID': 'User ID', +'Users': 'Users', 'value already in database or empty': 'waarde al in database of leeg', 'Verify Password': 'Verifieer Wachtwoord', 'versioning': 'versionering', @@ -369,6 +394,7 @@ 'Welcome to web2py': 'Welkom bij web2py', 'Welcome to web2py!': 'Welkom bij web2py!', 'Which called the function %s located in the file %s': 'Die functie %s aanriep en zich bevindt in het bestand %s', +'Working...': 'Working...', 'YES': 'JA', 'You are successfully running web2py': 'Je draait web2py succesvol', 'You can modify this application and adapt it to your needs': 'Je kan deze applicatie aanpassen naar je eigen behoeften', diff --git a/applications/welcome/languages/pl.py b/applications/welcome/languages/pl.py old mode 100644 new mode 100755 index aa1e5701..1e8cae26 --- a/applications/welcome/languages/pl.py +++ b/applications/welcome/languages/pl.py @@ -1,4 +1,4 @@ -# coding: utf8 +# -*- coding: utf-8 -*- { '!langcode!': 'pl', '!langname!': 'Polska', @@ -8,8 +8,10 @@ '%s selected': '%s wybranych', '%Y-%m-%d': '%Y-%m-%d', '%Y-%m-%d %H:%M:%S': '%Y-%m-%d %H:%M:%S', +'?': '?', 'About': 'About', 'Access Control': 'Access Control', +'admin': 'admin', 'Administrative Interface': 'Administrative Interface', 'Administrative interface': 'Kliknij aby przejść do panelu administracyjnego', 'Ajax Recipes': 'Ajax Recipes', @@ -18,8 +20,10 @@ 'Authentication': 'Uwierzytelnienie', 'Available Databases and Tables': 'Dostępne bazy danych i tabele', 'Buy this book': 'Buy this book', +"Buy web2py's book": "Buy web2py's book", 'cache': 'cache', 'Cache': 'Cache', +'Cache Cleared': 'Cache Cleared', 'Cache Keys': 'Cache Keys', 'Cannot be empty': 'Nie może być puste', 'Change Password': 'Zmień hasło', @@ -32,6 +36,7 @@ 'Client IP': 'IP klienta', 'Community': 'Community', 'Components and Plugins': 'Components and Plugins', +'Config.ini': 'Config.ini', 'Controller': 'Kontroler', 'Copyright': 'Copyright', 'Current request': 'Aktualne żądanie', @@ -41,6 +46,7 @@ 'data uploaded': 'dane wysłane', 'Database': 'baza danych', 'Database %s select': 'wybór z bazy danych %s', +'Database Administration (appadmin)': 'Database Administration (appadmin)', 'db': 'baza danych', 'DB Model': 'Model bazy danych', 'Delete:': 'Usuń:', @@ -48,6 +54,7 @@ 'Deployment Recipes': 'Deployment Recipes', 'Description': 'Opis', 'design': 'projektuj', +'Design': 'Design', 'DISK': 'DISK', 'Disk Cache Keys': 'Disk Cache Keys', 'Disk Cleared': 'Disk Cleared', @@ -69,9 +76,11 @@ 'Forms and Validators': 'Forms and Validators', 'Free Applications': 'Free Applications', 'Function disabled': 'Funkcja wyłączona', +'Graph Model': 'Graph Model', 'Group ID': 'ID grupy', 'Groups': 'Groups', 'Hello World': 'Witaj Świecie', +'Helping web2py': 'Helping web2py', 'Home': 'Home', 'How did you get here?': 'How did you get here?', 'import': 'import', @@ -90,20 +99,26 @@ 'Layout Plugins': 'Layout Plugins', 'Layouts': 'Layouts', 'Live Chat': 'Live Chat', +'Log In': 'Log In', 'login': 'login', 'Login': 'Zaloguj', 'logout': 'logout', 'Logout': 'Wyloguj', 'Lost Password': 'Przypomnij hasło', 'Main Menu': 'Menu główne', +'Manage %(action)s': 'Manage %(action)s', +'Manage Access Control': 'Manage Access Control', 'Manage Cache': 'Manage Cache', +'Memberships': 'Memberships', 'Menu Model': 'Model menu', 'My Sites': 'My Sites', 'Name': 'Nazwa', 'New Record': 'Nowy rekord', 'new record inserted': 'nowy rekord został wstawiony', +'next %s rows': 'next %s rows', 'next 100 rows': 'następne 100 wierszy', 'No databases in this application': 'Brak baz danych w tej aplikacji', +'Online book': 'Online book', 'Online examples': 'Kliknij aby przejść do interaktywnych przykładów', 'or import from csv file': 'lub zaimportuj z pliku csv', 'Origin': 'Źródło', @@ -112,10 +127,14 @@ 'Overview': 'Overview', 'Password': 'Hasło', "Password fields don't match": 'Pola hasła nie są zgodne ze sobą', +'Permission': 'Permission', +'Permissions': 'Permissions', 'Plugins': 'Plugins', 'Powered by': 'Zasilane przez', 'Preface': 'Preface', +'previous %s rows': 'previous %s rows', 'previous 100 rows': 'poprzednie 100 wierszy', +'pygraphviz library not found': 'pygraphviz library not found', 'Python': 'Python', 'Query:': 'Zapytanie:', 'Quick Examples': 'Quick Examples', @@ -131,10 +150,13 @@ 'register': 'register', 'Registration key': 'Klucz rejestracji', 'Role': 'Rola', +'Roles': 'Roles', 'Rows in Table': 'Wiersze w tabeli', 'Rows selected': 'Wybrane wiersze', +'Save model as...': 'Save model as...', 'Semantic': 'Semantic', 'Services': 'Services', +'Sign Up': 'Sign Up', 'Size of cache:': 'Size of cache:', 'state': 'stan', 'Statistics': 'Statistics', @@ -152,12 +174,15 @@ 'This App': 'This App', 'Time in Cache (h:m:s)': 'Time in Cache (h:m:s)', 'Timestamp': 'Znacznik czasu', +'Traceback': 'Traceback', 'Twitter': 'Twitter', 'unable to parse csv file': 'nie można sparsować pliku csv', 'Update:': 'Uaktualnij:', 'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Użyj (...)&(...) jako AND, (...)|(...) jako OR oraz ~(...) jako NOT do tworzenia bardziej skomplikowanych zapytań.', +'User': 'User', 'User %(id)s Registered': 'Użytkownik %(id)s został zarejestrowany', 'User ID': 'ID użytkownika', +'Users': 'Users', 'Verify Password': 'Potwierdź hasło', 'Videos': 'Videos', 'View': 'Widok', @@ -165,6 +190,7 @@ 'Welcome to web2py': 'Witaj w web2py', 'Welcome to web2py!': 'Welcome to web2py!', 'Which called the function %s located in the file %s': 'Which called the function %s located in the file %s', +'Working...': 'Working...', 'You are successfully running web2py': 'You are successfully running web2py', 'You can modify this application and adapt it to your needs': 'You can modify this application and adapt it to your needs', 'You visited the url %s': 'You visited the url %s', diff --git a/applications/welcome/languages/plural-cs.py b/applications/welcome/languages/plural-cs.py old mode 100644 new mode 100755 diff --git a/applications/welcome/languages/plural-en.py b/applications/welcome/languages/plural-en.py old mode 100644 new mode 100755 diff --git a/applications/welcome/languages/plural-es.py b/applications/welcome/languages/plural-es.py old mode 100644 new mode 100755 diff --git a/applications/welcome/languages/plural-ru.py b/applications/welcome/languages/plural-ru.py old mode 100644 new mode 100755 diff --git a/applications/welcome/languages/plural-uk.py b/applications/welcome/languages/plural-uk.py old mode 100644 new mode 100755 diff --git a/applications/welcome/languages/pt-br.py b/applications/welcome/languages/pt-br.py old mode 100644 new mode 100755 index 15280adc..ff77f771 --- a/applications/welcome/languages/pt-br.py +++ b/applications/welcome/languages/pt-br.py @@ -3,26 +3,37 @@ '!langcode!': 'pt-br', '!langname!': 'Português (do Brasil)', '"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN': '"update" é uma expressão opcional como "campo1=\'novovalor\'". Você não pode atualizar ou apagar os resultados de um JOIN', -'%s %%{row} deleted': '%s linhas apagadas', -'%s %%{row} updated': '%s linhas atualizadas', +'%s %%{row} deleted': '%s linha apagadas', +'%s %%{row} updated': '%s linha atualizadas', '%s selected': '%s selecionado', '%Y-%m-%d': '%d-%m-%Y', '%Y-%m-%d %H:%M:%S': '%d-%m-%Y %H:%M:%S', +'(**%.0d MB**)': '(**%.0d MB**)', +'**%(items)s** %%{item(items)}, **%(bytes)s** %%{byte(bytes)}': '**%(items)s** %%{item(items)}, **%(bytes)s** %%{byte(bytes)}', +'**%(items)s** items, **%(bytes)s** %%{byte(bytes)}': '**%(items)s** items, **%(bytes)s** %%{byte(bytes)}', +'**not available** (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)': '**not available** (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)', +'?': '?', +'@markmin\x01An error occured, please [[reload %s]] the page': 'Ocorreu um erro, por favor [[reload %s]] a página', +'``**not available**``:red (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)': '``**not available**``:red (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)', 'About': 'Sobre', 'Access Control': 'Controle de Acesso', +'admin': 'admin', 'Administrative Interface': 'Interface Administrativa', -'@markmin\x01An error occured, please [[reload %s]] the page': 'Ocorreu um erro, por favor [[reload %s]] a página', 'Administrative interface': 'Interface administrativa', 'Ajax Recipes': 'Receitas de Ajax', +'An error occured, please [[reload %s]] the page': 'An error occured, please [[reload %s]] the page', 'appadmin is disabled because insecure channel': 'Administração desativada porque o canal não é seguro', -'Are you sure you want to delete this object?': 'Você está certo que deseja apagar este objeto?', +'Are you sure you want to delete this object?': 'Você tem certeza que quer apagar este objeto?', 'Available Databases and Tables': 'Bancos de dados e tabelas disponíveis', 'Buy this book': 'Compre o livro', +"Buy web2py's book": "Compre o livro do web2buy", 'cache': 'cache', 'Cache': 'Cache', +'Cache Cleared': 'Cache limpo', +'Cache contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.': 'Cache contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.', 'Cache Keys': 'Chaves de cache', -'Cannot be empty': 'Não pode ser vazio', -'change password': 'modificar senha', +'Cannot be empty': 'Não pode estar vazio', +'change password': 'mudar senha', 'Check to delete': 'Marque para apagar', 'Clear CACHE?': 'Limpar CACHE?', 'Clear DISK': 'Limpar DISCO', @@ -30,15 +41,17 @@ 'Client IP': 'IP do cliente', 'Community': 'Comunidade', 'Components and Plugins': 'Componentes e Plugins', +'Config.ini': 'Config.ini', 'Controller': 'Controlador', 'Copyright': 'Copyright', 'Current request': 'Requisição atual', 'Current response': 'Resposta atual', 'Current session': 'Sessão atual', -'customize me!': 'Personalize-me!', +'customize me!': 'personalize-me!', 'data uploaded': 'dados enviados', 'Database': 'banco de dados', 'Database %s select': 'Selecionar banco de dados %s', +'Database Administration (appadmin)': 'Database Administration (appadmin)', 'db': 'bd', 'DB Model': 'Modelo BD', 'Delete:': 'Apagar:', @@ -46,11 +59,13 @@ 'Deployment Recipes': 'Receitas de deploy', 'Description': 'Descrição', 'design': 'projeto', +'Design': 'Design', 'DISK': 'DISK', 'Disk Cache Keys': 'Chaves do Cache de Disco', 'Disk Cleared': 'Disco Limpo', +'DISK contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.': 'DISK contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.', 'Documentation': 'Documentação', -"Don't know what to do?": "Não sabe o que fazer?", +"Don't know what to do?": 'Não sabe o que fazer?', 'done!': 'concluído!', 'Download': 'Download', 'E-mail': 'E-mail', @@ -59,16 +74,19 @@ 'edit profile': 'editar perfil', 'Edit This App': 'Editar esta aplicação', 'Email and SMS': 'Email e SMS', -'Errors': 'Erros', 'Enter an integer between %(min)g and %(max)g': 'Informe um valor inteiro entre %(min)g e %(max)g', +'Errors': 'Erros', 'export as csv file': 'exportar como um arquivo csv', 'FAQ': 'Perguntas frequentes', 'First name': 'Nome', 'Forms and Validators': 'Formulários e Validadores', 'Free Applications': 'Aplicações gratuitas', +'Graph Model': 'Graph Model', 'Group ID': 'ID do Grupo', 'Groups': 'Grupos', 'Hello World': 'Olá Mundo', +'Helping web2py': 'Helping web2py', +'Hit Ratio: **%(ratio)s%%** (**%(hits)s** %%{hit(hits)} and **%(misses)s** %%{miss(misses)})': 'Hit Ratio: **%(ratio)s%%** (**%(hits)s** %%{hit(hits)} and **%(misses)s** %%{miss(misses)})', 'Home': 'Principal', 'How did you get here?': 'Como você chegou aqui?', 'import': 'importar', @@ -88,21 +106,28 @@ 'Layouts': 'Layouts', 'Live chat': 'Chat ao vivo', 'Live Chat': 'Chat ao vivo', +'Log In': 'Log In', 'login': 'Entrar', 'Login': 'Autentique-se', 'logout': 'Sair', 'Lost Password': 'Esqueceu sua senha?', 'lost password?': 'esqueceu sua senha?', 'Main Menu': 'Menu Principal', +'Manage %(action)s': 'Manage %(action)s', +'Manage Access Control': 'Manage Access Control', 'Manage Cache': 'Gerenciar Cache', +'Memberships': 'Memberships', 'Menu Model': 'Modelo de Menu', 'My Sites': 'Meus sites', 'Name': 'Nome', 'New Record': 'Novo Registro', 'new record inserted': 'novo registro inserido', +'next %s rows': 'next %s rows', 'next 100 rows': 'próximas 100 linhas', 'No databases in this application': 'Não há bancos de dados nesta aplicação', +'Number of entries: **%s**': 'Number of entries: **%s**', 'Object or table name': 'Nome do objeto do da tabela', +'Online book': 'Online book', 'Online examples': 'Exemplos online', 'or import from csv file': 'ou importar de um arquivo csv', 'Origin': 'Origem', @@ -110,16 +135,21 @@ 'Other Recipes': 'Outras Receitas', 'Overview': 'Visão Geral', 'Password': 'Senha', +'Permission': 'Permission', +'Permissions': 'Permissions', 'Plugins': 'Plugins', 'Powered by': 'Desenvolvido com', 'Preface': 'Prefácio', +'previous %s rows': 'previous %s rows', 'previous 100 rows': '100 linhas anteriores', +'pygraphviz library not found': 'pygraphviz library not found', 'Python': 'Python', 'Query:': 'Consulta:', 'Quick Examples': 'Exemplos rápidos', 'RAM': 'RAM', 'RAM Cache Keys': 'RAM Cache Keys', 'Ram Cleared': 'Ram Cleared', +'RAM contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.': 'RAM contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.', 'Recipes': 'Receitas', 'Record': 'Registro', 'record does not exist': 'registro não existe', @@ -127,15 +157,18 @@ 'Record id': 'id do registro', 'Register': 'Registre-se', 'register': 'Registre-se', +'Registration identifier': 'Idenficador de registro', 'Registration key': 'Chave de registro', 'Reset Password key': 'Resetar chave de senha', 'Resources': 'Recursos', 'Role': 'Papel', -'Registration identifier': 'Idenficador de registro', +'Roles': 'Roles', 'Rows in Table': 'Linhas na tabela', 'Rows selected': 'Linhas selecionadas', +'Save model as...': 'Save model as...', 'Semantic': 'Semântico', 'Services': 'Serviço', +'Sign Up': 'Sign Up', 'Size of cache:': 'Tamanho do cache:', 'state': 'estado', 'Statistics': 'Estatísticas', @@ -154,12 +187,15 @@ 'This is a copy of the scaffolding application': 'Isto é uma cópia da aplicação modelo', 'Time in Cache (h:m:s)': 'Tempo em Cache (h:m:s)', 'Timestamp': 'Timestamp', +'Traceback': 'Traceback', 'Twitter': 'Twitter', 'unable to parse csv file': 'não foi possível analisar arquivo csv', 'Update:': 'Atualizar:', 'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Use (...)&(...) para AND, (...)|(...) para OR, e ~(...) para NOT para construir consultas mais complexas.', +'User': 'User', 'User ID': 'ID do Usuário', 'User Voice': 'Opinião dos usuários', +'Users': 'Users', 'Videos': 'Vídeos', 'View': 'Visualização', 'Web2py': 'Web2py', @@ -168,9 +204,10 @@ 'Welcome to web2py': 'Bem-vindo ao web2py', 'Welcome to web2py!': 'Bem-vindo ao web2py!', 'Which called the function %s located in the file %s': 'Que chamou a função %s localizada no arquivo %s', +'Working...': 'Trabalhando...', 'You are successfully running web2py': 'Você está executando o web2py com sucesso', 'You are successfully running web2py.': 'Você está executando o web2py com sucesso.', 'You can modify this application and adapt it to your needs': 'Você pode modificar esta aplicação e adaptá-la às suas necessidades', 'You visited the url %s': 'Você acessou a url %s', -'Working...': 'Trabalhando...', } + diff --git a/applications/welcome/languages/pt.py b/applications/welcome/languages/pt.py old mode 100644 new mode 100755 index 8d36be6f..f0945906 --- a/applications/welcome/languages/pt.py +++ b/applications/welcome/languages/pt.py @@ -1,4 +1,4 @@ -# coding: utf8 +# -*- coding: utf-8 -*- { '!langcode!': 'pt', '!langname!': 'Português', @@ -8,56 +8,71 @@ '%s selected': '%s seleccionado(s)', '%Y-%m-%d': '%Y-%m-%d', '%Y-%m-%d %H:%M:%S': '%Y-%m-%d %H:%M:%S', +'(**%.0d MB**)': '(**%.0d MB**)', +'**%(items)s** %%{item(items)}, **%(bytes)s** %%{byte(bytes)}': '**%(items)s** %%{item(items)}, **%(bytes)s** %%{byte(bytes)}', +'**%(items)s** items, **%(bytes)s** %%{byte(bytes)}': '**%(items)s** items, **%(bytes)s** %%{byte(bytes)}', +'**not available** (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)': '**not available** (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)', +'?': '?', +'``**not available**``:red (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)': '``**not available**``:red (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)', 'About': 'About', -'Access Control': 'Access Control', -'Administrative Interface': 'Administrative Interface', -'Administrative interface': 'Painel administrativo', -'Ajax Recipes': 'Ajax Recipes', +'Access Control': 'Controle de acesso', +'admin': 'administrador', +'Administrative Interface': 'Interface Administrativa', +'Administrative interface': 'Painel Administrativo', +'Ajax Recipes': 'Formulas Ajax', +'An error occured, please [[reload %s]] the page': 'Ocorreu um erro, por favor [[recarregue %s]] a página', 'appadmin is disabled because insecure channel': 'appadmin está desactivada pois o canal é inseguro', -'Are you sure you want to delete this object?': 'Are you sure you want to delete this object?', +'Are you sure you want to delete this object?': 'Tem a certeza que quer deletar este objeto?', 'Author Reference Auth User': 'Author Reference Auth User', 'Author Reference Auth User.username': 'Author Reference Auth User.username', 'Available Databases and Tables': 'bases de dados e tabelas disponíveis', -'Buy this book': 'Buy this book', +'Buy this book': 'Comprar este Livro', +"Buy web2py's book": "Comprar Livros web2py", 'cache': 'cache', 'Cache': 'Cache', +'Cache Cleared': 'Cache Limpo', +'Cache contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.': 'Cache contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.', 'Cache Keys': 'Cache Keys', 'Cannot be empty': 'não pode ser vazio', -'Category Create': 'Category Create', -'Category Select': 'Category Select', +'Category Create': 'Criar Categoria', +'Category Select': 'Selecionar Categoria', 'change password': 'alterar palavra-chave', 'Check to delete': 'seleccione para eliminar', -'Clear CACHE?': 'Clear CACHE?', -'Clear DISK': 'Clear DISK', -'Clear RAM': 'Clear RAM', -'Comment Create': 'Comment Create', -'Comment Select': 'Comment Select', -'Community': 'Community', -'Components and Plugins': 'Components and Plugins', -'Content': 'Content', +'Clear CACHE?': 'apagar CACHE?', +'Clear DISK': 'apagar DISK', +'Clear RAM': 'apagar RAM', +'Comment Create': 'Criar Comentário', +'Comment Select': 'Selecionar Comentário', +'Community': 'Comunidade', +'Components and Plugins': 'Componentes e Plugins', +'Config.ini': 'Config.ini', +'Content': 'Conteudo', 'Controller': 'Controlador', -'Copyright': 'Direitos de cópia', -'create new category': 'create new category', -'create new comment': 'create new comment', -'create new post': 'create new post', -'Created By': 'Created By', -'Created On': 'Created On', -'Current request': 'pedido currente', -'Current response': 'resposta currente', -'Current session': 'sessão currente', +'Copyright': 'Direitos de Autor', +'create new category': 'Criar Nova Categoria', +'create new comment': 'Criar Novo Comentário', +'create new post': 'Criar novo post', +'Created By': 'Creado Por', +'Created On': 'Creado Em', +'Current request': 'Pedido Corrente', +'Current response': 'Resposta Corrente', +'Current session': 'Sessão Corrente', 'customize me!': 'Personaliza-me!', -'data uploaded': 'informação enviada', +'data uploaded': 'Informação enviada', 'Database': 'base de dados', 'Database %s select': 'selecção de base de dados %s', +'Database Administration (appadmin)': 'Base de Dados da Administração (appadmin)', 'db': 'bd', 'DB Model': 'Modelo de BD', 'Delete:': 'Eliminar:', 'Demo': 'Demo', 'Deployment Recipes': 'Deployment Recipes', 'design': 'design', +'Design': 'Design', 'DISK': 'DISK', 'Disk Cache Keys': 'Disk Cache Keys', 'Disk Cleared': 'Disk Cleared', +'DISK contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.': 'DISK contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.', 'Documentation': 'Documentation', "Don't know what to do?": "Don't know what to do?", 'done!': 'concluído!', @@ -78,8 +93,11 @@ 'For %s #%s': 'For %s #%s', 'Forms and Validators': 'Forms and Validators', 'Free Applications': 'Free Applications', +'Graph Model': 'Graph Model', 'Groups': 'Groups', 'Hello World': 'Olá Mundo', +'Helping web2py': 'Helping web2py', +'Hit Ratio: **%(ratio)s%%** (**%(hits)s** %%{hit(hits)} and **%(misses)s** %%{miss(misses)})': 'Hit Ratio: **%(ratio)s%%** (**%(hits)s** %%{hit(hits)} and **%(misses)s** %%{miss(misses)})', 'Home': 'Home', 'How did you get here?': 'How did you get here?', 'import': 'import', @@ -97,11 +115,15 @@ 'Layout Plugins': 'Layout Plugins', 'Layouts': 'Layouts', 'Live Chat': 'Live Chat', +'Log In': 'Log In', 'login': 'login', 'logout': 'logout', 'Lost Password': 'Lost Password', 'Main Menu': 'Menu Principal', +'Manage %(action)s': 'Manage %(action)s', +'Manage Access Control': 'Manage Access Control', 'Manage Cache': 'Manage Cache', +'Memberships': 'Memberships', 'Menu Model': 'Menu do Modelo', 'Modified By': 'Modified By', 'Modified On': 'Modified On', @@ -109,27 +131,35 @@ 'Name': 'Name', 'New Record': 'Novo Registo', 'new record inserted': 'novo registo inserido', +'next %s rows': 'next %s rows', 'next 100 rows': 'próximas 100 linhas', 'No Data': 'No Data', 'No databases in this application': 'Não há bases de dados nesta aplicação', +'Number of entries: **%s**': 'Number of entries: **%s**', +'Online book': 'Online book', 'Online examples': 'Exemplos online', 'or import from csv file': 'ou importe a partir de ficheiro csv', 'Other Plugins': 'Other Plugins', 'Other Recipes': 'Other Recipes', 'Overview': 'Overview', 'Password': 'Password', +'Permission': 'Permission', +'Permissions': 'Permissions', 'Plugins': 'Plugins', 'Post Create': 'Post Create', 'Post Select': 'Post Select', 'Powered by': 'Suportado por', 'Preface': 'Preface', +'previous %s rows': 'previous %s rows', 'previous 100 rows': '100 linhas anteriores', +'pygraphviz library not found': 'pygraphviz library not found', 'Python': 'Python', 'Query:': 'Interrogação:', 'Quick Examples': 'Quick Examples', 'RAM': 'RAM', 'RAM Cache Keys': 'RAM Cache Keys', 'Ram Cleared': 'Ram Cleared', +'RAM contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.': 'RAM contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.', 'Recipes': 'Recipes', 'Record': 'registo', 'record does not exist': 'registo inexistente', @@ -137,8 +167,11 @@ 'Register': 'Register', 'register': 'register', 'Replyto Reference Post': 'Replyto Reference Post', +'Role': 'Role', +'Roles': 'Roles', 'Rows in Table': 'Linhas numa tabela', 'Rows selected': 'Linhas seleccionadas', +'Save model as...': 'Save model as...', 'search category': 'search category', 'search comment': 'search comment', 'search post': 'search post', @@ -150,6 +183,7 @@ 'show category': 'show category', 'show comment': 'show comment', 'show post': 'show post', +'Sign Up': 'Sign Up', 'Size of cache:': 'Size of cache:', 'state': 'estado', 'Statistics': 'Statistics', @@ -165,11 +199,14 @@ 'This App': 'This App', 'Time in Cache (h:m:s)': 'Time in Cache (h:m:s)', 'Title': 'Title', +'Traceback': 'Traceback', 'Twitter': 'Twitter', 'unable to parse csv file': 'não foi possível carregar ficheiro csv', 'Update:': 'Actualização:', 'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Utilize (...)&(...) para AND, (...)|(...) para OR, e ~(...) para NOT para construir interrogações mais complexas.', +'User': 'User', 'Username': 'Username', +'Users': 'Users', 'Videos': 'Videos', 'View': 'Vista', 'Welcome %s': 'Bem-vindo(a) %s', @@ -178,7 +215,9 @@ 'Welcome to web2py!': 'Welcome to web2py!', 'When': 'When', 'Which called the function %s located in the file %s': 'Which called the function %s located in the file %s', +'Working...': 'Working...', 'You are successfully running web2py': 'You are successfully running web2py', 'You can modify this application and adapt it to your needs': 'You can modify this application and adapt it to your needs', 'You visited the url %s': 'You visited the url %s', } + diff --git a/applications/welcome/languages/ro.py b/applications/welcome/languages/ro.py old mode 100644 new mode 100755 index 0f830e3d..8be157eb --- a/applications/welcome/languages/ro.py +++ b/applications/welcome/languages/ro.py @@ -1,4 +1,4 @@ -# coding: utf8 +# -*- coding: utf-8 -*- { '!=': '!=', '!langcode!': 'ro', @@ -20,6 +20,7 @@ '=': '=', '>': '>', '>=': '>=', +'?': '?', 'A new version of web2py is available': 'O nouă versiune de web2py este disponibilă', 'A new version of web2py is available: %s': 'O nouă versiune de web2py este disponibilă: %s', 'About': 'Despre', @@ -28,6 +29,7 @@ 'Access Control': 'Control acces', 'Add': 'Adaugă', 'additional code for your application': 'cod suplimentar pentru aplicația dvs.', +'admin': 'admin', 'admin disabled because no admin password': 'administrare dezactivată deoarece parola de administrator nu a fost furnizată', 'admin disabled because not supported on google app engine': 'administrare dezactivată deoarece funcționalitatea nu e suportat pe Google App Engine', 'admin disabled because unable to access password file': 'administrare dezactivată deoarece nu există acces la fișierul cu parole', @@ -56,8 +58,10 @@ 'Available Databases and Tables': 'Baze de date și tabele disponibile', 'Back': 'Înapoi', 'Buy this book': 'Cumpără această carte', +"Buy web2py's book": "Buy web2py's book", 'Cache': 'Cache', 'cache': 'cache', +'Cache Cleared': 'Cache Cleared', 'Cache Keys': 'Chei cache', 'cache, errors and sessions cleaned': 'cache, erori și sesiuni golite', 'Cannot be empty': 'Nu poate fi vid', @@ -80,6 +84,7 @@ 'compile': 'compilare', 'compiled application removed': 'aplicația compilată a fost ștearsă', 'Components and Plugins': 'Componente și plugin-uri', +'Config.ini': 'Config.ini', 'contains': 'conține', 'Controller': 'Controlor', 'Controllers': 'Controlori', @@ -98,6 +103,7 @@ 'Database': 'bază de date', 'Database %s select': 'selectare bază de date %s', 'database administration': 'administrare bază de date', +'Database Administration (appadmin)': 'Database Administration (appadmin)', 'Date and Time': 'Data și ora', 'db': 'db', 'DB Model': 'Model bază de date', @@ -112,6 +118,7 @@ 'Description': 'Descriere', 'design': 'design', 'DESIGN': 'DESIGN', +'Design': 'Design', 'Design for': 'Design pentru', 'DISK': 'DISK', 'Disk Cache Keys': 'Chei cache de disc', @@ -160,12 +167,14 @@ 'Forms and Validators': 'Formulare și validatori', 'Free Applications': 'Aplicații gratuite', 'Functions with no doctests will result in [passed] tests.': 'Funcțiile fără doctests vor genera teste [trecute].', +'Graph Model': 'Graph Model', 'Group %(group_id)s created': 'Grup %(group_id)s creat', 'Group ID': 'ID grup', 'Group uniquely assigned to user %(id)s': 'Grup asociat în mod unic utilizatorului %(id)s', 'Groups': 'Grupuri', 'Hello World': 'Salutare lume', 'help': 'ajutor', +'Helping web2py': 'Helping web2py', 'Home': 'Acasă', 'How did you get here?': 'Cum ați ajuns aici?', 'htmledit': 'editare html', @@ -200,6 +209,7 @@ 'License for': 'Licență pentru', 'Live Chat': 'Chat live', 'loading...': 'încarc...', +'Log In': 'Log In', 'Logged in': 'Logat', 'Logged out': 'Delogat', 'Login': 'Autentificare', @@ -210,7 +220,10 @@ 'Lost Password': 'Parolă pierdută', 'Lost password?': 'Parolă pierdută?', 'Main Menu': 'Meniu principal', +'Manage %(action)s': 'Manage %(action)s', +'Manage Access Control': 'Manage Access Control', 'Manage Cache': 'Manage Cache', +'Memberships': 'Memberships', 'Menu Model': 'Model meniu', 'merge': 'unește', 'Models': 'Modele', @@ -224,11 +237,13 @@ 'New password': 'Parola nouă', 'New Record': 'Înregistrare nouă', 'new record inserted': 'înregistrare nouă adăugată', +'next %s rows': 'next %s rows', 'next 100 rows': 'următoarele 100 de linii', 'NO': 'NU', 'No databases in this application': 'Aplicație fără bază de date', 'Object or table name': 'Obiect sau nume de tabel', 'Old password': 'Parola veche', +'Online book': 'Online book', 'Online examples': 'Exemple online', 'Or': 'Sau', 'or import from csv file': 'sau importă din fișier csv', @@ -243,12 +258,16 @@ 'Password': 'Parola', "Password fields don't match": 'Câmpurile de parolă nu se potrivesc', 'Peeking at file': 'Vizualizare fișier', +'Permission': 'Permission', +'Permissions': 'Permissions', 'please input your password again': 'introduceți parola din nou', 'Plugins': 'Plugin-uri', 'Powered by': 'Pus în mișcare de', 'Preface': 'Prefață', +'previous %s rows': 'previous %s rows', 'previous 100 rows': '100 de linii anterioare', 'Profile': 'Profil', +'pygraphviz library not found': 'pygraphviz library not found', 'Python': 'Python', 'Query': 'Interogare', 'Query:': 'Interogare:', @@ -274,9 +293,11 @@ 'restore': 'restaurare', 'revert': 'revenire', 'Role': 'Rol', +'Roles': 'Roles', 'Rows in Table': 'Linii în tabel', 'Rows selected': 'Linii selectate', 'save': 'salvare', +'Save model as...': 'Save model as...', 'Save profile': 'Salvează profil', 'Saved file hash:': 'Hash fișier salvat:', 'Search': 'Căutare', @@ -284,6 +305,7 @@ 'Services': 'Servicii', 'session expired': 'sesiune expirată', 'shell': 'line de commandă', +'Sign Up': 'Sign Up', 'site': 'site', 'Size of cache:': 'Size of cache:', 'some files could not be removed': 'anumite fișiere n-au putut fi șterse', @@ -323,6 +345,7 @@ 'Timestamp': 'Moment în timp (timestamp)', 'to previous version.': 'la versiunea anterioară.', 'too short': 'prea scurt', +'Traceback': 'Traceback', 'translation strings for the application': 'șiruri de caractere folosite la traducerea aplicației', 'True': 'Adevărat', 'try': 'încearcă', @@ -344,6 +367,7 @@ 'Upload existing application': 'Încarcă aplicația existentă', 'upload file:': 'încarcă fișier:', 'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Folosiți (...)&(...) pentru AND, (...)|(...) pentru OR, și ~(...) pentru NOT, pentru a crea interogări complexe.', +'User': 'User', 'User %(id)s Logged-in': 'Utilizator %(id)s autentificat', 'User %(id)s Logged-out': 'Utilizator %(id)s delogat', 'User %(id)s Password changed': 'Parola utilizatorului %(id)s a fost schimbată', @@ -351,6 +375,7 @@ 'User %(id)s Profile updated': 'Profil utilizator %(id)s actualizat', 'User %(id)s Registered': 'Utilizator %(id)s înregistrat', 'User ID': 'ID utilizator', +'Users': 'Users', 'value already in database or empty': 'Valoare existentă în baza de date sau vidă', 'Verify Password': 'Verifică parola', 'versioning': 'versiuni', @@ -366,6 +391,7 @@ 'Welcome to web2py': 'Bun venit la web2py', 'Welcome to web2py!': 'Bun venit la web2py!', 'Which called the function %s located in the file %s': 'Care a apelat funcția %s prezentă în fișierul %s', +'Working...': 'Working...', 'YES': 'DA', 'You are successfully running web2py': 'Rulați cu succes web2py', 'You can modify this application and adapt it to your needs': 'Puteți modifica și adapta aplicația nevoilor dvs.', diff --git a/applications/welcome/languages/ru.py b/applications/welcome/languages/ru.py old mode 100644 new mode 100755 index 85644ea2..a3f38240 --- a/applications/welcome/languages/ru.py +++ b/applications/welcome/languages/ru.py @@ -1,4 +1,4 @@ -# coding: utf8 +# -*- coding: utf-8 -*- { '!langcode!': 'ru', '!langname!': 'Русский', @@ -22,8 +22,10 @@ '1 second ago': '1 секунду тому', '1 week ago': '1 неделю тому', '1 year ago': '1 год тому', +'?': '?', 'About': 'About', 'Access Control': 'Access Control', +'admin': 'admin', 'Administrative Interface': 'Administrative Interface', 'Administrative interface': 'административный интерфейс', 'Ajax Recipes': 'Ajax Recipes', @@ -31,8 +33,10 @@ 'Are you sure you want to delete this object?': 'Вы уверены, что хотите удалить этот объект?', 'Available Databases and Tables': 'Базы данных и таблицы', 'Buy this book': 'Buy this book', +"Buy web2py's book": "Buy web2py's book", 'cache': 'cache', 'Cache': 'Cache', +'Cache Cleared': 'Cache Cleared', 'Cache Keys': 'Cache Keys', 'Cannot be empty': 'Пустое значение недопустимо', 'Change Password': 'Смените пароль', @@ -44,6 +48,7 @@ 'Client IP': 'Client IP', 'Community': 'Community', 'Components and Plugins': 'Components and Plugins', +'Config.ini': 'Config.ini', 'Controller': 'Controller', 'Copyright': 'Copyright', 'Current request': 'Текущий запрос', @@ -53,6 +58,7 @@ 'data uploaded': 'данные загружены', 'Database': 'Database', 'Database %s select': 'выбор базы данных %s', +'Database Administration (appadmin)': 'Database Administration (appadmin)', 'db': 'БД', 'DB Model': 'DB Model', 'Delete:': 'Удалить:', @@ -60,6 +66,7 @@ 'Deployment Recipes': 'Deployment Recipes', 'Description': 'Описание', 'design': 'дизайн', +'Design': 'Design', 'DISK': 'DISK', 'Disk Cache Keys': 'Disk Cache Keys', 'Disk Cleared': 'Disk Cleared', @@ -78,9 +85,11 @@ 'First name': 'Имя', 'Forms and Validators': 'Forms and Validators', 'Free Applications': 'Free Applications', +'Graph Model': 'Graph Model', 'Group ID': 'Group ID', 'Groups': 'Groups', 'Hello World': 'Заработало!', +'Helping web2py': 'Helping web2py', 'Home': 'Home', 'How did you get here?': 'How did you get here?', 'import': 'import', @@ -100,6 +109,7 @@ 'Layout Plugins': 'Layout Plugins', 'Layouts': 'Layouts', 'Live Chat': 'Live Chat', +'Log In': 'Log In', 'Logged in': 'Вход выполнен', 'Logged out': 'Выход выполнен', 'login': 'вход', @@ -108,18 +118,23 @@ 'Logout': 'Выход', 'Lost Password': 'Забыли пароль?', 'Lost password?': 'Lost password?', +'Manage %(action)s': 'Manage %(action)s', +'Manage Access Control': 'Manage Access Control', 'Manage Cache': 'Manage Cache', +'Memberships': 'Memberships', 'Menu Model': 'Menu Model', 'My Sites': 'My Sites', 'Name': 'Name', 'New password': 'Новый пароль', 'New Record': 'Новая запись', 'new record inserted': 'новая запись добавлена', +'next %s rows': 'next %s rows', 'next 100 rows': 'следующие 100 строк', 'No databases in this application': 'В приложении нет баз данных', 'now': 'сейчас', 'Object or table name': 'Object or table name', 'Old password': 'Старый пароль', +'Online book': 'Online book', 'Online examples': 'примеры он-лайн', 'or import from csv file': 'или импорт из csv-файла', 'Origin': 'Происхождение', @@ -129,11 +144,15 @@ 'Password': 'Пароль', 'password': 'пароль', "Password fields don't match": 'Пароли не совпадают', +'Permission': 'Permission', +'Permissions': 'Permissions', 'Plugins': 'Plugins', 'Powered by': 'Powered by', 'Preface': 'Preface', +'previous %s rows': 'previous %s rows', 'previous 100 rows': 'предыдущие 100 строк', 'profile': 'профиль', +'pygraphviz library not found': 'pygraphviz library not found', 'Python': 'Python', 'Query:': 'Запрос:', 'Quick Examples': 'Quick Examples', @@ -151,10 +170,13 @@ 'Remember me (for 30 days)': 'Запомнить меня (на 30 дней)', 'Reset Password key': 'Сбросить ключ пароля', 'Role': 'Роль', +'Roles': 'Roles', 'Rows in Table': 'Строк в таблице', 'Rows selected': 'Выделено строк', +'Save model as...': 'Save model as...', 'Semantic': 'Semantic', 'Services': 'Services', +'Sign Up': 'Sign Up', 'Size of cache:': 'Size of cache:', 'state': 'состояние', 'Statistics': 'Statistics', @@ -172,16 +194,19 @@ 'This App': 'This App', 'Time in Cache (h:m:s)': 'Time in Cache (h:m:s)', 'Timestamp': 'Отметка времени', +'Traceback': 'Traceback', 'Twitter': 'Twitter', 'unable to parse csv file': 'нечитаемый csv-файл', 'Update:': 'Изменить:', 'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Для построение сложных запросов используйте операторы "И": (...)&(...), "ИЛИ": (...)|(...), "НЕ": ~(...).', +'User': 'User', 'User %(id)s Logged-in': 'Пользователь %(id)s вошёл', 'User %(id)s Logged-out': 'Пользователь %(id)s вышел', 'User %(id)s Password changed': 'Пользователь %(id)s сменил пароль', 'User %(id)s Profile updated': 'Пользователь %(id)s обновил профиль', 'User %(id)s Registered': 'Пользователь %(id)s зарегистрировался', 'User ID': 'ID пользователя', +'Users': 'Users', 'Verify Password': 'Повторите пароль', 'Videos': 'Videos', 'View': 'View', @@ -189,6 +214,7 @@ 'Welcome to web2py': 'Добро пожаловать в web2py', 'Welcome to web2py!': 'Welcome to web2py!', 'Which called the function %s located in the file %s': 'Which called the function %s located in the file %s', +'Working...': 'Working...', 'You are successfully running web2py': 'You are successfully running web2py', 'You can modify this application and adapt it to your needs': 'You can modify this application and adapt it to your needs', 'You visited the url %s': 'You visited the url %s', diff --git a/applications/welcome/languages/sk.py b/applications/welcome/languages/sk.py old mode 100644 new mode 100755 index 88f8343f..0cf6f411 --- a/applications/welcome/languages/sk.py +++ b/applications/welcome/languages/sk.py @@ -1,4 +1,4 @@ -# coding: utf8 +# -*- coding: utf-8 -*- { '!langcode!': 'sk', '!langname!': 'Slovenský', @@ -8,116 +8,135 @@ '%s selected': '%s označených', '%Y-%m-%d': '%d.%m.%Y', '%Y-%m-%d %H:%M:%S': '%d.%m.%Y %H:%M:%S', -'About': 'About', -'Access Control': 'Access Control', -'Administrative Interface': 'Administrative Interface', +'?': '?', +'About': 'O nás', +'Access Control': 'Kontrola prístupu', +'admin': 'admin', +'Administrative Interface': 'Administrátorské rozhranie', 'Administrative interface': 'pre administrátorské rozhranie kliknite sem', -'Ajax Recipes': 'Ajax Recipes', +'Ajax Recipes': 'Ajax recepty', 'appadmin is disabled because insecure channel': 'appadmin je zakázaný bez zabezpečeného spojenia', -'Are you sure you want to delete this object?': 'Are you sure you want to delete this object?', +'Are you sure you want to delete this object?': 'Ste si istý, že chcete vymazať tento objekt?', 'Available Databases and Tables': 'Dostupné databázy a tabuľky', -'Buy this book': 'Buy this book', +'Buy this book': 'Kúpte si túto knihu', +"Buy web2py's book": "Kúpte si web2py's knihu", 'cache': 'cache', 'Cache': 'Cache', -'Cache Keys': 'Cache Keys', +'Cache Cleared': 'Cache vymazané', +'Cache Keys': 'Cache kľúče', 'Cannot be empty': 'Nemôže byť prázdne', 'Check to delete': 'Označiť na zmazanie', -'Clear CACHE?': 'Clear CACHE?', -'Clear DISK': 'Clear DISK', -'Clear RAM': 'Clear RAM', -'Community': 'Community', -'Components and Plugins': 'Components and Plugins', -'Controller': 'Controller', +'Clear CACHE?': 'Vyčistiť CACHE?', +'Clear DISK': 'Vyčistiť DISK', +'Clear RAM': 'Vyčistiť RAM', +'Community': 'komunita', +'Components and Plugins': 'Komponenty a pluginy', +'Config.ini': 'Config.ini', +'Controller': 'Kontrolér', 'Copyright': 'Copyright', 'Current request': 'Aktuálna požiadavka', 'Current response': 'Aktuálna odpoveď', 'Current session': 'Aktuálne sedenie', 'customize me!': 'prispôsob ma!', 'data uploaded': 'údaje naplnené', -'Database': 'databáza', -'Database %s select': 'databáza %s výber', +'Database': 'Databáza', +'Database %s select': 'Databáza %s výber', +'Database Administration (appadmin)': 'Správa databázy (appadmin)', 'db': 'db', 'DB Model': 'DB Model', 'Delete:': 'Zmazať:', 'Demo': 'Demo', -'Deployment Recipes': 'Deployment Recipes', +'Deployment Recipes': 'Recepty pre nasadenie', 'Description': 'Popis', 'design': 'návrh', +'Design': 'Návrh', 'DISK': 'DISK', 'Disk Cache Keys': 'Disk Cache Keys', -'Disk Cleared': 'Disk Cleared', +'Disk Cleared': 'Disk vyčistený', 'Documentation': 'Dokumentácia', -"Don't know what to do?": "Don't know what to do?", +"Don't know what to do?": 'Neviete, čo robiť?', 'done!': 'hotovo!', -'Download': 'Download', +'Download': 'Stiahnuť', 'Edit': 'Upraviť', 'Edit current record': 'Upraviť aktuálny záznam', 'Edit Profile': 'Upraviť profil', -'Email and SMS': 'Email and SMS', -'Errors': 'Errors', +'Email and SMS': 'Email a SMS', +'Errors': 'Chyby', 'export as csv file': 'exportovať do csv súboru', 'FAQ': 'FAQ', 'First name': 'Krstné meno', -'Forms and Validators': 'Forms and Validators', -'Free Applications': 'Free Applications', +'Forms and Validators': 'Formuláre a schvalovače', +'Free Applications': 'Aplikácie zadarmo', +'Graph Model': 'Model grafu', 'Group ID': 'ID skupiny', -'Groups': 'Groups', +'Groups': 'Skupiny', 'Hello World': 'Ahoj svet', -'Home': 'Home', -'How did you get here?': 'How did you get here?', +'Helping web2py': 'Pomáhať web2py', +'Home': 'Domov', +'How did you get here?': 'Ako ste sa sem dostali?', 'import': 'import', 'Import/Export': 'Import/Export', 'Index': 'Index', -'insert new': 'vložiť nový záznam ', -'insert new %s': 'vložiť nový záznam %s', +'insert new': 'vložiť nový', +'insert new %s': 'vložiť nový%s', 'Internal State': 'Vnútorný stav', -'Introduction': 'Introduction', +'Introduction': 'Úvod', 'Invalid email': 'Neplatný email', 'Invalid password': 'Nesprávne heslo', 'Invalid Query': 'Neplatná otázka', 'invalid request': 'Neplatná požiadavka', -'Key': 'Key', +'Key': 'Kľúč', 'Last name': 'Priezvisko', -'Layout': 'Layout', -'Layout Plugins': 'Layout Plugins', -'Layouts': 'Layouts', -'Live Chat': 'Live Chat', +'Layout': 'Usporiadanie', +'Layout Plugins': 'Pluginy pre usporiadanie', +'Layouts': 'Usporiadania', +'Live Chat': 'Živý Chat', +'Log In': 'Prihlásiť sa', 'Logged in': 'Prihlásený', 'Logged out': 'Odhlásený', 'login': 'prihlásiť', 'logout': 'odhlásiť', 'Lost Password': 'Stratené heslo?', 'lost password?': 'stratené heslo?', -'Manage Cache': 'Manage Cache', -'Menu Model': 'Menu Model', -'My Sites': 'My Sites', +'Manage %(action)s': 'Spravovať %(action)s', +'Manage Access Control': 'Spravovať kontrolu prístupu', +'Manage Cache': 'Spravovať cache', +'Memberships': 'Členstvá', +'Menu Model': 'Model menu', +'My Sites': 'Moje stránky', 'Name': 'Meno', 'New password': 'Nové heslo', 'New Record': 'Nový záznam', 'new record inserted': 'nový záznam bol vložený', +'next %s rows': 'next %s rows', 'next 100 rows': 'ďalších 100 riadkov', 'No databases in this application': 'V tejto aplikácii nie sú databázy', 'Old password': 'Staré heslo', -'Online examples': 'pre online príklady kliknite sem', +'Online book': 'Online kniha', +'Online examples': 'online príklady', 'or import from csv file': 'alebo naimportovať z csv súboru', 'Origin': 'Pôvod', -'Other Plugins': 'Other Plugins', -'Other Recipes': 'Other Recipes', -'Overview': 'Overview', +'Other Plugins': 'Ostatné pluginy', +'Other Recipes': 'Ostatné recepty', +'Overview': 'Náhľad', 'password': 'heslo', 'Password': 'Heslo', -'Plugins': 'Plugins', -'Powered by': 'Powered by', -'Preface': 'Preface', +'Permission': 'Povolenie', +'Permissions': 'Povolenia', +'Plugins': 'Pluginy', +'Powered by': 'Beží na', +'Preface': 'Predslov', +'previous %s rows': 'predchádzajúce %s riadky', 'previous 100 rows': 'predchádzajúcich 100 riadkov', +'pygraphviz library not found': 'knižnica pygraphviz nenájdená', 'Python': 'Python', 'Query:': 'Otázka:', -'Quick Examples': 'Quick Examples', +'Quick Examples': 'Rýchle príklady', 'RAM': 'RAM', -'RAM Cache Keys': 'RAM Cache Keys', -'Ram Cleared': 'Ram Cleared', -'Recipes': 'Recipes', -'Record': 'záznam', +'RAM Cache Keys': 'RAM cache kľúče', +'Ram Cleared': 'Ram vyčistená', +'Recipes': 'Recepty', +'Record': 'Záznam', 'record does not exist': 'záznam neexistuje', 'Record ID': 'ID záznamu', 'Record id': 'id záznamu', @@ -127,44 +146,51 @@ 'Remember me (for 30 days)': 'Zapamätaj si ma (na 30 dní)', 'Reset Password key': 'Nastaviť registračný kľúč', 'Role': 'Rola', -'Rows in Table': 'riadkov v tabuľke', -'Rows selected': 'označených riadkov', -'Semantic': 'Semantic', -'Services': 'Services', -'Size of cache:': 'Size of cache:', +'Roles': 'Role', +'Rows in Table': 'Riadkov v tabuľke', +'Rows selected': 'Označených riadkov', +'Save model as...': 'Uložiť model ako...', +'Semantic': 'Významový', +'Services': 'Služby', +'Sign Up': 'Prihlásiť sa', +'Size of cache:': 'Veľkosť cache:', 'state': 'stav', -'Statistics': 'Statistics', +'Statistics': 'Štatistiky', 'Stylesheet': 'Stylesheet', -'submit': 'submit', +'submit': 'odoslať', 'Submit': 'Odoslať', -'Support': 'Support', +'Support': 'Podpora', 'Sure you want to delete this object?': 'Ste si istí, že chcete zmazať tento objekt?', -'Table': 'tabuľka', +'Table': 'Tabuľka', 'Table name': 'Názov tabuľky', 'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.': '"query" je podmienka ako "db.table1.field1==\'value\'". Niečo ako "db.table1.field1==db.table2.field2" má za výsledok SQL JOIN.', -'The Core': 'The Core', -'The output of the file is a dictionary that was rendered by the view %s': 'Výstup zo súboru je slovník, ktorý bol zobrazený vo view %s', -'The Views': 'The Views', -'This App': 'This App', +'The Core': 'Jadro', +'The output of the file is a dictionary that was rendered by the view %s': 'Výstup zo súboru je slovník, ktorý bol vykreslený v zobrazení %s', +'The Views': 'Zobrazenia', +'This App': 'Táto aplikácia', 'This is a copy of the scaffolding application': 'Toto je kópia skeletu aplikácie', -'Time in Cache (h:m:s)': 'Time in Cache (h:m:s)', +'Time in Cache (h:m:s)': 'Čas v cache (h:m:s)', 'Timestamp': 'Časová pečiatka', +'Traceback': 'Vystopovať', 'Twitter': 'Twitter', 'unable to parse csv file': 'nedá sa načítať csv súbor', 'Update:': 'Upraviť:', 'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Použite (...)&(...) pre AND, (...)|(...) pre OR a ~(...) pre NOT na poskladanie komplexnejších otázok.', +'User': 'User', 'User %(id)s Logged-in': 'Používateľ %(id)s prihlásený', 'User %(id)s Logged-out': 'Používateľ %(id)s odhlásený', 'User %(id)s Password changed': 'Používateľ %(id)s zmenil heslo', 'User %(id)s Profile updated': 'Používateľ %(id)s upravil profil', 'User %(id)s Registered': 'Používateľ %(id)s sa zaregistroval', 'User ID': 'ID používateľa', +'Users': 'Používatelia', 'Verify Password': 'Zopakujte heslo', -'Videos': 'Videos', +'Videos': 'Videá', 'View': 'Zobraziť', 'Welcome to web2py': 'Vitajte vo web2py', -'Welcome to web2py!': 'Welcome to web2py!', +'Welcome to web2py!': 'Vitajte vo web2py!', 'Which called the function %s located in the file %s': 'Ktorý zavolal funkciu %s nachádzajúci sa v súbore %s', +'Working...': 'Pracuje...', 'You are successfully running web2py': 'Úspešne ste spustili web2py', 'You can modify this application and adapt it to your needs': 'Môžete upraviť túto aplikáciu a prispôsobiť ju svojim potrebám', 'You visited the url %s': 'Navštívili ste URL %s', diff --git a/applications/welcome/languages/tr.py b/applications/welcome/languages/tr.py old mode 100644 new mode 100755 index bf5d4e1a..23d0b87c --- a/applications/welcome/languages/tr.py +++ b/applications/welcome/languages/tr.py @@ -1,4 +1,4 @@ -# coding: utf-8 +# -*- coding: utf-8 -*- { '!langcode!': 'tr', '!langname!': 'Türkçe', @@ -6,34 +6,51 @@ '%s %%(shop)': '%s %%(shop)', '%s %%(shop[0])': '%s %%(shop[0])', '%s %%{quark[0]}': '%s %%{quark[0]}', +'%s %%{row} deleted': '%s %%{row} deleted', +'%s %%{row} updated': '%s %%{row} updated', '%s %%{shop[0]}': '%s %%{shop[0]}', '%s %%{shop}': '%s %%{shop}', '%s selected': '%s selected', '%Y-%m-%d': '%d-%m-%Y', '%Y-%m-%d %H:%M:%S': '%d-%m-%Y %H:%M:%S', +'?': '?', '@markmin\x01**Hello World**': '**Merhaba Dünya**', '@markmin\x01An error occured, please [[reload %s]] the page': 'Bir hata oluştu, lütfen sayfayı [[yenileyin yükleyin %s]] ', 'About': 'Hakkında', 'Access Control': 'Erişim Denetimi', +'admin': 'admin', 'Administrative Interface': 'Yönetim Arayüzü', 'Ajax Recipes': 'Ajax Tarifleri', 'An error occured, please %s the page': 'Bir hata meydana geldi, lütfen sayfayı %s', +'appadmin is disabled because insecure channel': 'appadmin is disabled because insecure channel', 'Apply changes': 'Değişiklikleri uygula', 'Are you sure you want to delete this object?': 'Bu nesneyi silmek istediğinden emin misin?', 'Available Databases and Tables': 'Kullanılabilir Varitabanları ve Tablolar', 'Buy this book': 'Bu kitabı satın alın', +"Buy web2py's book": "Buy web2py's book", 'cache': 'zula', +'Cache': 'Cache', +'Cache Cleared': 'Cache Cleared', +'Cache Keys': 'Cache Keys', 'Cannot be empty': 'Boş bırakılamaz', 'Change password': 'Parolayı değiştir', 'Check to delete': 'Silmek için denetle', +'Clear CACHE?': 'Clear CACHE?', +'Clear DISK': 'Clear DISK', +'Clear RAM': 'Clear RAM', 'Client IP': 'İstemci IP', 'Community': 'Topluluk', 'Components and Plugins': 'Bileşenler ve Eklentiler', +'Config.ini': 'Config.ini', 'Controller': 'Denetçi', 'Copyright': 'Telif', 'Created By': 'Tasarlayan', 'Created On': 'Oluşturma tarihi', +'Current request': 'Current request', +'Current response': 'Current response', +'Current session': 'Current session', 'customize me!': 'burayı değiştir!', +'data uploaded': 'data uploaded', 'Database': 'Veritabanı', 'Database %s select': '%s veritabanı seç', 'Database Administration (appadmin)': 'Veritabanı Yönetimi (appadmin)', @@ -44,10 +61,16 @@ 'Deployment Recipes': 'Yayınlama tarifleri', 'Description': 'Açıklama', 'design': 'tasarım', +'Design': 'Design', +'DISK': 'DISK', +'Disk Cache Keys': 'Disk Cache Keys', +'Disk Cleared': 'Disk Cleared', 'Documentation': 'Kitap', "Don't know what to do?": 'Neleri nasıl yapacağını bilmiyor musun?', +'done!': 'done!', 'Download': 'İndir', 'E-mail': 'E-posta', +'Edit current record': 'Edit current record', 'Email and SMS': 'E-posta ve kısa mesaj (SMS)', 'enter a value': 'bir değer giriniz', 'enter an integer between %(min)g and %(max)g': '%(min)g ve %(max)g arasında bir sayı girin', @@ -69,25 +92,36 @@ 'Hello World': 'Merhaba Dünya', 'Hello World ## comment': 'Merhaba Dünya ## yorum ', 'Hello World## comment': 'Merhaba Dünya## yorum ', +'Helping web2py': 'Helping web2py', 'Home': 'Anasayfa', 'How did you get here?': 'Bu sayfayı görüntüleme uğruna neler mi oldu?', 'import': 'import', 'Import/Export': 'Dışa/İçe Aktar', +'Internal State': 'Internal State', 'Introduction': 'Giriş', +'invalid controller': 'geçersiz denetleyici', 'Invalid email': 'Yanlış eposta', +'Invalid Query': 'Invalid Query', +'invalid request': 'invalid request', 'Is Active': 'Etkin', 'Kayıt ol': 'Kayıt ol', +'Key': 'Key', 'Last name': 'Soyad', 'Layout': 'Şablon', 'Layout Plugins': 'Şablon Eklentileri', 'Layouts': 'Şablonlar', 'Live Chat': 'Canlı Sohbet', +'Log In': 'Log In', 'Logged in': 'Giriş yapıldı', 'Logged out': 'Çıkış yapıldı', 'Login': 'Giriş', 'Logout': 'Terket', 'Lost Password': 'Şifremi unuttum', 'Lost password?': 'Şifrenizimi unuttunuz?', +'Manage %(action)s': 'Manage %(action)s', +'Manage Access Control': 'Manage Access Control', +'Manage Cache': 'Manage Cache', +'Memberships': 'Memberships', 'Menu Model': 'Model Menü', 'Modified By': 'Değiştiren', 'Modified On': 'Değiştirilme tarihi', @@ -95,8 +129,12 @@ 'Name': 'İsim', 'New password': 'Yeni parola', 'New Record': 'Yeni Kayıt', +'new record inserted': 'new record inserted', +'next %s rows': 'next %s rows', +'No databases in this application': 'No databases in this application', 'Object or table name': 'Nesne ya da tablo adı', 'Old password': 'Eski parola', +'Online book': 'Online book', 'Online examples': 'Canlı örnekler', 'or import from csv file': 'veya csv dosyasından içe aktar', 'Origin': 'Asıl', @@ -105,17 +143,26 @@ 'Overview': 'Göz gezdir', 'Password': 'Parola', "Password fields don't match": 'Parolalar uyuşmuyor', +'Permission': 'Permission', +'Permissions': 'Permissions', 'please input your password again': 'lütfen parolanızı tekrar girin', 'Plugins': 'Eklentiler', 'Powered by': 'Yazılım Temeli', 'Preface': 'Önzös', +'previous %s rows': 'previous %s rows', 'Profile': 'Profil', 'pygraphviz library not found': 'pygraphviz library not found', 'Python': 'Python', 'Query:': 'Sorgu:', 'Quick Examples': 'Hızlı Örnekler', +'RAM': 'RAM', +'RAM Cache Keys': 'RAM Cache Keys', +'Ram Cleared': 'Ram Cleared', 'Recipes': 'Tarifeler', +'Record': 'Record', +'record does not exist': 'record does not exist', 'Record ID': 'Kayıt ID', +'Record id': 'Record id', 'Register': 'Kayıt ol', 'Registration identifier': 'Kayıt belirleyicisi', 'Registration key': 'Kayıt anahtarı', @@ -125,11 +172,16 @@ 'Request reset password': 'Parolanı sıfırla', 'Reset Password key': 'Parola anahtarını sıfırla', 'Role': 'Rol', +'Roles': 'Roles', 'Rows in Table': 'Tablodaki Satırlar', +'Rows selected': 'Rows selected', 'Save model as...': 'Modeli farklı kaydet...', 'Semantic': 'Anlamsal', 'Services': 'Hizmetler', +'Sign Up': 'Sign Up', +'Size of cache:': 'Size of cache:', 'state': 'durum', +'Statistics': 'Statistics', 'Stylesheet': 'Stil Şablonu', 'submit': 'gönder', 'Submit': 'Gönder', @@ -141,15 +193,20 @@ 'The Views': 'Görünümler', 'This App': 'Bu Uygulama', 'This email already has an account': 'Bu e-postaya ait bir hesap zaten var', +'Time in Cache (h:m:s)': 'Time in Cache (h:m:s)', 'Timestamp': 'Zaman damgası', +'Traceback': 'Traceback', 'Twitter': 'Twitter', +'unable to parse csv file': 'unable to parse csv file', 'Update:': 'Güncelle:', 'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Karmaşık sorgularda Ve (AND) için (...)&(...) kullanın, Veya (OR) için (...)|(...) kullanın ve DEĞİL (NOT) için ~(...) kullanın. ', +'User': 'User', 'User %(id)s Logged-in': '%(id)s Giriş yaptı', 'User %(id)s Logged-out': '%(id)s çıkış yaptı', 'User %(id)s Password reset': 'Kullanıc %(id)s Parolasını sıfırla', 'User %(id)s Registered': '%(id)s Kayıt oldu', 'User ID': 'Kullanıcı ID', +'Users': 'Users', 'value already in database or empty': 'değer boş ya da veritabanında zaten mevcut', 'Verify Password': 'Parolanı Onayla', 'Videos': 'Videolar', @@ -161,6 +218,4 @@ 'You are successfully running web2py': 'web2py çatısını çalıştırmayı başardın', 'You can modify this application and adapt it to your needs': 'Artık uygulamayı istediğin gibi düzenleyebilirsin!', 'You visited the url %s': '%s adresini ziyaret ettin', -'invalid controller': 'geçersiz denetleyici', } - diff --git a/applications/welcome/languages/uk.py b/applications/welcome/languages/uk.py old mode 100644 new mode 100755 index 17bfde51..b40fd1dd --- a/applications/welcome/languages/uk.py +++ b/applications/welcome/languages/uk.py @@ -1,4 +1,4 @@ -# coding: utf8 +# -*- coding: utf-8 -*- { '!langcode!': 'uk', '!langname!': 'Українська', @@ -22,6 +22,7 @@ '1 second ago': '1 секунду тому', '1 week ago': '1 тиждень тому', '1 year ago': '1 рік тому', +'?': '?', '@markmin\x01(**%.0d MB**)': '(**``%.0d``:red МБ**)', '@markmin\x01**%(items)s** %%{item(items)}, **%(bytes)s** %%{byte(bytes)}': '**%(items)s** %%{елемент(items)}, **%(bytes)s** %%{байт(bytes)}', '@markmin\x01``**not available**``:red (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)': '``**нема в наявності**``:red (потребує Пітонівської бібліотеки [[guppy [посилання відкриється у новому вікні] http://pypi.python.org/pypi/guppy/ popup]])', @@ -33,14 +34,17 @@ '@markmin\x01RAM contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.': "Час життя об'єктів в ОЗП-КЕШІ сягає **%(hours)02d** %%{годину(hours)} **%(min)02d** %%{хвилину(min)} та **%(sec)02d** %%{секунду(sec)}.", 'About': 'Про додаток', 'Access Control': 'Контроль доступу', +'admin': 'admin', 'Administrative Interface': 'Адміністративний інтерфейс', 'Ajax Recipes': 'Рецепти для Ajax', 'appadmin is disabled because insecure channel': 'використовується незахищенний канал (HTTP). Appadmin вимкнено', 'Are you sure you want to delete this object?': "Ви впевнені, що хочете вилучити цей об'єкт?", 'Available Databases and Tables': 'Доступні бази даних та таблиці', 'Buy this book': 'Купити книжку', +"Buy web2py's book": "Buy web2py's book", 'cache': 'кеш', 'Cache': 'Кеш', +'Cache Cleared': 'Cache Cleared', 'Cache Keys': 'Ключі кешу', 'Cannot be empty': 'Порожнє значення неприпустиме', 'Change password': 'Змінити пароль', @@ -52,6 +56,7 @@ 'Client IP': 'IP клієнта', 'Community': 'Спільнота', 'Components and Plugins': 'Компоненти та втулки', +'Config.ini': 'Config.ini', 'Controller': 'Контролер', 'Copyright': 'Правовласник', 'Created By': 'Створив(ла)', @@ -71,6 +76,7 @@ 'Deployment Recipes': 'Способи розгортання', 'Description': 'Опис', 'design': 'налаштування', +'Design': 'Design', 'DISK': 'ДИСК', 'Disk Cache Keys': 'Ключі дискового кешу', 'Disk Cleared': 'Дисковий кеш очищено', @@ -100,6 +106,7 @@ 'Group uniquely assigned to user %(id)s': "Група унікально зв'язана з користувачем %(id)s", 'Groups': 'Групи', 'Hello World': 'Привіт, світ!', +'Helping web2py': 'Helping web2py', 'Home': 'Початок', 'How did you get here?': 'Як цього було досягнуто?', 'import': 'Імпортувати', @@ -120,13 +127,17 @@ 'Layout Plugins': 'Втулки макетів', 'Layouts': 'Макети', 'Live Chat': 'Чат', +'Log In': 'Log In', 'Logged in': 'Вхід здійснено', 'Logged out': 'Вихід здійснено', 'Login': 'Вхід', 'Logout': 'Вихід', 'Lost Password': 'Забули пароль', 'Lost password?': 'Забули пароль?', +'Manage %(action)s': 'Manage %(action)s', +'Manage Access Control': 'Manage Access Control', 'Manage Cache': 'Управління кешем', +'Memberships': 'Memberships', 'Menu Model': 'Модель меню', 'Modified By': 'Зміни провадив(ла)', 'Modified On': 'Змінено в', @@ -135,11 +146,13 @@ 'New password': 'Новий пароль', 'New Record': 'Новий запис', 'new record inserted': 'новий рядок додано', +'next %s rows': 'next %s rows', 'next 100 rows': 'наступні 100 рядків', 'No databases in this application': 'Даний додаток не використовує базу даних', 'now': 'зараз', 'Object or table name': "Об'єкт або назва таблиці", 'Old password': 'Старий пароль', +'Online book': 'Online book', 'Online examples': 'Зразковий демо-сайт', 'or import from csv file': 'або імпортувати з csv-файлу', 'Origin': 'Походження', @@ -151,10 +164,13 @@ 'Password': 'Пароль', 'Password changed': 'Пароль змінено', "Password fields don't match": 'Пароль не співпав', +'Permission': 'Permission', +'Permissions': 'Permissions', 'please input your password again': 'Будь-ласка введіть пароль ще раз', 'Plugins': 'Втулки (Plugins)', 'Powered by': 'Працює на', 'Preface': 'Передмова', +'previous %s rows': 'previous %s rows', 'previous 100 rows': 'попередні 100 рядків', 'Profile': 'Параметри', 'Profile updated': 'Параметри змінено', @@ -180,11 +196,14 @@ 'Request reset password': 'Запит на зміну пароля', 'Reset Password key': 'Ключ скидання пароля', 'Role': 'Роль', +'Roles': 'Roles', 'Rows in Table': 'Рядки в таблиці', 'Rows selected': 'Відмічено рядків', +'Save model as...': 'Save model as...', 'Save profile': 'Зберегти параметри', 'Semantic': 'Семантика', 'Services': 'Сервіс', +'Sign Up': 'Sign Up', 'Size of cache:': 'Розмір кешу:', 'state': 'стан', 'Statistics': 'Статистика', @@ -202,10 +221,12 @@ 'Time in Cache (h:m:s)': 'Час знаходження в кеші (h:m:s)', 'Timestamp': 'Відмітка часу', 'too short': 'Занадто короткий', +'Traceback': 'Traceback', 'Twitter': 'Твіттер', 'unable to parse csv file': 'не вдається розібрати csv-файл', 'Update:': 'Оновити:', 'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Для створення складних запитів використовуйте (...)&(...) замість AND, (...)|(...) замість OR, та ~(...) замість NOT.', +'User': 'User', 'User %(id)s Logged-in': 'Користувач %(id)s увійшов', 'User %(id)s Logged-out': 'Користувач %(id)s вийшов', 'User %(id)s Password changed': 'Користувач %(id)s змінив свій пароль', @@ -213,6 +234,7 @@ 'User %(id)s Profile updated': 'Параметри користувача %(id)s змінено', 'User %(id)s Registered': 'Користувач %(id)s зареєструвався', 'User ID': 'Ід.користувача', +'Users': 'Users', 'value already in database or empty': 'значення вже в базі даних або порожнє', 'Verify Password': 'Повторити пароль', 'Videos': 'Відео', diff --git a/applications/welcome/languages/zh-cn.py b/applications/welcome/languages/zh-cn.py old mode 100644 new mode 100755 index 61009f6e..888040c5 --- a/applications/welcome/languages/zh-cn.py +++ b/applications/welcome/languages/zh-cn.py @@ -1,4 +1,4 @@ -# coding: utf8 +# -*- coding: utf-8 -*- { '!langcode!': 'zh-cn', '!langname!': '中文', @@ -9,12 +9,14 @@ '%Y-%m-%d': '%Y-%m-%d', '%Y-%m-%d %H:%M:%S': '%Y-%m-%d %H:%M:%S', '(something like "it-it")': '(格式类似 "zh-tw")', +'?': '?', 'A new version of web2py is available': '新版 web2py 已推出', 'A new version of web2py is available: %s': '新版 web2py 已推出: %s', 'about': '关于', 'About': '关于', 'About application': '关于本应用程序', 'Access Control': 'Access Control', +'admin': 'admin', 'Admin is disabled because insecure channel': '管理功能(Admin)在非安全连接环境下自动关闭', 'Admin is disabled because unsecure channel': '管理功能(Admin)在非安全连接环境下自动关闭', 'Administrative Interface': 'Administrative Interface', @@ -33,8 +35,10 @@ 'Authentication': '验证', 'Available Databases and Tables': '可提供的数据库和数据表', 'Buy this book': '购买本书', +"Buy web2py's book": "Buy web2py's book", 'cache': '高速缓存', 'Cache': 'Cache', +'Cache Cleared': 'Cache Cleared', 'Cache Keys': 'Cache Keys', 'Cannot be empty': '不可空白', 'Cannot compile: there are errors in your app. Debug it, correct errors and try again.': '编译失败:应用程序有错误,请排除错误后再尝试编译.', @@ -48,6 +52,7 @@ 'Client IP': '客户端网址(IP)', 'Community': 'Community', 'Components and Plugins': 'Components and Plugins', +'Config.ini': 'Config.ini', 'Controller': '控件', 'Controllers': '控件', 'Copyright': '版权所有', @@ -61,6 +66,7 @@ 'data uploaded': '数据已上传', 'Database': '数据库', 'Database %s select': '已选择 %s 数据库', +'Database Administration (appadmin)': 'Database Administration (appadmin)', 'Date and Time': '日期和时间', 'db': 'db', 'DB Model': '数据库模型', @@ -71,6 +77,7 @@ 'Deployment Recipes': 'Deployment Recipes', 'Description': '描述', 'DESIGN': '设计', +'Design': 'Design', 'design': '设计', 'Design for': '设计用于', 'DISK': 'DISK', @@ -101,9 +108,11 @@ 'Forms and Validators': 'Forms and Validators', 'Free Applications': 'Free Applications', 'Functions with no doctests will result in [passed] tests.': '沒有 doctests 的函数会显示 [passed].', +'Graph Model': 'Graph Model', 'Group ID': '群组编号', 'Groups': 'Groups', 'Hello World': 'Hello World', +'Helping web2py': 'Helping web2py', 'Home': 'Home', 'How did you get here?': 'How did you get here?', 'import': 'import', @@ -129,6 +138,7 @@ 'Layouts': 'Layouts', 'License for': '软件授权', 'Live Chat': 'Live Chat', +'Log In': 'Log In', 'login': '登录', 'Login': '登录', 'Login to the Administrative Interface': '登录到管理员界面', @@ -137,7 +147,10 @@ 'Lost Password': '忘记密码', 'Lost password?': '忘记密码?', 'Main Menu': '主菜单', +'Manage %(action)s': 'Manage %(action)s', +'Manage Access Control': 'Manage Access Control', 'Manage Cache': 'Manage Cache', +'Memberships': 'Memberships', 'Menu Model': '菜单模型(menu)', 'Models': '数据模型', 'Modified By': '修改者', @@ -147,10 +160,12 @@ 'Name': '名字', 'New Record': '新记录', 'new record inserted': '已插入新记录', +'next %s rows': 'next %s rows', 'next 100 rows': '往后 100 笔', 'NO': '否', 'No databases in this application': '该应用程序不含数据库', 'Object or table name': 'Object or table name', +'Online book': 'Online book', 'Online examples': '点击进入在线例子', 'or import from csv file': '或导入CSV文件', 'Origin': '原文', @@ -161,10 +176,14 @@ 'Password': '密码', "Password fields don't match": '密码不匹配', 'Peeking at file': '选择文件', +'Permission': 'Permission', +'Permissions': 'Permissions', 'Plugins': 'Plugins', 'Powered by': '基于下列技术构建:', 'Preface': 'Preface', +'previous %s rows': 'previous %s rows', 'previous 100 rows': '往前 100 笔', +'pygraphviz library not found': 'pygraphviz library not found', 'Python': 'Python', 'Query:': '查询:', 'Quick Examples': 'Quick Examples', @@ -185,11 +204,14 @@ 'Reset Password key': '重置密码', 'Resolve Conflict file': '解决冲突文件', 'Role': '角色', +'Roles': 'Roles', 'Rows in Table': '在数据表里的记录', 'Rows selected': '笔记录被选择', +'Save model as...': 'Save model as...', 'Saved file hash:': '已保存文件的哈希值:', 'Semantic': 'Semantic', 'Services': 'Services', +'Sign Up': 'Sign Up', 'Size of cache:': 'Size of cache:', 'state': '状态', 'Static files': '静态文件', @@ -217,6 +239,7 @@ 'Ticket': '问题清单', 'Time in Cache (h:m:s)': 'Time in Cache (h:m:s)', 'Timestamp': '时间戳', +'Traceback': 'Traceback', 'Twitter': 'Twitter', 'Unable to check for upgrades': '查询新版本失败', 'Unable to download': '无法下载', @@ -225,9 +248,11 @@ 'Update:': '更新:', 'Upload existing application': '上传已有应用程序', 'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': '使用下列方式可得到更复杂的条件表达式, (...)&(...) 代表必须都满足, (...)|(...) 代表其一, ~(...)则代表否.', +'User': 'User', 'User %(id)s Logged-in': '用户 %(id)s 已登录', 'User %(id)s Registered': '用户 %(id)s 已注册', 'User ID': '用户编号', +'Users': 'Users', 'Verify Password': '验证密码', 'Videos': '视频', 'View': '查看', @@ -237,6 +262,7 @@ 'Welcome to web2py': '欢迎使用 web2py', 'Welcome to web2py!': '欢迎使用 web2py!', 'Which called the function %s located in the file %s': 'Which called the function %s located in the file %s', +'Working...': 'Working...', 'YES': '是', 'You are successfully running web2py': '您已成功运行 web2py', 'You can modify this application and adapt it to your needs': '请根据您的需要修改本程序', diff --git a/applications/welcome/languages/zh-tw.py b/applications/welcome/languages/zh-tw.py old mode 100644 new mode 100755 index 5b109604..33e94daf --- a/applications/welcome/languages/zh-tw.py +++ b/applications/welcome/languages/zh-tw.py @@ -1,4 +1,4 @@ -# coding: utf8 +# -*- coding: utf-8 -*- { '!langcode!': 'zh-cn', '!langname!': '中文', @@ -9,12 +9,14 @@ '%Y-%m-%d': '%Y-%m-%d', '%Y-%m-%d %H:%M:%S': '%Y-%m-%d %H:%M:%S', '(something like "it-it")': '(格式類似 "zh-tw")', +'?': '?', 'A new version of web2py is available': '新版的 web2py 已發行', 'A new version of web2py is available: %s': '新版的 web2py 已發行: %s', 'about': '關於', 'About': '關於', 'About application': '關於本應用程式', 'Access Control': 'Access Control', +'admin': 'admin', 'Admin is disabled because insecure channel': '管理功能(Admin)在不安全連線環境下自動關閉', 'Admin is disabled because unsecure channel': '管理功能(Admin)在不安全連線環境下自動關閉', 'Administrative Interface': 'Administrative Interface', @@ -33,8 +35,10 @@ 'Authentication': '驗證', 'Available Databases and Tables': '可提供的資料庫和資料表', 'Buy this book': 'Buy this book', +"Buy web2py's book": "Buy web2py's book", 'cache': '快取記憶體', 'Cache': 'Cache', +'Cache Cleared': 'Cache Cleared', 'Cache Keys': 'Cache Keys', 'Cannot be empty': '不可空白', 'Cannot compile: there are errors in your app. Debug it, correct errors and try again.': '無法編譯:應用程式中含有錯誤,請除錯後再試一次.', @@ -48,6 +52,7 @@ 'Client IP': '客戶端網址(IP)', 'Community': 'Community', 'Components and Plugins': 'Components and Plugins', +'Config.ini': 'Config.ini', 'Controller': '控件', 'Controllers': '控件', 'Copyright': '版權所有', @@ -61,6 +66,7 @@ 'data uploaded': '資料已上傳', 'Database': '資料庫', 'Database %s select': '已選擇 %s 資料庫', +'Database Administration (appadmin)': 'Database Administration (appadmin)', 'Date and Time': '日期和時間', 'db': 'db', 'DB Model': '資料庫模組', @@ -71,6 +77,7 @@ 'Deployment Recipes': 'Deployment Recipes', 'Description': '描述', 'DESIGN': '設計', +'Design': 'Design', 'design': '設計', 'Design for': '設計為了', 'DISK': 'DISK', @@ -101,9 +108,11 @@ 'Forms and Validators': 'Forms and Validators', 'Free Applications': 'Free Applications', 'Functions with no doctests will result in [passed] tests.': '沒有 doctests 的函式會顯示 [passed].', +'Graph Model': 'Graph Model', 'Group ID': '群組編號', 'Groups': 'Groups', 'Hello World': '嗨! 世界', +'Helping web2py': 'Helping web2py', 'Home': 'Home', 'How did you get here?': 'How did you get here?', 'import': 'import', @@ -129,6 +138,7 @@ 'Layouts': 'Layouts', 'License for': '軟體版權為', 'Live Chat': 'Live Chat', +'Log In': 'Log In', 'login': '登入', 'Login': '登入', 'Login to the Administrative Interface': '登入到管理員介面', @@ -137,7 +147,10 @@ 'Lost Password': '密碼遺忘', 'Lost password?': 'Lost password?', 'Main Menu': '主選單', +'Manage %(action)s': 'Manage %(action)s', +'Manage Access Control': 'Manage Access Control', 'Manage Cache': 'Manage Cache', +'Memberships': 'Memberships', 'Menu Model': '選單模組(menu)', 'Models': '資料模組', 'Modified By': 'Modified By', @@ -147,10 +160,12 @@ 'Name': '名字', 'New Record': '新紀錄', 'new record inserted': '已插入新紀錄', +'next %s rows': 'next %s rows', 'next 100 rows': '往後 100 筆', 'NO': '否', 'No databases in this application': '這應用程式不含資料庫', 'Object or table name': 'Object or table name', +'Online book': 'Online book', 'Online examples': '點此處進入線上範例', 'or import from csv file': '或是從逗號分隔檔(CSV)匯入', 'Origin': '原文', @@ -161,10 +176,14 @@ 'Password': '密碼', "Password fields don't match": '密碼欄不匹配', 'Peeking at file': '選擇檔案', +'Permission': 'Permission', +'Permissions': 'Permissions', 'Plugins': 'Plugins', 'Powered by': '基於以下技術構建:', 'Preface': 'Preface', +'previous %s rows': 'previous %s rows', 'previous 100 rows': '往前 100 筆', +'pygraphviz library not found': 'pygraphviz library not found', 'Python': 'Python', 'Query:': '查詢:', 'Quick Examples': 'Quick Examples', @@ -185,11 +204,14 @@ 'Reset Password key': '重設密碼', 'Resolve Conflict file': '解決衝突檔案', 'Role': '角色', +'Roles': 'Roles', 'Rows in Table': '在資料表裏的資料', 'Rows selected': '筆資料被選擇', +'Save model as...': 'Save model as...', 'Saved file hash:': '檔案雜湊值已紀錄:', 'Semantic': 'Semantic', 'Services': 'Services', +'Sign Up': 'Sign Up', 'Size of cache:': 'Size of cache:', 'state': '狀態', 'Static files': '靜態檔案', @@ -217,6 +239,7 @@ 'Ticket': '問題單', 'Time in Cache (h:m:s)': 'Time in Cache (h:m:s)', 'Timestamp': '時間標記', +'Traceback': 'Traceback', 'Twitter': 'Twitter', 'Unable to check for upgrades': '無法做升級檢查', 'Unable to download': '無法下載', @@ -225,9 +248,11 @@ 'Update:': '更新:', 'Upload existing application': '更新存在的應用程式', 'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': '使用下列方式來組合更複雜的條件式, (...)&(...) 代表同時存在的條件, (...)|(...) 代表擇一的條件, ~(...)則代表反向條件.', +'User': 'User', 'User %(id)s Logged-in': '使用者 %(id)s 已登入', 'User %(id)s Registered': '使用者 %(id)s 已註冊', 'User ID': '使用者編號', +'Users': 'Users', 'Verify Password': '驗證密碼', 'Videos': 'Videos', 'View': '視圖', @@ -237,6 +262,7 @@ 'Welcome to web2py': '歡迎使用 web2py', 'Welcome to web2py!': 'Welcome to web2py!', 'Which called the function %s located in the file %s': 'Which called the function %s located in the file %s', +'Working...': 'Working...', 'YES': '是', 'You are successfully running web2py': 'You are successfully running web2py', 'You can modify this application and adapt it to your needs': 'You can modify this application and adapt it to your needs', diff --git a/applications/welcome/languages/zh.py b/applications/welcome/languages/zh.py old mode 100644 new mode 100755 index 263918ce..e92241a2 --- a/applications/welcome/languages/zh.py +++ b/applications/welcome/languages/zh.py @@ -1,4 +1,4 @@ -# coding: utf8 +# -*- coding: utf-8 -*- { '!langcode!': 'zh-tw', '!langname!': '中文', @@ -9,12 +9,14 @@ '%Y-%m-%d': '%Y-%m-%d', '%Y-%m-%d %H:%M:%S': '%Y-%m-%d %H:%M:%S', '(something like "it-it")': '(格式類似 "zh-tw")', +'?': '?', 'A new version of web2py is available': '新版的 web2py 已發行', 'A new version of web2py is available: %s': '新版的 web2py 已發行: %s', 'about': '關於', 'About': '關於', 'About application': '關於本應用程式', 'Access Control': 'Access Control', +'admin': 'admin', 'Admin is disabled because insecure channel': '管理功能(Admin)在不安全連線環境下自動關閉', 'Admin is disabled because unsecure channel': '管理功能(Admin)在不安全連線環境下自動關閉', 'Administrative Interface': 'Administrative Interface', @@ -32,8 +34,10 @@ 'Authentication': '驗證', 'Available Databases and Tables': '可提供的資料庫和資料表', 'Buy this book': 'Buy this book', +"Buy web2py's book": "Buy web2py's book", 'cache': '快取記憶體', 'Cache': 'Cache', +'Cache Cleared': 'Cache Cleared', 'Cache Keys': 'Cache Keys', 'Cannot be empty': '不可空白', 'Cannot compile: there are errors in your app. Debug it, correct errors and try again.': '無法編譯:應用程式中含有錯誤,請除錯後再試一次.', @@ -47,6 +51,7 @@ 'Client IP': '客戶端網址(IP)', 'Community': 'Community', 'Components and Plugins': 'Components and Plugins', +'Config.ini': 'Config.ini', 'Controller': '控件', 'Controllers': '控件', 'Copyright': '版權所有', @@ -58,6 +63,7 @@ 'data uploaded': '資料已上傳', 'Database': '資料庫', 'Database %s select': '已選擇 %s 資料庫', +'Database Administration (appadmin)': 'Database Administration (appadmin)', 'Date and Time': '日期和時間', 'db': 'db', 'DB Model': '資料庫模組', @@ -68,6 +74,7 @@ 'Deployment Recipes': 'Deployment Recipes', 'Description': '描述', 'DESIGN': '設計', +'Design': 'Design', 'design': '設計', 'Design for': '設計為了', 'DISK': 'DISK', @@ -96,9 +103,11 @@ 'Forms and Validators': 'Forms and Validators', 'Free Applications': 'Free Applications', 'Functions with no doctests will result in [passed] tests.': '沒有 doctests 的函式會顯示 [passed].', +'Graph Model': 'Graph Model', 'Group ID': '群組編號', 'Groups': 'Groups', 'Hello World': '嗨! 世界', +'Helping web2py': 'Helping web2py', 'Home': 'Home', 'How did you get here?': 'How did you get here?', 'import': 'import', @@ -123,6 +132,7 @@ 'Layouts': 'Layouts', 'License for': '軟體版權為', 'Live Chat': 'Live Chat', +'Log In': 'Log In', 'login': '登入', 'Login': '登入', 'Login to the Administrative Interface': '登入到管理員介面', @@ -130,7 +140,10 @@ 'Logout': '登出', 'Lost Password': '密碼遺忘', 'Main Menu': '主選單', +'Manage %(action)s': 'Manage %(action)s', +'Manage Access Control': 'Manage Access Control', 'Manage Cache': 'Manage Cache', +'Memberships': 'Memberships', 'Menu Model': '選單模組(menu)', 'Models': '資料模組', 'Modules': '程式模組', @@ -138,9 +151,11 @@ 'Name': '名字', 'New Record': '新紀錄', 'new record inserted': '已插入新紀錄', +'next %s rows': 'next %s rows', 'next 100 rows': '往後 100 筆', 'NO': '否', 'No databases in this application': '這應用程式不含資料庫', +'Online book': 'Online book', 'Online examples': '點此處進入線上範例', 'or import from csv file': '或是從逗號分隔檔(CSV)匯入', 'Origin': '原文', @@ -151,10 +166,14 @@ 'Password': '密碼', "Password fields don't match": '密碼欄不匹配', 'Peeking at file': '選擇檔案', +'Permission': 'Permission', +'Permissions': 'Permissions', 'Plugins': 'Plugins', 'Powered by': '基於以下技術構建:', 'Preface': 'Preface', +'previous %s rows': 'previous %s rows', 'previous 100 rows': '往前 100 筆', +'pygraphviz library not found': 'pygraphviz library not found', 'Python': 'Python', 'Query:': '查詢:', 'Quick Examples': 'Quick Examples', @@ -173,11 +192,14 @@ 'Reset Password key': '重設密碼', 'Resolve Conflict file': '解決衝突檔案', 'Role': '角色', +'Roles': 'Roles', 'Rows in Table': '在資料表裏的資料', 'Rows selected': '筆資料被選擇', +'Save model as...': 'Save model as...', 'Saved file hash:': '檔案雜湊值已紀錄:', 'Semantic': 'Semantic', 'Services': 'Services', +'Sign Up': 'Sign Up', 'Size of cache:': 'Size of cache:', 'state': '狀態', 'Static files': '靜態檔案', @@ -205,6 +227,7 @@ 'Ticket': '問題單', 'Time in Cache (h:m:s)': 'Time in Cache (h:m:s)', 'Timestamp': '時間標記', +'Traceback': 'Traceback', 'Twitter': 'Twitter', 'Unable to check for upgrades': '無法做升級檢查', 'Unable to download': '無法下載', @@ -213,9 +236,11 @@ 'Update:': '更新:', 'Upload existing application': '更新存在的應用程式', 'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': '使用下列方式來組合更複雜的條件式, (...)&(...) 代表同時存在的條件, (...)|(...) 代表擇一的條件, ~(...)則代表反向條件.', +'User': 'User', 'User %(id)s Logged-in': '使用者 %(id)s 已登入', 'User %(id)s Registered': '使用者 %(id)s 已註冊', 'User ID': '使用者編號', +'Users': 'Users', 'Verify Password': '驗證密碼', 'Videos': 'Videos', 'View': '視圖', @@ -224,6 +249,7 @@ 'Welcome to web2py': '歡迎使用 web2py', 'Welcome to web2py!': 'Welcome to web2py!', 'Which called the function %s located in the file %s': 'Which called the function %s located in the file %s', +'Working...': 'Working...', 'YES': '是', 'You are successfully running web2py': 'You are successfully running web2py', 'You can modify this application and adapt it to your needs': 'You can modify this application and adapt it to your needs', From 05537b99161df488e958b0921aebd61c4c61765c Mon Sep 17 00:00:00 2001 From: Vinyl Darkscratch Date: Fri, 9 Sep 2016 00:43:39 -0700 Subject: [PATCH 03/49] Language update --- applications/welcome/languages/ar.py | 11 +++++++++++ applications/welcome/languages/ca.py | 11 +++++++++++ applications/welcome/languages/cs.py | 13 ++++++++++++- applications/welcome/languages/de.py | 2 +- applications/welcome/languages/es.py | 3 +-- applications/welcome/languages/fr-ca.py | 11 +++++++++++ applications/welcome/languages/hi.py | 11 +++++++++++ applications/welcome/languages/hu.py | 11 +++++++++++ applications/welcome/languages/id.py | 11 +++++++++++ applications/welcome/languages/it.py | 11 +++++++++++ applications/welcome/languages/my-mm.py | 11 +++++++++++ applications/welcome/languages/my.py | 11 +++++++++++ applications/welcome/languages/nl.py | 11 +++++++++++ applications/welcome/languages/pl.py | 11 +++++++++++ applications/welcome/languages/pt-br.py | 3 +-- applications/welcome/languages/pt.py | 3 +-- applications/welcome/languages/ro.py | 11 +++++++++++ applications/welcome/languages/ru.py | 11 +++++++++++ applications/welcome/languages/sk.py | 11 +++++++++++ applications/welcome/languages/tr.py | 11 +++++++++++ applications/welcome/languages/uk.py | 11 +++++++++++ applications/welcome/languages/zh-cn.py | 11 +++++++++++ applications/welcome/languages/zh-tw.py | 11 +++++++++++ applications/welcome/languages/zh.py | 11 +++++++++++ 24 files changed, 225 insertions(+), 8 deletions(-) diff --git a/applications/welcome/languages/ar.py b/applications/welcome/languages/ar.py index c3908eba..dce4610f 100755 --- a/applications/welcome/languages/ar.py +++ b/applications/welcome/languages/ar.py @@ -13,13 +13,19 @@ '%s selected': '%s selected', '%Y-%m-%d': '%Y-%m-%d', '%Y-%m-%d %H:%M:%S': '%Y-%m-%d %H:%M:%S', +'(**%.0d MB**)': '(**%.0d MB**)', +'**%(items)s** %%{item(items)}, **%(bytes)s** %%{byte(bytes)}': '**%(items)s** %%{item(items)}, **%(bytes)s** %%{byte(bytes)}', +'**%(items)s** items, **%(bytes)s** %%{byte(bytes)}': '**%(items)s** items, **%(bytes)s** %%{byte(bytes)}', +'**not available** (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)': '**not available** (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)', '?': '?', '@markmin\x01**Hello World**': '**مرحباً بالعالم**', +'``**not available**``:red (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)': '``**not available**``:red (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)', 'About': 'نبذة', 'Access Control': 'متحكمات الوصول', 'admin': 'admin', 'Administrative Interface': 'واجهة التحكم', 'Ajax Recipes': 'وصفات أجاكس', +'An error occured, please [[reload %s]] the page': 'An error occured, please [[reload %s]] the page', 'appadmin is disabled because insecure channel': 'appadmin is disabled because insecure channel', 'Are you sure you want to delete this object?': 'هل أنت متأكد بحذف هذا الكائن ؟', 'Available Databases and Tables': 'Available Databases and Tables', @@ -28,6 +34,7 @@ 'cache': 'cache', 'Cache': 'Cache', 'Cache Cleared': 'Cache Cleared', +'Cache contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.': 'Cache contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.', 'Cache Keys': 'Cache Keys', 'Cannot be empty': 'لا يمكن بأن يكون خالي', 'Check to delete': 'أختر للحذف', @@ -61,6 +68,7 @@ 'DISK': 'DISK', 'Disk Cache Keys': 'Disk Cache Keys', 'Disk Cleared': 'Disk Cleared', +'DISK contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.': 'DISK contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.', 'Documentation': 'المستندات', "Don't know what to do?": 'لا تعلم ماذا ستفعل ؟', 'done!': 'done!', @@ -85,6 +93,7 @@ 'Hello World ## comment': ' مرحباً بالعالم', 'Hello World## comment': 'مرحباً بالعالم', 'Helping web2py': 'Helping web2py', +'Hit Ratio: **%(ratio)s%%** (**%(hits)s** %%{hit(hits)} and **%(misses)s** %%{miss(misses)})': 'Hit Ratio: **%(ratio)s%%** (**%(hits)s** %%{hit(hits)} and **%(misses)s** %%{miss(misses)})', 'Home': 'الرئيسية', 'How did you get here?': 'كيف أستطعت الوصول إلى هنا ؟', 'import': 'import', @@ -121,6 +130,7 @@ 'new record inserted': 'new record inserted', 'next %s rows': 'next %s rows', 'No databases in this application': 'No databases in this application', +'Number of entries: **%s**': 'Number of entries: **%s**', 'Object or table name': 'أسم الكائن أو الجدول', 'Online book': 'Online book', 'Online examples': 'أمثلة على الأنترنت', @@ -146,6 +156,7 @@ 'RAM': 'RAM', 'RAM Cache Keys': 'RAM Cache Keys', 'Ram Cleared': 'Ram Cleared', +'RAM contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.': 'RAM contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.', 'Recipes': 'وصفات', 'Record': 'Record', 'record does not exist': 'record does not exist', diff --git a/applications/welcome/languages/ca.py b/applications/welcome/languages/ca.py index 2fb827f1..951894dc 100755 --- a/applications/welcome/languages/ca.py +++ b/applications/welcome/languages/ca.py @@ -10,10 +10,15 @@ '%s selected': '%s %%{seleccionat}', '%Y-%m-%d': '%d/%m/%Y', '%Y-%m-%d %H:%M:%S': '%d/%m/%Y %H:%M:%S', +'(**%.0d MB**)': '(**%.0d MB**)', '(something like "it-it")': '(similar a "això-això")', +'**%(items)s** %%{item(items)}, **%(bytes)s** %%{byte(bytes)}': '**%(items)s** %%{item(items)}, **%(bytes)s** %%{byte(bytes)}', +'**%(items)s** items, **%(bytes)s** %%{byte(bytes)}': '**%(items)s** items, **%(bytes)s** %%{byte(bytes)}', +'**not available** (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)': '**not available** (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)', '?': '?', '@markmin\x01An error occured, please [[reload %s]] the page': 'Hi ha hagut un error, si us plau [[recarregui %s]] la pàgina', '@markmin\x01Number of entries: **%s**': "Nombre d'entrades: **%s**", +'``**not available**``:red (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)': '``**not available**``:red (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)', 'A new version of web2py is available': 'Hi ha una nova versió de wep2py disponible', 'A new version of web2py is available: %s': 'Hi ha una nova versió de wep2py disponible: %s', 'About': 'Sobre', @@ -35,6 +40,7 @@ 'Administrator Password:': 'Contrasenya del Administrador:', 'Ajax Recipes': 'Receptes AJAX', 'An error occured, please %s the page': 'Hi ha hagut un error, per favor %s la pàgina', +'An error occured, please [[reload %s]] the page': 'An error occured, please [[reload %s]] the page', 'And': 'I', 'and rename it (required):': 'i renombri-la (requerit):', 'and rename it:': " i renombri'l:", @@ -63,6 +69,7 @@ 'Cache': 'Caché', 'cache': 'caché', 'Cache Cleared': 'Caché Netejada', +'Cache contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.': 'Cache contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.', 'Cache Keys': 'Claus de la Caché', 'cache, errors and sessions cleaned': 'caché, errors i sessions eliminats', 'Cannot be empty': 'No pot estar buit', @@ -138,6 +145,7 @@ 'DISK': 'DISC', 'Disk Cache Keys': 'Claus de Caché en Disc', 'Disk Cleared': 'Disc netejat', +'DISK contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.': 'DISK contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.', 'Documentation': 'Documentació', "Don't know what to do?": 'No sap què fer?', 'done!': '¡fet!', @@ -207,6 +215,7 @@ 'Hello World': 'Hola Món', 'help': 'ajuda', 'Helping web2py': 'Helping web2py', +'Hit Ratio: **%(ratio)s%%** (**%(hits)s** %%{hit(hits)} and **%(misses)s** %%{miss(misses)})': 'Hit Ratio: **%(ratio)s%%** (**%(hits)s** %%{hit(hits)} and **%(misses)s** %%{miss(misses)})', 'Home': 'Inici', 'Hosted by': 'Hosted by', 'How did you get here?': 'Com has arribat aquí?', @@ -294,6 +303,7 @@ 'No records found': "No s'han trobat registres", 'Not authorized': 'No autoritzat', 'not in': 'no a', +'Number of entries: **%s**': 'Number of entries: **%s**', 'Object or table name': 'Nom del objecte o taula', 'Old password': 'Contrasenya anterior', 'Online book': 'Online book', @@ -334,6 +344,7 @@ 'RAM': 'RAM', 'RAM Cache Keys': 'Claus de la Caché en RAM', 'Ram Cleared': 'Ram Netjeda', +'RAM contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.': 'RAM contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.', 'Recipes': 'Receptes', 'Record': 'Registre', 'Record %(id)s created': 'Registre %(id)s creat', diff --git a/applications/welcome/languages/cs.py b/applications/welcome/languages/cs.py index 11d980db..4a86a697 100755 --- a/applications/welcome/languages/cs.py +++ b/applications/welcome/languages/cs.py @@ -11,12 +11,17 @@ '%s selected': '%s označených', '%Y-%m-%d': '%d.%m.%Y', '%Y-%m-%d %H:%M:%S': '%d.%m.%Y %H:%M:%S', +'(**%.0d MB**)': '(**%.0d MB**)', '(requires internet access)': '(vyžaduje připojení k internetu)', '(requires internet access, experimental)': '(requires internet access, experimental)', '(something like "it-it")': '(například "cs-cs")', +'**%(items)s** %%{item(items)}, **%(bytes)s** %%{byte(bytes)}': '**%(items)s** %%{item(items)}, **%(bytes)s** %%{byte(bytes)}', +'**%(items)s** items, **%(bytes)s** %%{byte(bytes)}': '**%(items)s** items, **%(bytes)s** %%{byte(bytes)}', +'**not available** (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)': '**not available** (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)', '?': '?', '@markmin\x01(file **gluon/contrib/plural_rules/%s.py** is not found)': '(soubor **gluon/contrib/plural_rules/%s.py** nenalezen)', '@markmin\x01Searching: **%s** %%{file}': 'Hledání: **%s** %%{soubor}', +'``**not available**``:red (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)': '``**not available**``:red (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)', 'About': 'O programu', 'About application': 'O aplikaci', 'Access Control': 'Řízení přístupu', @@ -31,6 +36,7 @@ 'Administrator Password:': 'Administrátorské heslo:', 'Ajax Recipes': 'Recepty s ajaxem', 'An error occured, please %s the page': 'An error occured, please %s the page', +'An error occured, please [[reload %s]] the page': 'An error occured, please [[reload %s]] the page', 'and rename it:': 'a přejmenovat na:', 'appadmin': 'appadmin', 'appadmin is disabled because insecure channel': 'appadmin je zakázaná bez zabezpečeného spojení', @@ -60,6 +66,7 @@ 'Cache': 'Cache', 'cache': 'cache', 'Cache Cleared': 'Cache Cleared', +'Cache contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.': 'Cache contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.', 'Cache Keys': 'Klíče cache', 'cache, errors and sessions cleaned': 'cache, chyby a relace byly pročištěny', 'can be a git repo': 'může to být git repo', @@ -141,6 +148,7 @@ 'DISK': 'DISK', 'Disk Cache Keys': 'Klíče diskové cache', 'Disk Cleared': 'Disk smazán', +'DISK contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.': 'DISK contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.', 'docs': 'dokumentace', 'Documentation': 'Dokumentace', "Don't know what to do?": 'Nevíte kudy kam?', @@ -210,6 +218,7 @@ 'Help': 'Nápověda', 'Helping web2py': 'Helping web2py', 'Hide/Show Translated strings': 'Skrýt/Zobrazit přeložené texty', +'Hit Ratio: **%(ratio)s%%** (**%(hits)s** %%{hit(hits)} and **%(misses)s** %%{miss(misses)})': 'Hit Ratio: **%(ratio)s%%** (**%(hits)s** %%{hit(hits)} and **%(misses)s** %%{miss(misses)})', 'Hits': 'Kolikrát dosaženo', 'Home': 'Domovská stránka', 'honored only if the expression evaluates to true': 'brát v potaz jen když se tato podmínka vyhodnotí kladně', @@ -279,8 +288,8 @@ 'My Sites': 'Správa aplikací', 'Name': 'Jméno', 'new application "%s" created': 'nová aplikace "%s" vytvořena', -'New Application Wizard': 'Nový průvodce aplikací', 'New application wizard': 'Nový průvodce aplikací', +'New Application Wizard': 'Nový průvodce aplikací', 'New password': 'Nové heslo', 'New Record': 'Nový záznam', 'new record inserted': 'nový záznam byl založen', @@ -291,6 +300,7 @@ 'No databases in this application': 'V této aplikaci nejsou žádné databáze', 'No Interaction yet': 'Ještě žádná interakce nenastala', 'No ticket_storage.txt found under /private folder': 'Soubor ticket_storage.txt v adresáři /private nenalezen', +'Number of entries: **%s**': 'Number of entries: **%s**', 'Object or table name': 'Objekt či tabulka', 'Old password': 'Původní heslo', 'Online book': 'Online book', @@ -336,6 +346,7 @@ 'RAM': 'RAM', 'RAM Cache Keys': 'Klíče RAM Cache', 'Ram Cleared': 'RAM smazána', +'RAM contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.': 'RAM contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.', 'Readme': 'Nápověda', 'Recipes': 'Postupy jak na to', 'Record': 'Záznam', diff --git a/applications/welcome/languages/de.py b/applications/welcome/languages/de.py index 2e40b349..2aefeb38 100755 --- a/applications/welcome/languages/de.py +++ b/applications/welcome/languages/de.py @@ -215,4 +215,4 @@ 'You are successfully running web2py': 'web2py wird erfolgreich ausgeführt', 'You can modify this application and adapt it to your needs': 'Sie können diese Anwendung verändern und Ihren Bedürfnissen anpassen', 'You visited the url %s': 'Sie haben die URL %s besucht', -} \ No newline at end of file +} diff --git a/applications/welcome/languages/es.py b/applications/welcome/languages/es.py index c2154767..b8c12cf1 100755 --- a/applications/welcome/languages/es.py +++ b/applications/welcome/languages/es.py @@ -63,7 +63,7 @@ 'Available Databases and Tables': 'Bases de datos y tablas disponibles', 'Back': 'Atrás', 'Buy this book': 'Compra este libro', -"Buy web2py's book": "Compra el libro de web2py", +"Buy web2py's book": 'Compra el libro de web2py', 'Cache': 'Caché', 'cache': 'caché', 'Cache Cleared': 'Cache Limpiada', @@ -466,4 +466,3 @@ 'You visited the url %s': 'Usted visitó la url %s', 'Your username is: %(username)s': 'Su nombre de usuario es: %(username)s', } - diff --git a/applications/welcome/languages/fr-ca.py b/applications/welcome/languages/fr-ca.py index 310afadc..afa290bf 100755 --- a/applications/welcome/languages/fr-ca.py +++ b/applications/welcome/languages/fr-ca.py @@ -8,7 +8,12 @@ '%s selected': '%s sélectionné', '%Y-%m-%d': '%Y-%m-%d', '%Y-%m-%d %H:%M:%S': '%Y-%m-%d %H:%M:%S', +'(**%.0d MB**)': '(**%.0d MB**)', +'**%(items)s** %%{item(items)}, **%(bytes)s** %%{byte(bytes)}': '**%(items)s** %%{item(items)}, **%(bytes)s** %%{byte(bytes)}', +'**%(items)s** items, **%(bytes)s** %%{byte(bytes)}': '**%(items)s** items, **%(bytes)s** %%{byte(bytes)}', +'**not available** (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)': '**not available** (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)', '?': '?', +'``**not available**``:red (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)': '``**not available**``:red (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)', 'about': 'à propos', 'About': 'À propos', 'Access Control': "Contrôle d'accès", @@ -16,6 +21,7 @@ 'Administrative Interface': 'Administrative Interface', 'Administrative interface': "Interface d'administration", 'Ajax Recipes': 'Recettes Ajax', +'An error occured, please [[reload %s]] the page': 'An error occured, please [[reload %s]] the page', 'appadmin is disabled because insecure channel': "appadmin est désactivée parce que le canal n'est pas sécurisé", 'Are you sure you want to delete this object?': 'Êtes-vous sûr de vouloir supprimer cet objet?', 'Authentication': 'Authentification', @@ -25,6 +31,7 @@ 'cache': 'cache', 'Cache': 'Cache', 'Cache Cleared': 'Cache Cleared', +'Cache contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.': 'Cache contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.', 'Cache Keys': 'Cache Keys', 'Cannot be empty': 'Ne peut pas être vide', 'change password': 'changer le mot de passe', @@ -58,6 +65,7 @@ 'DISK': 'DISK', 'Disk Cache Keys': 'Disk Cache Keys', 'Disk Cleared': 'Disk Cleared', +'DISK contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.': 'DISK contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.', 'Documentation': 'Documentation', "Don't know what to do?": "Don't know what to do?", 'done!': 'fait!', @@ -83,6 +91,7 @@ 'Groups': 'Groupes', 'Hello World': 'Bonjour le monde', 'Helping web2py': 'Helping web2py', +'Hit Ratio: **%(ratio)s%%** (**%(hits)s** %%{hit(hits)} and **%(misses)s** %%{miss(misses)})': 'Hit Ratio: **%(ratio)s%%** (**%(hits)s** %%{hit(hits)} and **%(misses)s** %%{miss(misses)})', 'Home': 'Accueil', 'How did you get here?': 'How did you get here?', 'import': 'import', @@ -123,6 +132,7 @@ 'next %s rows': 'next %s rows', 'next 100 rows': '100 prochaines lignes', 'No databases in this application': "Cette application n'a pas de bases de données", +'Number of entries: **%s**': 'Number of entries: **%s**', 'Online book': 'Online book', 'Online examples': 'Exemples en ligne', 'or import from csv file': "ou importer d'un fichier CSV", @@ -149,6 +159,7 @@ 'RAM': 'RAM', 'RAM Cache Keys': 'RAM Cache Keys', 'Ram Cleared': 'Ram Cleared', +'RAM contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.': 'RAM contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.', 'Readme': 'Lisez-moi', 'Recipes': 'Recettes', 'Record': 'enregistrement', diff --git a/applications/welcome/languages/hi.py b/applications/welcome/languages/hi.py index 19fe70fd..5c741e1c 100755 --- a/applications/welcome/languages/hi.py +++ b/applications/welcome/languages/hi.py @@ -8,13 +8,19 @@ '%s selected': '%s चुना हुआ', '%Y-%m-%d': '%Y-%m-%d', '%Y-%m-%d %H:%M:%S': '%Y-%m-%d %H:%M:%S', +'(**%.0d MB**)': '(**%.0d MB**)', +'**%(items)s** %%{item(items)}, **%(bytes)s** %%{byte(bytes)}': '**%(items)s** %%{item(items)}, **%(bytes)s** %%{byte(bytes)}', +'**%(items)s** items, **%(bytes)s** %%{byte(bytes)}': '**%(items)s** items, **%(bytes)s** %%{byte(bytes)}', +'**not available** (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)': '**not available** (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)', '?': '?', +'``**not available**``:red (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)': '``**not available**``:red (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)', 'About': 'About', 'Access Control': 'Access Control', 'admin': 'admin', 'Administrative Interface': 'Administrative Interface', 'Administrative interface': 'प्रशासनिक इंटरफेस के लिए यहाँ क्लिक करें', 'Ajax Recipes': 'Ajax Recipes', +'An error occured, please [[reload %s]] the page': 'An error occured, please [[reload %s]] the page', 'appadmin is disabled because insecure channel': 'अप आडमिन (appadmin) अक्षम है क्योंकि असुरक्षित चैनल', 'Are you sure you want to delete this object?': 'Are you sure you want to delete this object?', 'Available Databases and Tables': 'उपलब्ध डेटाबेस और तालिका', @@ -23,6 +29,7 @@ 'cache': 'cache', 'Cache': 'Cache', 'Cache Cleared': 'Cache Cleared', +'Cache contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.': 'Cache contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.', 'Cache Keys': 'Cache Keys', 'Cannot be empty': 'खाली नहीं हो सकता', 'Change Password': 'पासवर्ड बदलें', @@ -54,6 +61,7 @@ 'DISK': 'DISK', 'Disk Cache Keys': 'Disk Cache Keys', 'Disk Cleared': 'Disk Cleared', +'DISK contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.': 'DISK contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.', 'Documentation': 'Documentation', "Don't know what to do?": "Don't know what to do?", 'done!': 'हो गया!', @@ -74,6 +82,7 @@ 'Hello from MyApp': 'Hello from MyApp', 'Hello World': 'Hello World', 'Helping web2py': 'Helping web2py', +'Hit Ratio: **%(ratio)s%%** (**%(hits)s** %%{hit(hits)} and **%(misses)s** %%{miss(misses)})': 'Hit Ratio: **%(ratio)s%%** (**%(hits)s** %%{hit(hits)} and **%(misses)s** %%{miss(misses)})', 'Home': 'Home', 'How did you get here?': 'How did you get here?', 'import': 'import', @@ -108,6 +117,7 @@ 'next %s rows': 'next %s rows', 'next 100 rows': 'अगले 100 पंक्तियाँ', 'No databases in this application': 'इस अनुप्रयोग में कोई डेटाबेस नहीं हैं', +'Number of entries: **%s**': 'Number of entries: **%s**', 'Online book': 'Online book', 'Online examples': 'ऑनलाइन उदाहरण के लिए यहाँ क्लिक करें', 'or import from csv file': 'या csv फ़ाइल से आयात', @@ -128,6 +138,7 @@ 'RAM': 'RAM', 'RAM Cache Keys': 'RAM Cache Keys', 'Ram Cleared': 'Ram Cleared', +'RAM contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.': 'RAM contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.', 'Recipes': 'Recipes', 'Record': 'Record', 'record does not exist': 'रिकॉर्ड मौजूद नहीं है', diff --git a/applications/welcome/languages/hu.py b/applications/welcome/languages/hu.py index c020c409..992140ee 100755 --- a/applications/welcome/languages/hu.py +++ b/applications/welcome/languages/hu.py @@ -8,13 +8,19 @@ '%s selected': '%s kiválasztott', '%Y-%m-%d': '%Y.%m.%d.', '%Y-%m-%d %H:%M:%S': '%Y.%m.%d. %H:%M:%S', +'(**%.0d MB**)': '(**%.0d MB**)', +'**%(items)s** %%{item(items)}, **%(bytes)s** %%{byte(bytes)}': '**%(items)s** %%{item(items)}, **%(bytes)s** %%{byte(bytes)}', +'**%(items)s** items, **%(bytes)s** %%{byte(bytes)}': '**%(items)s** items, **%(bytes)s** %%{byte(bytes)}', +'**not available** (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)': '**not available** (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)', '?': '?', +'``**not available**``:red (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)': '``**not available**``:red (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)', 'About': 'About', 'Access Control': 'Access Control', 'admin': 'admin', 'Administrative Interface': 'Administrative Interface', 'Administrative interface': 'az adminisztrációs felületért kattints ide', 'Ajax Recipes': 'Ajax Recipes', +'An error occured, please [[reload %s]] the page': 'An error occured, please [[reload %s]] the page', 'appadmin is disabled because insecure channel': 'az appadmin a biztonságtalan csatorna miatt letiltva', 'Are you sure you want to delete this object?': 'Are you sure you want to delete this object?', 'Available Databases and Tables': 'Elérhető adatbázisok és táblák', @@ -23,6 +29,7 @@ 'cache': 'gyorsítótár', 'Cache': 'Cache', 'Cache Cleared': 'Cache Cleared', +'Cache contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.': 'Cache contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.', 'Cache Keys': 'Cache Keys', 'Cannot be empty': 'Nem lehet üres', 'change password': 'jelszó megváltoztatása', @@ -55,6 +62,7 @@ 'DISK': 'DISK', 'Disk Cache Keys': 'Disk Cache Keys', 'Disk Cleared': 'Disk Cleared', +'DISK contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.': 'DISK contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.', 'Documentation': 'Documentation', "Don't know what to do?": "Don't know what to do?", 'done!': 'kész!', @@ -76,6 +84,7 @@ 'Groups': 'Groups', 'Hello World': 'Hello Világ', 'Helping web2py': 'Helping web2py', +'Hit Ratio: **%(ratio)s%%** (**%(hits)s** %%{hit(hits)} and **%(misses)s** %%{miss(misses)})': 'Hit Ratio: **%(ratio)s%%** (**%(hits)s** %%{hit(hits)} and **%(misses)s** %%{miss(misses)})', 'Home': 'Home', 'How did you get here?': 'How did you get here?', 'import': 'import', @@ -112,6 +121,7 @@ 'next %s rows': 'next %s rows', 'next 100 rows': 'következő 100 sor', 'No databases in this application': 'Nincs adatbázis ebben az alkalmazásban', +'Number of entries: **%s**': 'Number of entries: **%s**', 'Online book': 'Online book', 'Online examples': 'online példákért kattints ide', 'or import from csv file': 'vagy betöltés csv fájlból', @@ -134,6 +144,7 @@ 'RAM': 'RAM', 'RAM Cache Keys': 'RAM Cache Keys', 'Ram Cleared': 'Ram Cleared', +'RAM contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.': 'RAM contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.', 'Recipes': 'Recipes', 'Record': 'bejegyzés', 'record does not exist': 'bejegyzés nem létezik', diff --git a/applications/welcome/languages/id.py b/applications/welcome/languages/id.py index e34864ed..621d3d8a 100755 --- a/applications/welcome/languages/id.py +++ b/applications/welcome/languages/id.py @@ -16,8 +16,12 @@ '%s selected': '%s dipilih', '%Y-%m-%d': '%d-%m-%Y', '%Y-%m-%d %H:%M:%S': '%d-%m-%Y %H:%M:%S', +'(**%.0d MB**)': '(**%.0d MB**)', '(requires internet access, experimental)': '(membutuhkan akses internet, eksperimental)', '(something like "it-it")': '(sesuatu seperti "it-it")', +'**%(items)s** %%{item(items)}, **%(bytes)s** %%{byte(bytes)}': '**%(items)s** %%{item(items)}, **%(bytes)s** %%{byte(bytes)}', +'**%(items)s** items, **%(bytes)s** %%{byte(bytes)}': '**%(items)s** items, **%(bytes)s** %%{byte(bytes)}', +'**not available** (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)': '**not available** (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)', '1 day ago': '1 hari yang lalu', '1 hour ago': '1 jam yang lalu', '1 minute ago': '1 menit yang lalu', @@ -27,6 +31,7 @@ '1 year ago': '1 tahun yang lalu', '< Previous': '< Sebelumnya', '?': '?', +'``**not available**``:red (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)': '``**not available**``:red (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)', 'About': 'Tentang', 'About application': 'Tentang Aplikasi', 'Access Control': 'Access Control', @@ -39,6 +44,7 @@ 'Administrator Password:': 'Administrator Kata Sandi:', 'Ajax Recipes': 'Resep Ajax', 'An error occured, please %s the page': 'Terjadi kesalahan, silakan %s halaman', +'An error occured, please [[reload %s]] the page': 'An error occured, please [[reload %s]] the page', 'And': 'Dan', 'and rename it:': 'dan memberi nama baru itu:', 'Answer': 'Jawaban', @@ -56,6 +62,7 @@ 'Cache': 'Cache', 'cache': 'cache', 'Cache Cleared': 'Cache Cleared', +'Cache contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.': 'Cache contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.', 'Cache Keys': 'Cache Keys', 'cache, errors and sessions cleaned': 'cache, kesalahan dan sesi dibersihkan', 'can be a git repo': 'bisa menjadi repo git', @@ -114,6 +121,7 @@ 'DISK': 'DISK', 'Disk Cache Keys': 'Disk Cache Keys', 'Disk Cleared': 'Disk Dihapus', +'DISK contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.': 'DISK contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.', 'Documentation': 'Dokumentasi', "Don't know what to do?": 'Tidak tahu apa yang harus dilakukan?', 'done!': 'selesai!', @@ -152,6 +160,7 @@ 'Hello World': 'Halo Dunia', 'Help': 'Bantuan', 'Helping web2py': 'Helping web2py', +'Hit Ratio: **%(ratio)s%%** (**%(hits)s** %%{hit(hits)} and **%(misses)s** %%{miss(misses)})': 'Hit Ratio: **%(ratio)s%%** (**%(hits)s** %%{hit(hits)} and **%(misses)s** %%{miss(misses)})', 'Home': 'Halaman Utama', 'How did you get here?': 'Bagaimana kamu bisa di sini?', 'Image': 'Gambar', @@ -210,6 +219,7 @@ 'No ticket_storage.txt found under /private folder': 'Tidak ditemukan ticket_storage.txt dalam folder /private', 'not a Zip Code': 'bukan Kode Pos', 'Note': 'Catatan', +'Number of entries: **%s**': 'Number of entries: **%s**', 'Old password': 'Kata sandi lama', 'Online book': 'Online book', 'Online examples': 'Contoh Online', @@ -250,6 +260,7 @@ 'RAM': 'RAM', 'RAM Cache Keys': 'RAM Cache Keys', 'Ram Cleared': 'Ram Dihapus', +'RAM contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.': 'RAM contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.', 'Recipes': 'Resep', 'Record': 'Record', 'record does not exist': 'record does not exist', diff --git a/applications/welcome/languages/it.py b/applications/welcome/languages/it.py index 1f779c13..f145075e 100755 --- a/applications/welcome/languages/it.py +++ b/applications/welcome/languages/it.py @@ -11,6 +11,10 @@ '%s selected': '%s selezionato', '%Y-%m-%d': '%d/%m/%Y', '%Y-%m-%d %H:%M:%S': '%d/%m/%Y %H:%M:%S', +'(**%.0d MB**)': '(**%.0d MB**)', +'**%(items)s** %%{item(items)}, **%(bytes)s** %%{byte(bytes)}': '**%(items)s** %%{item(items)}, **%(bytes)s** %%{byte(bytes)}', +'**%(items)s** items, **%(bytes)s** %%{byte(bytes)}': '**%(items)s** items, **%(bytes)s** %%{byte(bytes)}', +'**not available** (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)': '**not available** (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)', '<': '<', '<=': '<=', '=': '=', @@ -19,6 +23,7 @@ '?': '?', '@markmin\x01An error occured, please [[reload %s]] the page': 'An error occured, please [[reload %s]] the page', '@markmin\x01Number of entries: **%s**': 'Numero di entità: **%s**', +'``**not available**``:red (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)': '``**not available**``:red (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)', 'About': 'About', 'Access Control': 'Controllo Accessi', 'Add': 'Aggiungi', @@ -27,6 +32,7 @@ 'Administrative interface': 'Interfaccia amministrativa', 'Ajax Recipes': 'Ajax Recipes', 'An error occured, please %s the page': 'È stato rilevato un errore, prego %s la pagina', +'An error occured, please [[reload %s]] the page': 'An error occured, please [[reload %s]] the page', 'And': 'E', 'appadmin is disabled because insecure channel': 'Amministrazione (appadmin) disabilitata: comunicazione non sicura', 'Are you sure you want to delete this object?': 'Sicuro di voler cancellare questo oggetto ?', @@ -37,6 +43,7 @@ 'cache': 'cache', 'Cache': 'Cache', 'Cache Cleared': 'Cache Cleared', +'Cache contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.': 'Cache contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.', 'Cache Keys': 'Cache Keys', 'Cannot be empty': 'Non può essere vuoto', 'Change password': 'Cambia Password', @@ -79,6 +86,7 @@ 'DISK': 'DISK', 'Disk Cache Keys': 'Disk Cache Keys', 'Disk Cleared': 'Disk Cleared', +'DISK contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.': 'DISK contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.', 'Documentation': 'Documentazione', "Don't know what to do?": 'Non sai cosa fare?', 'done!': 'fatto!', @@ -111,6 +119,7 @@ 'Hello World': 'Salve Mondo', 'Hello World in a flash!': 'Salve Mondo in un flash!', 'Helping web2py': 'Helping web2py', +'Hit Ratio: **%(ratio)s%%** (**%(hits)s** %%{hit(hits)} and **%(misses)s** %%{miss(misses)})': 'Hit Ratio: **%(ratio)s%%** (**%(hits)s** %%{hit(hits)} and **%(misses)s** %%{miss(misses)})', 'Home': 'Home', 'How did you get here?': 'Come sei arrivato qui?', 'HTML': 'HTML', @@ -163,6 +172,7 @@ 'Nome': 'Nome', 'Non può essere vuoto': 'Non può essere vuoto', 'not authorized': 'non autorizzato', +'Number of entries: **%s**': 'Number of entries: **%s**', 'Object or table name': 'Oggeto o nome tabella', 'Old password': 'Vecchia password', 'Online book': 'Online book', @@ -191,6 +201,7 @@ 'RAM': 'RAM', 'RAM Cache Keys': 'RAM Cache Keys', 'Ram Cleared': 'Ram Cleared', +'RAM contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.': 'RAM contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.', 'Recipes': 'Recipes', 'Record': 'Record', 'record does not exist': 'il record non esiste', diff --git a/applications/welcome/languages/my-mm.py b/applications/welcome/languages/my-mm.py index 97e39ffe..38bd3523 100755 --- a/applications/welcome/languages/my-mm.py +++ b/applications/welcome/languages/my-mm.py @@ -8,10 +8,15 @@ '%s selected': '%s ခု ရွေးထားသည်', '%Y-%m-%d': '%Y-%m-%d', '%Y-%m-%d %H:%M:%S': '%Y-%m-%d %H:%M:%S', +'(**%.0d MB**)': '(**%.0d MB**)', '(requires internet access, experimental)': '(requires internet access, experimental)', '(something like "it-it")': '(something like "it-it")', +'**%(items)s** %%{item(items)}, **%(bytes)s** %%{byte(bytes)}': '**%(items)s** %%{item(items)}, **%(bytes)s** %%{byte(bytes)}', +'**%(items)s** items, **%(bytes)s** %%{byte(bytes)}': '**%(items)s** items, **%(bytes)s** %%{byte(bytes)}', +'**not available** (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)': '**not available** (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)', '?': '?', '@markmin\x01An error occured, please [[reload %s]] the page': 'An error occured, please [[reload %s]] the page', +'``**not available**``:red (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)': '``**not available**``:red (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)', 'About': 'အကြောင်း', 'Access Control': 'အသုံးပြု ခြင်းဆိုင်ရာ ထိန်းချုပ်ရန်', 'Additional code for your application': 'Additional code for your application', @@ -21,6 +26,7 @@ 'Administrative Interface': 'စီမံခန့်ခွဲရာ အင်တာဖေ့စ်', 'Administrator Password:': 'Administrator Password:', 'Ajax Recipes': 'Ajax Recipes', +'An error occured, please [[reload %s]] the page': 'An error occured, please [[reload %s]] the page', 'and rename it:': 'and rename it:', 'appadmin is disabled because insecure channel': 'စိတ်မချရသော လမ်းကြောင်းမှ ဝင်ရောက်သဖြင့် appadmin ကို အသုံးပြု၍ မရပါ', 'Application name:': 'Application name:', @@ -33,6 +39,7 @@ 'cache': 'cache', 'Cache': 'Cache', 'Cache Cleared': 'Cache Cleared', +'Cache contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.': 'Cache contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.', 'Cache Keys': 'Cache Keys', 'can be a git repo': 'can be a git repo', 'Cannot be empty': 'အလွတ် မဖြစ်ရပါ', @@ -87,6 +94,7 @@ 'DISK': 'DISK', 'Disk Cache Keys': 'Disk Cache Keys', 'Disk Cleared': 'Disk ရှင်းလင်းပြီးပြီ', +'DISK contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.': 'DISK contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.', 'Documentation': 'စာရွက်စာတမ်း အထောက်အကူများ', "Don't know what to do?": 'ဘာလုပ်ရမည်မသိ ဖြစ်နေပါသလား။', 'done!': 'လုပ်ငန်း ဆောင်ရွက်ပြီးပြီ!', @@ -116,6 +124,7 @@ 'Hello World': 'မင်္ဂလာပါ ကမ္ဘာကြီး။', 'Help': 'အကူအညီ', 'Helping web2py': 'Helping web2py', +'Hit Ratio: **%(ratio)s%%** (**%(hits)s** %%{hit(hits)} and **%(misses)s** %%{miss(misses)})': 'Hit Ratio: **%(ratio)s%%** (**%(hits)s** %%{hit(hits)} and **%(misses)s** %%{miss(misses)})', 'Home': 'မူလသို့', 'How did you get here?': 'သင် ဘယ်လို ရောက်လာခဲ့သလဲ။', 'import': 'သွင်းယူရန်', @@ -165,6 +174,7 @@ 'next %s rows': 'နောက်အတန်း %s တန်း', 'No databases in this application': 'ဒီ application တွင် မည်သည့် ဒေတာဘေစ့်မှ မရှိပါ', 'no package selected': 'no package selected', +'Number of entries: **%s**': 'Number of entries: **%s**', 'Object or table name': 'Object or table name', 'Online book': 'Online book', 'Online examples': 'အွန်လိုင်း နမူနာများ', @@ -198,6 +208,7 @@ 'RAM': 'RAM', 'RAM Cache Keys': 'RAM Cache Keys', 'Ram Cleared': 'Ram ရှင်းလင်းပြီးပြီ', +'RAM contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.': 'RAM contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.', 'Recipes': 'Recipes', 'Record': 'မှတ်တမ်း', 'record does not exist': 'မှတ်တမ်း မရှိပါ', diff --git a/applications/welcome/languages/my.py b/applications/welcome/languages/my.py index cf9589b6..ef29f272 100755 --- a/applications/welcome/languages/my.py +++ b/applications/welcome/languages/my.py @@ -16,8 +16,12 @@ '%s selected': '%s dipilih', '%Y-%m-%d': '%d-%m-%Y', '%Y-%m-%d %H:%M:%S': '%d-%m-%Y %H:%M:%S', +'(**%.0d MB**)': '(**%.0d MB**)', '(requires internet access, experimental)': '(memerlukan akses internet, percubaan)', '(something like "it-it")': '(sesuatu seperti "it-it")', +'**%(items)s** %%{item(items)}, **%(bytes)s** %%{byte(bytes)}': '**%(items)s** %%{item(items)}, **%(bytes)s** %%{byte(bytes)}', +'**%(items)s** items, **%(bytes)s** %%{byte(bytes)}': '**%(items)s** items, **%(bytes)s** %%{byte(bytes)}', +'**not available** (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)': '**not available** (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)', '1 day ago': '1 hari yang lalu', '1 hour ago': '1 jam yang lalu', '1 minute ago': '1 minit yang lalu', @@ -27,6 +31,7 @@ '1 year ago': '1 tahun yang lalu', '< Previous': '< Sebelumnya', '?': '?', +'``**not available**``:red (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)': '``**not available**``:red (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)', 'About': 'Mengenai', 'Access Control': 'Access Control', 'Add': 'Tambah', @@ -35,6 +40,7 @@ 'Administrator Password:': 'Kata laluan Administrator:', 'Ajax Recipes': 'Resipi Ajax', 'An error occured, please %s the page': 'Kesilapan telah berlaku, sila %s laman', +'An error occured, please [[reload %s]] the page': 'An error occured, please [[reload %s]] the page', 'And': 'Dan', 'and rename it:': 'dan menamakan itu:', 'appadmin is disabled because insecure channel': 'appadmin is disabled because insecure channel', @@ -47,6 +53,7 @@ 'cache': 'cache', 'Cache': 'Cache', 'Cache Cleared': 'Cache Cleared', +'Cache contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.': 'Cache contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.', 'Cache Keys': 'Cache Keys', 'cache, errors and sessions cleaned': 'cache, kesilapan dan sesi dibersihkan', 'Cancel': 'Batal', @@ -91,6 +98,7 @@ 'DISK': 'DISK', 'Disk Cache Keys': 'Disk Cache Keys', 'Disk Cleared': 'Disk Dihapuskan', +'DISK contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.': 'DISK contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.', 'Documentation': 'Dokumentasi', "Don't know what to do?": 'Tidak tahu apa yang perlu dilakukan?', 'done!': 'selesai!', @@ -122,6 +130,7 @@ 'Hello World': 'Halo Dunia', 'Help': 'Bantuan', 'Helping web2py': 'Helping web2py', +'Hit Ratio: **%(ratio)s%%** (**%(hits)s** %%{hit(hits)} and **%(misses)s** %%{miss(misses)})': 'Hit Ratio: **%(ratio)s%%** (**%(hits)s** %%{hit(hits)} and **%(misses)s** %%{miss(misses)})', 'Home': 'Laman Utama', 'How did you get here?': 'Bagaimana kamu boleh di sini?', 'Image': 'Gambar', @@ -174,6 +183,7 @@ 'No databases in this application': 'No databases in this application', 'No ticket_storage.txt found under /private folder': 'Ticket_storage.txt tidak dijumpai di bawah folder /private', 'not a Zip Code': 'bukan Pos', +'Number of entries: **%s**': 'Number of entries: **%s**', 'Old password': 'Kata laluan lama', 'Online book': 'Online book', 'Online examples': 'Contoh Online', @@ -210,6 +220,7 @@ 'RAM': 'RAM', 'RAM Cache Keys': 'RAM Cache Keys', 'Ram Cleared': 'Ram Dihapuskan', +'RAM contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.': 'RAM contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.', 'Recipes': 'Resipi', 'Record': 'Record', 'record does not exist': 'record does not exist', diff --git a/applications/welcome/languages/nl.py b/applications/welcome/languages/nl.py index 1000587e..7ff72e46 100755 --- a/applications/welcome/languages/nl.py +++ b/applications/welcome/languages/nl.py @@ -11,7 +11,11 @@ '%s selected': '%s geselecteerd', '%Y-%m-%d': '%Y-%m-%d', '%Y-%m-%d %H:%M:%S': '%Y-%m-%d %H:%M:%S', +'(**%.0d MB**)': '(**%.0d MB**)', '(something like "it-it")': '(zoiets als "nl-nl")', +'**%(items)s** %%{item(items)}, **%(bytes)s** %%{byte(bytes)}': '**%(items)s** %%{item(items)}, **%(bytes)s** %%{byte(bytes)}', +'**%(items)s** items, **%(bytes)s** %%{byte(bytes)}': '**%(items)s** items, **%(bytes)s** %%{byte(bytes)}', +'**not available** (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)': '**not available** (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)', '1 day ago': '1 dag geleden', '1 week ago': '1 week gelden', '<': '<', @@ -20,6 +24,7 @@ '>': '>', '>=': '>=', '?': '?', +'``**not available**``:red (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)': '``**not available**``:red (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)', 'A new version of web2py is available': 'Een nieuwe versie van web2py is beschikbaar', 'A new version of web2py is available: %s': 'Een nieuwe versie van web2py is beschikbaar: %s', 'About': 'Over', @@ -38,6 +43,7 @@ 'Administrative Interface': 'Administratieve Interface', 'Administrator Password:': 'Administrator Wachtwoord', 'Ajax Recipes': 'Ajax Recepten', +'An error occured, please [[reload %s]] the page': 'An error occured, please [[reload %s]] the page', 'And': 'En', 'and rename it (required):': 'en hernoem deze (vereist)', 'and rename it:': 'en hernoem:', @@ -60,6 +66,7 @@ 'Cache': 'Cache', 'cache': 'cache', 'Cache Cleared': 'Cache Cleared', +'Cache contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.': 'Cache contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.', 'Cache Keys': 'Cache Keys', 'cache, errors and sessions cleaned': 'cache, errors en sessies geleegd', 'Cannot be empty': 'Mag niet leeg zijn', @@ -123,6 +130,7 @@ 'DISK': 'DISK', 'Disk Cache Keys': 'Disk Cache Keys', 'Disk Cleared': 'Disk Geleegd', +'DISK contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.': 'DISK contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.', 'Documentation': 'Documentatie', "Don't know what to do?": 'Weet je niet wat je moet doen?', 'done!': 'gereed!', @@ -175,6 +183,7 @@ 'Hello World': 'Hallo Wereld', 'help': 'help', 'Helping web2py': 'Helping web2py', +'Hit Ratio: **%(ratio)s%%** (**%(hits)s** %%{hit(hits)} and **%(misses)s** %%{miss(misses)})': 'Hit Ratio: **%(ratio)s%%** (**%(hits)s** %%{hit(hits)} and **%(misses)s** %%{miss(misses)})', 'Home': 'Home', 'How did you get here?': 'Hoe ben je hier gekomen?', 'htmledit': 'Bewerk HTML', @@ -244,6 +253,7 @@ 'next 100 rows': 'volgende 100 rijen', 'NO': 'NEE', 'No databases in this application': 'Geen database in deze applicatie', +'Number of entries: **%s**': 'Number of entries: **%s**', 'Object or table name': 'Object of tabelnaam', 'Old password': 'Oude wachtwoord', 'Online book': 'Online book', @@ -278,6 +288,7 @@ 'RAM': 'RAM', 'RAM Cache Keys': 'RAM Cache Keys', 'Ram Cleared': 'Ram Geleegd', +'RAM contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.': 'RAM contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.', 'Recipes': 'Recepten', 'Record': 'Record', 'record does not exist': 'record bestaat niet', diff --git a/applications/welcome/languages/pl.py b/applications/welcome/languages/pl.py index 1e8cae26..f77b6adf 100755 --- a/applications/welcome/languages/pl.py +++ b/applications/welcome/languages/pl.py @@ -8,13 +8,19 @@ '%s selected': '%s wybranych', '%Y-%m-%d': '%Y-%m-%d', '%Y-%m-%d %H:%M:%S': '%Y-%m-%d %H:%M:%S', +'(**%.0d MB**)': '(**%.0d MB**)', +'**%(items)s** %%{item(items)}, **%(bytes)s** %%{byte(bytes)}': '**%(items)s** %%{item(items)}, **%(bytes)s** %%{byte(bytes)}', +'**%(items)s** items, **%(bytes)s** %%{byte(bytes)}': '**%(items)s** items, **%(bytes)s** %%{byte(bytes)}', +'**not available** (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)': '**not available** (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)', '?': '?', +'``**not available**``:red (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)': '``**not available**``:red (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)', 'About': 'About', 'Access Control': 'Access Control', 'admin': 'admin', 'Administrative Interface': 'Administrative Interface', 'Administrative interface': 'Kliknij aby przejść do panelu administracyjnego', 'Ajax Recipes': 'Ajax Recipes', +'An error occured, please [[reload %s]] the page': 'An error occured, please [[reload %s]] the page', 'appadmin is disabled because insecure channel': 'administracja aplikacji wyłączona z powodu braku bezpiecznego połączenia', 'Are you sure you want to delete this object?': 'Are you sure you want to delete this object?', 'Authentication': 'Uwierzytelnienie', @@ -24,6 +30,7 @@ 'cache': 'cache', 'Cache': 'Cache', 'Cache Cleared': 'Cache Cleared', +'Cache contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.': 'Cache contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.', 'Cache Keys': 'Cache Keys', 'Cannot be empty': 'Nie może być puste', 'Change Password': 'Zmień hasło', @@ -58,6 +65,7 @@ 'DISK': 'DISK', 'Disk Cache Keys': 'Disk Cache Keys', 'Disk Cleared': 'Disk Cleared', +'DISK contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.': 'DISK contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.', 'Documentation': 'Documentation', "Don't know what to do?": "Don't know what to do?", 'done!': 'zrobione!', @@ -81,6 +89,7 @@ 'Groups': 'Groups', 'Hello World': 'Witaj Świecie', 'Helping web2py': 'Helping web2py', +'Hit Ratio: **%(ratio)s%%** (**%(hits)s** %%{hit(hits)} and **%(misses)s** %%{miss(misses)})': 'Hit Ratio: **%(ratio)s%%** (**%(hits)s** %%{hit(hits)} and **%(misses)s** %%{miss(misses)})', 'Home': 'Home', 'How did you get here?': 'How did you get here?', 'import': 'import', @@ -118,6 +127,7 @@ 'next %s rows': 'next %s rows', 'next 100 rows': 'następne 100 wierszy', 'No databases in this application': 'Brak baz danych w tej aplikacji', +'Number of entries: **%s**': 'Number of entries: **%s**', 'Online book': 'Online book', 'Online examples': 'Kliknij aby przejść do interaktywnych przykładów', 'or import from csv file': 'lub zaimportuj z pliku csv', @@ -141,6 +151,7 @@ 'RAM': 'RAM', 'RAM Cache Keys': 'RAM Cache Keys', 'Ram Cleared': 'Ram Cleared', +'RAM contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.': 'RAM contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.', 'Recipes': 'Recipes', 'Record': 'rekord', 'record does not exist': 'rekord nie istnieje', diff --git a/applications/welcome/languages/pt-br.py b/applications/welcome/languages/pt-br.py index ff77f771..d2e32e20 100755 --- a/applications/welcome/languages/pt-br.py +++ b/applications/welcome/languages/pt-br.py @@ -26,7 +26,7 @@ 'Are you sure you want to delete this object?': 'Você tem certeza que quer apagar este objeto?', 'Available Databases and Tables': 'Bancos de dados e tabelas disponíveis', 'Buy this book': 'Compre o livro', -"Buy web2py's book": "Compre o livro do web2buy", +"Buy web2py's book": 'Compre o livro do web2buy', 'cache': 'cache', 'Cache': 'Cache', 'Cache Cleared': 'Cache limpo', @@ -210,4 +210,3 @@ 'You can modify this application and adapt it to your needs': 'Você pode modificar esta aplicação e adaptá-la às suas necessidades', 'You visited the url %s': 'Você acessou a url %s', } - diff --git a/applications/welcome/languages/pt.py b/applications/welcome/languages/pt.py index f0945906..8680e65e 100755 --- a/applications/welcome/languages/pt.py +++ b/applications/welcome/languages/pt.py @@ -27,7 +27,7 @@ 'Author Reference Auth User.username': 'Author Reference Auth User.username', 'Available Databases and Tables': 'bases de dados e tabelas disponíveis', 'Buy this book': 'Comprar este Livro', -"Buy web2py's book": "Comprar Livros web2py", +"Buy web2py's book": 'Comprar Livros web2py', 'cache': 'cache', 'Cache': 'Cache', 'Cache Cleared': 'Cache Limpo', @@ -220,4 +220,3 @@ 'You can modify this application and adapt it to your needs': 'You can modify this application and adapt it to your needs', 'You visited the url %s': 'You visited the url %s', } - diff --git a/applications/welcome/languages/ro.py b/applications/welcome/languages/ro.py index 8be157eb..059a19be 100755 --- a/applications/welcome/languages/ro.py +++ b/applications/welcome/languages/ro.py @@ -12,7 +12,11 @@ '%s selected': '%s selectat(e)', '%Y-%m-%d': '%Y-%m-%d', '%Y-%m-%d %H:%M:%S': '%Y-%m-%d %H:%M:%S', +'(**%.0d MB**)': '(**%.0d MB**)', '(something like "it-it")': '(ceva ce seamănă cu "it-it")', +'**%(items)s** %%{item(items)}, **%(bytes)s** %%{byte(bytes)}': '**%(items)s** %%{item(items)}, **%(bytes)s** %%{byte(bytes)}', +'**%(items)s** items, **%(bytes)s** %%{byte(bytes)}': '**%(items)s** items, **%(bytes)s** %%{byte(bytes)}', +'**not available** (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)': '**not available** (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)', '1 day ago': '1 day ago', '1 week ago': '1 week ago', '<': '<', @@ -21,6 +25,7 @@ '>': '>', '>=': '>=', '?': '?', +'``**not available**``:red (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)': '``**not available**``:red (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)', 'A new version of web2py is available': 'O nouă versiune de web2py este disponibilă', 'A new version of web2py is available: %s': 'O nouă versiune de web2py este disponibilă: %s', 'About': 'Despre', @@ -39,6 +44,7 @@ 'Administrative Interface': 'Interfață administrare', 'Administrator Password:': 'Parolă administrator:', 'Ajax Recipes': 'Rețete Ajax', +'An error occured, please [[reload %s]] the page': 'An error occured, please [[reload %s]] the page', 'And': 'Și', 'and rename it (required):': 'și renumiți (obligatoriu):', 'and rename it:': ' și renumiți:', @@ -62,6 +68,7 @@ 'Cache': 'Cache', 'cache': 'cache', 'Cache Cleared': 'Cache Cleared', +'Cache contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.': 'Cache contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.', 'Cache Keys': 'Chei cache', 'cache, errors and sessions cleaned': 'cache, erori și sesiuni golite', 'Cannot be empty': 'Nu poate fi vid', @@ -123,6 +130,7 @@ 'DISK': 'DISK', 'Disk Cache Keys': 'Chei cache de disc', 'Disk Cleared': 'Disk Cleared', +'DISK contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.': 'DISK contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.', 'Documentation': 'Documentație', "Don't know what to do?": 'Nu știți ce să faceți?', 'done!': 'gata!', @@ -175,6 +183,7 @@ 'Hello World': 'Salutare lume', 'help': 'ajutor', 'Helping web2py': 'Helping web2py', +'Hit Ratio: **%(ratio)s%%** (**%(hits)s** %%{hit(hits)} and **%(misses)s** %%{miss(misses)})': 'Hit Ratio: **%(ratio)s%%** (**%(hits)s** %%{hit(hits)} and **%(misses)s** %%{miss(misses)})', 'Home': 'Acasă', 'How did you get here?': 'Cum ați ajuns aici?', 'htmledit': 'editare html', @@ -241,6 +250,7 @@ 'next 100 rows': 'următoarele 100 de linii', 'NO': 'NU', 'No databases in this application': 'Aplicație fără bază de date', +'Number of entries: **%s**': 'Number of entries: **%s**', 'Object or table name': 'Obiect sau nume de tabel', 'Old password': 'Parola veche', 'Online book': 'Online book', @@ -275,6 +285,7 @@ 'RAM': 'RAM', 'RAM Cache Keys': 'Chei cache RAM', 'Ram Cleared': 'Ram Cleared', +'RAM contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.': 'RAM contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.', 'Recipes': 'Rețete', 'Record': 'înregistrare', 'record does not exist': 'înregistrare inexistentă', diff --git a/applications/welcome/languages/ru.py b/applications/welcome/languages/ru.py index a3f38240..0f9e09db 100755 --- a/applications/welcome/languages/ru.py +++ b/applications/welcome/languages/ru.py @@ -15,6 +15,10 @@ '%s selected': '%%{!выбрана[0]} %s %%{запись[0]}', '%Y-%m-%d': '%Y-%m-%d', '%Y-%m-%d %H:%M:%S': '%Y-%m-%d %H:%M:%S', +'(**%.0d MB**)': '(**%.0d MB**)', +'**%(items)s** %%{item(items)}, **%(bytes)s** %%{byte(bytes)}': '**%(items)s** %%{item(items)}, **%(bytes)s** %%{byte(bytes)}', +'**%(items)s** items, **%(bytes)s** %%{byte(bytes)}': '**%(items)s** items, **%(bytes)s** %%{byte(bytes)}', +'**not available** (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)': '**not available** (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)', '1 day ago': '1 день тому', '1 hour ago': '1 час тому', '1 minute ago': '1 минуту тому', @@ -23,12 +27,14 @@ '1 week ago': '1 неделю тому', '1 year ago': '1 год тому', '?': '?', +'``**not available**``:red (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)': '``**not available**``:red (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)', 'About': 'About', 'Access Control': 'Access Control', 'admin': 'admin', 'Administrative Interface': 'Administrative Interface', 'Administrative interface': 'административный интерфейс', 'Ajax Recipes': 'Ajax Recipes', +'An error occured, please [[reload %s]] the page': 'An error occured, please [[reload %s]] the page', 'appadmin is disabled because insecure channel': 'appadmin is disabled because insecure channel', 'Are you sure you want to delete this object?': 'Вы уверены, что хотите удалить этот объект?', 'Available Databases and Tables': 'Базы данных и таблицы', @@ -37,6 +43,7 @@ 'cache': 'cache', 'Cache': 'Cache', 'Cache Cleared': 'Cache Cleared', +'Cache contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.': 'Cache contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.', 'Cache Keys': 'Cache Keys', 'Cannot be empty': 'Пустое значение недопустимо', 'Change Password': 'Смените пароль', @@ -70,6 +77,7 @@ 'DISK': 'DISK', 'Disk Cache Keys': 'Disk Cache Keys', 'Disk Cleared': 'Disk Cleared', +'DISK contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.': 'DISK contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.', 'Documentation': 'Documentation', "Don't know what to do?": "Don't know what to do?", 'done!': 'готово!', @@ -90,6 +98,7 @@ 'Groups': 'Groups', 'Hello World': 'Заработало!', 'Helping web2py': 'Helping web2py', +'Hit Ratio: **%(ratio)s%%** (**%(hits)s** %%{hit(hits)} and **%(misses)s** %%{miss(misses)})': 'Hit Ratio: **%(ratio)s%%** (**%(hits)s** %%{hit(hits)} and **%(misses)s** %%{miss(misses)})', 'Home': 'Home', 'How did you get here?': 'How did you get here?', 'import': 'import', @@ -132,6 +141,7 @@ 'next 100 rows': 'следующие 100 строк', 'No databases in this application': 'В приложении нет баз данных', 'now': 'сейчас', +'Number of entries: **%s**': 'Number of entries: **%s**', 'Object or table name': 'Object or table name', 'Old password': 'Старый пароль', 'Online book': 'Online book', @@ -159,6 +169,7 @@ 'RAM': 'RAM', 'RAM Cache Keys': 'RAM Cache Keys', 'Ram Cleared': 'Ram Cleared', +'RAM contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.': 'RAM contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.', 'Recipes': 'Recipes', 'Record': 'Record', 'record does not exist': 'запись не найдена', diff --git a/applications/welcome/languages/sk.py b/applications/welcome/languages/sk.py index 0cf6f411..01d31069 100755 --- a/applications/welcome/languages/sk.py +++ b/applications/welcome/languages/sk.py @@ -8,13 +8,19 @@ '%s selected': '%s označených', '%Y-%m-%d': '%d.%m.%Y', '%Y-%m-%d %H:%M:%S': '%d.%m.%Y %H:%M:%S', +'(**%.0d MB**)': '(**%.0d MB**)', +'**%(items)s** %%{item(items)}, **%(bytes)s** %%{byte(bytes)}': '**%(items)s** %%{item(items)}, **%(bytes)s** %%{byte(bytes)}', +'**%(items)s** items, **%(bytes)s** %%{byte(bytes)}': '**%(items)s** items, **%(bytes)s** %%{byte(bytes)}', +'**not available** (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)': '**not available** (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)', '?': '?', +'``**not available**``:red (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)': '``**not available**``:red (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)', 'About': 'O nás', 'Access Control': 'Kontrola prístupu', 'admin': 'admin', 'Administrative Interface': 'Administrátorské rozhranie', 'Administrative interface': 'pre administrátorské rozhranie kliknite sem', 'Ajax Recipes': 'Ajax recepty', +'An error occured, please [[reload %s]] the page': 'An error occured, please [[reload %s]] the page', 'appadmin is disabled because insecure channel': 'appadmin je zakázaný bez zabezpečeného spojenia', 'Are you sure you want to delete this object?': 'Ste si istý, že chcete vymazať tento objekt?', 'Available Databases and Tables': 'Dostupné databázy a tabuľky', @@ -23,6 +29,7 @@ 'cache': 'cache', 'Cache': 'Cache', 'Cache Cleared': 'Cache vymazané', +'Cache contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.': 'Cache contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.', 'Cache Keys': 'Cache kľúče', 'Cannot be empty': 'Nemôže byť prázdne', 'Check to delete': 'Označiť na zmazanie', @@ -53,6 +60,7 @@ 'DISK': 'DISK', 'Disk Cache Keys': 'Disk Cache Keys', 'Disk Cleared': 'Disk vyčistený', +'DISK contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.': 'DISK contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.', 'Documentation': 'Dokumentácia', "Don't know what to do?": 'Neviete, čo robiť?', 'done!': 'hotovo!', @@ -72,6 +80,7 @@ 'Groups': 'Skupiny', 'Hello World': 'Ahoj svet', 'Helping web2py': 'Pomáhať web2py', +'Hit Ratio: **%(ratio)s%%** (**%(hits)s** %%{hit(hits)} and **%(misses)s** %%{miss(misses)})': 'Hit Ratio: **%(ratio)s%%** (**%(hits)s** %%{hit(hits)} and **%(misses)s** %%{miss(misses)})', 'Home': 'Domov', 'How did you get here?': 'Ako ste sa sem dostali?', 'import': 'import', @@ -111,6 +120,7 @@ 'next %s rows': 'next %s rows', 'next 100 rows': 'ďalších 100 riadkov', 'No databases in this application': 'V tejto aplikácii nie sú databázy', +'Number of entries: **%s**': 'Number of entries: **%s**', 'Old password': 'Staré heslo', 'Online book': 'Online kniha', 'Online examples': 'online príklady', @@ -135,6 +145,7 @@ 'RAM': 'RAM', 'RAM Cache Keys': 'RAM cache kľúče', 'Ram Cleared': 'Ram vyčistená', +'RAM contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.': 'RAM contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.', 'Recipes': 'Recepty', 'Record': 'Záznam', 'record does not exist': 'záznam neexistuje', diff --git a/applications/welcome/languages/tr.py b/applications/welcome/languages/tr.py index 23d0b87c..63fb71af 100755 --- a/applications/welcome/languages/tr.py +++ b/applications/welcome/languages/tr.py @@ -13,15 +13,21 @@ '%s selected': '%s selected', '%Y-%m-%d': '%d-%m-%Y', '%Y-%m-%d %H:%M:%S': '%d-%m-%Y %H:%M:%S', +'(**%.0d MB**)': '(**%.0d MB**)', +'**%(items)s** %%{item(items)}, **%(bytes)s** %%{byte(bytes)}': '**%(items)s** %%{item(items)}, **%(bytes)s** %%{byte(bytes)}', +'**%(items)s** items, **%(bytes)s** %%{byte(bytes)}': '**%(items)s** items, **%(bytes)s** %%{byte(bytes)}', +'**not available** (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)': '**not available** (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)', '?': '?', '@markmin\x01**Hello World**': '**Merhaba Dünya**', '@markmin\x01An error occured, please [[reload %s]] the page': 'Bir hata oluştu, lütfen sayfayı [[yenileyin yükleyin %s]] ', +'``**not available**``:red (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)': '``**not available**``:red (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)', 'About': 'Hakkında', 'Access Control': 'Erişim Denetimi', 'admin': 'admin', 'Administrative Interface': 'Yönetim Arayüzü', 'Ajax Recipes': 'Ajax Tarifleri', 'An error occured, please %s the page': 'Bir hata meydana geldi, lütfen sayfayı %s', +'An error occured, please [[reload %s]] the page': 'An error occured, please [[reload %s]] the page', 'appadmin is disabled because insecure channel': 'appadmin is disabled because insecure channel', 'Apply changes': 'Değişiklikleri uygula', 'Are you sure you want to delete this object?': 'Bu nesneyi silmek istediğinden emin misin?', @@ -31,6 +37,7 @@ 'cache': 'zula', 'Cache': 'Cache', 'Cache Cleared': 'Cache Cleared', +'Cache contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.': 'Cache contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.', 'Cache Keys': 'Cache Keys', 'Cannot be empty': 'Boş bırakılamaz', 'Change password': 'Parolayı değiştir', @@ -65,6 +72,7 @@ 'DISK': 'DISK', 'Disk Cache Keys': 'Disk Cache Keys', 'Disk Cleared': 'Disk Cleared', +'DISK contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.': 'DISK contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.', 'Documentation': 'Kitap', "Don't know what to do?": 'Neleri nasıl yapacağını bilmiyor musun?', 'done!': 'done!', @@ -93,6 +101,7 @@ 'Hello World ## comment': 'Merhaba Dünya ## yorum ', 'Hello World## comment': 'Merhaba Dünya## yorum ', 'Helping web2py': 'Helping web2py', +'Hit Ratio: **%(ratio)s%%** (**%(hits)s** %%{hit(hits)} and **%(misses)s** %%{miss(misses)})': 'Hit Ratio: **%(ratio)s%%** (**%(hits)s** %%{hit(hits)} and **%(misses)s** %%{miss(misses)})', 'Home': 'Anasayfa', 'How did you get here?': 'Bu sayfayı görüntüleme uğruna neler mi oldu?', 'import': 'import', @@ -132,6 +141,7 @@ 'new record inserted': 'new record inserted', 'next %s rows': 'next %s rows', 'No databases in this application': 'No databases in this application', +'Number of entries: **%s**': 'Number of entries: **%s**', 'Object or table name': 'Nesne ya da tablo adı', 'Old password': 'Eski parola', 'Online book': 'Online book', @@ -158,6 +168,7 @@ 'RAM': 'RAM', 'RAM Cache Keys': 'RAM Cache Keys', 'Ram Cleared': 'Ram Cleared', +'RAM contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.': 'RAM contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.', 'Recipes': 'Tarifeler', 'Record': 'Record', 'record does not exist': 'record does not exist', diff --git a/applications/welcome/languages/uk.py b/applications/welcome/languages/uk.py index b40fd1dd..eb2678eb 100755 --- a/applications/welcome/languages/uk.py +++ b/applications/welcome/languages/uk.py @@ -15,6 +15,10 @@ '%s selected': 'Вибрано %s %%{запис}', '%Y-%m-%d': '%Y/%m/%d', '%Y-%m-%d %H:%M:%S': '%Y/%m/%d %H:%M:%S', +'(**%.0d MB**)': '(**%.0d MB**)', +'**%(items)s** %%{item(items)}, **%(bytes)s** %%{byte(bytes)}': '**%(items)s** %%{item(items)}, **%(bytes)s** %%{byte(bytes)}', +'**%(items)s** items, **%(bytes)s** %%{byte(bytes)}': '**%(items)s** items, **%(bytes)s** %%{byte(bytes)}', +'**not available** (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)': '**not available** (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)', '1 day ago': '1 день тому', '1 hour ago': '1 годину тому', '1 minute ago': '1 хвилину тому', @@ -32,11 +36,13 @@ '@markmin\x01Hit Ratio: **%(ratio)s%%** (**%(hits)s** %%{hit(hits)} and **%(misses)s** %%{miss(misses)})': 'Оцінка поцілювання: **%(ratio)s%%** (**%(hits)s** %%{поцілювання(hits)} та **%(misses)s** %%{схибнення(misses)})', '@markmin\x01Number of entries: **%s**': 'Кількість входжень: ``**%s**``:red', '@markmin\x01RAM contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.': "Час життя об'єктів в ОЗП-КЕШІ сягає **%(hours)02d** %%{годину(hours)} **%(min)02d** %%{хвилину(min)} та **%(sec)02d** %%{секунду(sec)}.", +'``**not available**``:red (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)': '``**not available**``:red (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)', 'About': 'Про додаток', 'Access Control': 'Контроль доступу', 'admin': 'admin', 'Administrative Interface': 'Адміністративний інтерфейс', 'Ajax Recipes': 'Рецепти для Ajax', +'An error occured, please [[reload %s]] the page': 'An error occured, please [[reload %s]] the page', 'appadmin is disabled because insecure channel': 'використовується незахищенний канал (HTTP). Appadmin вимкнено', 'Are you sure you want to delete this object?': "Ви впевнені, що хочете вилучити цей об'єкт?", 'Available Databases and Tables': 'Доступні бази даних та таблиці', @@ -45,6 +51,7 @@ 'cache': 'кеш', 'Cache': 'Кеш', 'Cache Cleared': 'Cache Cleared', +'Cache contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.': 'Cache contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.', 'Cache Keys': 'Ключі кешу', 'Cannot be empty': 'Порожнє значення неприпустиме', 'Change password': 'Змінити пароль', @@ -80,6 +87,7 @@ 'DISK': 'ДИСК', 'Disk Cache Keys': 'Ключі дискового кешу', 'Disk Cleared': 'Дисковий кеш очищено', +'DISK contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.': 'DISK contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.', 'Documentation': 'Документація', "Don't know what to do?": 'Не знаєте що робити далі?', 'done!': 'зроблено!', @@ -107,6 +115,7 @@ 'Groups': 'Групи', 'Hello World': 'Привіт, світ!', 'Helping web2py': 'Helping web2py', +'Hit Ratio: **%(ratio)s%%** (**%(hits)s** %%{hit(hits)} and **%(misses)s** %%{miss(misses)})': 'Hit Ratio: **%(ratio)s%%** (**%(hits)s** %%{hit(hits)} and **%(misses)s** %%{miss(misses)})', 'Home': 'Початок', 'How did you get here?': 'Як цього було досягнуто?', 'import': 'Імпортувати', @@ -150,6 +159,7 @@ 'next 100 rows': 'наступні 100 рядків', 'No databases in this application': 'Даний додаток не використовує базу даних', 'now': 'зараз', +'Number of entries: **%s**': 'Number of entries: **%s**', 'Object or table name': "Об'єкт або назва таблиці", 'Old password': 'Старий пароль', 'Online book': 'Online book', @@ -181,6 +191,7 @@ 'RAM': "ОПЕРАТИВНА ПАМ'ЯТЬ (ОЗП)", 'RAM Cache Keys': 'Ключі ОЗП-кешу', 'Ram Cleared': 'ОЗП-кеш очищено', +'RAM contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.': 'RAM contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.', 'Recipes': 'Рецепти', 'Record': 'запис', 'Record %(id)s updated': 'Запис %(id)s змінено', diff --git a/applications/welcome/languages/zh-cn.py b/applications/welcome/languages/zh-cn.py index 888040c5..916384d5 100755 --- a/applications/welcome/languages/zh-cn.py +++ b/applications/welcome/languages/zh-cn.py @@ -8,8 +8,13 @@ '%s selected': '%s 已选择', '%Y-%m-%d': '%Y-%m-%d', '%Y-%m-%d %H:%M:%S': '%Y-%m-%d %H:%M:%S', +'(**%.0d MB**)': '(**%.0d MB**)', '(something like "it-it")': '(格式类似 "zh-tw")', +'**%(items)s** %%{item(items)}, **%(bytes)s** %%{byte(bytes)}': '**%(items)s** %%{item(items)}, **%(bytes)s** %%{byte(bytes)}', +'**%(items)s** items, **%(bytes)s** %%{byte(bytes)}': '**%(items)s** items, **%(bytes)s** %%{byte(bytes)}', +'**not available** (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)': '**not available** (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)', '?': '?', +'``**not available**``:red (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)': '``**not available**``:red (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)', 'A new version of web2py is available': '新版 web2py 已推出', 'A new version of web2py is available: %s': '新版 web2py 已推出: %s', 'about': '关于', @@ -24,6 +29,7 @@ 'Administrator Password:': '管理员密码:', 'Ajax Recipes': 'Ajax Recipes', 'An error occured, please %s the page': 'An error occured, please %s the page', +'An error occured, please [[reload %s]] the page': 'An error occured, please [[reload %s]] the page', 'appadmin is disabled because insecure channel': '管理界面在非安全通道下被禁用', 'Are you sure you want to delete file "%s"?': '确定要删除文件"%s"?', 'Are you sure you want to delete this object?': '确定要删除该对象么?', @@ -39,6 +45,7 @@ 'cache': '高速缓存', 'Cache': 'Cache', 'Cache Cleared': 'Cache Cleared', +'Cache contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.': 'Cache contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.', 'Cache Keys': 'Cache Keys', 'Cannot be empty': '不可空白', 'Cannot compile: there are errors in your app. Debug it, correct errors and try again.': '编译失败:应用程序有错误,请排除错误后再尝试编译.', @@ -83,6 +90,7 @@ 'DISK': 'DISK', 'Disk Cache Keys': 'Disk Cache Keys', 'Disk Cleared': 'Disk Cleared', +'DISK contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.': 'DISK contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.', 'Documentation': 'Documentation', "Don't know what to do?": "Don't know what to do?", 'done!': '完成!', @@ -113,6 +121,7 @@ 'Groups': 'Groups', 'Hello World': 'Hello World', 'Helping web2py': 'Helping web2py', +'Hit Ratio: **%(ratio)s%%** (**%(hits)s** %%{hit(hits)} and **%(misses)s** %%{miss(misses)})': 'Hit Ratio: **%(ratio)s%%** (**%(hits)s** %%{hit(hits)} and **%(misses)s** %%{miss(misses)})', 'Home': 'Home', 'How did you get here?': 'How did you get here?', 'import': 'import', @@ -164,6 +173,7 @@ 'next 100 rows': '往后 100 笔', 'NO': '否', 'No databases in this application': '该应用程序不含数据库', +'Number of entries: **%s**': 'Number of entries: **%s**', 'Object or table name': 'Object or table name', 'Online book': 'Online book', 'Online examples': '点击进入在线例子', @@ -190,6 +200,7 @@ 'RAM': 'RAM', 'RAM Cache Keys': 'RAM Cache Keys', 'Ram Cleared': 'Ram Cleared', +'RAM contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.': 'RAM contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.', 'Recipes': 'Recipes', 'Record': '记录', 'record does not exist': '记录不存在', diff --git a/applications/welcome/languages/zh-tw.py b/applications/welcome/languages/zh-tw.py index 33e94daf..2b64c75d 100755 --- a/applications/welcome/languages/zh-tw.py +++ b/applications/welcome/languages/zh-tw.py @@ -8,8 +8,13 @@ '%s selected': '%s 已選擇', '%Y-%m-%d': '%Y-%m-%d', '%Y-%m-%d %H:%M:%S': '%Y-%m-%d %H:%M:%S', +'(**%.0d MB**)': '(**%.0d MB**)', '(something like "it-it")': '(格式類似 "zh-tw")', +'**%(items)s** %%{item(items)}, **%(bytes)s** %%{byte(bytes)}': '**%(items)s** %%{item(items)}, **%(bytes)s** %%{byte(bytes)}', +'**%(items)s** items, **%(bytes)s** %%{byte(bytes)}': '**%(items)s** items, **%(bytes)s** %%{byte(bytes)}', +'**not available** (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)': '**not available** (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)', '?': '?', +'``**not available**``:red (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)': '``**not available**``:red (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)', 'A new version of web2py is available': '新版的 web2py 已發行', 'A new version of web2py is available: %s': '新版的 web2py 已發行: %s', 'about': '關於', @@ -24,6 +29,7 @@ 'Administrator Password:': '管理員密碼:', 'Ajax Recipes': 'Ajax Recipes', 'An error occured, please %s the page': 'An error occured, please %s the page', +'An error occured, please [[reload %s]] the page': 'An error occured, please [[reload %s]] the page', 'appadmin is disabled because insecure channel': '因為來自非安全通道,管理介面關閉', 'Are you sure you want to delete file "%s"?': '確定要刪除檔案"%s"?', 'Are you sure you want to delete this object?': 'Are you sure you want to delete this object?', @@ -39,6 +45,7 @@ 'cache': '快取記憶體', 'Cache': 'Cache', 'Cache Cleared': 'Cache Cleared', +'Cache contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.': 'Cache contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.', 'Cache Keys': 'Cache Keys', 'Cannot be empty': '不可空白', 'Cannot compile: there are errors in your app. Debug it, correct errors and try again.': '無法編譯:應用程式中含有錯誤,請除錯後再試一次.', @@ -83,6 +90,7 @@ 'DISK': 'DISK', 'Disk Cache Keys': 'Disk Cache Keys', 'Disk Cleared': 'Disk Cleared', +'DISK contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.': 'DISK contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.', 'Documentation': 'Documentation', "Don't know what to do?": "Don't know what to do?", 'done!': '完成!', @@ -113,6 +121,7 @@ 'Groups': 'Groups', 'Hello World': '嗨! 世界', 'Helping web2py': 'Helping web2py', +'Hit Ratio: **%(ratio)s%%** (**%(hits)s** %%{hit(hits)} and **%(misses)s** %%{miss(misses)})': 'Hit Ratio: **%(ratio)s%%** (**%(hits)s** %%{hit(hits)} and **%(misses)s** %%{miss(misses)})', 'Home': 'Home', 'How did you get here?': 'How did you get here?', 'import': 'import', @@ -164,6 +173,7 @@ 'next 100 rows': '往後 100 筆', 'NO': '否', 'No databases in this application': '這應用程式不含資料庫', +'Number of entries: **%s**': 'Number of entries: **%s**', 'Object or table name': 'Object or table name', 'Online book': 'Online book', 'Online examples': '點此處進入線上範例', @@ -190,6 +200,7 @@ 'RAM': 'RAM', 'RAM Cache Keys': 'RAM Cache Keys', 'Ram Cleared': 'Ram Cleared', +'RAM contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.': 'RAM contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.', 'Recipes': 'Recipes', 'Record': '紀錄', 'record does not exist': '紀錄不存在', diff --git a/applications/welcome/languages/zh.py b/applications/welcome/languages/zh.py index e92241a2..97940322 100755 --- a/applications/welcome/languages/zh.py +++ b/applications/welcome/languages/zh.py @@ -8,8 +8,13 @@ '%s selected': '%s 已選擇', '%Y-%m-%d': '%Y-%m-%d', '%Y-%m-%d %H:%M:%S': '%Y-%m-%d %H:%M:%S', +'(**%.0d MB**)': '(**%.0d MB**)', '(something like "it-it")': '(格式類似 "zh-tw")', +'**%(items)s** %%{item(items)}, **%(bytes)s** %%{byte(bytes)}': '**%(items)s** %%{item(items)}, **%(bytes)s** %%{byte(bytes)}', +'**%(items)s** items, **%(bytes)s** %%{byte(bytes)}': '**%(items)s** items, **%(bytes)s** %%{byte(bytes)}', +'**not available** (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)': '**not available** (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)', '?': '?', +'``**not available**``:red (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)': '``**not available**``:red (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)', 'A new version of web2py is available': '新版的 web2py 已發行', 'A new version of web2py is available: %s': '新版的 web2py 已發行: %s', 'about': '關於', @@ -23,6 +28,7 @@ 'Administrative interface': '點此處進入管理介面', 'Administrator Password:': '管理員密碼:', 'Ajax Recipes': 'Ajax Recipes', +'An error occured, please [[reload %s]] the page': 'An error occured, please [[reload %s]] the page', 'appadmin is disabled because insecure channel': '因為來自非安全通道,管理介面關閉', 'Are you sure you want to delete file "%s"?': '確定要刪除檔案"%s"?', 'Are you sure you want to delete this object?': 'Are you sure you want to delete this object?', @@ -38,6 +44,7 @@ 'cache': '快取記憶體', 'Cache': 'Cache', 'Cache Cleared': 'Cache Cleared', +'Cache contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.': 'Cache contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.', 'Cache Keys': 'Cache Keys', 'Cannot be empty': '不可空白', 'Cannot compile: there are errors in your app. Debug it, correct errors and try again.': '無法編譯:應用程式中含有錯誤,請除錯後再試一次.', @@ -80,6 +87,7 @@ 'DISK': 'DISK', 'Disk Cache Keys': 'Disk Cache Keys', 'Disk Cleared': 'Disk Cleared', +'DISK contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.': 'DISK contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.', 'Documentation': 'Documentation', "Don't know what to do?": "Don't know what to do?", 'done!': '完成!', @@ -108,6 +116,7 @@ 'Groups': 'Groups', 'Hello World': '嗨! 世界', 'Helping web2py': 'Helping web2py', +'Hit Ratio: **%(ratio)s%%** (**%(hits)s** %%{hit(hits)} and **%(misses)s** %%{miss(misses)})': 'Hit Ratio: **%(ratio)s%%** (**%(hits)s** %%{hit(hits)} and **%(misses)s** %%{miss(misses)})', 'Home': 'Home', 'How did you get here?': 'How did you get here?', 'import': 'import', @@ -155,6 +164,7 @@ 'next 100 rows': '往後 100 筆', 'NO': '否', 'No databases in this application': '這應用程式不含資料庫', +'Number of entries: **%s**': 'Number of entries: **%s**', 'Online book': 'Online book', 'Online examples': '點此處進入線上範例', 'or import from csv file': '或是從逗號分隔檔(CSV)匯入', @@ -180,6 +190,7 @@ 'RAM': 'RAM', 'RAM Cache Keys': 'RAM Cache Keys', 'Ram Cleared': 'Ram Cleared', +'RAM contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.': 'RAM contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.', 'Recipes': 'Recipes', 'Record': '紀錄', 'record does not exist': '紀錄不存在', From f9dce481f79e97fa8b64531588a049c9dcfeb624 Mon Sep 17 00:00:00 2001 From: Vinyl Darkscratch Date: Fri, 9 Sep 2016 01:09:39 -0700 Subject: [PATCH 04/49] Added encoding to plural files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added “# -*- coding: utf-8 -*-“ lines to all plural files --- applications/admin/languages/plural-en.py | 1 + applications/admin/languages/plural-ru.py | 1 + applications/admin/languages/plural-uk.py | 1 + applications/welcome/languages/plural-cs.py | 1 + applications/welcome/languages/plural-en.py | 1 + applications/welcome/languages/plural-es.py | 3 ++- applications/welcome/languages/plural-ru.py | 1 + applications/welcome/languages/plural-uk.py | 1 + 8 files changed, 9 insertions(+), 1 deletion(-) diff --git a/applications/admin/languages/plural-en.py b/applications/admin/languages/plural-en.py index 638e23e3..3c711a31 100755 --- a/applications/admin/languages/plural-en.py +++ b/applications/admin/languages/plural-en.py @@ -1,4 +1,5 @@ #!/usr/bin/env python +# -*- coding: utf-8 -*- { # "singular form (0)": ["first plural form (1)", "second plural form (2)", ...], 'file': ['files'], diff --git a/applications/admin/languages/plural-ru.py b/applications/admin/languages/plural-ru.py index 4ccd46ad..0900bc91 100755 --- a/applications/admin/languages/plural-ru.py +++ b/applications/admin/languages/plural-ru.py @@ -1,4 +1,5 @@ #!/usr/bin/env python +# -*- coding: utf-8 -*- { # "singular form (0)": ["first plural form (1)", "second plural form (2)", ...], 'файл': ['файла','файлов'], diff --git a/applications/admin/languages/plural-uk.py b/applications/admin/languages/plural-uk.py index e2d7a0fb..cbb014ac 100755 --- a/applications/admin/languages/plural-uk.py +++ b/applications/admin/languages/plural-uk.py @@ -1,4 +1,5 @@ #!/usr/bin/env python +# -*- coding: utf-8 -*- { # "singular form (0)": ["first plural form (1)", "second plural form (2)", ...], 'останній': ['останні','останніх'], diff --git a/applications/welcome/languages/plural-cs.py b/applications/welcome/languages/plural-cs.py index a58226bf..2a795587 100755 --- a/applications/welcome/languages/plural-cs.py +++ b/applications/welcome/languages/plural-cs.py @@ -1,4 +1,5 @@ #!/usr/bin/env python +# -*- coding: utf-8 -*- { # "singular form (0)": ["first plural form (1)", "second plural form (2)", ...], 'vteřina': ['vteřiny', 'vteřin'], diff --git a/applications/welcome/languages/plural-en.py b/applications/welcome/languages/plural-en.py index fecf98ea..5103b462 100755 --- a/applications/welcome/languages/plural-en.py +++ b/applications/welcome/languages/plural-en.py @@ -1,4 +1,5 @@ #!/usr/bin/env python +# -*- coding: utf-8 -*- { # "singular form (0)": ["first plural form (1)", "second plural form (2)", ...], 'account': ['accounts'], diff --git a/applications/welcome/languages/plural-es.py b/applications/welcome/languages/plural-es.py index 5e3c9e16..235f1a3a 100755 --- a/applications/welcome/languages/plural-es.py +++ b/applications/welcome/languages/plural-es.py @@ -1,4 +1,5 @@ -# coding: utf-8 +#!/usr/bin/env python +# -*- coding: utf-8 -*- { # "singular form (0)": ["first plural form (1)", "second plural form (2)", ...], 'fila': ['filas'], diff --git a/applications/welcome/languages/plural-ru.py b/applications/welcome/languages/plural-ru.py index 61499183..d9e73a07 100755 --- a/applications/welcome/languages/plural-ru.py +++ b/applications/welcome/languages/plural-ru.py @@ -1,4 +1,5 @@ #!/usr/bin/env python +# -*- coding: utf-8 -*- { # "singular form (0)": ["first plural form (1)", "second plural form (2)", ...], 'выбрана': ['выбраны','выбрано'], diff --git a/applications/welcome/languages/plural-uk.py b/applications/welcome/languages/plural-uk.py index c07ebda4..e75ef121 100755 --- a/applications/welcome/languages/plural-uk.py +++ b/applications/welcome/languages/plural-uk.py @@ -1,4 +1,5 @@ #!/usr/bin/env python +# -*- coding: utf-8 -*- { # "singular form (0)": ["first plural form (1)", "second plural form (2)", ...], 'байт': ['байти','байтів'], From 2140eced7950fbd41c4dca906550ea3cfb9b50a2 Mon Sep 17 00:00:00 2001 From: Vinyl Darkscratch Date: Fri, 9 Sep 2016 01:26:41 -0700 Subject: [PATCH 05/49] Fixing a consistency error when updating T.M() translations --- gluon/languages.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gluon/languages.py b/gluon/languages.py index 98fa4790..afc5b332 100644 --- a/gluon/languages.py +++ b/gluon/languages.py @@ -962,7 +962,7 @@ def findT(path, language=DEFAULT_LANGUAGE): + listdir(vp, '^.+\.html$', 0) + listdir(mop, '^.+\.py$', 0): data = to_native(read_locked(filename)) items = regex_translate.findall(data) - items += regex_translate_m.findall(data) + items += ["@markmin\x01%s" %x for x in regex_translate_m.findall(data)] for item in items: try: message = safe_eval(item) @@ -976,7 +976,7 @@ def findT(path, language=DEFAULT_LANGUAGE): if len(tokens) == 2: message = tokens[0].strip() + '##' + tokens[1].strip() if message and not message in sentences: - sentences[message] = message + sentences[message] = message.replace("@markmin\x01", "") if not '!langcode!' in sentences: sentences['!langcode!'] = ( DEFAULT_LANGUAGE if language in ('default', DEFAULT_LANGUAGE) else language) From aee0f8dbc578bd80fa3a01af09e47b0779266ea8 Mon Sep 17 00:00:00 2001 From: Vinyl Darkscratch Date: Fri, 9 Sep 2016 01:59:14 -0700 Subject: [PATCH 06/49] Stripped unused strings from translations --- applications/admin/languages/af.py | 553 +++++++++- applications/admin/languages/bg.py | 630 ++++++++--- applications/admin/languages/cs.py | 242 ++++- applications/admin/languages/de.py | 290 ++++- applications/admin/languages/default.py | 184 ---- applications/admin/languages/en.py | 574 ++++++++++ applications/admin/languages/es.py | 13 +- applications/admin/languages/fr.py | 8 +- applications/admin/languages/he.py | 625 ++++++++--- applications/admin/languages/it.py | 295 ++++- applications/admin/languages/ja.py | 386 ++++++- applications/admin/languages/my-mm.py | 394 ++++++- applications/admin/languages/nl.py | 176 ++- applications/admin/languages/pl.py | 625 ++++++++--- applications/admin/languages/pt-br.py | 324 +++++- applications/admin/languages/pt.py | 1078 ++++++++++++------- applications/admin/languages/ro.py | 861 ++++++++++----- applications/admin/languages/ru.py | 342 +++++- applications/admin/languages/sl.py | 735 +++++++++---- applications/admin/languages/sr-cr.py | 391 ++++++- applications/admin/languages/sr-lt.py | 391 ++++++- applications/admin/languages/tr.py | 232 +++- applications/admin/languages/uk.py | 141 ++- applications/admin/languages/zh-tw.py | 690 +++++++++--- applications/admin/languages/zh.py | 669 +++++++++--- applications/welcome/languages/.DS_Store | Bin 0 -> 6148 bytes applications/welcome/languages/ca.py | 2 +- applications/welcome/languages/cs.py | 2 +- applications/welcome/languages/default.py | 122 --- applications/welcome/languages/en.py | 157 +++ applications/welcome/languages/plural-cs.py | 40 +- applications/welcome/languages/plural-en.py | 24 +- applications/welcome/languages/plural-es.py | 10 +- 33 files changed, 9192 insertions(+), 2014 deletions(-) delete mode 100755 applications/admin/languages/default.py create mode 100755 applications/admin/languages/en.py create mode 100644 applications/welcome/languages/.DS_Store delete mode 100755 applications/welcome/languages/default.py create mode 100755 applications/welcome/languages/en.py diff --git a/applications/admin/languages/af.py b/applications/admin/languages/af.py index d1a83621..6351ae09 100755 --- a/applications/admin/languages/af.py +++ b/applications/admin/languages/af.py @@ -2,88 +2,581 @@ { '!langcode!': 'af', '!langname!': 'Afrikaanse', -'%Y-%m-%d': '%Y-%m-%d', -'%Y-%m-%d %H:%M:%S': '%Y-%m-%d %H:%M:%S', +'"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN': '"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN', +'"User Exception" debug mode. ': '"User Exception" debug mode. ', +'%s': '%s', '%s %%{row} deleted': '%s rows deleted', '%s %%{row} updated': '%s rows updated', +'%s selected': '%s selected', +'%s students registered': '%s students registered', +'%Y-%m-%d': '%Y-%m-%d', +'%Y-%m-%d %H:%M:%S': '%Y-%m-%d %H:%M:%S', '(requires internet access)': '(vereis internet toegang)', +'(requires internet access, experimental)': '(requires internet access, experimental)', '(something like "it-it")': '(iets soos "it-it")', +'(version %s)': '(version %s)', +'?': '?', '@markmin\x01Searching: **%s** %%{file}': 'Soek: **%s** lêre', +'Abort': 'Abort', 'About': 'oor', 'About application': 'Oor program', +'Accept Terms': 'Accept Terms', +'Add breakpoint': 'Add breakpoint', 'Additional code for your application': 'Additionele kode vir u application', +'Admin design page': 'Admin design page', +'admin disabled because no admin password': 'admin disabled because no admin password', +'admin disabled because not supported on google app engine': 'admin disabled because not supported on google app engine', +'admin disabled because too many invalid login attempts': 'admin disabled because too many invalid login attempts', +'admin disabled because unable to access password file': 'admin disabled because unable to access password file', +'Admin is disabled because insecure channel': 'Admin is disabled because insecure channel', 'Admin language': 'Admin taal', +'Admin versioning page': 'Admin versioning page', +'administrative interface': 'administrative interface', +'Administrator Password:': 'Administrator Password:', +'and rename it:': 'en verander die naam:', +'App does not exist or you are not authorized': 'App does not exist or you are not authorized', +'appadmin': 'appadmin', +'appadmin is disabled because insecure channel': 'appadmin is disabled because insecure channel', +'Application': 'Application', +'application "%s" uninstalled': 'application "%s" uninstalled', +'Application cannot be generated in demo mode': 'Application cannot be generated in demo mode', +'application compiled': 'application compiled', +'Application exists already': 'Application exists already', +'application is compiled and cannot be designed': 'application is compiled and cannot be designed', 'Application name:': 'Program naam:', +'Application updated via git pull': 'Application updated via git pull', +'are not used': 'are not used', +'are not used yet': 'are not used yet', +'Are you sure you want to delete file "%s"?': 'Are you sure you want to delete file "%s"?', +'Are you sure you want to delete plugin "%s"?': 'Are you sure you want to delete plugin "%s"?', +'Are you sure you want to delete this object?': 'Are you sure you want to delete this object?', +'Are you sure you want to uninstall application "%s"?': 'Are you sure you want to uninstall application "%s"?', +'Are you sure?': 'Are you sure?', +'arguments': 'arguments', +'at char %s': 'at char %s', +'at line %s': 'at line %s', +'ATTENTION:': 'ATTENTION:', +'ATTENTION: Login requires a secure (HTTPS) connection or running on localhost.': 'ATTENTION: Login requires a secure (HTTPS) connection or running on localhost.', +'ATTENTION: TESTING IS NOT THREAD SAFE SO DO NOT PERFORM MULTIPLE TESTS CONCURRENTLY.': 'ATTENTION: TESTING IS NOT THREAD SAFE SO DO NOT PERFORM MULTIPLE TESTS CONCURRENTLY.', +'ATTENTION: you cannot edit the running application!': 'ATTENTION: you cannot edit the running application!', +'Autocomplete Python Code': 'Autocomplete Python Code', +'Available Databases and Tables': 'Available Databases and Tables', +'back': 'back', +'Back to the plugins list': 'Back to the plugins list', +'Back to wizard': 'Back to wizard', +'Basics': 'Basics', +'Begin': 'Begin', +'breakpoint': 'breakpoint', +'Breakpoints': 'Breakpoints', +'breakpoints': 'breakpoints', +'Bulk Register': 'Bulk Register', +'Bulk Student Registration': 'Bulk Student Registration', +'Cache': 'Cache', +'cache': 'cache', +'Cache Cleared': 'Cache Cleared', +'Cache Keys': 'Cache Keys', +'cache, errors and sessions cleaned': 'cache, errors and sessions cleaned', +'can be a git repo': 'can be a git repo', +'Cancel': 'Cancel', +'Cannot be empty': 'Cannot be empty', +'Cannot compile: there are errors in your app:': 'Cannot compile: there are errors in your app:', +'cannot create file': 'cannot create file', +'cannot upload file "%(filename)s"': 'cannot upload file "%(filename)s"', +'Change Admin Password': 'Change Admin Password', 'Change admin password': 'verander admin wagwoord', +'change editor settings': 'change editor settings', +'Changelog': 'Changelog', +'check all': 'check all', 'Check for upgrades': 'soek vir upgrades', +'Check to delete': 'Check to delete', +'Checking for upgrades...': 'Checking for upgrades...', 'Clean': 'maak skoon', +'Clear': 'Clear', +'Clear CACHE?': 'Clear CACHE?', +'Clear DISK': 'Clear DISK', +'Clear RAM': 'Clear RAM', +'Click row to expand traceback': 'Click row to expand traceback', +'Click row to view a ticket': 'Click row to view a ticket', +'code': 'code', +'Code listing': 'Code listing', +'collapse/expand all': 'collapse/expand all', +'Command': 'Command', +'Comment:': 'Comment:', +'Commit': 'Commit', +'Commit form': 'Commit form', +'Committed files': 'Committed files', 'Compile': 'kompileer', +'Compile (all or nothing)': 'Compile (all or nothing)', +'Compile (skip failed views)': 'Compile (skip failed views)', +'compiled application removed': 'compiled application removed', +'Condition': 'Condition', +'continue': 'continue', 'Controllers': 'Beheerders', +'controllers': 'beheerders', +'Count': 'Count', 'Create': 'skep', +'create file with filename:': 'skep lêer met naam:', +'Create/Upload': 'Create/Upload', +'created by': 'geskep deur', +'Created by:': 'Created by:', +'Created On': 'Created On', +'Created on:': 'Created on:', +'crontab': 'crontab', +'Current request': 'Current request', +'Current response': 'Current response', +'Current session': 'Current session', +'currently running': 'loop tans', +'currently saved or': 'currently saved or', +'data uploaded': 'data uploaded', +'Database': 'Database', +'Database %s select': 'Database %s select', +'Database administration': 'Database administration', +'database administration': 'database administration', +'Database Administration (appadmin)': 'Database Administration (appadmin)', +'Date and Time': 'Date and Time', +'db': 'db', +'Debug': 'Debug', +'defines tables': 'defines tables', +'Delete': 'Delete', +'delete': 'delete', +'delete all checked': 'delete all checked', +'delete plugin': 'delete plugin', +'Delete this file (you will be asked to confirm deletion)': 'Delete this file (you will be asked to confirm deletion)', +'Delete:': 'Delete:', +'deleted after first hit': 'deleted after first hit', +'Demo': 'Demo', 'Deploy': 'deploy', 'Deploy on Google App Engine': 'Stuur na Google App Engine toe', +'Deploy to OpenShift': 'Deploy to OpenShift', +'Deploy to pythonanywhere': 'Deploy to pythonanywhere', +'Deploy to PythonAnywhere': 'Deploy to PythonAnywhere', +'Deployment form': 'Deployment form', +'Deployment Interface': 'Deployment Interface', +'Description:': 'Description:', +'design': 'design', +'Detailed traceback description': 'Detailed traceback description', +'details': 'details', +'direction: ltr': 'direction: ltr', +'directory not found': 'directory not found', +'Disable': 'Disable', +'Disabled': 'Disabled', +'disabled in demo mode': 'disabled in demo mode', +'disabled in GAE mode': 'disabled in GAE mode', +'disabled in multi user mode': 'disabled in multi user mode', +'DISK': 'DISK', +'Disk Cache Keys': 'Disk Cache Keys', +'Disk Cleared': 'Disk Cleared', +'Display line numbers': 'Display line numbers', +'DO NOT use the "Pack compiled" feature.': 'DO NOT use the "Pack compiled" feature.', +'docs': 'docs', +'Docs': 'Docs', +'done!': 'done!', +'Downgrade': 'Downgrade', +'Download .w2p': 'Download .w2p', +'Download as .exe': 'Download as .exe', +'download layouts': 'aflaai layouts', +'Download layouts from repository': 'Download layouts from repository', +'download plugins': 'aflaai plugins', +'Download plugins from repository': 'Download plugins from repository', 'Edit': 'wysig', +'edit all': 'edit all', 'Edit application': 'Wysig program', +'edit controller:': 'edit controller:', +'Edit current record': 'Edit current record', +'edit views:': 'edit views:', +'Editing %s': 'Editing %s', +'Editing Language file': 'Editing Language file', +'Editing Plural Forms File': 'Editing Plural Forms File', +'Editor': 'Editor', +'Email Address': 'Email Address', +'Enable': 'Enable', +'Enable Close-Tag': 'Enable Close-Tag', +'Enable Code Folding': 'Enable Code Folding', +'Error': 'Error', +'Error logs for "%(app)s"': 'Error logs for "%(app)s"', +'Error snapshot': 'Error snapshot', +'Error ticket': 'Error ticket', 'Errors': 'foute', +'Exception %(extype)s: %(exvalue)s': 'Exception %(extype)s: %(exvalue)s', +'Exception %s': 'Exception %s', +'Exception instance attributes': 'Exception instance attributes', +'Exit Fullscreen': 'Exit Fullscreen', +'Expand Abbreviation (html files only)': 'Expand Abbreviation (html files only)', +'export as csv file': 'export as csv file', +'Exports:': 'Exports:', +'exposes': 'exposes', +'exposes:': 'exposes:', +'extends': 'extends', +'failed to compile file because:': 'failed to compile file because:', +'failed to reload module because:': 'failed to reload module because:', +'File': 'File', +'file "%(filename)s" created': 'file "%(filename)s" created', +'file "%(filename)s" deleted': 'file "%(filename)s" deleted', +'file "%(filename)s" uploaded': 'file "%(filename)s" uploaded', +'file "%s" of %s restored': 'file "%s" of %s restored', +'file changed on disk': 'file changed on disk', +'file does not exist': 'file does not exist', +'file not found': 'file not found', +'file saved on %(time)s': 'file saved on %(time)s', +'file saved on %s': 'file saved on %s', +'filename': 'filename', +'Filename': 'Filename', +'Files added': 'Files added', +'filter': 'filter', +'Find Next': 'Find Next', +'Find Previous': 'Find Previous', +'Form has errors': 'Form has errors', +'Frames': 'Frames', +'Functions with no doctests will result in [passed] tests.': 'Functions with no doctests will result in [passed] tests.', +'GAE Email': 'GAE Email', +'GAE Output': 'GAE Output', +'GAE Password': 'GAE Password', +'Generate': 'Generate', +'Git Pull': 'Git Pull', +'Git Push': 'Git Push', +'Globals##debug': 'Globals##debug', +'go!': 'go!', +'Google App Engine Deployment Interface': 'Google App Engine Deployment Interface', +'Google Application Id': 'Google Application Id', +'Goto': 'Goto', +'graph model': 'graph model', +'Graph Model': 'Graph Model', 'Help': 'hulp', +'here': 'here', +'Hide/Show Translated strings': 'Hide/Show Translated strings', +'Highlight current line': 'Highlight current line', +'Hits': 'Hits', +'Home': 'Home', +'honored only if the expression evaluates to true': 'honored only if the expression evaluates to true', +'If start the downgrade, be patient, it may take a while to rollback': 'If start the downgrade, be patient, it may take a while to rollback', +'If start the upgrade, be patient, it may take a while to download': 'If start the upgrade, be patient, it may take a while to download', +'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\n\t\tA green title indicates that all tests (if defined) passed. In this case test results are not shown.': 'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\n\t\tA green title indicates that all tests (if defined) passed. In this case test results are not shown.', +'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\nA green title indicates that all tests (if defined) passed. In this case test results are not shown.': 'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\nA green title indicates that all tests (if defined) passed. In this case test results are not shown.', +'if your application uses a database other than sqlite you will then have to configure its DAL in pythonanywhere.': 'if your application uses a database other than sqlite you will then have to configure its DAL in pythonanywhere.', +'import': 'import', +'Import/Export': 'Import/Export', +'In development, use the default Rocket webserver that is currently supported by this debugger.': 'In development, use the default Rocket webserver that is currently supported by this debugger.', +'includes': 'includes', +'Indent with tabs': 'Indent with tabs', +'inspect attributes': 'inspect attributes', 'Install': 'installeer', +'Installation of %(plugin)s for %(app)s': 'Installation of %(plugin)s for %(app)s', 'Installed applications': 'Geinstalleerde apps', +'Interaction at %s line %s': 'Interaction at %s line %s', +'Interactive console': 'Interactive console', +'internal error': 'internal error', +'internal error: %s': 'internal error: %s', +'Internal State': 'Internal State', +'Invalid action': 'Invalid action', +'Invalid application name': 'Invalid application name', +'invalid circular reference': 'invalid circular reference', +'Invalid git repository specified.': 'Invalid git repository specified.', +'invalid password': 'invalid password', +'invalid password.': 'invalid password.', +'Invalid Query': 'Invalid Query', +'invalid request': 'invalid request', +'Invalid request': 'Invalid request', +'invalid table names (auth_* tables already defined)': 'invalid table names (auth_* tables already defined)', +'invalid ticket': 'invalid ticket', +'Key': 'Key', +'Keyboard shortcuts': 'Keyboard shortcuts', +'kill process': 'kill process', +'language file "%(filename)s" created/updated': 'language file "%(filename)s" created/updated', +'Language files (static strings) updated': 'Language files (static strings) updated', +'languages': 'tale', 'Languages': 'Tale', +'Last Revision': 'Last Revision', +'Last saved on:': 'Last saved on:', 'License for': 'Lisensie vir', +'License:': 'License:', +'Line Nr': 'Line Nr', +'Line number': 'Line number', +'lists by exception': 'lists by exception', +'lists by ticket': 'lists by ticket', +'Loading...': 'Loading...', +'loading...': 'laai...', +'Local Apps': 'Local Apps', +'locals': 'locals', +'Locals##debug': 'Locals##debug', +'Login': 'Login', +'Login successful': 'Login successful', +'Login to the Administrative Interface': 'Login to the Administrative Interface', +'Login/Register': 'Login/Register', 'Logout': 'logout', +'lost password': 'lost password', +'Main Menu': 'Main Menu', +'Manage': 'Manage', +'Manage %(action)s': 'Manage %(action)s', +'Manage Access Control': 'Manage Access Control', +'Manage Admin Users/Students': 'Manage Admin Users/Students', +'Manage Cache': 'Manage Cache', +'Manage Students': 'Manage Students', +'Memberships': 'Memberships', +'merge': 'merge', 'Models': 'Modelle', +'models': 'modelle', +'Modified On': 'Modified On', 'Modules': 'Modules', +'modules': 'modules', +'Multi User Mode': 'Multi User Mode', +'new application "%s" created': 'new application "%s" created', +'new application "%s" imported': 'new application "%s" imported', +'New Application Wizard': 'New Application Wizard', 'New application wizard': 'Nuwe app wizard', +'new plugin installed': 'new plugin installed', +'New plugin installed: %s': 'New plugin installed: %s', +'New Record': 'New Record', +'new record inserted': 'new record inserted', 'New simple application': 'Nuwe eenvoudige app', +'next': 'next', +'next %s rows': 'next %s rows', +'NO': 'NO', +'no changes': 'no changes', +'No databases in this application': 'No databases in this application', +'No Interaction yet': 'No Interaction yet', +'no match': 'no match', +'no package selected': 'no package selected', +'no permission to uninstall "%s"': 'no permission to uninstall "%s"', +'Node:': 'Node:', +'Not Authorized': 'Not Authorized', +'Not supported': 'Not supported', +'Note: If you receive an error with github status code of 128, ensure the system and account you are deploying from has a cooresponding ssh key configured in the openshift account.': 'Note: If you receive an error with github status code of 128, ensure the system and account you are deploying from has a cooresponding ssh key configured in the openshift account.', +"On production, you'll have to configure your webserver to use one process and multiple threads to use this debugger.": "On production, you'll have to configure your webserver to use one process and multiple threads to use this debugger.", +'Open new app in new window': 'Open new app in new window', +'OpenShift Deployment Interface': 'OpenShift Deployment Interface', +'OpenShift Output': 'OpenShift Output', +'or alternatively': 'or alternatively', +'Or Get from URL:': 'Or Get from URL:', +'or import from csv file': 'or import from csv file', +'Original/Translation': 'Original/Translation', +'Overview': 'Overview', 'Overwrite installed app': 'skryf oor geinstalleerde program', 'Pack all': 'pack alles', +'Pack compiled': 'Pack compiled', +'Pack custom': 'Pack custom', +'pack plugin': 'pack plugin', +'password changed': 'password changed', +'Past revisions': 'Past revisions', +'Path to appcfg.py': 'Path to appcfg.py', +'Path to local openshift repo root.': 'Path to local openshift repo root.', +'Peeking at file': 'Peeking at file', +'Permission': 'Permission', +'Permissions': 'Permissions', +'Please': 'Please', +'Please wait, giving pythonanywhere a moment...': 'Please wait, giving pythonanywhere a moment...', +'plugin "%(plugin)s" deleted': 'plugin "%(plugin)s" deleted', +'Plugin "%s" in application': 'Plugin "%s" in application', +'plugin not specified': 'plugin not specified', +'Plugin page': 'Plugin page', +'plugins': 'plugins', 'Plugins': 'Plugins', +'Plural Form #%s': 'Plural Form #%s', +'Plural-Forms:': 'Plural-Forms:', 'Powered by': 'Aangedryf deur', +'Preferences saved correctly': 'Preferences saved correctly', +'Preferences saved on session only': 'Preferences saved on session only', +'previous %s rows': 'previous %s rows', +'Private files': 'Private files', +'private files': 'private files', +'Project Progress': 'Project Progress', +'Pull': 'Pull', +'Pull failed, certain files could not be checked out. Check logs for details.': 'Pull failed, certain files could not be checked out. Check logs for details.', +'Pull is not possible because you have unmerged files. Fix them up in the work tree, and then try again.': 'Pull is not possible because you have unmerged files. Fix them up in the work tree, and then try again.', +'Push': 'Push', +'Push failed, there are unmerged entries in the cache. Resolve merge issues manually and try again.': 'Push failed, there are unmerged entries in the cache. Resolve merge issues manually and try again.', +'pygraphviz library not found': 'pygraphviz library not found', +'PythonAnywhere Apps': 'PythonAnywhere Apps', +'PythonAnywhere Password': 'PythonAnywhere Password', +'Query:': 'Query:', +'RAM': 'RAM', +'RAM Cache Keys': 'RAM Cache Keys', +'Ram Cleared': 'Ram Cleared', +'Rapid Search': 'Rapid Search', +'Record': 'Record', +'record does not exist': 'record does not exist', +'Record id': 'Record id', +'refresh': 'refresh', +'register': 'register', +'Reload routes': 'Reload routes', +'Remove compiled': 'Remove compiled', +'Removed Breakpoint on %s at line %s': 'Removed Breakpoint on %s at line %s', +'Replace': 'Replace', +'Replace All': 'Replace All', +'Repository (%s)': 'Repository (%s)', +'request': 'request', +'requires distutils, but not installed': 'requires distutils, but not installed', +'requires python-git, but not installed': 'requires python-git, but not installed', +'Resolve Conflict file': 'Resolve Conflict file', +'response': 'response', +'restart': 'restart', +'restore': 'restore', +'return': 'return', +'Revert': 'Revert', +'revert': 'revert', +'reverted to revision %s': 'reverted to revision %s', +'Revision %s': 'Revision %s', +'Revision:': 'Revision:', +'Role': 'Role', +'Roles': 'Roles', +'Rows in Table': 'Rows in Table', +'Rows selected': 'Rows selected', +'rules are not defined': 'rules are not defined', +'Run tests': 'Run tests', +'Run tests in this file': 'Run tests in this file', +"Run tests in this file (to run all files, you may also use the button labelled 'test')": "Run tests in this file (to run all files, you may also use the button labelled 'test')", +'Running on %s': 'Running on %s', +'Save': 'Save', +'Save file:': 'Save file:', +'Save file: %s': 'Save file: %s', +'Save model as...': 'Save model as...', +'Save via Ajax': 'Save via Ajax', +'Saved file hash:': 'Saved file hash:', +'Screenshot %s': 'Screenshot %s', +'Search': 'Search', +'Select Files to Package': 'Select Files to Package', +'session': 'session', +'session expired': 'session expired', +'Session saved correctly': 'Session saved correctly', +'Session saved on session only': 'Session saved on session only', +'Set Breakpoint on %s at line %s: %s': 'Set Breakpoint on %s at line %s: %s', +'shell': 'shell', +'Showing %s to %s of %s %s found': 'Showing %s to %s of %s %s found', +'Singular Form': 'Singular Form', 'Site': 'site', +'Size of cache:': 'Size of cache:', +'skip to generate': 'skip to generate', +'some files could not be removed': 'some files could not be removed', +'Something went wrong please wait a few minutes before retrying': 'Something went wrong please wait a few minutes before retrying', +'Sorry, could not find mercurial installed': 'Sorry, could not find mercurial installed', +'source : db': 'source : db', +'source : filesystem': 'source : filesystem', +'Start a new app': 'Start a new app', +'Start searching': 'Start searching', 'Start wizard': 'start wizard', +'state': 'state', +'Static': 'Static', +'static': 'static', 'Static files': 'Static files', +'Statistics': 'Statistics', +'Step': 'Step', +'step': 'step', +'stop': 'stop', +'submit': 'submit', +'Submit': 'Submit', +'successful': 'successful', 'Sure you want to delete this object?': 'Is jy seker jy will hierde object verwyder?', +'switch to : db': 'switch to : db', +'switch to : filesystem': 'switch to : filesystem', +'Tab width (# characters)': 'Tab width (# characters)', +'Table': 'Table', +'Temporary': 'Temporary', +'test': 'toets', +'Testing application': 'Testing application', +'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.': 'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.', +'The app exists, was created by wizard, continue to overwrite!': 'The app exists, was created by wizard, continue to overwrite!', +'The app exists, was NOT created by wizard, continue to overwrite!': 'The app exists, was NOT created by wizard, continue to overwrite!', 'The application logic, each URL path is mapped in one exposed function in the controller': 'The application logic, each URL path is mapped in one exposed function in the controller', 'The data representation, define database tables and sets': 'The data representation, define database tables and sets', 'The presentations layer, views are also known as templates': 'The presentations layer, views are also known as templates', +'Theme': 'Theme', +'There are no controllers': 'There are no controllers', +'There are no models': 'There are no models', +'There are no modules': 'There are no modules', 'There are no plugins': 'Daar is geen plugins', +'There are no private files': 'There are no private files', +'There are no static files': 'There are no static files', +'There are no translators': 'There are no translators', +'There are no translators, only default language is supported': 'There are no translators, only default language is supported', +'There are no views': 'There are no views', +'These files are not served, they are only available from within your app': 'These files are not served, they are only available from within your app', 'These files are served without processing, your images go here': 'Hierdie lêre is sonder veranderinge geserved, jou images gaan hier', +"This debugger may not work properly if you don't have a threaded webserver or you're using multiple daemon processes.": "This debugger may not work properly if you don't have a threaded webserver or you're using multiple daemon processes.", +'This is an experimental feature and it needs more testing. If you decide to downgrade you do it at your own risk': 'This is an experimental feature and it needs more testing. If you decide to downgrade you do it at your own risk', +'This is an experimental feature and it needs more testing. If you decide to upgrade you do it at your own risk': 'This is an experimental feature and it needs more testing. If you decide to upgrade you do it at your own risk', +"This page can commit your changes to an openshift app repo and push them to your cloud instance. This assumes that you've already created the application instance using the web2py skeleton and have that repo somewhere on a filesystem that this web2py instance can access. This functionality requires GitPython installed and on the python path of the runtime that web2py is operating in.": "This page can commit your changes to an openshift app repo and push them to your cloud instance. This assumes that you've already created the application instance using the web2py skeleton and have that repo somewhere on a filesystem that this web2py instance can access. This functionality requires GitPython installed and on the python path of the runtime that web2py is operating in.", +'This page can upload your application to the Google App Engine computing cloud. Mind that you must first create indexes locally and this is done by installing the Google appserver and running the app locally with it once, or there will be errors when selecting records. Attention: deployment may take long time, depending on the network speed. Attention: it will overwrite your app.yaml. DO NOT SUBMIT TWICE.': 'This page can upload your application to the Google App Engine computing cloud. Mind that you must first create indexes locally and this is done by installing the Google appserver and running the app locally with it once, or there will be errors when selecting records. Attention: deployment may take long time, depending on the network speed. Attention: it will overwrite your app.yaml. DO NOT SUBMIT TWICE.', +'this page to see if a breakpoint was hit and debug interaction is required.': 'this page to see if a breakpoint was hit and debug interaction is required.', +'This will pull changes from the remote repo for application "%s"?': 'This will pull changes from the remote repo for application "%s"?', +'This will push changes to the remote repo for application "%s".': 'This will push changes to the remote repo for application "%s".', +'Ticket': 'Ticket', +'Ticket ID': 'Ticket ID', +'Ticket Missing': 'Ticket Missing', +'Time in Cache (h:m:s)': 'Time in Cache (h:m:s)', +'to previous version.': 'to previous version.', 'To create a plugin, name a file/folder plugin_[name]': 'Om n plugin te skep, noem n lêer/gids plugin_[name]', +'To emulate a breakpoint programatically, write:': 'To emulate a breakpoint programatically, write:', +'to use the debugger!': 'to use the debugger!', +'toggle breakpoint': 'toggle breakpoint', +'Toggle comment': 'Toggle comment', +'Toggle Fullscreen': 'Toggle Fullscreen', +'Traceback': 'Traceback', 'Translation strings for the application': 'Vertaling woorde vir die program', +'try something like': 'try something like', +'Try the mobile interface': 'Try the mobile interface', +'try view': 'try view', +'Type PDB debugger command in here and hit Return (Enter) to execute it.': 'Type PDB debugger command in here and hit Return (Enter) to execute it.', +'Type some Python code in here and hit Return (Enter) to execute it.': 'Type some Python code in here and hit Return (Enter) to execute it.', +'Unable to check for upgrades': 'Unable to check for upgrades', +'unable to create application "%s"': 'unable to create application "%s"', +'unable to delete file "%(filename)s"': 'unable to delete file "%(filename)s"', +'unable to delete file plugin "%(plugin)s"': 'unable to delete file plugin "%(plugin)s"', +'Unable to determine the line number!': 'Unable to determine the line number!', +'Unable to download app because:': 'Unable to download app because:', +'unable to download layout': 'unable to download layout', +'unable to download plugin: %s': 'unable to download plugin: %s', +'Unable to download the list of plugins': 'Unable to download the list of plugins', +'unable to install plugin "%s"': 'unable to install plugin "%s"', +'unable to parse csv file': 'unable to parse csv file', +'unable to uninstall "%s"': 'unable to uninstall "%s"', +'unable to upgrade because "%s"': 'unable to upgrade because "%s"', +'uncheck all': 'uncheck all', 'Uninstall': 'verwyder', +'Unsupported webserver working mode: %s': 'Unsupported webserver working mode: %s', +'update': 'update', +'update all languages': 'update all languages', +'Update:': 'Update:', +'Upgrade': 'Upgrade', +'upgrade now to %s': 'upgrade now to %s', +'upload': 'oplaai', +'Upload': 'Upload', 'Upload & install packed application': 'Oplaai & install gepakte program', 'Upload a package:': 'Oplaai n package:', -'Use an url:': 'Gebruik n url:', -'Views': 'Views', -'administrative interface': 'administrative interface', -'and rename it:': 'en verander die naam:', -'collapse/expand all': 'collapse/expand all', -'controllers': 'beheerders', -'create file with filename:': 'skep lêer met naam:', -'created by': 'geskep deur', -'crontab': 'crontab', -'currently running': 'loop tans', -'database administration': 'database administration', -'direction: ltr': 'direction: ltr', -'download layouts': 'aflaai layouts', -'download plugins': 'aflaai plugins', -'exposes': 'exposes', -'extends': 'extends', -'filter': 'filter', -'includes': 'includes', -'languages': 'tale', -'loading...': 'laai...', -'models': 'modelle', -'modules': 'modules', -'plugins': 'plugins', -'shell': 'shell', -'static': 'static', -'test': 'toets', -'update all languages': 'update all languages', -'upload': 'oplaai', +'Upload and install packed application': 'Upload and install packed application', 'upload file:': 'oplaai lêer:', 'upload plugin file:': 'upload plugin lêer:', +'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.', +'Use an url:': 'Gebruik n url:', +'User': 'User', +'Username': 'Username', +'Users': 'Users', +'Using the shell may lock the database to other users of this app.': 'Using the shell may lock the database to other users of this app.', +'variables': 'variables', +'Version': 'Version', +'Versioning': 'Versioning', 'versioning': 'versioning', +'Views': 'Views', 'views': 'views', +'Warning!': 'Warning!', +'WARNING:': 'WARNING:', +'WARNING: The following views could not be compiled:': 'WARNING: The following views could not be compiled:', +'Web Framework': 'Web Framework', +'web2py Admin Password': 'web2py Admin Password', +'web2py apps to deploy': 'web2py apps to deploy', +'web2py Debugger': 'web2py Debugger', +'web2py downgrade': 'web2py downgrade', +'web2py is up to date': 'web2py is up to date', +'web2py online debugger': 'web2py online debugger', 'web2py Recent Tweets': 'web2py Onlangse Tweets', +'web2py upgrade': 'web2py upgrade', +'web2py upgraded; please restart it': 'web2py upgraded; please restart it', +'Working...': 'Working...', +'WSGI reference name': 'WSGI reference name', +'YES': 'YES', +'Yes': 'Yes', +'You can also set and remove breakpoint in the edit window, using the Toggle Breakpoint button': 'You can also set and remove breakpoint in the edit window, using the Toggle Breakpoint button', +'You can inspect variables using the console below': 'You can inspect variables using the console below', +'You have one more login attempt before you are locked out': 'You have one more login attempt before you are locked out', +'You need to set up and reach a': 'You need to set up and reach a', +'You only need these if you have already registered': 'You only need these if you have already registered', +'Your application will be blocked until you click an action button (next, step, continue, etc.)': 'Your application will be blocked until you click an action button (next, step, continue, etc.)', } diff --git a/applications/admin/languages/bg.py b/applications/admin/languages/bg.py index c8d02f87..c841bec6 100755 --- a/applications/admin/languages/bg.py +++ b/applications/admin/languages/bg.py @@ -3,203 +3,237 @@ '!langcode!': 'bg', '!langname!': 'Български', '"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN': '"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN', -'%Y-%m-%d': '%Y-%m-%d', -'%Y-%m-%d %H:%M:%S': '%Y-%m-%d %H:%M:%S', +'"User Exception" debug mode. ': '"User Exception" debug mode. ', +'%s': '%s', '%s %%{row} deleted': '%s записите бяха изтрити', '%s %%{row} updated': '%s записите бяха обновени', +'%s selected': '%s selected', +'%s students registered': '%s students registered', +'%Y-%m-%d': '%Y-%m-%d', +'%Y-%m-%d %H:%M:%S': '%Y-%m-%d %H:%M:%S', '(requires internet access)': '(requires internet access)', +'(requires internet access, experimental)': '(requires internet access, experimental)', '(something like "it-it")': '(something like "it-it")', +'(version %s)': '(version %s)', +'?': '?', '@markmin\x01Searching: **%s** %%{file}': 'Searching: **%s** files', 'A new version of web2py is available': 'A new version of web2py is available', 'A new version of web2py is available: %s': 'A new version of web2py is available: %s', -'ATTENTION: Login requires a secure (HTTPS) connection or running on localhost.': 'ATTENTION: Login requires a secure (HTTPS) connection or running on localhost.', -'ATTENTION: TESTING IS NOT THREAD SAFE SO DO NOT PERFORM MULTIPLE TESTS CONCURRENTLY.': 'ATTENTION: TESTING IS NOT THREAD SAFE SO DO NOT PERFORM MULTIPLE TESTS CONCURRENTLY.', -'ATTENTION: you cannot edit the running application!': 'ATTENTION: you cannot edit the running application!', +'Abort': 'Abort', 'About': 'about', 'About application': 'About application', +'Accept Terms': 'Accept Terms', +'Add breakpoint': 'Add breakpoint', +'additional code for your application': 'additional code for your application', 'Additional code for your application': 'Additional code for your application', +'Admin design page': 'Admin design page', +'admin disabled because no admin password': 'admin disabled because no admin password', +'admin disabled because not supported on google app engine': 'admin disabled because not supported on google apps engine', +'admin disabled because too many invalid login attempts': 'admin disabled because too many invalid login attempts', +'admin disabled because unable to access password file': 'admin disabled because unable to access password file', 'Admin is disabled because insecure channel': 'Admin is disabled because insecure channel', 'Admin is disabled because unsecure channel': 'Admin is disabled because unsecure channel', 'Admin language': 'Admin language', +'Admin versioning page': 'Admin versioning page', +'administrative interface': 'administrative interface', 'Administrator Password:': 'Administrator Password:', +'and rename it (required):': 'and rename it (required):', +'and rename it:': 'and rename it:', +'App does not exist or you are not authorized': 'App does not exist or you are not authorized', +'appadmin': 'appadmin', +'appadmin is disabled because insecure channel': 'appadmin is disabled because insecure channel', +'Application': 'Application', +'application "%s" uninstalled': 'application "%s" uninstalled', +'Application cannot be generated in demo mode': 'Application cannot be generated in demo mode', +'application compiled': 'application compiled', +'Application exists already': 'Application exists already', +'application is compiled and cannot be designed': 'application is compiled and cannot be designed', 'Application name:': 'Application name:', +'Application updated via git pull': 'Application updated via git pull', +'are not used': 'are not used', +'are not used yet': 'are not used yet', 'Are you sure you want to delete file "%s"?': 'Are you sure you want to delete file "%s"?', 'Are you sure you want to delete plugin "%s"?': 'Are you sure you want to delete plugin "%s"?', 'Are you sure you want to delete this object?': 'Are you sure you want to delete this object?', 'Are you sure you want to uninstall application "%s"': 'Are you sure you want to uninstall application "%s"', 'Are you sure you want to uninstall application "%s"?': 'Are you sure you want to uninstall application "%s"?', 'Are you sure you want to upgrade web2py now?': 'Are you sure you want to upgrade web2py now?', +'Are you sure?': 'Are you sure?', +'arguments': 'arguments', +'at char %s': 'at char %s', +'at line %s': 'at line %s', +'ATTENTION:': 'ATTENTION:', +'ATTENTION: Login requires a secure (HTTPS) connection or running on localhost.': 'ATTENTION: Login requires a secure (HTTPS) connection or running on localhost.', +'ATTENTION: TESTING IS NOT THREAD SAFE SO DO NOT PERFORM MULTIPLE TESTS CONCURRENTLY.': 'ATTENTION: TESTING IS NOT THREAD SAFE SO DO NOT PERFORM MULTIPLE TESTS CONCURRENTLY.', +'ATTENTION: you cannot edit the running application!': 'ATTENTION: you cannot edit the running application!', +'Autocomplete Python Code': 'Autocomplete Python Code', 'Available databases and tables': 'Available databases and tables', +'Available Databases and Tables': 'Available Databases and Tables', +'back': 'back', +'Back to the plugins list': 'Back to the plugins list', +'Back to wizard': 'Back to wizard', +'Basics': 'Basics', +'Begin': 'Begin', +'breakpoint': 'breakpoint', +'Breakpoints': 'Breakpoints', +'breakpoints': 'breakpoints', +'Bulk Register': 'Bulk Register', +'Bulk Student Registration': 'Bulk Student Registration', +'Cache': 'Cache', +'cache': 'cache', +'Cache Cleared': 'Cache Cleared', +'Cache Keys': 'Cache Keys', +'cache, errors and sessions cleaned': 'cache, errors and sessions cleaned', +'can be a git repo': 'can be a git repo', +'Cancel': 'Cancel', 'Cannot be empty': 'Cannot be empty', 'Cannot compile: there are errors in your app. Debug it, correct errors and try again.': 'Cannot compile: there are errors in your app. Debug it, correct errors and try again.', 'Cannot compile: there are errors in your app:': 'Cannot compile: there are errors in your app:', +'cannot create file': 'cannot create file', +'cannot upload file "%(filename)s"': 'cannot upload file "%(filename)s"', +'Change Admin Password': 'Change Admin Password', 'Change admin password': 'change admin password', +'change editor settings': 'change editor settings', +'Changelog': 'Changelog', +'check all': 'check all', 'Check for upgrades': 'check for upgrades', 'Check to delete': 'Check to delete', 'Checking for upgrades...': 'Checking for upgrades...', 'Clean': 'clean', +'Clear': 'Clear', +'Clear CACHE?': 'Clear CACHE?', +'Clear DISK': 'Clear DISK', +'Clear RAM': 'Clear RAM', +'click here for online examples': 'щракни тук за онлайн примери', +'click here for the administrative interface': 'щракни тук за административния интерфейс', +'Click row to expand traceback': 'Click row to expand traceback', +'Click row to view a ticket': 'Click row to view a ticket', +'click to check for upgrades': 'click to check for upgrades', +'code': 'code', +'Code listing': 'Code listing', +'collapse/expand all': 'collapse/expand all', +'Command': 'Command', +'Comment:': 'Comment:', +'Commit': 'Commit', +'Commit form': 'Commit form', +'Committed files': 'Committed files', 'Compile': 'compile', +'Compile (all or nothing)': 'Compile (all or nothing)', +'Compile (skip failed views)': 'Compile (skip failed views)', +'compiled application removed': 'compiled application removed', +'Condition': 'Condition', +'continue': 'continue', 'Controllers': 'Controllers', +'controllers': 'controllers', +'Count': 'Count', 'Create': 'create', +'create file with filename:': 'create file with filename:', +'create new application:': 'create new application:', 'Create new simple application': 'Create new simple application', +'Create/Upload': 'Create/Upload', +'created by': 'created by', +'Created by:': 'Created by:', +'Created On': 'Created On', +'Created on:': 'Created on:', +'crontab': 'crontab', 'Current request': 'Current request', 'Current response': 'Current response', 'Current session': 'Current session', -'DESIGN': 'DESIGN', -'Date and Time': 'Date and Time', -'Debug': 'Debug', -'Delete': 'Delete', -'Delete:': 'Delete:', -'Deploy': 'deploy', -'Deploy on Google App Engine': 'Deploy on Google App Engine', -'Deploy to OpenShift': 'Deploy to OpenShift', -'Design for': 'Design for', -'Disable': 'Disable', -'EDIT': 'EDIT', -'Edit': 'edit', -'Edit application': 'Edit application', -'Edit current record': 'Edit current record', -'Editing Language file': 'Editing Language file', -'Editing file': 'Editing file', -'Editing file "%s"': 'Editing file "%s"', -'Enterprise Web Framework': 'Enterprise Web Framework', -'Error logs for "%(app)s"': 'Error logs for "%(app)s"', -'Errors': 'errors', -'Exception instance attributes': 'Exception instance attributes', -'Functions with no doctests will result in [passed] tests.': 'Functions with no doctests will result in [passed] tests.', -'Get from URL:': 'Get from URL:', -'Hello World': 'Здравей, свят', -'Help': 'help', -'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\nA green title indicates that all tests (if defined) passed. In this case test results are not shown.': 'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\nA green title indicates that all tests (if defined) passed. In this case test results are not shown.', -'Import/Export': 'Import/Export', -'Install': 'install', -'Installed applications': 'Installed applications', -'Internal State': 'Internal State', -'Invalid Query': 'Невалидна заявка', -'Invalid action': 'Invalid action', -'Language files (static strings) updated': 'Language files (static strings) updated', -'Languages': 'Languages', -'Last saved on:': 'Last saved on:', -'License for': 'License for', -'Login': 'Login', -'Login to the Administrative Interface': 'Login to the Administrative Interface', -'Logout': 'logout', -'Models': 'Models', -'Modules': 'Modules', -'NO': 'NO', -'New Record': 'New Record', -'New application wizard': 'New application wizard', -'New simple application': 'New simple application', -'No databases in this application': 'No databases in this application', -'Original/Translation': 'Original/Translation', -'Overwrite installed app': 'overwrite installed app', -'PAM authenticated user, cannot change password here': 'PAM authenticated user, cannot change password here', -'Pack all': 'pack all', -'Pack compiled': 'pack compiled', -'Peeking at file': 'Peeking at file', -'Plugin "%s" in application': 'Plugin "%s" in application', -'Plugins': 'Plugins', -'Powered by': 'Powered by', -'Query:': 'Query:', -'Reload routes': 'Reload routes', -'Remove compiled': 'remove compiled', -'Resolve Conflict file': 'Resolve Conflict file', -'Rows in table': 'Rows in table', -'Rows selected': 'Rows selected', -'Running on %s': 'Running on %s', -'Saved file hash:': 'Saved file hash:', -'Site': 'site', -'Start wizard': 'start wizard', -'Static files': 'Static files', -'Sure you want to delete this object?': 'Сигурен ли си, че искаш да изтриеш този обект?', -'TM': 'TM', -'Testing application': 'Testing application', -'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.': 'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.', -'The application logic, each URL path is mapped in one exposed function in the controller': 'The application logic, each URL path is mapped in one exposed function in the controller', -'The data representation, define database tables and sets': 'The data representation, define database tables and sets', -'The presentations layer, views are also known as templates': 'The presentations layer, views are also known as templates', -'There are no controllers': 'There are no controllers', -'There are no models': 'There are no models', -'There are no modules': 'There are no modules', -'There are no plugins': 'There are no plugins', -'There are no static files': 'There are no static files', -'There are no translators, only default language is supported': 'There are no translators, only default language is supported', -'There are no views': 'There are no views', -'These files are served without processing, your images go here': 'These files are served without processing, your images go here', -'This is the %(filename)s template': 'This is the %(filename)s template', -'Ticket': 'Ticket', -'To create a plugin, name a file/folder plugin_[name]': 'To create a plugin, name a file/folder plugin_[name]', -'Translation strings for the application': 'Translation strings for the application', -'Unable to check for upgrades': 'Unable to check for upgrades', -'Unable to download': 'Unable to download', -'Unable to download app because:': 'Unable to download app because:', -'Unable to download because': 'Unable to download because', -'Uninstall': 'uninstall', -'Update:': 'Update:', -'Upload & install packed application': 'Upload & install packed application', -'Upload a package:': 'Upload a package:', -'Upload and install packed application': 'Upload and install packed application', -'Upload existing application': 'Upload existing application', -'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.', -'Use an url:': 'Use an url:', -'Version': 'Version', -'Views': 'Views', -'Web Framework': 'Web Framework', -'Welcome to web2py': 'Добре дошъл в web2py', -'YES': 'YES', -'additional code for your application': 'additional code for your application', -'admin disabled because no admin password': 'admin disabled because no admin password', -'admin disabled because not supported on google app engine': 'admin disabled because not supported on google apps engine', -'admin disabled because unable to access password file': 'admin disabled because unable to access password file', -'administrative interface': 'administrative interface', -'and rename it (required):': 'and rename it (required):', -'and rename it:': 'and rename it:', -'appadmin': 'appadmin', -'appadmin is disabled because insecure channel': 'appadmin is disabled because insecure channel', -'application "%s" uninstalled': 'application "%s" uninstalled', -'application compiled': 'application compiled', -'application is compiled and cannot be designed': 'application is compiled and cannot be designed', -'arguments': 'arguments', -'back': 'back', -'cache': 'cache', -'cache, errors and sessions cleaned': 'cache, errors and sessions cleaned', -'cannot create file': 'cannot create file', -'cannot upload file "%(filename)s"': 'cannot upload file "%(filename)s"', -'check all': 'check all', -'click here for online examples': 'щракни тук за онлайн примери', -'click here for the administrative interface': 'щракни тук за административния интерфейс', -'click to check for upgrades': 'click to check for upgrades', -'code': 'code', -'collapse/expand all': 'collapse/expand all', -'compiled application removed': 'compiled application removed', -'controllers': 'controllers', -'create file with filename:': 'create file with filename:', -'create new application:': 'create new application:', -'created by': 'created by', -'crontab': 'crontab', 'currently running': 'currently running', 'currently saved or': 'currently saved or', 'data uploaded': 'данните бяха качени', +'Database': 'Database', 'database': 'database', +'Database %s select': 'Database %s select', 'database %s select': 'database %s select', +'Database administration': 'Database administration', 'database administration': 'database administration', +'Database Administration (appadmin)': 'Database Administration (appadmin)', +'Date and Time': 'Date and Time', 'db': 'дб', +'Debug': 'Debug', 'defines tables': 'defines tables', +'Delete': 'Delete', 'delete': 'delete', 'delete all checked': 'delete all checked', 'delete plugin': 'delete plugin', +'Delete this file (you will be asked to confirm deletion)': 'Delete this file (you will be asked to confirm deletion)', +'Delete:': 'Delete:', +'deleted after first hit': 'deleted after first hit', +'Demo': 'Demo', +'Deploy': 'deploy', +'Deploy on Google App Engine': 'Deploy on Google App Engine', +'Deploy to OpenShift': 'Deploy to OpenShift', +'Deploy to pythonanywhere': 'Deploy to pythonanywhere', +'Deploy to PythonAnywhere': 'Deploy to PythonAnywhere', +'Deployment form': 'Deployment form', +'Deployment Interface': 'Deployment Interface', +'Description:': 'Description:', 'design': 'дизайн', +'DESIGN': 'DESIGN', +'Design for': 'Design for', +'Detailed traceback description': 'Detailed traceback description', +'details': 'details', 'direction: ltr': 'direction: ltr', +'directory not found': 'directory not found', +'Disable': 'Disable', +'Disabled': 'Disabled', +'disabled in demo mode': 'disabled in demo mode', +'disabled in GAE mode': 'disabled in GAE mode', +'disabled in multi user mode': 'disabled in multi user mode', +'DISK': 'DISK', +'Disk Cache Keys': 'Disk Cache Keys', +'Disk Cleared': 'Disk Cleared', +'Display line numbers': 'Display line numbers', +'DO NOT use the "Pack compiled" feature.': 'DO NOT use the "Pack compiled" feature.', +'docs': 'docs', +'Docs': 'Docs', 'done!': 'готово!', +'Downgrade': 'Downgrade', +'Download .w2p': 'Download .w2p', +'Download as .exe': 'Download as .exe', 'download layouts': 'download layouts', +'Download layouts from repository': 'Download layouts from repository', 'download plugins': 'download plugins', +'Download plugins from repository': 'Download plugins from repository', +'EDIT': 'EDIT', +'Edit': 'edit', +'edit all': 'edit all', +'Edit application': 'Edit application', 'edit controller': 'edit controller', +'edit controller:': 'edit controller:', +'Edit current record': 'Edit current record', 'edit views:': 'edit views:', +'Editing %s': 'Editing %s', +'Editing file': 'Editing file', +'Editing file "%s"': 'Editing file "%s"', +'Editing Language file': 'Editing Language file', +'Editing Plural Forms File': 'Editing Plural Forms File', +'Editor': 'Editor', +'Email Address': 'Email Address', +'Enable': 'Enable', +'Enable Close-Tag': 'Enable Close-Tag', +'Enable Code Folding': 'Enable Code Folding', +'Enterprise Web Framework': 'Enterprise Web Framework', +'Error': 'Error', +'Error logs for "%(app)s"': 'Error logs for "%(app)s"', +'Error snapshot': 'Error snapshot', +'Error ticket': 'Error ticket', +'Errors': 'errors', +'Exception %(extype)s: %(exvalue)s': 'Exception %(extype)s: %(exvalue)s', +'Exception %s': 'Exception %s', +'Exception instance attributes': 'Exception instance attributes', +'Exit Fullscreen': 'Exit Fullscreen', +'Expand Abbreviation (html files only)': 'Expand Abbreviation (html files only)', 'export as csv file': 'export as csv file', +'Exports:': 'Exports:', 'exposes': 'exposes', +'exposes:': 'exposes:', 'extends': 'extends', +'failed to compile file because:': 'failed to compile file because:', 'failed to reload module': 'failed to reload module', 'failed to reload module because:': 'failed to reload module because:', +'File': 'File', 'file "%(filename)s" created': 'file "%(filename)s" created', 'file "%(filename)s" deleted': 'file "%(filename)s" deleted', 'file "%(filename)s" uploaded': 'file "%(filename)s" uploaded', @@ -207,80 +241,400 @@ 'file "%s" of %s restored': 'file "%s" of %s restored', 'file changed on disk': 'file changed on disk', 'file does not exist': 'file does not exist', +'file not found': 'file not found', 'file saved on %(time)s': 'file saved on %(time)s', 'file saved on %s': 'file saved on %s', +'filename': 'filename', +'Filename': 'Filename', +'Files added': 'Files added', 'filter': 'filter', +'Find Next': 'Find Next', +'Find Previous': 'Find Previous', +'Form has errors': 'Form has errors', +'Frames': 'Frames', +'Functions with no doctests will result in [passed] tests.': 'Functions with no doctests will result in [passed] tests.', +'GAE Email': 'GAE Email', +'GAE Output': 'GAE Output', +'GAE Password': 'GAE Password', +'Generate': 'Generate', +'Get from URL:': 'Get from URL:', +'Git Pull': 'Git Pull', +'Git Push': 'Git Push', +'Globals##debug': 'Globals##debug', +'go!': 'go!', +'Google App Engine Deployment Interface': 'Google App Engine Deployment Interface', +'Google Application Id': 'Google Application Id', +'Goto': 'Goto', +'graph model': 'graph model', +'Graph Model': 'Graph Model', +'Hello World': 'Здравей, свят', +'Help': 'help', +'here': 'here', +'Hide/Show Translated strings': 'Hide/Show Translated strings', +'Highlight current line': 'Highlight current line', +'Hits': 'Hits', +'Home': 'Home', +'honored only if the expression evaluates to true': 'honored only if the expression evaluates to true', 'htmledit': 'htmledit', +'If start the downgrade, be patient, it may take a while to rollback': 'If start the downgrade, be patient, it may take a while to rollback', +'If start the upgrade, be patient, it may take a while to download': 'If start the upgrade, be patient, it may take a while to download', +'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\n\t\tA green title indicates that all tests (if defined) passed. In this case test results are not shown.': 'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\n\t\tA green title indicates that all tests (if defined) passed. In this case test results are not shown.', +'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\nA green title indicates that all tests (if defined) passed. In this case test results are not shown.': 'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\nA green title indicates that all tests (if defined) passed. In this case test results are not shown.', +'if your application uses a database other than sqlite you will then have to configure its DAL in pythonanywhere.': 'if your application uses a database other than sqlite you will then have to configure its DAL in pythonanywhere.', +'import': 'import', +'Import/Export': 'Import/Export', +'In development, use the default Rocket webserver that is currently supported by this debugger.': 'In development, use the default Rocket webserver that is currently supported by this debugger.', 'includes': 'includes', +'Indent with tabs': 'Indent with tabs', 'insert new': 'insert new', 'insert new %s': 'insert new %s', +'inspect attributes': 'inspect attributes', +'Install': 'install', +'Installation of %(plugin)s for %(app)s': 'Installation of %(plugin)s for %(app)s', +'Installed applications': 'Installed applications', +'Interaction at %s line %s': 'Interaction at %s line %s', +'Interactive console': 'Interactive console', 'internal error': 'internal error', +'internal error: %s': 'internal error: %s', +'Internal State': 'Internal State', +'Invalid action': 'Invalid action', +'Invalid application name': 'Invalid application name', +'invalid circular reference': 'invalid circular reference', +'Invalid git repository specified.': 'Invalid git repository specified.', 'invalid password': 'invalid password', +'invalid password.': 'invalid password.', +'Invalid Query': 'Невалидна заявка', 'invalid request': 'невалидна заявка', +'Invalid request': 'Invalid request', +'invalid table names (auth_* tables already defined)': 'invalid table names (auth_* tables already defined)', 'invalid ticket': 'invalid ticket', +'Key': 'Key', +'Keyboard shortcuts': 'Keyboard shortcuts', +'kill process': 'kill process', 'language file "%(filename)s" created/updated': 'language file "%(filename)s" created/updated', +'Language files (static strings) updated': 'Language files (static strings) updated', 'languages': 'languages', +'Languages': 'Languages', 'languages updated': 'languages updated', +'Last Revision': 'Last Revision', +'Last saved on:': 'Last saved on:', +'License for': 'License for', +'License:': 'License:', +'Line Nr': 'Line Nr', +'Line number': 'Line number', +'lists by exception': 'lists by exception', +'lists by ticket': 'lists by ticket', +'Loading...': 'Loading...', 'loading...': 'loading...', +'Local Apps': 'Local Apps', +'locals': 'locals', +'Locals##debug': 'Locals##debug', +'Login': 'Login', 'login': 'login', +'Login successful': 'Login successful', +'Login to the Administrative Interface': 'Login to the Administrative Interface', +'Login/Register': 'Login/Register', +'Logout': 'logout', +'lost password': 'lost password', +'Main Menu': 'Main Menu', +'Manage': 'Manage', +'Manage %(action)s': 'Manage %(action)s', +'Manage Access Control': 'Manage Access Control', +'Manage Admin Users/Students': 'Manage Admin Users/Students', +'Manage Cache': 'Manage Cache', +'Manage Students': 'Manage Students', +'Memberships': 'Memberships', 'merge': 'merge', +'Models': 'Models', 'models': 'models', +'Modified On': 'Modified On', +'Modules': 'Modules', 'modules': 'modules', +'Multi User Mode': 'Multi User Mode', 'new application "%s" created': 'new application "%s" created', +'new application "%s" imported': 'new application "%s" imported', +'New Application Wizard': 'New Application Wizard', +'New application wizard': 'New application wizard', 'new plugin installed': 'new plugin installed', +'New plugin installed: %s': 'New plugin installed: %s', +'New Record': 'New Record', 'new record inserted': 'новият запис беше добавен', +'New simple application': 'New simple application', +'next': 'next', +'next %s rows': 'next %s rows', 'next 100 rows': 'next 100 rows', +'NO': 'NO', +'no changes': 'no changes', +'No databases in this application': 'No databases in this application', +'No Interaction yet': 'No Interaction yet', 'no match': 'no match', +'no package selected': 'no package selected', +'no permission to uninstall "%s"': 'no permission to uninstall "%s"', +'Node:': 'Node:', +'Not Authorized': 'Not Authorized', +'Not supported': 'Not supported', +'Note: If you receive an error with github status code of 128, ensure the system and account you are deploying from has a cooresponding ssh key configured in the openshift account.': 'Note: If you receive an error with github status code of 128, ensure the system and account you are deploying from has a cooresponding ssh key configured in the openshift account.', +"On production, you'll have to configure your webserver to use one process and multiple threads to use this debugger.": "On production, you'll have to configure your webserver to use one process and multiple threads to use this debugger.", +'Open new app in new window': 'Open new app in new window', +'OpenShift Deployment Interface': 'OpenShift Deployment Interface', +'OpenShift Output': 'OpenShift Output', +'or alternatively': 'or alternatively', +'Or Get from URL:': 'Or Get from URL:', 'or import from csv file': 'or import from csv file', 'or provide app url:': 'or provide app url:', 'or provide application url:': 'or provide application url:', +'Original/Translation': 'Original/Translation', +'Overview': 'Overview', +'Overwrite installed app': 'overwrite installed app', +'Pack all': 'pack all', +'Pack compiled': 'pack compiled', +'Pack custom': 'Pack custom', 'pack plugin': 'pack plugin', +'PAM authenticated user, cannot change password here': 'PAM authenticated user, cannot change password here', 'password changed': 'password changed', +'Past revisions': 'Past revisions', +'Path to appcfg.py': 'Path to appcfg.py', +'Path to local openshift repo root.': 'Path to local openshift repo root.', +'Peeking at file': 'Peeking at file', +'Permission': 'Permission', +'Permissions': 'Permissions', +'Please': 'Please', +'Please wait, giving pythonanywhere a moment...': 'Please wait, giving pythonanywhere a moment...', 'plugin "%(plugin)s" deleted': 'plugin "%(plugin)s" deleted', +'Plugin "%s" in application': 'Plugin "%s" in application', +'plugin not specified': 'plugin not specified', +'Plugin page': 'Plugin page', 'plugins': 'plugins', +'Plugins': 'Plugins', +'Plural Form #%s': 'Plural Form #%s', +'Plural-Forms:': 'Plural-Forms:', +'Powered by': 'Powered by', +'Preferences saved correctly': 'Preferences saved correctly', +'Preferences saved on session only': 'Preferences saved on session only', +'previous %s rows': 'previous %s rows', 'previous 100 rows': 'previous 100 rows', +'Private files': 'Private files', +'private files': 'private files', +'Project Progress': 'Project Progress', +'Pull': 'Pull', +'Pull failed, certain files could not be checked out. Check logs for details.': 'Pull failed, certain files could not be checked out. Check logs for details.', +'Pull is not possible because you have unmerged files. Fix them up in the work tree, and then try again.': 'Pull is not possible because you have unmerged files. Fix them up in the work tree, and then try again.', +'Push': 'Push', +'Push failed, there are unmerged entries in the cache. Resolve merge issues manually and try again.': 'Push failed, there are unmerged entries in the cache. Resolve merge issues manually and try again.', +'pygraphviz library not found': 'pygraphviz library not found', +'PythonAnywhere Apps': 'PythonAnywhere Apps', +'PythonAnywhere Password': 'PythonAnywhere Password', +'Query:': 'Query:', +'RAM': 'RAM', +'RAM Cache Keys': 'RAM Cache Keys', +'Ram Cleared': 'Ram Cleared', +'Rapid Search': 'Rapid Search', +'Record': 'Record', 'record': 'record', 'record does not exist': 'записът не съществува', 'record id': 'record id', +'Record id': 'Record id', +'refresh': 'refresh', +'register': 'register', +'Reload routes': 'Reload routes', +'Remove compiled': 'remove compiled', +'Removed Breakpoint on %s at line %s': 'Removed Breakpoint on %s at line %s', +'Replace': 'Replace', +'Replace All': 'Replace All', +'Repository (%s)': 'Repository (%s)', +'request': 'request', +'requires distutils, but not installed': 'requires distutils, but not installed', +'requires python-git, but not installed': 'requires python-git, but not installed', +'Resolve Conflict file': 'Resolve Conflict file', +'response': 'response', +'restart': 'restart', 'restore': 'restore', +'return': 'return', +'Revert': 'Revert', 'revert': 'revert', +'reverted to revision %s': 'reverted to revision %s', +'Revision %s': 'Revision %s', +'Revision:': 'Revision:', +'Role': 'Role', +'Roles': 'Roles', +'Rows in table': 'Rows in table', +'Rows in Table': 'Rows in Table', +'Rows selected': 'Rows selected', +'rules are not defined': 'rules are not defined', +'Run tests': 'Run tests', +'Run tests in this file': 'Run tests in this file', +"Run tests in this file (to run all files, you may also use the button labelled 'test')": "Run tests in this file (to run all files, you may also use the button labelled 'test')", +'Running on %s': 'Running on %s', +'Save': 'Save', 'save': 'save', +'Save file:': 'Save file:', +'Save file: %s': 'Save file: %s', +'Save model as...': 'Save model as...', +'Save via Ajax': 'Save via Ajax', +'Saved file hash:': 'Saved file hash:', +'Screenshot %s': 'Screenshot %s', +'Search': 'Search', +'Select Files to Package': 'Select Files to Package', 'selected': 'selected', +'session': 'session', 'session expired': 'session expired', +'Session saved correctly': 'Session saved correctly', +'Session saved on session only': 'Session saved on session only', +'Set Breakpoint on %s at line %s: %s': 'Set Breakpoint on %s at line %s: %s', 'shell': 'shell', +'Showing %s to %s of %s %s found': 'Showing %s to %s of %s %s found', +'Singular Form': 'Singular Form', +'Site': 'site', +'Size of cache:': 'Size of cache:', +'skip to generate': 'skip to generate', 'some files could not be removed': 'some files could not be removed', +'Something went wrong please wait a few minutes before retrying': 'Something went wrong please wait a few minutes before retrying', +'Sorry, could not find mercurial installed': 'Sorry, could not find mercurial installed', +'source : db': 'source : db', +'source : filesystem': 'source : filesystem', +'Start a new app': 'Start a new app', +'Start searching': 'Start searching', +'Start wizard': 'start wizard', 'state': 'състояние', +'Static': 'Static', 'static': 'static', +'Static files': 'Static files', +'Statistics': 'Statistics', +'Step': 'Step', +'step': 'step', +'stop': 'stop', 'submit': 'submit', +'Submit': 'Submit', +'successful': 'successful', +'Sure you want to delete this object?': 'Сигурен ли си, че искаш да изтриеш този обект?', +'switch to : db': 'switch to : db', +'switch to : filesystem': 'switch to : filesystem', +'Tab width (# characters)': 'Tab width (# characters)', 'table': 'table', +'Table': 'Table', +'Temporary': 'Temporary', 'test': 'test', +'Testing application': 'Testing application', +'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.': 'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.', +'The app exists, was created by wizard, continue to overwrite!': 'The app exists, was created by wizard, continue to overwrite!', +'The app exists, was NOT created by wizard, continue to overwrite!': 'The app exists, was NOT created by wizard, continue to overwrite!', 'the application logic, each URL path is mapped in one exposed function in the controller': 'the application logic, each URL path is mapped in one exposed function in the controller', +'The application logic, each URL path is mapped in one exposed function in the controller': 'The application logic, each URL path is mapped in one exposed function in the controller', 'the data representation, define database tables and sets': 'the data representation, define database tables and sets', +'The data representation, define database tables and sets': 'The data representation, define database tables and sets', +'The presentations layer, views are also known as templates': 'The presentations layer, views are also known as templates', 'the presentations layer, views are also known as templates': 'the presentations layer, views are also known as templates', +'Theme': 'Theme', +'There are no controllers': 'There are no controllers', +'There are no models': 'There are no models', +'There are no modules': 'There are no modules', +'There are no plugins': 'There are no plugins', +'There are no private files': 'There are no private files', +'There are no static files': 'There are no static files', +'There are no translators': 'There are no translators', +'There are no translators, only default language is supported': 'There are no translators, only default language is supported', +'There are no views': 'There are no views', +'These files are not served, they are only available from within your app': 'These files are not served, they are only available from within your app', +'These files are served without processing, your images go here': 'These files are served without processing, your images go here', 'these files are served without processing, your images go here': 'these files are served without processing, your images go here', +"This debugger may not work properly if you don't have a threaded webserver or you're using multiple daemon processes.": "This debugger may not work properly if you don't have a threaded webserver or you're using multiple daemon processes.", +'This is an experimental feature and it needs more testing. If you decide to downgrade you do it at your own risk': 'This is an experimental feature and it needs more testing. If you decide to downgrade you do it at your own risk', +'This is an experimental feature and it needs more testing. If you decide to upgrade you do it at your own risk': 'This is an experimental feature and it needs more testing. If you decide to upgrade you do it at your own risk', +'This is the %(filename)s template': 'This is the %(filename)s template', +"This page can commit your changes to an openshift app repo and push them to your cloud instance. This assumes that you've already created the application instance using the web2py skeleton and have that repo somewhere on a filesystem that this web2py instance can access. This functionality requires GitPython installed and on the python path of the runtime that web2py is operating in.": "This page can commit your changes to an openshift app repo and push them to your cloud instance. This assumes that you've already created the application instance using the web2py skeleton and have that repo somewhere on a filesystem that this web2py instance can access. This functionality requires GitPython installed and on the python path of the runtime that web2py is operating in.", +'This page can upload your application to the Google App Engine computing cloud. Mind that you must first create indexes locally and this is done by installing the Google appserver and running the app locally with it once, or there will be errors when selecting records. Attention: deployment may take long time, depending on the network speed. Attention: it will overwrite your app.yaml. DO NOT SUBMIT TWICE.': 'This page can upload your application to the Google App Engine computing cloud. Mind that you must first create indexes locally and this is done by installing the Google appserver and running the app locally with it once, or there will be errors when selecting records. Attention: deployment may take long time, depending on the network speed. Attention: it will overwrite your app.yaml. DO NOT SUBMIT TWICE.', +'this page to see if a breakpoint was hit and debug interaction is required.': 'this page to see if a breakpoint was hit and debug interaction is required.', +'This will pull changes from the remote repo for application "%s"?': 'This will pull changes from the remote repo for application "%s"?', +'This will push changes to the remote repo for application "%s".': 'This will push changes to the remote repo for application "%s".', +'Ticket': 'Ticket', +'Ticket ID': 'Ticket ID', +'Ticket Missing': 'Ticket Missing', +'Time in Cache (h:m:s)': 'Time in Cache (h:m:s)', +'TM': 'TM', 'to previous version.': 'to previous version.', +'To create a plugin, name a file/folder plugin_[name]': 'To create a plugin, name a file/folder plugin_[name]', +'To emulate a breakpoint programatically, write:': 'To emulate a breakpoint programatically, write:', +'to use the debugger!': 'to use the debugger!', +'toggle breakpoint': 'toggle breakpoint', +'Toggle comment': 'Toggle comment', +'Toggle Fullscreen': 'Toggle Fullscreen', +'Traceback': 'Traceback', 'translation strings for the application': 'translation strings for the application', +'Translation strings for the application': 'Translation strings for the application', 'try': 'try', 'try something like': 'try something like', +'Try the mobile interface': 'Try the mobile interface', +'try view': 'try view', +'Type PDB debugger command in here and hit Return (Enter) to execute it.': 'Type PDB debugger command in here and hit Return (Enter) to execute it.', +'Type some Python code in here and hit Return (Enter) to execute it.': 'Type some Python code in here and hit Return (Enter) to execute it.', +'Unable to check for upgrades': 'Unable to check for upgrades', 'unable to create application "%s"': 'unable to create application "%s"', 'unable to delete file "%(filename)s"': 'unable to delete file "%(filename)s"', 'unable to delete file plugin "%(plugin)s"': 'unable to delete file plugin "%(plugin)s"', +'Unable to determine the line number!': 'Unable to determine the line number!', +'Unable to download': 'Unable to download', +'Unable to download app because:': 'Unable to download app because:', +'Unable to download because': 'Unable to download because', +'unable to download layout': 'unable to download layout', +'unable to download plugin: %s': 'unable to download plugin: %s', +'Unable to download the list of plugins': 'Unable to download the list of plugins', +'unable to install plugin "%s"': 'unable to install plugin "%s"', 'unable to parse csv file': 'не е възможна обработката на csv файла', 'unable to uninstall "%s"': 'unable to uninstall "%s"', 'unable to upgrade because "%s"': 'unable to upgrade because "%s"', 'uncheck all': 'uncheck all', +'Uninstall': 'uninstall', +'Unsupported webserver working mode: %s': 'Unsupported webserver working mode: %s', 'update': 'update', 'update all languages': 'update all languages', +'Update:': 'Update:', +'Upgrade': 'Upgrade', +'upgrade now to %s': 'upgrade now to %s', 'upgrade web2py now': 'upgrade web2py now', 'upload': 'upload', +'Upload': 'Upload', +'Upload & install packed application': 'Upload & install packed application', +'Upload a package:': 'Upload a package:', +'Upload and install packed application': 'Upload and install packed application', 'upload application:': 'upload application:', +'Upload existing application': 'Upload existing application', 'upload file:': 'upload file:', 'upload plugin file:': 'upload plugin file:', +'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.', +'Use an url:': 'Use an url:', +'User': 'User', +'Username': 'Username', +'Users': 'Users', +'Using the shell may lock the database to other users of this app.': 'Using the shell may lock the database to other users of this app.', 'variables': 'variables', +'Version': 'Version', +'Versioning': 'Versioning', 'versioning': 'versioning', 'view': 'view', +'Views': 'Views', 'views': 'views', -'web2py Recent Tweets': 'web2py Recent Tweets', +'Warning!': 'Warning!', +'WARNING:': 'WARNING:', +'WARNING: The following views could not be compiled:': 'WARNING: The following views could not be compiled:', +'Web Framework': 'Web Framework', +'web2py Admin Password': 'web2py Admin Password', +'web2py apps to deploy': 'web2py apps to deploy', +'web2py Debugger': 'web2py Debugger', +'web2py downgrade': 'web2py downgrade', 'web2py is up to date': 'web2py is up to date', +'web2py online debugger': 'web2py online debugger', +'web2py Recent Tweets': 'web2py Recent Tweets', +'web2py upgrade': 'web2py upgrade', 'web2py upgraded; please restart it': 'web2py upgraded; please restart it', +'Welcome to web2py': 'Добре дошъл в web2py', +'Working...': 'Working...', +'WSGI reference name': 'WSGI reference name', +'YES': 'YES', +'Yes': 'Yes', +'You can also set and remove breakpoint in the edit window, using the Toggle Breakpoint button': 'You can also set and remove breakpoint in the edit window, using the Toggle Breakpoint button', +'You can inspect variables using the console below': 'You can inspect variables using the console below', +'You have one more login attempt before you are locked out': 'You have one more login attempt before you are locked out', +'You need to set up and reach a': 'You need to set up and reach a', +'You only need these if you have already registered': 'You only need these if you have already registered', +'Your application will be blocked until you click an action button (next, step, continue, etc.)': 'Your application will be blocked until you click an action button (next, step, continue, etc.)', } diff --git a/applications/admin/languages/cs.py b/applications/admin/languages/cs.py index 1b9481ef..e4667c24 100755 --- a/applications/admin/languages/cs.py +++ b/applications/admin/languages/cs.py @@ -3,26 +3,39 @@ '!langcode!': 'cs-cz', '!langname!': 'čeština', '"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN': 'Kolonka "Upravit" je nepovinný výraz, například "pole1=\'nováhodnota\'". Výsledky databázového JOINu nemůžete mazat ani upravovat.', +'"User Exception" debug mode. ': '"User Exception" debug mode. ', '"User Exception" debug mode. An error ticket could be issued!': '"User Exception" debug mode. An error ticket could be issued!', '%%{Row} in Table': '%%{řádek} v tabulce', '%%{Row} selected': 'označených %%{řádek}', +'%s': '%s', '%s %%{row} deleted': '%s smazaných %%{záznam}', '%s %%{row} updated': '%s upravených %%{záznam}', '%s selected': '%s označených', +'%s students registered': '%s students registered', '%Y-%m-%d': '%d.%m.%Y', '%Y-%m-%d %H:%M:%S': '%d.%m.%Y %H:%M:%S', '(requires internet access)': '(vyžaduje připojení k internetu)', '(requires internet access, experimental)': '(requires internet access, experimental)', '(something like "it-it")': '(například "cs-cs")', +'(version %s)': '(version %s)', +'?': '?', '@markmin\x01(file **gluon/contrib/plural_rules/%s.py** is not found)': '(soubor **gluon/contrib/plural_rules/%s.py** nenalezen)', '@markmin\x01Searching: **%s** %%{file}': 'Hledání: **%s** %%{soubor}', +'Abort': 'Abort', 'About': 'O programu', 'About application': 'O aplikaci', +'Accept Terms': 'Accept Terms', 'Access Control': 'Řízení přístupu', 'Add breakpoint': 'Přidat bod přerušení', 'Additional code for your application': 'Další kód pro Vaši aplikaci', 'Admin design page': 'Admin design page', +'admin disabled because no admin password': 'admin disabled because no admin password', +'admin disabled because not supported on google app engine': 'admin disabled because not supported on google app engine', +'admin disabled because too many invalid login attempts': 'admin disabled because too many invalid login attempts', +'admin disabled because unable to access password file': 'admin disabled because unable to access password file', +'Admin is disabled because insecure channel': 'Admin is disabled because insecure channel', 'Admin language': 'jazyk rozhraní', +'Admin versioning page': 'Admin versioning page', 'Administrative interface': 'pro administrátorské rozhraní klikněte sem', 'Administrative Interface': 'Administrátorské rozhraní', 'administrative interface': 'rozhraní pro správu', @@ -30,46 +43,67 @@ 'Ajax Recipes': 'Recepty s ajaxem', 'An error occured, please %s the page': 'An error occured, please %s the page', 'and rename it:': 'a přejmenovat na:', +'App does not exist or you are not authorized': 'App does not exist or you are not authorized', 'appadmin': 'appadmin', 'appadmin is disabled because insecure channel': 'appadmin je zakázaná bez zabezpečeného spojení', 'Application': 'Application', 'application "%s" uninstalled': 'application "%s" odinstalována', +'Application cannot be generated in demo mode': 'Application cannot be generated in demo mode', 'application compiled': 'aplikace zkompilována', +'Application exists already': 'Application exists already', +'application is compiled and cannot be designed': 'application is compiled and cannot be designed', 'Application name:': 'Název aplikace:', +'Application updated via git pull': 'Application updated via git pull', 'are not used': 'nepoužita', 'are not used yet': 'ještě nepoužita', +'Are you sure you want to delete file "%s"?': 'Are you sure you want to delete file "%s"?', +'Are you sure you want to delete plugin "%s"?': 'Are you sure you want to delete plugin "%s"?', 'Are you sure you want to delete this object?': 'Opravdu chcete odstranit tento objekt?', 'Are you sure you want to uninstall application "%s"?': 'Opravdu chcete odinstalovat aplikaci "%s"?', +'Are you sure?': 'Are you sure?', 'arguments': 'arguments', 'at char %s': 'at char %s', 'at line %s': 'at line %s', 'ATTENTION:': 'ATTENTION:', +'ATTENTION: Login requires a secure (HTTPS) connection or running on localhost.': 'ATTENTION: Login requires a secure (HTTPS) connection or running on localhost.', 'ATTENTION: TESTING IS NOT THREAD SAFE SO DO NOT PERFORM MULTIPLE TESTS CONCURRENTLY.': 'ATTENTION: TESTING IS NOT THREAD SAFE SO DO NOT PERFORM MULTIPLE TESTS CONCURRENTLY.', +'ATTENTION: you cannot edit the running application!': 'ATTENTION: you cannot edit the running application!', +'Autocomplete Python Code': 'Autocomplete Python Code', 'Available Databases and Tables': 'Dostupné databáze a tabulky', 'back': 'zpět', +'Back to the plugins list': 'Back to the plugins list', 'Back to wizard': 'Back to wizard', 'Basics': 'Basics', 'Begin': 'Začít', 'breakpoint': 'bod přerušení', 'Breakpoints': 'Body přerušení', 'breakpoints': 'body přerušení', +'Bulk Register': 'Bulk Register', +'Bulk Student Registration': 'Bulk Student Registration', 'Buy this book': 'Koupit web2py knihu', 'Cache': 'Cache', 'cache': 'cache', +'Cache Cleared': 'Cache Cleared', 'Cache Keys': 'Klíče cache', 'cache, errors and sessions cleaned': 'cache, chyby a relace byly pročištěny', 'can be a git repo': 'může to být git repo', 'Cancel': 'Storno', 'Cannot be empty': 'Nemůže být prázdné', +'Cannot compile: there are errors in your app:': 'Cannot compile: there are errors in your app:', +'cannot create file': 'cannot create file', +'cannot upload file "%(filename)s"': 'cannot upload file "%(filename)s"', 'Change Admin Password': 'Změnit heslo pro správu', 'Change admin password': 'Změnit heslo pro správu aplikací', +'change editor settings': 'change editor settings', 'Change password': 'Změna hesla', +'Changelog': 'Changelog', 'check all': 'vše označit', 'Check for upgrades': 'Zkusit aktualizovat', 'Check to delete': 'Označit ke smazání', 'Check to delete:': 'Označit ke smazání:', 'Checking for upgrades...': 'Zjišťuji, zda jsou k dispozici aktualizace...', 'Clean': 'Pročistit', +'Clear': 'Clear', 'Clear CACHE?': 'Vymazat CACHE?', 'Clear DISK': 'Vymazat DISK', 'Clear RAM': 'Vymazat RAM', @@ -79,8 +113,15 @@ 'code': 'code', 'Code listing': 'Code listing', 'collapse/expand all': 'vše sbalit/rozbalit', +'Command': 'Command', +'Comment:': 'Comment:', +'Commit': 'Commit', +'Commit form': 'Commit form', +'Committed files': 'Committed files', 'Community': 'Komunita', 'Compile': 'Zkompilovat', +'Compile (all or nothing)': 'Compile (all or nothing)', +'Compile (skip failed views)': 'Compile (skip failed views)', 'compiled application removed': 'zkompilovaná aplikace smazána', 'Components and Plugins': 'Komponenty a zásuvné moduly', 'Condition': 'Podmínka', @@ -92,9 +133,12 @@ 'Count': 'Počet', 'Create': 'Vytvořit', 'create file with filename:': 'vytvořit soubor s názvem:', +'Create/Upload': 'Create/Upload', 'created by': 'vytvořil', 'Created By': 'Vytvořeno - kým', +'Created by:': 'Created by:', 'Created On': 'Vytvořeno - kdy', +'Created on:': 'Created on:', 'crontab': 'crontab', 'Current request': 'Aktuální požadavek', 'Current response': 'Aktuální odpověď', @@ -107,6 +151,7 @@ 'Database %s select': 'databáze %s výběr', 'Database administration': 'Database administration', 'database administration': 'správa databáze', +'Database Administration (appadmin)': 'Database Administration (appadmin)', 'Date and Time': 'Datum a čas', 'day': 'den', 'db': 'db', @@ -124,36 +169,60 @@ 'Deploy': 'Nahrát', 'Deploy on Google App Engine': 'Nahrát na Google App Engine', 'Deploy to OpenShift': 'Nahrát na OpenShift', +'Deploy to pythonanywhere': 'Deploy to pythonanywhere', +'Deploy to PythonAnywhere': 'Deploy to PythonAnywhere', +'Deployment form': 'Deployment form', +'Deployment Interface': 'Deployment Interface', 'Deployment Recipes': 'Postupy pro deployment', 'Description': 'Popis', +'Description:': 'Description:', 'design': 'návrh', 'Detailed traceback description': 'Podrobný výpis prostředí', 'details': 'podrobnosti', 'direction: ltr': 'směr: ltr', +'directory not found': 'directory not found', 'Disable': 'Zablokovat', +'Disabled': 'Disabled', +'disabled in demo mode': 'disabled in demo mode', +'disabled in GAE mode': 'disabled in GAE mode', +'disabled in multi user mode': 'disabled in multi user mode', 'DISK': 'DISK', 'Disk Cache Keys': 'Klíče diskové cache', 'Disk Cleared': 'Disk smazán', +'Display line numbers': 'Display line numbers', +'DO NOT use the "Pack compiled" feature.': 'DO NOT use the "Pack compiled" feature.', 'docs': 'dokumentace', +'Docs': 'Docs', 'Documentation': 'Dokumentace', "Don't know what to do?": 'Nevíte kudy kam?', 'done!': 'hotovo!', +'Downgrade': 'Downgrade', 'Download': 'Stáhnout', +'Download .w2p': 'Download .w2p', +'Download as .exe': 'Download as .exe', 'download layouts': 'stáhnout moduly rozvržení stránky', +'Download layouts from repository': 'Download layouts from repository', 'download plugins': 'stáhnout zásuvné moduly', +'Download plugins from repository': 'Download plugins from repository', 'E-mail': 'E-mail', 'Edit': 'Upravit', 'edit all': 'edit all', 'Edit application': 'Správa aplikace', 'edit controller': 'edit controller', +'edit controller:': 'edit controller:', 'Edit current record': 'Upravit aktuální záznam', 'Edit Profile': 'Upravit profil', 'edit views:': 'upravit pohled:', +'Editing %s': 'Editing %s', 'Editing file "%s"': 'Úprava souboru "%s"', 'Editing Language file': 'Úprava jazykového souboru', 'Editing Plural Forms File': 'Editing Plural Forms File', +'Editor': 'Editor', +'Email Address': 'Email Address', 'Email and SMS': 'Email a SMS', 'Enable': 'Odblokovat', +'Enable Close-Tag': 'Enable Close-Tag', +'Enable Code Folding': 'Enable Code Folding', 'enter a number between %(min)g and %(max)g': 'zadejte číslo mezi %(min)g a %(max)g', 'enter an integer between %(min)g and %(max)g': 'zadejte celé číslo mezi %(min)g a %(max)g', 'Error': 'Chyba', @@ -164,124 +233,199 @@ 'Exception %(extype)s: %(exvalue)s': 'Exception %(extype)s: %(exvalue)s', 'Exception %s': 'Exception %s', 'Exception instance attributes': 'Prvky instance výjimky', +'Exit Fullscreen': 'Exit Fullscreen', 'Expand Abbreviation': 'Expand Abbreviation', +'Expand Abbreviation (html files only)': 'Expand Abbreviation (html files only)', 'export as csv file': 'exportovat do .csv souboru', +'Exports:': 'Exports:', 'exposes': 'vystavuje', 'exposes:': 'vystavuje funkce:', 'extends': 'rozšiřuje', 'failed to compile file because:': 'soubor se nepodařilo zkompilovat, protože:', +'failed to reload module because:': 'failed to reload module because:', 'FAQ': 'Často kladené dotazy', 'File': 'Soubor', 'file': 'soubor', 'file "%(filename)s" created': 'file "%(filename)s" created', +'file "%(filename)s" deleted': 'file "%(filename)s" deleted', +'file "%(filename)s" uploaded': 'file "%(filename)s" uploaded', +'file "%s" of %s restored': 'file "%s" of %s restored', +'file changed on disk': 'file changed on disk', +'file does not exist': 'file does not exist', +'file not found': 'file not found', 'file saved on %(time)s': 'soubor uložen %(time)s', 'file saved on %s': 'soubor uložen %s', +'filename': 'filename', 'Filename': 'Název souboru', +'Files added': 'Files added', 'filter': 'filtr', 'Find Next': 'Najít další', 'Find Previous': 'Najít předchozí', 'First name': 'Křestní jméno', 'Forgot username?': 'Zapomněl jste svoje přihlašovací jméno?', 'forgot username?': 'zapomněl jste svoje přihlašovací jméno?', +'Form has errors': 'Form has errors', 'Forms and Validators': 'Formuláře a validátory', 'Frames': 'Frames', 'Free Applications': 'Aplikace zdarma', 'Functions with no doctests will result in [passed] tests.': 'Functions with no doctests will result in [passed] tests.', +'GAE Email': 'GAE Email', +'GAE Output': 'GAE Output', +'GAE Password': 'GAE Password', 'Generate': 'Vytvořit', 'Get from URL:': 'Stáhnout z internetu:', 'Git Pull': 'Git Pull', 'Git Push': 'Git Push', 'Globals##debug': 'Globální proměnné', 'go!': 'OK!', +'Google App Engine Deployment Interface': 'Google App Engine Deployment Interface', +'Google Application Id': 'Google Application Id', 'Goto': 'Goto', 'graph model': 'graph model', +'Graph Model': 'Graph Model', 'Group %(group_id)s created': 'Skupina %(group_id)s vytvořena', 'Group ID': 'ID skupiny', 'Groups': 'Skupiny', 'Hello World': 'Ahoj světe', 'Help': 'Nápověda', +'here': 'here', 'Hide/Show Translated strings': 'Skrýt/Zobrazit přeložené texty', +'Highlight current line': 'Highlight current line', 'Hits': 'Kolikrát dosaženo', 'Home': 'Domovská stránka', 'honored only if the expression evaluates to true': 'brát v potaz jen když se tato podmínka vyhodnotí kladně', 'How did you get here?': 'Jak jste se sem vlastně dostal?', +'If start the downgrade, be patient, it may take a while to rollback': 'If start the downgrade, be patient, it may take a while to rollback', 'If start the upgrade, be patient, it may take a while to download': 'If start the upgrade, be patient, it may take a while to download', +'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\n\t\tA green title indicates that all tests (if defined) passed. In this case test results are not shown.': 'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\n\t\tA green title indicates that all tests (if defined) passed. In this case test results are not shown.', 'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\nA green title indicates that all tests (if defined) passed. In this case test results are not shown.': 'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\nA green title indicates that all tests (if defined) passed. In this case test results are not shown.', +'if your application uses a database other than sqlite you will then have to configure its DAL in pythonanywhere.': 'if your application uses a database other than sqlite you will then have to configure its DAL in pythonanywhere.', 'import': 'import', 'Import/Export': 'Import/Export', +'In development, use the default Rocket webserver that is currently supported by this debugger.': 'In development, use the default Rocket webserver that is currently supported by this debugger.', 'includes': 'zahrnuje', +'Indent with tabs': 'Indent with tabs', 'Index': 'Index', 'insert new': 'vložit nový záznam ', 'insert new %s': 'vložit nový záznam %s', 'inspect attributes': 'inspect attributes', 'Install': 'Instalovat', +'Installation of %(plugin)s for %(app)s': 'Installation of %(plugin)s for %(app)s', 'Installed applications': 'Nainstalované aplikace', 'Interaction at %s line %s': 'Interakce v %s, na řádce %s', 'Interactive console': 'Interaktivní příkazová řádka', +'internal error': 'internal error', +'internal error: %s': 'internal error: %s', 'Internal State': 'Vnitřní stav', 'Introduction': 'Úvod', +'Invalid action': 'Invalid action', +'Invalid application name': 'Invalid application name', +'invalid circular reference': 'invalid circular reference', 'Invalid email': 'Neplatný email', +'Invalid git repository specified.': 'Invalid git repository specified.', 'Invalid password': 'Nesprávné heslo', +'invalid password': 'invalid password', 'invalid password.': 'neplatné heslo', 'Invalid Query': 'Neplatný dotaz', 'invalid request': 'Neplatný požadavek', +'Invalid request': 'Invalid request', +'invalid table names (auth_* tables already defined)': 'invalid table names (auth_* tables already defined)', +'invalid ticket': 'invalid ticket', 'Is Active': 'Je aktivní', 'It is %s %%{day} today.': 'Dnes je to %s %%{den}.', 'Key': 'Klíč', 'Key bindings': 'Vazby klíčů', 'Key bindings for ZenCoding Plugin': 'Key bindings for ZenCoding Plugin', +'Keyboard shortcuts': 'Keyboard shortcuts', +'kill process': 'kill process', +'language file "%(filename)s" created/updated': 'language file "%(filename)s" created/updated', +'Language files (static strings) updated': 'Language files (static strings) updated', 'languages': 'jazyky', 'Languages': 'Jazyky', 'Last name': 'Příjmení', +'Last Revision': 'Last Revision', 'Last saved on:': 'Naposledy uloženo:', 'Layout': 'Rozvržení stránky (layout)', 'Layout Plugins': 'Moduly rozvržení stránky (Layout Plugins)', 'Layouts': 'Rozvržení stránek', 'License for': 'Licence pro', +'License:': 'License:', +'Line Nr': 'Line Nr', 'Line number': 'Číslo řádku', 'LineNo': 'Č.řádku', +'lists by exception': 'lists by exception', +'lists by ticket': 'lists by ticket', 'Live Chat': 'Online pokec', +'Loading...': 'Loading...', 'loading...': 'nahrávám...', +'Local Apps': 'Local Apps', 'locals': 'locals', 'Locals##debug': 'Lokální proměnné', 'Logged in': 'Přihlášení proběhlo úspěšně', 'Logged out': 'Odhlášení proběhlo úspěšně', -'Login': 'Přihlásit se', 'login': 'přihlásit se', +'Login': 'Přihlásit se', +'Login successful': 'Login successful', 'Login to the Administrative Interface': 'Přihlásit se do Správce aplikací', +'Login/Register': 'Login/Register', 'logout': 'odhlásit se', 'Logout': 'Odhlásit se', +'lost password': 'lost password', 'Lost Password': 'Zapomněl jste heslo', 'Lost password?': 'Zapomněl jste heslo?', 'lost password?': 'zapomněl jste heslo?', +'Main Menu': 'Main Menu', 'Manage': 'Manage', +'Manage %(action)s': 'Manage %(action)s', +'Manage Access Control': 'Manage Access Control', +'Manage Admin Users/Students': 'Manage Admin Users/Students', 'Manage Cache': 'Manage Cache', +'Manage Students': 'Manage Students', +'Memberships': 'Memberships', 'Menu Model': 'Model rozbalovací nabídky', +'merge': 'merge', 'Models': 'Modely', 'models': 'modely', 'Modified By': 'Změněno - kým', 'Modified On': 'Změněno - kdy', 'Modules': 'Moduly', 'modules': 'moduly', +'Multi User Mode': 'Multi User Mode', 'My Sites': 'Správa aplikací', 'Name': 'Jméno', 'new application "%s" created': 'nová aplikace "%s" vytvořena', +'new application "%s" imported': 'new application "%s" imported', 'New Application Wizard': 'Nový průvodce aplikací', 'New application wizard': 'Nový průvodce aplikací', 'New password': 'Nové heslo', +'new plugin installed': 'new plugin installed', +'New plugin installed: %s': 'New plugin installed: %s', 'New Record': 'Nový záznam', 'new record inserted': 'nový záznam byl založen', 'New simple application': 'Vytvořit primitivní aplikaci', 'next': 'next', +'next %s rows': 'next %s rows', 'next 100 rows': 'dalších 100 řádků', +'NO': 'NO', +'no changes': 'no changes', 'No databases in this application': 'V této aplikaci nejsou žádné databáze', 'No Interaction yet': 'Ještě žádná interakce nenastala', +'no match': 'no match', +'no package selected': 'no package selected', +'no permission to uninstall "%s"': 'no permission to uninstall "%s"', 'No ticket_storage.txt found under /private folder': 'Soubor ticket_storage.txt v adresáři /private nenalezen', +'Node:': 'Node:', +'Not Authorized': 'Not Authorized', +'Not supported': 'Not supported', +'Note: If you receive an error with github status code of 128, ensure the system and account you are deploying from has a cooresponding ssh key configured in the openshift account.': 'Note: If you receive an error with github status code of 128, ensure the system and account you are deploying from has a cooresponding ssh key configured in the openshift account.', 'Object or table name': 'Objekt či tabulka', 'Old password': 'Původní heslo', +"On production, you'll have to configure your webserver to use one process and multiple threads to use this debugger.": "On production, you'll have to configure your webserver to use one process and multiple threads to use this debugger.", 'online designer': 'online návrhář', 'Online examples': 'Příklady online', 'Open new app in new window': 'Open new app in new window', +'OpenShift Deployment Interface': 'OpenShift Deployment Interface', +'OpenShift Output': 'OpenShift Output', 'or alternatively': 'or alternatively', 'Or Get from URL:': 'Or Get from URL:', 'or import from csv file': 'nebo importovat z .csv souboru', @@ -293,30 +437,53 @@ 'Overwrite installed app': 'Přepsat instalovanou aplikaci', 'Pack all': 'Zabalit', 'Pack compiled': 'Zabalit zkompilované', +'Pack custom': 'Pack custom', 'pack plugin': 'pack plugin', -'password': 'heslo', 'Password': 'Heslo', +'password': 'heslo', +'password changed': 'password changed', "Password fields don't match": 'Hesla se neshodují', +'Past revisions': 'Past revisions', +'Path to appcfg.py': 'Path to appcfg.py', +'Path to local openshift repo root.': 'Path to local openshift repo root.', 'Peeking at file': 'Peeking at file', +'Permission': 'Permission', +'Permissions': 'Permissions', 'Please': 'Prosím', +'Please wait, giving pythonanywhere a moment...': 'Please wait, giving pythonanywhere a moment...', +'plugin "%(plugin)s" deleted': 'plugin "%(plugin)s" deleted', 'Plugin "%s" in application': 'Plugin "%s" in application', +'plugin not specified': 'plugin not specified', +'Plugin page': 'Plugin page', 'plugins': 'zásuvné moduly', 'Plugins': 'Zásuvné moduly', 'Plural Form #%s': 'Plural Form #%s', 'Plural-Forms:': 'Množná čísla:', 'Powered by': 'Poháněno', 'Preface': 'Předmluva', +'Preferences saved correctly': 'Preferences saved correctly', +'Preferences saved on session only': 'Preferences saved on session only', +'previous %s rows': 'previous %s rows', 'previous 100 rows': 'předchozích 100 řádků', 'Private files': 'Soukromé soubory', 'private files': 'soukromé soubory', 'profile': 'profil', 'Project Progress': 'Vývoj projektu', +'Pull': 'Pull', +'Pull failed, certain files could not be checked out. Check logs for details.': 'Pull failed, certain files could not be checked out. Check logs for details.', +'Pull is not possible because you have unmerged files. Fix them up in the work tree, and then try again.': 'Pull is not possible because you have unmerged files. Fix them up in the work tree, and then try again.', +'Push': 'Push', +'Push failed, there are unmerged entries in the cache. Resolve merge issues manually and try again.': 'Push failed, there are unmerged entries in the cache. Resolve merge issues manually and try again.', +'pygraphviz library not found': 'pygraphviz library not found', 'Python': 'Python', +'PythonAnywhere Apps': 'PythonAnywhere Apps', +'PythonAnywhere Password': 'PythonAnywhere Password', 'Query:': 'Dotaz:', 'Quick Examples': 'Krátké příklady', 'RAM': 'RAM', 'RAM Cache Keys': 'Klíče RAM Cache', 'Ram Cleared': 'RAM smazána', +'Rapid Search': 'Rapid Search', 'Readme': 'Nápověda', 'Recipes': 'Postupy jak na to', 'Record': 'Záznam', @@ -335,35 +502,58 @@ 'Removed Breakpoint on %s at line %s': 'Bod přerušení smazán - soubor %s na řádce %s', 'Replace': 'Zaměnit', 'Replace All': 'Zaměnit vše', +'Repository (%s)': 'Repository (%s)', 'request': 'request', +'requires distutils, but not installed': 'requires distutils, but not installed', +'requires python-git, but not installed': 'requires python-git, but not installed', 'Reset Password key': 'Reset registračního klíče', +'Resolve Conflict file': 'Resolve Conflict file', 'response': 'response', 'restart': 'restart', 'restore': 'obnovit', 'Retrieve username': 'Získat přihlašovací jméno', 'return': 'return', +'Revert': 'Revert', 'revert': 'vrátit se k původnímu', +'reverted to revision %s': 'reverted to revision %s', +'Revision %s': 'Revision %s', +'Revision:': 'Revision:', 'Role': 'Role', +'Roles': 'Roles', 'Rows in Table': 'Záznamy v tabulce', 'Rows selected': 'Záznamů zobrazeno', 'rules are not defined': 'pravidla nejsou definována', +'Run tests': 'Run tests', +'Run tests in this file': 'Run tests in this file', "Run tests in this file (to run all files, you may also use the button labelled 'test')": "Spustí testy v tomto souboru (ke spuštění všech testů, použijte tlačítko 'test')", 'Running on %s': 'Běží na %s', 'Save': 'Uložit', 'Save file:': 'Save file:', +'Save file: %s': 'Save file: %s', +'Save model as...': 'Save model as...', 'Save via Ajax': 'Uložit pomocí Ajaxu', 'Saved file hash:': 'hash uloženého souboru:', +'Screenshot %s': 'Screenshot %s', +'Search': 'Search', +'Select Files to Package': 'Select Files to Package', 'Semantic': 'Modul semantic', 'Services': 'Služby', 'session': 'session', 'session expired': 'session expired', +'Session saved correctly': 'Session saved correctly', +'Session saved on session only': 'Session saved on session only', 'Set Breakpoint on %s at line %s: %s': 'Bod přerušení nastaven v souboru %s na řádce %s: %s', 'shell': 'příkazová řádka', +'Showing %s to %s of %s %s found': 'Showing %s to %s of %s %s found', 'Singular Form': 'Singular Form', 'Site': 'Správa aplikací', 'Size of cache:': 'Velikost cache:', 'skip to generate': 'skip to generate', +'some files could not be removed': 'some files could not be removed', +'Something went wrong please wait a few minutes before retrying': 'Something went wrong please wait a few minutes before retrying', 'Sorry, could not find mercurial installed': 'Bohužel mercurial není nainstalován.', +'source : db': 'source : db', +'source : filesystem': 'source : filesystem', 'Start a new app': 'Vytvořit novou aplikaci', 'Start searching': 'Začít hledání', 'Start wizard': 'Spustit průvodce', @@ -381,34 +571,49 @@ 'successful': 'úspěšně', 'Support': 'Podpora', 'Sure you want to delete this object?': 'Opravdu chcete smazat tento objekt?', +'switch to : db': 'switch to : db', +'switch to : filesystem': 'switch to : filesystem', +'Tab width (# characters)': 'Tab width (# characters)', 'Table': 'tabulka', 'Table name': 'Název tabulky', 'Temporary': 'Dočasný', 'test': 'test', 'Testing application': 'Testing application', 'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.': '"Dotaz" je podmínka, například "db.tabulka1.pole1==\'hodnota\'". Podmínka "db.tabulka1.pole1==db.tabulka2.pole2" pak vytvoří SQL JOIN.', +'The app exists, was created by wizard, continue to overwrite!': 'The app exists, was created by wizard, continue to overwrite!', +'The app exists, was NOT created by wizard, continue to overwrite!': 'The app exists, was NOT created by wizard, continue to overwrite!', 'The application logic, each URL path is mapped in one exposed function in the controller': 'Logika aplikace: každá URL je mapována na funkci vystavovanou kontrolérem.', 'The Core': 'Jádro (The Core)', 'The data representation, define database tables and sets': 'Reprezentace dat: definovat tabulky databáze a záznamy', 'The output of the file is a dictionary that was rendered by the view %s': 'Výstup ze souboru je slovník, který se zobrazil v pohledu %s.', 'The presentations layer, views are also known as templates': 'Prezentační vrstva: pohledy či templaty (šablony)', 'The Views': 'Pohledy (The Views)', +'Theme': 'Theme', 'There are no controllers': 'There are no controllers', +'There are no models': 'There are no models', 'There are no modules': 'There are no modules', 'There are no plugins': 'Žádné moduly nejsou instalovány.', 'There are no private files': 'Žádné soukromé soubory neexistují.', 'There are no static files': 'There are no static files', +'There are no translators': 'There are no translators', 'There are no translators, only default language is supported': 'There are no translators, only default language is supported', 'There are no views': 'There are no views', 'These files are not served, they are only available from within your app': 'Tyto soubory jsou klientům nepřístupné. K dispozici jsou pouze v rámci aplikace.', 'These files are served without processing, your images go here': 'Tyto soubory jsou servírovány bez přídavné logiky, sem patří např. obrázky.', 'This App': 'Tato aplikace', +"This debugger may not work properly if you don't have a threaded webserver or you're using multiple daemon processes.": "This debugger may not work properly if you don't have a threaded webserver or you're using multiple daemon processes.", 'This is a copy of the scaffolding application': 'Toto je kopie aplikace skelet.', +'This is an experimental feature and it needs more testing. If you decide to downgrade you do it at your own risk': 'This is an experimental feature and it needs more testing. If you decide to downgrade you do it at your own risk', 'This is an experimental feature and it needs more testing. If you decide to upgrade you do it at your own risk': 'This is an experimental feature and it needs more testing. If you decide to upgrade you do it at your own risk', 'This is the %(filename)s template': 'This is the %(filename)s template', +"This page can commit your changes to an openshift app repo and push them to your cloud instance. This assumes that you've already created the application instance using the web2py skeleton and have that repo somewhere on a filesystem that this web2py instance can access. This functionality requires GitPython installed and on the python path of the runtime that web2py is operating in.": "This page can commit your changes to an openshift app repo and push them to your cloud instance. This assumes that you've already created the application instance using the web2py skeleton and have that repo somewhere on a filesystem that this web2py instance can access. This functionality requires GitPython installed and on the python path of the runtime that web2py is operating in.", +'This page can upload your application to the Google App Engine computing cloud. Mind that you must first create indexes locally and this is done by installing the Google appserver and running the app locally with it once, or there will be errors when selecting records. Attention: deployment may take long time, depending on the network speed. Attention: it will overwrite your app.yaml. DO NOT SUBMIT TWICE.': 'This page can upload your application to the Google App Engine computing cloud. Mind that you must first create indexes locally and this is done by installing the Google appserver and running the app locally with it once, or there will be errors when selecting records. Attention: deployment may take long time, depending on the network speed. Attention: it will overwrite your app.yaml. DO NOT SUBMIT TWICE.', 'this page to see if a breakpoint was hit and debug interaction is required.': 'tuto stránku, abyste uviděli, zda se dosáhlo bodu přerušení.', +'This will pull changes from the remote repo for application "%s"?': 'This will pull changes from the remote repo for application "%s"?', +'This will push changes to the remote repo for application "%s".': 'This will push changes to the remote repo for application "%s".', 'Ticket': 'Ticket', 'Ticket ID': 'Ticket ID', +'Ticket Missing': 'Ticket Missing', 'Time in Cache (h:m:s)': 'Čas v Cache (h:m:s)', 'Timestamp': 'Časové razítko', 'to previous version.': 'k předchozí verzi.', @@ -416,6 +621,7 @@ 'To emulate a breakpoint programatically, write:': 'K nastavení bodu přerušení v kódu programu, napište:', 'to use the debugger!': ', abyste mohli ladící program používat!', 'toggle breakpoint': 'vyp./zap. bod přerušení', +'Toggle comment': 'Toggle comment', 'Toggle Fullscreen': 'Na celou obrazovku a zpět', 'too short': 'Příliš krátké', 'Traceback': 'Traceback', @@ -424,12 +630,25 @@ 'Try the mobile interface': 'Zkuste rozhraní pro mobilní zařízení', 'try view': 'try view', 'Twitter': 'Twitter', +'Type PDB debugger command in here and hit Return (Enter) to execute it.': 'Type PDB debugger command in here and hit Return (Enter) to execute it.', 'Type python statement in here and hit Return (Enter) to execute it.': 'Type python statement in here and hit Return (Enter) to execute it.', 'Type some Python code in here and hit Return (Enter) to execute it.': 'Type some Python code in here and hit Return (Enter) to execute it.', 'Unable to check for upgrades': 'Unable to check for upgrades', +'unable to create application "%s"': 'unable to create application "%s"', +'unable to delete file "%(filename)s"': 'unable to delete file "%(filename)s"', +'unable to delete file plugin "%(plugin)s"': 'unable to delete file plugin "%(plugin)s"', +'Unable to determine the line number!': 'Unable to determine the line number!', +'Unable to download app because:': 'Unable to download app because:', +'unable to download layout': 'unable to download layout', +'unable to download plugin: %s': 'unable to download plugin: %s', +'Unable to download the list of plugins': 'Unable to download the list of plugins', +'unable to install plugin "%s"': 'unable to install plugin "%s"', 'unable to parse csv file': 'csv soubor nedá sa zpracovat', +'unable to uninstall "%s"': 'unable to uninstall "%s"', +'unable to upgrade because "%s"': 'unable to upgrade because "%s"', 'uncheck all': 'vše odznačit', 'Uninstall': 'Odinstalovat', +'Unsupported webserver working mode: %s': 'Unsupported webserver working mode: %s', 'update': 'aktualizovat', 'update all languages': 'aktualizovat všechny jazyky', 'Update:': 'Upravit:', @@ -443,6 +662,7 @@ 'upload file:': 'nahrát soubor:', 'upload plugin file:': 'nahrát soubor modulu:', 'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Použijte (...)&(...) pro AND, (...)|(...) pro OR a ~(...) pro NOT pro sestavení složitějších dotazů.', +'User': 'User', 'User %(id)s Logged-in': 'Uživatel %(id)s přihlášen', 'User %(id)s Logged-out': 'Uživatel %(id)s odhlášen', 'User %(id)s Password changed': 'Uživatel %(id)s změnil heslo', @@ -451,6 +671,8 @@ 'User %(id)s Username retrieved': 'Uživatel %(id)s si nachal zaslat přihlašovací jméno', 'User ID': 'ID uživatele', 'Username': 'Přihlašovací jméno', +'Users': 'Users', +'Using the shell may lock the database to other users of this app.': 'Using the shell may lock the database to other users of this app.', 'variables': 'variables', 'Verify Password': 'Zopakujte heslo', 'Version': 'Verze', @@ -460,7 +682,14 @@ 'View': 'Pohled (View)', 'Views': 'Pohledy', 'views': 'pohledy', +'Warning!': 'Warning!', +'WARNING:': 'WARNING:', +'WARNING: The following views could not be compiled:': 'WARNING: The following views could not be compiled:', 'Web Framework': 'Web Framework', +'web2py Admin Password': 'web2py Admin Password', +'web2py apps to deploy': 'web2py apps to deploy', +'web2py Debugger': 'web2py Debugger', +'web2py downgrade': 'web2py downgrade', 'web2py is up to date': 'Máte aktuální verzi web2py.', 'web2py online debugger': 'Ladící online web2py program', 'web2py Recent Tweets': 'Štěbetání na Twitteru o web2py', @@ -470,11 +699,18 @@ 'Welcome to web2py': 'Vitejte ve web2py', 'Welcome to web2py!': 'Vítejte ve web2py!', 'Which called the function %s located in the file %s': 'která zavolala funkci %s v souboru (kontroléru) %s.', +'Working...': 'Working...', +'WSGI reference name': 'WSGI reference name', +'YES': 'YES', +'Yes': 'Yes', 'You are successfully running web2py': 'Úspěšně jste spustili web2py.', 'You can also set and remove breakpoint in the edit window, using the Toggle Breakpoint button': 'Nastavovat a mazat body přerušení je též možno v rámci editování zdrojového souboru přes tlačítko Vyp./Zap. bod přerušení', +'You can inspect variables using the console bellow': 'Níže pomocí příkazové řádky si můžete prohlédnout proměnné', +'You can inspect variables using the console below': 'You can inspect variables using the console below', 'You can modify this application and adapt it to your needs': 'Tuto aplikaci si můžete upravit a přizpůsobit ji svým potřebám.', +'You have one more login attempt before you are locked out': 'You have one more login attempt before you are locked out', 'You need to set up and reach a': 'Je třeba nejprve nastavit a dojít až na', +'You only need these if you have already registered': 'You only need these if you have already registered', 'You visited the url %s': 'Navštívili jste stránku %s,', 'Your application will be blocked until you click an action button (next, step, continue, etc.)': 'Aplikace bude blokována než se klikne na jedno z tlačítek (další, krok, pokračovat, atd.)', -'You can inspect variables using the console bellow': 'Níže pomocí příkazové řádky si můžete prohlédnout proměnné', } diff --git a/applications/admin/languages/de.py b/applications/admin/languages/de.py index 654aa43c..da4fa1a9 100755 --- a/applications/admin/languages/de.py +++ b/applications/admin/languages/de.py @@ -3,13 +3,19 @@ '!langcode!': 'de', '!langname!': 'Deutsch', '"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN': '"Update" ist ein optionaler Ausdruck wie "Feld1 = \'newvalue". JOIN Ergebnisse können nicht aktualisiert oder gelöscht werden', +'"User Exception" debug mode. ': '"User Exception" debug mode. ', +'%s': '%s', '%s %%{row} deleted': '%s %%{row} Zeilen gelöscht', '%s %%{row} updated': '%s %%{row} Zeilen aktualisiert', +'%s selected': '%s selected', +'%s students registered': '%s students registered', '%Y-%m-%d': '%d.%m.%Y', '%Y-%m-%d %H:%M:%S': '%d.%m.%Y %H:%M:%S', '(requires internet access)': '(Benötigt Internetzugang)', '(requires internet access, experimental)': '(Benötigt Internetzugang)', '(something like "it-it")': '(so etwas wie "it-it")', +'(version %s)': '(version %s)', +'?': '?', '@markmin\x01(file **gluon/contrib/plural_rules/%s.py** is not found)': '(Datei **gluon/contrib/plural_rules/%s.py** wurde nicht gefunden)', '@markmin\x01An error occured, please [[reload %s]] the page': 'Ein Fehler ist aufgetreten, bitte [[reload %s]] sie die Seite erneut', '@markmin\x01Searching: **%s** %%{file}': '@markmin\x01Suche: **%s** Dateien', @@ -18,35 +24,48 @@ 'Abort': 'Abbrechen', 'About': 'Über', 'About application': 'Über die Anwendung', +'Accept Terms': 'Accept Terms', +'Add breakpoint': 'Add breakpoint', 'Additional code for your application': 'Zusätzlicher Code für Ihre Anwendung', +'Admin design page': 'Admin design page', 'admin disabled because no admin password': 'admin ist deaktiviert, weil kein Admin-Passwort gesetzt ist', +'admin disabled because not supported on google app engine': 'admin disabled because not supported on google app engine', 'admin disabled because not supported on google apps engine': 'admin ist deaktiviert, es existiert dafür keine Unterstützung auf der google apps engine', +'admin disabled because too many invalid login attempts': 'admin disabled because too many invalid login attempts', 'admin disabled because unable to access password file': 'admin ist deaktiviert, weil kein Zugriff auf die Passwortdatei besteht', 'Admin is disabled because insecure channel': 'Appadmin ist deaktiviert, wegen der Benutzung eines unsicheren Kanals', 'Admin is disabled because unsecure channel': 'Appadmin ist deaktiviert, wegen der Benutzung eines unsicheren Kanals', 'Admin language': 'Admin-Sprache', +'Admin versioning page': 'Admin versioning page', 'administrative interface': 'Administrative Schnittstelle', 'Administrator Password:': 'Administrator Passwort:', 'An error occured, please %s the page': 'Ein Fehler ist aufgetereten, bitte %s die Seite', 'and rename it (required):': 'und benenne sie um (erforderlich):', 'and rename it:': ' und benenne sie um:', +'App does not exist or you are not authorized': 'App does not exist or you are not authorized', 'appadmin': 'appadmin', 'appadmin is disabled because insecure channel': 'Appadmin ist deaktiviert, wegen der Benutzung eines unsicheren Kanals', 'Application': 'Anwendung', 'application "%s" uninstalled': 'Anwendung "%s" deinstalliert', +'Application cannot be generated in demo mode': 'Application cannot be generated in demo mode', 'application compiled': 'Anwendung kompiliert', +'Application exists already': 'Application exists already', 'application is compiled and cannot be designed': 'Die Anwendung ist kompiliert und kann deswegen nicht mehr geändert werden', 'Application name:': 'Name der Anwendung:', +'Application updated via git pull': 'Application updated via git pull', 'are not used': 'werden nicht verwendet', 'are not used yet': 'werden bisher nicht verwendet', 'Are you sure you want to delete file "%s"?': 'Sind Sie sich sicher, dass Sie diese Datei löschen wollen "%s"?', +'Are you sure you want to delete plugin "%s"?': 'Are you sure you want to delete plugin "%s"?', 'Are you sure you want to delete this object?': 'Sind Sie sich sicher, dass Sie dieses Objekt löschen wollen?', 'Are you sure you want to uninstall application "%s"': 'Sind Sie sich sicher, dass Sie diese Anwendung deinstallieren wollen "%s"', 'Are you sure you want to uninstall application "%s"?': 'Sind Sie sich sicher, dass Sie diese Anwendung deinstallieren wollen "%s"?', 'Are you sure you want to upgrade web2py now?': 'Sind Sie sich sicher, dass Sie web2py jetzt upgraden möchten?', +'Are you sure?': 'Are you sure?', 'arguments': 'arguments', 'at char %s': 'bei Zeichen %s', 'at line %s': 'in Linie %s', +'ATTENTION:': 'ATTENTION:', 'ATTENTION: Login requires a secure (HTTPS) connection or running on localhost.': 'ACHTUNG: Die Einwahl benötigt eine sichere (HTTPS) Verbindung. Es sei denn sie läuft Lokal (localhost).', 'ATTENTION: TESTING IS NOT THREAD SAFE SO DO NOT PERFORM MULTIPLE TESTS CONCURRENTLY.': 'ACHTUNG: Testen ist nicht threadsicher. Führen Sie also nicht mehrere Tests gleichzeitig aus.', 'ATTENTION: This is an experimental feature and it needs more testing.': 'ACHTUNG: Dies ist eine experimentelle Funktion und benötigt noch weitere Tests.', @@ -54,35 +73,66 @@ 'Authentication': 'Authentifizierung', 'Autocomplete Python Code': 'Autocomplete Python Code', 'Available databases and tables': 'Verfügbare Datenbanken und Tabellen', +'Available Databases and Tables': 'Available Databases and Tables', 'back': 'Zurück', +'Back to the plugins list': 'Back to the plugins list', +'Back to wizard': 'Back to wizard', +'Basics': 'Basics', 'beautify': 'Verschönern', +'Begin': 'Begin', +'breakpoint': 'breakpoint', +'Breakpoints': 'Breakpoints', +'breakpoints': 'breakpoints', +'Bulk Register': 'Bulk Register', +'Bulk Student Registration': 'Bulk Student Registration', +'Cache': 'Cache', 'cache': 'Zwischenspeicher', +'Cache Cleared': 'Cache Cleared', +'Cache Keys': 'Cache Keys', 'cache, errors and sessions cleaned': 'Zwischenspeicher (cache), Fehler und Sitzungen (sessions) gelöscht', 'call': 'Aufruf', 'can be a git repo': 'kann ein git Repository sein', 'Cancel': 'Abbrechen', 'Cannot be empty': 'Darf nicht leer sein', 'Cannot compile: there are errors in your app. Debug it, correct errors and try again.': 'Nicht Kompilierbar: Es sind Fehler in der Anwendung. Beseitigen Sie die Fehler und versuchen Sie es erneut.', +'Cannot compile: there are errors in your app:': 'Cannot compile: there are errors in your app:', 'cannot create file': 'Kann Datei nicht erstellen', 'cannot upload file "%(filename)s"': 'Kann Datei nicht Hochladen "%(filename)s"', +'Change Admin Password': 'Change Admin Password', 'Change admin password': 'Administrator-Passwort ändern', 'change editor settings': 'Editoreinstellungen ändern', 'Change Password': 'Passwort ändern', 'change password': 'Passwort ändern', +'Changelog': 'Changelog', 'check all': 'alles auswählen', 'Check for upgrades': 'Versionsüberprüfung', 'Check to delete': 'Markiere zum löschen', 'Checking for upgrades...': 'Überprüfe auf Updates...', 'Clean': 'Leeren', +'Clear': 'Clear', +'Clear CACHE?': 'Clear CACHE?', +'Clear DISK': 'Clear DISK', +'Clear RAM': 'Clear RAM', 'click here for online examples': 'hier klicken für online Beispiele', 'click here for the administrative interface': 'hier klicken für die Administrationsoberfläche ', 'Click row to expand traceback': 'Klicke auf die Zeile für Fehlerverfolgung', +'Click row to view a ticket': 'Click row to view a ticket', 'click to check for upgrades': 'hier klicken um nach Upgrades zu suchen', 'Client IP': 'Client IP', 'code': 'code', +'Code listing': 'Code listing', 'collapse/expand all': 'alles zu- bzw. aufklappen', +'Command': 'Command', +'Comment:': 'Comment:', +'Commit': 'Commit', +'Commit form': 'Commit form', +'Committed files': 'Committed files', 'Compile': 'kompilieren', +'Compile (all or nothing)': 'Compile (all or nothing)', +'Compile (skip failed views)': 'Compile (skip failed views)', 'compiled application removed': 'kompilierte Anwendung gelöscht', +'Condition': 'Condition', +'continue': 'continue', 'Controller': 'Controller', 'Controllers': 'Controllers', 'controllers': 'controllers', @@ -92,7 +142,11 @@ 'create file with filename:': 'Erzeuge Datei mit Dateinamen:', 'create new application:': 'Erzeuge neue Anwendung:', 'Create new simple application': 'Erzeuge neue Anwendung', +'Create/Upload': 'Create/Upload', 'created by': 'Erstellt von', +'Created by:': 'Created by:', +'Created On': 'Created On', +'Created on:': 'Created on:', 'crontab': 'crontab', 'Current request': 'Aktuelle Anfrage (request)', 'Current response': 'Aktuelle Antwort (response)', @@ -103,8 +157,11 @@ 'data uploaded': 'Daten hochgeladen', 'Database': 'Datenbank', 'database': 'Datenbank', +'Database %s select': 'Database %s select', 'database %s select': 'Datenbank %s ausgewählt', +'Database administration': 'Database administration', 'database administration': 'Datenbankadministration', +'Database Administration (appadmin)': 'Database Administration (appadmin)', 'Date and Time': 'Datum und Uhrzeit', 'db': 'db', 'DB Model': 'DB Modell', @@ -116,25 +173,49 @@ 'delete plugin': 'Plugin löschen', 'Delete this file (you will be asked to confirm deletion)': 'Diese Datei löschen (mit Bestätigungsdialog)', 'Delete:': 'Löschen:', +'deleted after first hit': 'deleted after first hit', +'Demo': 'Demo', 'Deploy': 'Installieren', 'Deploy on Google App Engine': 'Auf Google App Engine installieren', 'Deploy to OpenShift': 'Auf OpenShift installieren', +'Deploy to pythonanywhere': 'Deploy to pythonanywhere', +'Deploy to PythonAnywhere': 'Deploy to PythonAnywhere', +'Deployment form': 'Deployment form', +'Deployment Interface': 'Deployment Interface', 'Description': 'Beschreibung', +'Description:': 'Description:', 'design': 'design', 'DESIGN': 'DESIGN', 'Design for': 'Design für', 'Detailed traceback description': 'Detaillierte traceback Beschreibung', +'details': 'details', 'direction: ltr': 'direction: ltr', +'directory not found': 'directory not found', 'Disable': 'Deaktivieren', +'Disabled': 'Disabled', +'disabled in demo mode': 'disabled in demo mode', +'disabled in GAE mode': 'disabled in GAE mode', +'disabled in multi user mode': 'disabled in multi user mode', +'DISK': 'DISK', +'Disk Cache Keys': 'Disk Cache Keys', +'Disk Cleared': 'Disk Cleared', +'Display line numbers': 'Display line numbers', +'DO NOT use the "Pack compiled" feature.': 'DO NOT use the "Pack compiled" feature.', 'docs': 'docs', +'Docs': 'Docs', 'documentation': 'Dokumentation', 'done!': 'fertig!', +'Downgrade': 'Downgrade', 'Download .w2p': 'Download .w2p', +'Download as .exe': 'Download as .exe', 'download layouts': 'Layouts herunterladen', +'Download layouts from repository': 'Download layouts from repository', 'download plugins': 'Plugins herunterladen', +'Download plugins from repository': 'Download plugins from repository', 'E-mail': 'E-mail', 'EDIT': 'BEARBEITEN', 'Edit': 'Bearbeiten', +'edit all': 'edit all', 'Edit application': 'Bearbeite Anwendung', 'edit controller': 'Bearbeite Controller', 'edit controller:': 'bearbeite Controller:', @@ -147,7 +228,12 @@ 'Editing file': 'Bearbeite Datei', 'Editing file "%s"': 'Bearbeite Datei "%s"', 'Editing Language file': 'Sprachdatei bearbeiten', +'Editing Plural Forms File': 'Editing Plural Forms File', +'Editor': 'Editor', +'Email Address': 'Email Address', 'Enable': 'Aktivieren', +'Enable Close-Tag': 'Enable Close-Tag', +'Enable Code Folding': 'Enable Code Folding', 'Enterprise Web Framework': 'Enterprise Web Framework', 'Error': 'Fehler', 'Error logs for "%(app)s"': 'Fehlerprotokoll für "%(app)s"', @@ -155,16 +241,20 @@ 'Error ticket': 'Error ticket', 'Errors': 'Fehlermeldungen', 'escape': 'escape', +'Exception %(extype)s: %(exvalue)s': 'Exception %(extype)s: %(exvalue)s', +'Exception %s': 'Exception %s', 'Exception instance attributes': 'Attribute der Ausnahmeinstanz', 'Exit Fullscreen': 'Vollbild beenden', 'Expand Abbreviation': 'Kürzel erweitern', 'Expand Abbreviation (html files only)': 'Abkürzungen ausschreiben (nur HTML Dateien)', 'export as csv file': 'Exportieren als CSV-Datei', +'Exports:': 'Exports:', 'exposes': 'stellt zur Verfügung', 'exposes:': 'stellt folgendes zur Verfügung:', 'extends': 'erweitert', 'failed to compile file because:': 'Datei konnte nicht kompiliert werden, da:', 'failed to reload module': 'neu laden des Moduls fehlgeschlagen', +'failed to reload module because:': 'failed to reload module because:', 'File': 'Datei', 'file "%(filename)s" created': 'Datei "%(filename)s" erstellt', 'file "%(filename)s" deleted': 'Datei "%(filename)s" gelöscht', @@ -173,93 +263,166 @@ 'file "%s" of %s restored': 'Datei "%s" von %s wiederhergestellt', 'file changed on disk': 'Datei auf Festplatte geändert', 'file does not exist': 'Datei existiert nicht', +'file not found': 'file not found', 'file saved on %(time)s': 'Datei gespeichert am %(time)s', 'file saved on %s': 'Datei gespeichert auf %s', +'filename': 'filename', +'Filename': 'Filename', +'Files added': 'Files added', 'filter': 'Filter', 'Find Next': 'Nächster', 'Find Previous': 'Vorheriger', 'First name': 'Vorname', +'Form has errors': 'Form has errors', 'Frames': 'Frames', 'Functions with no doctests will result in [passed] tests.': 'Funktionen ohne doctests erzeugen [passed] in Tests', +'GAE Email': 'GAE Email', +'GAE Output': 'GAE Output', +'GAE Password': 'GAE Password', +'Generate': 'Generate', 'Get from URL:': 'Get from URL:', 'Git Pull': 'Git Pull', 'Git Push': 'Git Push', +'Globals##debug': 'Globals##debug', 'Go to Matching Pair': 'Gehe zum übereinstimmenden Paar', +'go!': 'go!', +'Google App Engine Deployment Interface': 'Google App Engine Deployment Interface', +'Google Application Id': 'Google Application Id', 'Goto': 'Goto', 'graph model': 'graph model', +'Graph Model': 'Graph Model', 'Group ID': 'Gruppen ID', 'Hello World': 'Hallo Welt', 'Help': 'Hilfe', +'here': 'here', 'Hide/Show Translated strings': 'Zeige/Verstecke übersetzte Strings', +'Highlight current line': 'Highlight current line', +'Hits': 'Hits', 'Home': 'Startseite', +'honored only if the expression evaluates to true': 'honored only if the expression evaluates to true', 'htmledit': 'htmledit', +'If start the downgrade, be patient, it may take a while to rollback': 'If start the downgrade, be patient, it may take a while to rollback', +'If start the upgrade, be patient, it may take a while to download': 'If start the upgrade, be patient, it may take a while to download', +'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\n\t\tA green title indicates that all tests (if defined) passed. In this case test results are not shown.': 'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\n\t\tA green title indicates that all tests (if defined) passed. In this case test results are not shown.', 'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\nA green title indicates that all tests (if defined) passed. In this case test results are not shown.': 'Falls der obere Test eine Fehler-Ticketnummer enthält deutet das auf einen Fehler in der Ausführung des Controllers hin, noch bevor der Doctest ausgeführt werden konnte. Gewöhnlich Führen fehlerhafte Einrückungen oder fehlerhafter Code ausserhalb der Funktion zu solchen Fehlern. Ein grüner Titel deutet darauf hin, dass alle Test(wenn sie vorhanden sind) erfolgreich durchlaufen wurden. In diesem Fall werden die Testresultate nicht angezeigt.', 'If you answer "yes", be patient, it may take a while to download': 'Wenn Sie mit "Ja" antworten, seien Sie bitte geduldig. Der Download könnte eine Weile dauern.', 'If you answer yes, be patient, it may take a while to download': 'Wenn Sie mit Ja antworten, seien Sie bitte geduldig. Der Download könnte eine Weile dauern.', +'if your application uses a database other than sqlite you will then have to configure its DAL in pythonanywhere.': 'if your application uses a database other than sqlite you will then have to configure its DAL in pythonanywhere.', +'import': 'import', 'Import/Export': 'Importieren/Exportieren', +'In development, use the default Rocket webserver that is currently supported by this debugger.': 'In development, use the default Rocket webserver that is currently supported by this debugger.', 'includes': 'Einfügen', +'Indent with tabs': 'Indent with tabs', 'Index': 'Index', 'index': 'index', 'insert new': 'neu Einfügen', 'insert new %s': 'neu Einfügen %s', 'inspect attributes': 'Attribute inspizieren', 'Install': 'Installieren', +'Installation of %(plugin)s for %(app)s': 'Installation of %(plugin)s for %(app)s', 'Installed applications': 'Installierte Anwendungen', +'Interaction at %s line %s': 'Interaction at %s line %s', +'Interactive console': 'Interactive console', 'internal error': 'Interner Fehler', +'internal error: %s': 'internal error: %s', 'Internal State': 'Interner Status', 'Invalid action': 'Ungültige Aktion', +'Invalid application name': 'Invalid application name', +'invalid circular reference': 'invalid circular reference', 'Invalid email': 'Ungültige Email', +'Invalid git repository specified.': 'Invalid git repository specified.', 'invalid password': 'Ungültiges Passwort', +'invalid password.': 'invalid password.', 'Invalid Query': 'Ungültige Abfrage', 'invalid request': 'Ungültige Anfrage', +'Invalid request': 'Invalid request', +'invalid table names (auth_* tables already defined)': 'invalid table names (auth_* tables already defined)', 'invalid ticket': 'Ungültiges Ticket', +'Key': 'Key', 'Key bindings': 'Tastenbelegungen', 'Key bindings for ZenCoding Plugin': 'Key bindings for ZenCoding Plugin', 'Key bindings for ZenConding Plugin': 'Tastenbelegungen für das ZenConding Plugin', 'Keyboard shortcuts': 'Tastenkombination', +'kill process': 'kill process', 'language file "%(filename)s" created/updated': 'Sprachdatei "%(filename)s" erstellt/aktualisiert', 'Language files (static strings) updated': 'Sprachdatei (statisch Strings) aktualisiert', 'languages': 'Sprachen', 'Languages': 'Sprachen', 'languages updated': 'Sprachen aktualisiert', 'Last name': 'Nachname', +'Last Revision': 'Last Revision', 'Last saved on:': 'Zuletzt gespeichert am:', 'Layout': 'Layout', 'License for': 'Lizenz für', +'License:': 'License:', +'Line Nr': 'Line Nr', +'Line number': 'Line number', +'lists by exception': 'lists by exception', 'lists by ticket': 'nach Ticket aufgelistet', +'Loading...': 'Loading...', 'loading...': 'lade...', +'Local Apps': 'Local Apps', 'locals': 'locals', +'Locals##debug': 'Locals##debug', 'located in the file': 'befindet sich in der Datei', -'Login': 'Anmelden', 'login': 'anmelden', +'Login': 'Anmelden', +'Login successful': 'Login successful', 'Login to the Administrative Interface': 'An das Administrations-Interface anmelden', +'Login/Register': 'Login/Register', 'Logout': 'Abmelden', +'lost password': 'lost password', 'Lost Password': 'Passwort vergessen', 'lost password?': 'Passwort vergessen?', 'Main Menu': 'Hauptmenü', 'Manage': 'Verwalten', +'Manage %(action)s': 'Manage %(action)s', +'Manage Access Control': 'Manage Access Control', +'Manage Admin Users/Students': 'Manage Admin Users/Students', +'Manage Cache': 'Manage Cache', +'Manage Students': 'Manage Students', 'Match Pair': 'Paare finden', +'Memberships': 'Memberships', 'Menu Model': 'Menü Modell', 'merge': 'verbinden', 'Merge Lines': 'Zeilen zusammenfügen', 'Models': 'Modelle', 'models': 'Modelle', +'Modified On': 'Modified On', 'Modules': 'Module', 'modules': 'Module', +'Multi User Mode': 'Multi User Mode', 'Name': 'Name', 'new application "%s" created': 'neue Anwendung "%s" erzeugt', +'new application "%s" imported': 'new application "%s" imported', +'New Application Wizard': 'New Application Wizard', 'New application wizard': 'Neue Anwendung per Assistent', 'new plugin installed': 'Neues Plugin wurde installiert', +'New plugin installed: %s': 'New plugin installed: %s', 'New Record': 'Neuer Datensatz', 'new record inserted': 'Neuer wurde Datensatz eingefügt', 'New simple application': 'Neue einfache Anwendung', +'next': 'next', +'next %s rows': 'next %s rows', 'next 100 rows': 'nächsten 100 Zeilen', 'Next Edit Point': 'nächster Bearbeitungsschritt', 'NO': 'NEIN', +'no changes': 'no changes', 'No databases in this application': 'Keine Datenbank in dieser Anwendung', +'No Interaction yet': 'No Interaction yet', +'no match': 'no match', 'no package selected': 'Kein Paket ausgewählt', +'no permission to uninstall "%s"': 'no permission to uninstall "%s"', 'No ticket_storage.txt found under /private folder': 'Kein ticket_storage.txt unter /private folder gefunden', +'Node:': 'Node:', +'Not Authorized': 'Not Authorized', +'Not supported': 'Not supported', +'Note: If you receive an error with github status code of 128, ensure the system and account you are deploying from has a cooresponding ssh key configured in the openshift account.': 'Note: If you receive an error with github status code of 128, ensure the system and account you are deploying from has a cooresponding ssh key configured in the openshift account.', +"On production, you'll have to configure your webserver to use one process and multiple threads to use this debugger.": "On production, you'll have to configure your webserver to use one process and multiple threads to use this debugger.", 'online designer': 'Online Designer', +'Open new app in new window': 'Open new app in new window', +'OpenShift Deployment Interface': 'OpenShift Deployment Interface', +'OpenShift Output': 'OpenShift Output', 'or alternatively': 'oder Alternativ', 'Or Get from URL:': 'oder von folgender URL herunterladen:', 'or import from csv file': 'oder importieren von cvs Datei', @@ -267,77 +430,144 @@ 'or provide application url:': 'oder geben Sie eine Anwendungs-URL an:', 'Origin': 'Herkunft', 'Original/Translation': 'Original/übersetzung', +'Overview': 'Overview', 'Overwrite installed app': 'Installierte Anwendungen überschreiben', 'Pack all': 'Verpacke alles', 'Pack compiled': 'Verpacke kompiliert', 'Pack custom': 'Verpacke individuell', 'pack plugin': 'Plugin verpacken', 'Password': 'Passwort', +'password changed': 'password changed', +'Past revisions': 'Past revisions', +'Path to appcfg.py': 'Path to appcfg.py', +'Path to local openshift repo root.': 'Path to local openshift repo root.', 'Peeking at file': 'Dateiansicht', +'Permission': 'Permission', +'Permissions': 'Permissions', +'Please': 'Please', 'please wait!': 'Bitte warten!', +'Please wait, giving pythonanywhere a moment...': 'Please wait, giving pythonanywhere a moment...', +'plugin "%(plugin)s" deleted': 'plugin "%(plugin)s" deleted', 'Plugin "%s" in application': 'Plugin "%s" in Anwendung', +'plugin not specified': 'plugin not specified', +'Plugin page': 'Plugin page', 'plugins': 'plugins', 'Plugins': 'Plugins', +'Plural Form #%s': 'Plural Form #%s', 'Plural-Forms:': 'Plural-Forms:', 'Powered by': 'Unterstützt von', +'Preferences saved correctly': 'Preferences saved correctly', +'Preferences saved on session only': 'Preferences saved on session only', +'previous %s rows': 'previous %s rows', 'previous 100 rows': 'vorherige 100 zeilen', 'Previous Edit Point': 'vorheriger Bearbeitungsschritt', 'Private files': 'Private files', 'private files': 'private files', 'Project Progress': 'Projekt Fortschritt', +'Pull': 'Pull', +'Pull failed, certain files could not be checked out. Check logs for details.': 'Pull failed, certain files could not be checked out. Check logs for details.', +'Pull is not possible because you have unmerged files. Fix them up in the work tree, and then try again.': 'Pull is not possible because you have unmerged files. Fix them up in the work tree, and then try again.', +'Push': 'Push', +'Push failed, there are unmerged entries in the cache. Resolve merge issues manually and try again.': 'Push failed, there are unmerged entries in the cache. Resolve merge issues manually and try again.', +'pygraphviz library not found': 'pygraphviz library not found', +'PythonAnywhere Apps': 'PythonAnywhere Apps', +'PythonAnywhere Password': 'PythonAnywhere Password', 'Query:': 'Abfrage:', +'RAM': 'RAM', +'RAM Cache Keys': 'RAM Cache Keys', +'Ram Cleared': 'Ram Cleared', 'Rapid Search': 'Schnelle Suche', +'Record': 'Record', 'record': 'Datensatz', 'record does not exist': 'Datensatz existiert nicht', 'record id': 'Datensatz id', 'Record ID': 'Datensatz ID', -'register': 'Registrierung', +'Record id': 'Record id', +'refresh': 'refresh', 'Register': 'Registrieren', +'register': 'Registrierung', 'Registration key': 'Registrierungsschlüssel', 'reload': 'Neu laden', 'Reload routes': 'Routen neu laden', 'Remove compiled': 'Bytecode löschen', +'Removed Breakpoint on %s at line %s': 'Removed Breakpoint on %s at line %s', 'Replace': 'Ersetzen', 'Replace All': 'Alle Ersetzen', +'Repository (%s)': 'Repository (%s)', 'request': 'Anfrage', +'requires distutils, but not installed': 'requires distutils, but not installed', +'requires python-git, but not installed': 'requires python-git, but not installed', 'Reset Password key': 'Passwortschlüssel zurücksetzen', 'Resolve Conflict file': 'bereinige Konflikt-Datei', 'response': 'Antwort', +'restart': 'restart', 'restore': 'wiederherstellen', +'return': 'return', +'Revert': 'Revert', 'revert': 'zurückkehren', +'reverted to revision %s': 'reverted to revision %s', +'Revision %s': 'Revision %s', +'Revision:': 'Revision:', 'Role': 'Rolle', +'Roles': 'Roles', 'Rows in table': 'Zeilen in Tabelle', +'Rows in Table': 'Rows in Table', 'Rows selected': 'Zeilen ausgewählt', 'rules are not defined': 'Regeln sind nicht definiert', +'Run tests': 'Run tests', +'Run tests in this file': 'Run tests in this file', "Run tests in this file (to run all files, you may also use the button labelled 'test')": "Tests in dieser Datei ausführen (um alle Dateien auszuführen, kann auch der Button 'test' genutzt werden)", 'Running on %s': 'läuft auf %s', 'Save': 'Speichern', 'save': 'Speichern', 'Save file:': 'Speichere Datei:', 'Save file: %s': 'Speichere Datei: %s', +'Save model as...': 'Save model as...', 'Save via Ajax': 'via Ajax speichern', 'Saved file hash:': 'Gespeicherter Datei-Hash:', +'Screenshot %s': 'Screenshot %s', +'Search': 'Search', 'Select Files to Package': 'Dateien zum Paketieren wählen', 'selected': 'ausgewählt(e)', 'session': 'Sitzung', 'session expired': 'Sitzung abgelaufen', +'Session saved correctly': 'Session saved correctly', +'Session saved on session only': 'Session saved on session only', +'Set Breakpoint on %s at line %s: %s': 'Set Breakpoint on %s at line %s: %s', 'shell': 'Shell', +'Showing %s to %s of %s %s found': 'Showing %s to %s of %s %s found', +'Singular Form': 'Singular Form', 'Site': 'Seite', +'Size of cache:': 'Size of cache:', +'skip to generate': 'skip to generate', 'some files could not be removed': 'einige Dateien konnten nicht gelöscht werden', +'Something went wrong please wait a few minutes before retrying': 'Something went wrong please wait a few minutes before retrying', +'Sorry, could not find mercurial installed': 'Sorry, could not find mercurial installed', +'source : db': 'source : db', 'source : filesystem': 'Quelle : Dateisystem', +'Start a new app': 'Start a new app', 'Start searching': 'Suche beginnen', 'Start wizard': 'Assistent starten', 'state': 'Status', 'Static': 'Statisch', 'static': 'statische Dateien', 'Static files': 'statische Dateien', +'Statistics': 'Statistics', +'Step': 'Step', +'step': 'step', +'stop': 'stop', 'Stylesheet': 'Stylesheet', -'Submit': 'Submit', 'submit': 'Absenden', +'Submit': 'Submit', +'successful': 'successful', 'Sure you want to delete this object?': 'Wollen Sie das Objekt wirklich löschen?', 'switch to : db': 'wechsel zu : db', +'switch to : filesystem': 'switch to : filesystem', +'Tab width (# characters)': 'Tab width (# characters)', 'table': 'Tabelle', +'Table': 'Table', 'Table name': 'Tabellen Name', +'Temporary': 'Temporary', 'test': 'Test', 'test_def': 'test_def', 'test_for': 'test_for', @@ -346,6 +576,8 @@ 'Testing application': 'Teste die Anwendung', 'Testing controller': 'Teste Controller', 'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.': 'Die "query" ist eine Bedingung wie "db.table1.field1 == \'Wert\'". Etwas wie "db.table1.field1 db.table2.field2 ==" führt zu einem SQL JOIN.', +'The app exists, was created by wizard, continue to overwrite!': 'The app exists, was created by wizard, continue to overwrite!', +'The app exists, was NOT created by wizard, continue to overwrite!': 'The app exists, was NOT created by wizard, continue to overwrite!', 'the application logic, each URL path is mapped in one exposed function in the controller': 'Die Logik der Anwendung, jeder URL-Pfad wird auf eine Funktion abgebildet die der Controller zur Verfügung stellt', 'The application logic, each URL path is mapped in one exposed function in the controller': 'Die Logik der Anwendung, jeder URL-Pfad wird auf eine Funktion abgebildet die der Controller zur Verfügung stellt', 'the data representation, define database tables and sets': 'Die Datenrepräsentation definiert Mengen von Tabellen und Datenbanken', @@ -353,25 +585,39 @@ 'The output of the file is a dictionary that was rendered by the view': 'Die Ausgabe der Datei ist ein "dictionary" und wurde vom "view" gerendert', 'The presentations layer, views are also known as templates': 'Die Präsentationsschicht, Views sind auch bekannt als Vorlagen/Templates', 'the presentations layer, views are also known as templates': 'Die Präsentationsschicht, Views sind auch bekannt als Vorlagen/Templates', +'Theme': 'Theme', 'There are no controllers': 'Keine Controller vorhanden', 'There are no models': 'Keine Modelle vorhanden', 'There are no modules': 'Keine Module vorhanden', 'There are no plugins': 'Keine Plugins vorhanden', 'There are no private files': 'Keine privaten Dateien vorhanden', 'There are no static files': 'Keine statischen Dateien vorhanden', +'There are no translators': 'There are no translators', 'There are no translators, only default language is supported': 'Keine übersetzungen vorhanden, nur die voreingestellte Sprache wird Unterstützt', 'There are no views': 'Keine Views vorhanden', 'These files are not served, they are only available from within your app': 'Diese Dateien werden nicht ausgeliefert, sie sind nur innerhalb Ihrer App verfügbar', 'These files are served without processing, your images go here': 'Diese Dateien werden ohne Verarbeitung ausgeliefert. Beispielsweise Bilder kommen hier hin.', 'these files are served without processing, your images go here': 'Diese Dateien werden ohne Verarbeitung ausgeliefert. Beispielsweise Bilder kommen hier hin.', +"This debugger may not work properly if you don't have a threaded webserver or you're using multiple daemon processes.": "This debugger may not work properly if you don't have a threaded webserver or you're using multiple daemon processes.", 'This is a copy of the scaffolding application': 'Dies ist eine Kopie einer Grundgerüst-Anwendung', +'This is an experimental feature and it needs more testing. If you decide to downgrade you do it at your own risk': 'This is an experimental feature and it needs more testing. If you decide to downgrade you do it at your own risk', +'This is an experimental feature and it needs more testing. If you decide to upgrade you do it at your own risk': 'This is an experimental feature and it needs more testing. If you decide to upgrade you do it at your own risk', 'This is the %(filename)s template': 'Dies ist das Template %(filename)s', +"This page can commit your changes to an openshift app repo and push them to your cloud instance. This assumes that you've already created the application instance using the web2py skeleton and have that repo somewhere on a filesystem that this web2py instance can access. This functionality requires GitPython installed and on the python path of the runtime that web2py is operating in.": "This page can commit your changes to an openshift app repo and push them to your cloud instance. This assumes that you've already created the application instance using the web2py skeleton and have that repo somewhere on a filesystem that this web2py instance can access. This functionality requires GitPython installed and on the python path of the runtime that web2py is operating in.", +'This page can upload your application to the Google App Engine computing cloud. Mind that you must first create indexes locally and this is done by installing the Google appserver and running the app locally with it once, or there will be errors when selecting records. Attention: deployment may take long time, depending on the network speed. Attention: it will overwrite your app.yaml. DO NOT SUBMIT TWICE.': 'This page can upload your application to the Google App Engine computing cloud. Mind that you must first create indexes locally and this is done by installing the Google appserver and running the app locally with it once, or there will be errors when selecting records. Attention: deployment may take long time, depending on the network speed. Attention: it will overwrite your app.yaml. DO NOT SUBMIT TWICE.', +'this page to see if a breakpoint was hit and debug interaction is required.': 'this page to see if a breakpoint was hit and debug interaction is required.', +'This will pull changes from the remote repo for application "%s"?': 'This will pull changes from the remote repo for application "%s"?', +'This will push changes to the remote repo for application "%s".': 'This will push changes to the remote repo for application "%s".', 'Ticket': 'Ticket', 'Ticket ID': 'Ticket ID', +'Ticket Missing': 'Ticket Missing', +'Time in Cache (h:m:s)': 'Time in Cache (h:m:s)', 'Timestamp': 'Zeitstempel', 'TM': 'TM', 'to previous version.': 'zu einer früheren Version.', 'To create a plugin, name a file/folder plugin_[name]': 'Um ein Plugin zu erstellen benennen Sie eine(n) Datei/Ordner plugin_[Name]', +'To emulate a breakpoint programatically, write:': 'To emulate a breakpoint programatically, write:', +'to use the debugger!': 'to use the debugger!', 'toggle breakpoint': 'Breakpoint aktivieren/deaktivieren', 'Toggle comment': ' Kommentar ein-/ausblenden', 'Toggle Fullscreen': 'Vollbild ein-/ausschalten', @@ -382,18 +628,31 @@ 'try something like': 'Versuchen Sie so etwas wie', 'Try the mobile interface': 'Testen Sie das Interface für Handys', 'try view': 'Versuche view', +'Type PDB debugger command in here and hit Return (Enter) to execute it.': 'Type PDB debugger command in here and hit Return (Enter) to execute it.', +'Type some Python code in here and hit Return (Enter) to execute it.': 'Type some Python code in here and hit Return (Enter) to execute it.', 'Unable to check for upgrades': 'Überprüfen von Upgrades nicht möglich', 'unable to create application "%s"': 'Erzeugen von Anwendung "%s" nicht möglich', 'unable to delete file "%(filename)s"': 'Löschen von Dateien "%(filename)s" nicht möglich', +'unable to delete file plugin "%(plugin)s"': 'unable to delete file plugin "%(plugin)s"', +'Unable to determine the line number!': 'Unable to determine the line number!', 'Unable to download': 'Herunterladen nicht möglich', 'Unable to download app': 'Herunterladen der Anwendung nicht möglich', +'Unable to download app because:': 'Unable to download app because:', +'unable to download layout': 'unable to download layout', +'unable to download plugin: %s': 'unable to download plugin: %s', +'Unable to download the list of plugins': 'Unable to download the list of plugins', +'unable to install plugin "%s"': 'unable to install plugin "%s"', 'unable to parse csv file': 'Analysieren der cvs Datei nicht möglich', 'unable to uninstall "%s"': 'Deinstallieren von "%s" nicht möglich', +'unable to upgrade because "%s"': 'unable to upgrade because "%s"', 'uncheck all': 'Auswahl entfernen', 'Uninstall': 'Deinstallieren', +'Unsupported webserver working mode: %s': 'Unsupported webserver working mode: %s', 'update': 'Aktualisieren', 'update all languages': 'Aktualisiere alle Sprachen', 'Update:': 'Aktualisiere:', +'Upgrade': 'Upgrade', +'upgrade now to %s': 'upgrade now to %s', 'upgrade web2py now': 'web2py jetzt upgraden', 'upload': 'upload', 'Upload': 'Upload', @@ -407,26 +666,49 @@ 'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Benutze (...)&(...) für AND, (...)|(...) für OR, und ~(...) für NOT, um komplexe Abfragen zu erstellen.', 'Use an url:': 'Verwende URL:', 'user': 'Nutzer', +'User': 'User', 'User ID': 'Benutzer ID', +'Username': 'Username', +'Users': 'Users', +'Using the shell may lock the database to other users of this app.': 'Using the shell may lock the database to other users of this app.', 'variables': 'Variablen', 'Version': 'Version', 'Version %s.%s.%s (%s) %s': 'Version %s.%s.%s (%s) %s', -'versioning': 'Versionsverwaltung', 'Versioning': 'Versionsverwaltung', +'versioning': 'Versionsverwaltung', 'View': 'Ansicht', 'view': 'Ansicht', 'Views': 'Ansichten', 'views': 'Ansichten', +'Warning!': 'Warning!', +'WARNING:': 'WARNING:', +'WARNING: The following views could not be compiled:': 'WARNING: The following views could not be compiled:', 'Web Framework': 'Web Framework', +'web2py Admin Password': 'web2py Admin Password', +'web2py apps to deploy': 'web2py apps to deploy', +'web2py Debugger': 'web2py Debugger', +'web2py downgrade': 'web2py downgrade', 'web2py is up to date': 'web2py ist aktuell', +'web2py online debugger': 'web2py online debugger', 'web2py Recent Tweets': 'Neuste Tweets von web2py', +'web2py upgrade': 'web2py upgrade', +'web2py upgraded; please restart it': 'web2py upgraded; please restart it', 'Welcome %s': 'Willkommen %s', 'Welcome to web2py': 'Willkommen zu web2py', 'Which called the function': 'welche die Funktion aufrief', +'Working...': 'Working...', 'Wrap with Abbreviation': 'mit Kürzel einhüllen', +'WSGI reference name': 'WSGI reference name', 'xml': 'xml', 'YES': 'JA', +'Yes': 'Yes', 'You are successfully running web2py': 'web2by wird erfolgreich ausgeführt', +'You can also set and remove breakpoint in the edit window, using the Toggle Breakpoint button': 'You can also set and remove breakpoint in the edit window, using the Toggle Breakpoint button', +'You can inspect variables using the console below': 'You can inspect variables using the console below', 'You can modify this application and adapt it to your needs': 'Sie können diese Anwendung verändern und Ihren Bedürfnissen anpassen', +'You have one more login attempt before you are locked out': 'You have one more login attempt before you are locked out', +'You need to set up and reach a': 'You need to set up and reach a', +'You only need these if you have already registered': 'You only need these if you have already registered', 'You visited the url': 'Sie besuchten die URL', +'Your application will be blocked until you click an action button (next, step, continue, etc.)': 'Your application will be blocked until you click an action button (next, step, continue, etc.)', } diff --git a/applications/admin/languages/default.py b/applications/admin/languages/default.py deleted file mode 100755 index 779145a8..00000000 --- a/applications/admin/languages/default.py +++ /dev/null @@ -1,184 +0,0 @@ -# -*- coding: utf-8 -*- -{ -'!langcode!': 'en-us', -'!langname!': 'English (US)', -'%Y-%m-%d': '%m-%d-%Y', -'%Y-%m-%d %H:%M:%S': '%m-%d-%Y %H:%M:%S', -'(requires internet access)': '(requires internet access)', -'(something like "it-it")': '(something like "it-it")', -'About': 'About', -'Additional code for your application': 'Additional code for your application', -'admin disabled because unable to access password file': 'admin disabled because unable to access password file', -'Admin language': 'Admin language', -'administrative interface': 'administrative interface', -'Administrator Password:': 'Administrator Password:', -'and rename it:': 'and rename it:', -'Application name:': 'Application name:', -'are not used yet': 'are not used yet', -'Are you sure you want to delete this object?': 'Are you sure you want to delete this object?', -'arguments': 'arguments', -'at char %s': 'at char %s', -'at line %s': 'at line %s', -'back': '<': '>', '>=': '>=', +'?': '?', '@markmin\x01Searching: **%s** %%{file}': 'Căutare: **%s** fișiere', 'A new version of web2py is available': 'O nouă versiune de web2py este disponibilă', 'A new version of web2py is available: %s': 'O nouă versiune de web2py este disponibilă: %s', -'ATTENTION: Login requires a secure (HTTPS) connection or running on localhost.': 'ATENȚIE: Nu vă puteți conecta decât utilizând o conexiune securizată (HTTPS) sau rulând aplicația pe computerul local.', -'ATTENTION: TESTING IS NOT THREAD SAFE SO DO NOT PERFORM MULTIPLE TESTS CONCURRENTLY.': 'ATENȚIE: Nu puteți efectua mai multe teste o dată deoarece lansarea în execuție a mai multor subpocese nu este sigură.', -'ATTENTION: you cannot edit the running application!': 'ATENȚIE: nu puteți edita o aplicație în curs de execuție!', 'Abort': 'Anulează', 'About': 'Despre', +'about': 'despre', 'About application': 'Despre aplicație', +'Accept Terms': 'Accept Terms', 'Access Control': 'Control acces', 'Add': 'Adaugă', +'Add breakpoint': 'Add breakpoint', +'additional code for your application': 'cod suplimentar pentru aplicația dvs.', 'Additional code for your application': 'Cod suplimentar pentru aplicație', +'Admin design page': 'Admin design page', +'admin disabled because no admin password': 'administrare dezactivată deoarece parola de administrator nu a fost furnizată', +'admin disabled because not supported on google app engine': 'administrare dezactivată deoarece funcționalitatea nu e suportat pe Google App Engine', +'admin disabled because too many invalid login attempts': 'admin disabled because too many invalid login attempts', +'admin disabled because unable to access password file': 'administrare dezactivată deoarece nu există acces la fișierul cu parole', 'Admin is disabled because insecure channel': 'Adminstrarea este dezactivată deoarece conexiunea nu este sigură', 'Admin is disabled because unsecure channel': 'Administrarea este dezactivată deoarece conexiunea nu este securizată', 'Admin language': 'Limba de administrare', +'Admin versioning page': 'Admin versioning page', 'Administration': 'Administrare', +'administrative interface': 'interfață de administrare', 'Administrative Interface': 'Interfață administrare', 'Administrator Password:': 'Parolă administrator:', 'Ajax Recipes': 'Rețete Ajax', 'And': 'Și', +'and rename it (required):': 'și renumește (obligatoriu):', +'and rename it:': ' și renumește:', +'App does not exist or you are not authorized': 'App does not exist or you are not authorized', +'appadmin': 'appadmin', +'appadmin is disabled because insecure channel': 'appadmin dezactivat deoarece conexiunea nu e sigură', +'Application': 'Application', +'application "%s" uninstalled': 'aplicația "%s" a fost dezinstalată', +'Application cannot be generated in demo mode': 'Application cannot be generated in demo mode', +'application compiled': 'aplicația a fost compilată', +'Application exists already': 'Application exists already', +'application is compiled and cannot be designed': 'aplicația este compilată și nu poate fi editată', 'Application name:': 'Nume aplicație:', +'Application updated via git pull': 'Application updated via git pull', +'are not used': 'are not used', +'are not used yet': 'are not used yet', 'Are you sure you want to delete file "%s"?': 'Sigur ștergeți fișierul "%s"?', +'Are you sure you want to delete plugin "%s"?': 'Are you sure you want to delete plugin "%s"?', 'Are you sure you want to delete this object?': 'Sigur ștergeți acest obiect?', 'Are you sure you want to uninstall application "%s"': 'Sigur dezinstalați aplicația "%s"', 'Are you sure you want to uninstall application "%s"?': 'Sigur dezinstalați aplicația "%s"?', +'Are you sure?': 'Are you sure?', +'arguments': 'argumente', +'at char %s': 'at char %s', +'at line %s': 'at line %s', +'ATTENTION:': 'ATTENTION:', +'ATTENTION: Login requires a secure (HTTPS) connection or running on localhost.': 'ATENȚIE: Nu vă puteți conecta decât utilizând o conexiune securizată (HTTPS) sau rulând aplicația pe computerul local.', +'ATTENTION: TESTING IS NOT THREAD SAFE SO DO NOT PERFORM MULTIPLE TESTS CONCURRENTLY.': 'ATENȚIE: Nu puteți efectua mai multe teste o dată deoarece lansarea în execuție a mai multor subpocese nu este sigură.', +'ATTENTION: you cannot edit the running application!': 'ATENȚIE: nu puteți edita o aplicație în curs de execuție!', 'Authentication': 'Autentificare', +'Autocomplete Python Code': 'Autocomplete Python Code', 'Available databases and tables': 'Baze de date și tabele disponibile', +'Available Databases and Tables': 'Available Databases and Tables', 'Back': 'Înapoi', +'back': 'înapoi', +'Back to the plugins list': 'Back to the plugins list', +'Back to wizard': 'Back to wizard', +'Basics': 'Basics', 'Begin': 'Început', +'breakpoint': 'breakpoint', +'Breakpoints': 'Breakpoints', +'breakpoints': 'breakpoints', +'Bulk Register': 'Bulk Register', +'Bulk Student Registration': 'Bulk Student Registration', 'Buy this book': 'Cumpără această carte', +'Cache': 'Cache', +'cache': 'cache', +'Cache Cleared': 'Cache Cleared', 'Cache Keys': 'Chei cache', +'cache, errors and sessions cleaned': 'cache, erori și sesiuni golite', +'can be a git repo': 'can be a git repo', +'Cancel': 'Cancel', 'Cannot be empty': 'Nu poate fi vid', 'Cannot compile: there are errors in your app. Debug it, correct errors and try again.': 'Compilare imposibilă: aplicația conține erori. Debogați aplicația și încercați din nou.', -'Change Password': 'Schimbare parolă', +'Cannot compile: there are errors in your app:': 'Cannot compile: there are errors in your app:', +'cannot create file': 'fișier imposibil de creat', +'cannot upload file "%(filename)s"': 'imposibil de încărcat fișierul "%(filename)s"', +'Change Admin Password': 'Change Admin Password', 'Change admin password': 'Schimbă parola de administrare', +'change editor settings': 'change editor settings', +'Change Password': 'Schimbare parolă', 'Change password': 'Schimbare parolă', +'change password': 'schimbare parolă', +'Changelog': 'Changelog', +'check all': 'coșează tot', 'Check for upgrades': 'Verifică dacă există upgrade-uri', 'Check to delete': 'Coșați pentru a șterge', 'Checking for upgrades...': 'Verifică dacă există actualizări...', +'clean': 'golire', 'Clean': 'Curăță', 'Clear': 'Golește', +'Clear CACHE?': 'Clear CACHE?', +'Clear DISK': 'Clear DISK', +'Clear RAM': 'Clear RAM', 'Click row to expand traceback': 'Clic pe linie pentru a extinde mesajul de trasabilitate', 'Click row to view a ticket': 'Click row to view a ticket', +'click to check for upgrades': 'Clic pentru a verifica dacă există upgrade-uri', 'Client IP': 'IP client', +'code': 'code', +'Code listing': 'Code listing', +'collapse/expand all': 'restrânge/extinde tot', +'Command': 'Command', +'Comment:': 'Comment:', +'Commit': 'Commit', +'Commit form': 'Commit form', +'Committed files': 'Committed files', 'Community': 'Comunitate', 'Compile': 'Compilează', +'compile': 'compilare', +'Compile (all or nothing)': 'Compile (all or nothing)', +'Compile (skip failed views)': 'Compile (skip failed views)', +'compiled application removed': 'aplicația compilată a fost ștearsă', 'Components and Plugins': 'Componente și plugin-uri', +'Condition': 'Condition', +'contains': 'conține', +'continue': 'continue', 'Controller': 'Controlor', 'Controllers': 'Controlori', +'controllers': 'controlori', 'Copyright': 'Drepturi de autor', 'Count': 'Număr', 'Create': 'Crează', +'create file with filename:': 'crează fișier cu numele:', 'Create new application': 'Creați aplicație nouă', +'create new application:': 'crează aplicație nouă:', +'Create/Upload': 'Create/Upload', +'created by': 'creat de', +'Created by:': 'Created by:', +'Created On': 'Created On', +'Created on:': 'Created on:', +'crontab': 'crontab', 'Current request': 'Cerere curentă', 'Current response': 'Răspuns curent', 'Current session': 'Sesiune curentă', -'DB Model': 'Model bază de date', -'DESIGN': 'DESIGN', -'Database': 'Baza de date', -'Date and Time': 'Data și ora', -'Debug': 'Debogare', -'Delete': 'Șterge', -'Delete this file (you will be asked to confirm deletion)': 'Delete this file (you will be asked to confirm deletion)', -'Delete:': 'Șterge:', -'Demo': 'Demo', -'Deploy': 'Instalare', -'Deploy on Google App Engine': 'Instalare pe Google App Engine', -'Deployment Recipes': 'Rețete de instalare', -'Description': 'Descriere', -'Design for': 'Design pentru', -'Detailed traceback description': 'Descriere detaliată a mesajului de trasabilitate', -'Disable': 'Dezactivează', -'Disk Cache Keys': 'Chei cache de disc', -'Documentation': 'Documentație', -"Don't know what to do?": 'Nu știți ce să faceți?', -'Download': 'Descărcare', -'E-mail': 'E-mail', -'E-mail invalid': 'E-mail invalid', -'EDIT': 'EDITARE', -'Edit': 'Editare', -'Edit Profile': 'Editare profil', -'Edit This App': 'Editați această aplicație', -'Edit application': 'Editare aplicație', -'Edit current record': 'Editare înregistrare curentă', -'Editing file': 'Editare fișier', -'Editing file "%s"': 'Editare fișier "%s"', -'Email and SMS': 'E-mail și SMS', -'Error': 'Eroare', -'Error logs for "%(app)s"': 'Log erori pentru "%(app)s"', -'Error snapshot': 'Instantaneu eroare', -'Error ticket': 'Tichet eroare', -'Errors': 'Erori', -'Exception instance attributes': 'Exception instance attributes', -'Expand Abbreviation': 'Extinde abreviația', -'Export': 'Export', -'FAQ': 'Întrebări frecvente', -'False': 'Neadevărat', -'File': 'Fișier', -'First name': 'Prenume', -'Forbidden': 'Interzis', -'Forms and Validators': 'Formulare și validatori', -'Frames': 'Frames', -'Free Applications': 'Aplicații gratuite', -'Functions with no doctests will result in [passed] tests.': 'Funcțiile fără doctests vor genera teste [trecute].', -'Get from URL:': 'Obține de la adresa:', -'Go to Matching Pair': 'Mergi la perechea care se potrivește', -'Group %(group_id)s created': 'Grup %(group_id)s creat', -'Group ID': 'ID grup', -'Group uniquely assigned to user %(id)s': 'Grup asociat în mod unic utilizatorului %(id)s', -'Groups': 'Grupuri', -'Hello World': 'Salutare lume', -'Help': 'Ajutor', -'Home': 'Acasă', -'How did you get here?': 'Cum ați ajuns aici?', -'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\r\nA green title indicates that all tests (if defined) passed. In this case test results are not shown.': 'Dacă raportul de deasupra conține un număr de tichet, asta indică un eșec în executarea controlorului, înainte de orice încercare de a executa doctests-urile. Aceasta se întâmplă de obicei din cauza unei erori de identare sau a unei erori din afara corpului funcției.\r\nUn titlu în verde arată ca toate testele (dacă definite) au fost trecute. În acest caz rezultatele testelor nu sunt arătate.', -'Import/Export': 'Import/Export', -'Index': 'Index', -'Install': 'Instalează', -'Installed applications': 'Aplicații instalate', -'Internal State': 'Stare internă', -'Introduction': 'Introducere', -'Invalid Query': 'Interogare invalidă', -'Invalid action': 'Acțiune invalidă', -'Invalid email': 'E-mail invalid', -'Invalid password': 'Parolă invalidă', -'Key bindings': 'Combinație taste', -'Key bindings for ZenCoding Plugin': 'Key bindings for ZenCoding Plugin', -'Language files (static strings) updated': 'Fișierele de limbă (șirurile statice de caractere) actualizate', -'Languages': 'Limbi', -'Last name': 'Nume', -'Last saved on:': 'Ultima salvare:', -'Layout': 'Șablon', -'Layout Plugins': 'Șablon plugin-uri', -'Layouts': 'Șabloane', -'License for': 'Licență pentru', -'Live Chat': 'Chat live', -'Logged in': 'Logat', -'Logged out': 'Delogat', -'Login': 'Autentificare', -'Login to the Administrative Interface': 'Logare interfață de administrare', -'Logout': 'Ieșire', -'Lost Password': 'Parolă pierdută', -'Lost password?': 'Parolă pierdută?', -'Main Menu': 'Meniu principal', -'Match Pair': 'Potrivește pereche', -'Menu Model': 'Model meniu', -'Merge Lines': 'Unește linii', -'Models': 'Modele', -'Modules': 'Module', -'My Sites': 'Site-urile mele', -'NO': 'NU', -'Name': 'Nume', -'New': 'Nou', -'New Application Wizard': 'New Application Wizard', -'New Record': 'Înregistrare nouă', -'New application wizard': 'Magician aplicație nouă', -'New password': 'Parola nouă', -'New simple application': 'O nouă aplicație simplă', -'Next Edit Point': 'Următorul punct de editare', -'No databases in this application': 'Aplicație fără bază de date', -'No ticket_storage.txt found under /private folder': 'No ticket_storage.txt found under /private folder', -'OR': 'SAU', -'Object or table name': 'Obiect sau nume de tabel', -'Old password': 'Parola veche', -'Online examples': 'Exemple online', -'Or': 'Sau', -'Origin': 'Origine', -'Original/Translation': 'Original/Traducere', -'Other Plugins': 'Alte plugin-uri', -'Other Recipes': 'Alte rețete', -'Overview': 'Prezentare de ansamblu', -'Overwrite installed app': 'Suprascrie aplicație instalată', -'Pack all': 'Împachetează tot', -'Password': 'Parola', -"Password fields don't match": 'Câmpurile de parolă nu se potrivesc', -'Peeking at file': 'Vizualizare fișier', -'Plugins': 'Plugin-uri', -'Powered by': 'Pus în mișcare de', -'Preface': 'Prefață', -'Previous Edit Point': 'Punct de editare anterior', -'Profile': 'Profil', -'Project Progress': 'Progres proiect', -'Python': 'Python', -'Query': 'Interogare', -'Query:': 'Interogare:', -'Quick Examples': 'Exemple rapide', -'RAM Cache Keys': 'Chei cache RAM', -'Recipes': 'Rețete', -'Record ID': 'ID înregistrare', -'Register': 'Înregistrare', -'Registration identifier': 'Identificator de autentificare', -'Registration key': 'Cheie înregistrare', -'Registration successful': 'Autentificare reușită', -'Reload routes': 'Reîncarcare rute', -'Remember me (for 30 days)': 'Ține-mă minte (timp de 30 de zile)', -'Request reset password': 'Cerere resetare parolă', -'Reset Password key': 'Cheie resetare parolă', -'Resolve Conflict file': 'Rezolvă conflict fișier', -'Role': 'Rol', -'Rows in table': 'Linii în tabel', -'Rows selected': 'Linii selectate', -"Run tests in this file (to run all files, you may also use the button labelled 'test')": "Run tests in this file (to run all files, you may also use the button labelled 'test')", -'Save': 'Salvează', -'Save profile': 'Salvează profil', -'Save via Ajax': 'Salvează utilizând Ajax', -'Saved file hash:': 'Hash fișier salvat:', -'Search': 'Căutare', -'Semantic': 'Semantică', -'Services': 'Servicii', -'Set Breakpoint on %s at line %s: %s': 'Set Breakpoint on %s at line %s: %s', -'Site': 'Site', -'Sorry, could not find mercurial installed': 'Scuze, dar n-am gasit unde este instalat mercurial', -'Start a new app': 'Începe o nouă aplicație', -'Start wizard': 'Startează magician', -'Static files': 'Fișiere statice', -'Stylesheet': 'Foaie de stiluri', -'Submit': 'Înregistrează', -'Support': 'Suport', -'Sure you want to delete this object?': 'Sigur ștergeți acest obiect?', -'Table name': 'Nume tabel', -'Testing application': 'Testare aplicație', -'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.': '"Interogarea (query)" este o condiție de tipul "db.tabel1.câmp1==\'valoare\'". Ceva de genul "db.tabel1.câmp1==db.tabel2.câmp2" generează un JOIN SQL.', -'The Core': 'Nucleul', -'The Views': 'Vederile', -'The application logic, each URL path is mapped in one exposed function in the controller': 'Logica aplicației, fiecare rută URL este mapată într-o funcție expusă de controlor', -'The data representation, define database tables and sets': 'Reprezentarea datelor, definește tabele și seturi de date', -'The output of the file is a dictionary that was rendered by the view': 'Fișierul produce un dicționar care a fost prelucrat de vederea', -'The presentations layer, views are also known as templates': 'Nivelul de prezentare, vederile sunt cunoscute de asemenea ca șabloane', -'There are no controllers': 'Nu există controlori', -'There are no models': 'Nu există modele', -'There are no modules': 'Nu există module', -'There are no plugins': 'Nu există plugin-uri', -'There are no static files': 'Nu există fișiere statice', -'There are no translators, only default language is supported': 'Nu există traduceri, doar limba implicită este suportată', -'There are no views': 'Nu există vederi', -'These files are served without processing, your images go here': 'Aceste fișiere sunt servite fără procesare, fișierele imagine se pun aici', -'This App': 'Această aplicație', -'This is a copy of the scaffolding application': 'Aceasta este o copie a aplicației schelet', -'This is the %(filename)s template': 'Aceasta este șablonul fișierului %(filename)s', -'Ticket': 'Tichet', -'Ticket ID': 'ID tichet', -'Timestamp': 'Moment în timp (timestamp)', -'To create a plugin, name a file/folder plugin_[name]': 'Pentru a crea un plugin, numește un fișier/director plugin_[nume]', -'Traceback': 'Trasabilitate', -'Translation strings for the application': 'Șiruri de traducere pentru aplicație', -'True': 'Adevărat', -'Twitter': 'Twitter', -'Unable to check for upgrades': 'Imposibil de verificat dacă există actualizări', -'Unable to download': 'Imposibil de descărcat', -'Unable to download app': 'Imposibil de descărcat aplicația', -'Uninstall': 'Dezinstalează', -'Update:': 'Actualizare:', -'Upload a package:': 'Încarcă un pachet:', -'Upload and install packed application': 'Încarcă și instalează aplicație împachetată', -'Upload existing application': 'Încarcă aplicația existentă', -'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Folosiți (...)&(...) pentru ȘI, (...)|(...) pentru SAU, și ~(...) pentru NEGARE, pentru a crea interogări complexe.', -'User %(id)s Logged-in': 'Utilizator %(id)s autentificat', -'User %(id)s Logged-out': 'Utilizator %(id)s delogat', -'User %(id)s Password changed': 'Parola utilizatorului %(id)s a fost schimbată', -'User %(id)s Password reset': 'Resetare parola utilizator %(id)s', -'User %(id)s Profile updated': 'Profil utilizator %(id)s actualizat', -'User %(id)s Registered': 'Utilizator %(id)s înregistrat', -'User ID': 'ID utilizator', -'VERSION': 'VERSIUNE', -'Verify Password': 'Verifică parola', -'Version': 'Version', -'Version %s.%s.%s (%s) %s': 'Versiune %s.%s.%s (%s) %s', -'Versioning': 'Versiuni', -'Videos': 'Video-uri', -'View': 'Vedere', -'Views': 'Vederi', -'Web Framework': 'Framework web', -'Welcome': 'Bine ați venit', -'Welcome %s': 'Bine ați venit %s', -'Welcome to web2py': 'Bun venit la web2py', -'Welcome to web2py!': 'Bun venit la web2py!', -'Which called the function': 'Care a apelat funcția', -'Wrap with Abbreviation': 'Încadrează cu abreviația', -'YES': 'DA', -'You are successfully running web2py': 'Rulați cu succes web2py', -'You can modify this application and adapt it to your needs': 'Puteți modifica și adapta aplicația nevoilor dvs.', -'You visited the url': 'Ați vizitat adresa', -'about': 'despre', -'additional code for your application': 'cod suplimentar pentru aplicația dvs.', -'admin disabled because no admin password': 'administrare dezactivată deoarece parola de administrator nu a fost furnizată', -'admin disabled because not supported on google app engine': 'administrare dezactivată deoarece funcționalitatea nu e suportat pe Google App Engine', -'admin disabled because unable to access password file': 'administrare dezactivată deoarece nu există acces la fișierul cu parole', -'administrative interface': 'interfață de administrare', -'and rename it (required):': 'și renumește (obligatoriu):', -'and rename it:': ' și renumește:', -'appadmin': 'appadmin', -'appadmin is disabled because insecure channel': 'appadmin dezactivat deoarece conexiunea nu e sigură', -'application "%s" uninstalled': 'aplicația "%s" a fost dezinstalată', -'application compiled': 'aplicația a fost compilată', -'application is compiled and cannot be designed': 'aplicația este compilată și nu poate fi editată', -'arguments': 'argumente', -'back': 'înapoi', -'cache': 'cache', -'cache, errors and sessions cleaned': 'cache, erori și sesiuni golite', -'cannot create file': 'fișier imposibil de creat', -'cannot upload file "%(filename)s"': 'imposibil de încărcat fișierul "%(filename)s"', -'change password': 'schimbare parolă', -'check all': 'coșează tot', -'clean': 'golire', -'click to check for upgrades': 'Clic pentru a verifica dacă există upgrade-uri', -'code': 'code', -'collapse/expand all': 'restrânge/extinde tot', -'compile': 'compilare', -'compiled application removed': 'aplicația compilată a fost ștearsă', -'contains': 'conține', -'controllers': 'controlori', -'create file with filename:': 'crează fișier cu numele:', -'create new application:': 'crează aplicație nouă:', -'created by': 'creat de', -'crontab': 'crontab', 'currently running': 'acum în funcționare', 'currently saved or': 'în prezent salvat sau', 'customize me!': 'Personalizează-mă!', 'data uploaded': 'date încărcate', +'Database': 'Baza de date', 'database': 'bază de date', +'Database %s select': 'Database %s select', 'database %s select': 'selectare bază de date %s', +'Database administration': 'Database administration', 'database administration': 'administrare bază de date', +'Database Administration (appadmin)': 'Database Administration (appadmin)', +'Date and Time': 'Data și ora', 'db': 'db', +'DB Model': 'Model bază de date', +'Debug': 'Debogare', 'defines tables': 'definire tabele', +'Delete': 'Șterge', 'delete': 'șterge', 'delete all checked': 'șterge tot ce e coșat', +'delete plugin': 'delete plugin', +'Delete this file (you will be asked to confirm deletion)': 'Delete this file (you will be asked to confirm deletion)', +'Delete:': 'Șterge:', +'deleted after first hit': 'deleted after first hit', +'Demo': 'Demo', +'Deploy': 'Instalare', +'Deploy on Google App Engine': 'Instalare pe Google App Engine', +'Deploy to OpenShift': 'Deploy to OpenShift', +'Deploy to pythonanywhere': 'Deploy to pythonanywhere', +'Deploy to PythonAnywhere': 'Deploy to PythonAnywhere', +'Deployment form': 'Deployment form', +'Deployment Interface': 'Deployment Interface', +'Deployment Recipes': 'Rețete de instalare', +'Description': 'Descriere', +'Description:': 'Description:', 'design': 'design', +'DESIGN': 'DESIGN', +'Design for': 'Design pentru', +'Detailed traceback description': 'Descriere detaliată a mesajului de trasabilitate', 'details': 'detalii', 'direction: ltr': 'direcție: stânga-sus-dreapta', +'directory not found': 'directory not found', +'Disable': 'Dezactivează', +'Disabled': 'Disabled', +'disabled in demo mode': 'disabled in demo mode', +'disabled in GAE mode': 'disabled in GAE mode', +'disabled in multi user mode': 'disabled in multi user mode', +'DISK': 'DISK', +'Disk Cache Keys': 'Chei cache de disc', +'Disk Cleared': 'Disk Cleared', +'Display line numbers': 'Display line numbers', +'DO NOT use the "Pack compiled" feature.': 'DO NOT use the "Pack compiled" feature.', 'docs': 'documentație', +'Docs': 'Docs', +'Documentation': 'Documentație', +"Don't know what to do?": 'Nu știți ce să faceți?', 'done!': 'gata!', +'Downgrade': 'Downgrade', +'Download': 'Descărcare', +'Download .w2p': 'Download .w2p', +'Download as .exe': 'Download as .exe', 'download layouts': 'descărcare șabloane', +'Download layouts from repository': 'Download layouts from repository', 'download plugins': 'descărcare plugin-uri', +'Download plugins from repository': 'Download plugins from repository', +'E-mail': 'E-mail', +'E-mail invalid': 'E-mail invalid', 'edit': 'editare', +'EDIT': 'EDITARE', +'Edit': 'Editare', +'edit all': 'edit all', +'Edit application': 'Editare aplicație', 'edit controller': 'editare controlor', +'edit controller:': 'edit controller:', +'Edit current record': 'Editare înregistrare curentă', +'Edit Profile': 'Editare profil', 'edit profile': 'editare profil', +'Edit This App': 'Editați această aplicație', 'edit views:': 'editează vederi:', +'Editing %s': 'Editing %s', +'Editing file': 'Editare fișier', +'Editing file "%s"': 'Editare fișier "%s"', +'Editing Language file': 'Editing Language file', +'Editing Plural Forms File': 'Editing Plural Forms File', +'Editor': 'Editor', +'Email Address': 'Email Address', +'Email and SMS': 'E-mail și SMS', +'Enable': 'Enable', +'Enable Close-Tag': 'Enable Close-Tag', +'Enable Code Folding': 'Enable Code Folding', 'enter a number between %(min)g and %(max)g': 'introduceți un număr între %(min)g și %(max)g', 'enter an integer between %(min)g and %(max)g': 'introduceți un întreg între %(min)g și %(max)g', +'Error': 'Eroare', +'Error logs for "%(app)s"': 'Log erori pentru "%(app)s"', +'Error snapshot': 'Instantaneu eroare', +'Error ticket': 'Tichet eroare', 'errors': 'erori', +'Errors': 'Erori', +'Exception %(extype)s: %(exvalue)s': 'Exception %(extype)s: %(exvalue)s', +'Exception %s': 'Exception %s', +'Exception instance attributes': 'Exception instance attributes', +'Exit Fullscreen': 'Exit Fullscreen', +'Expand Abbreviation': 'Extinde abreviația', +'Expand Abbreviation (html files only)': 'Expand Abbreviation (html files only)', +'Export': 'Export', 'export as csv file': 'exportă ca fișier csv', +'Exports:': 'Exports:', 'exposes': 'expune', 'exposes:': 'expune:', 'extends': 'extinde', +'failed to compile file because:': 'failed to compile file because:', 'failed to reload module': 'reîncarcare modul nereușită', +'failed to reload module because:': 'failed to reload module because:', +'False': 'Neadevărat', +'FAQ': 'Întrebări frecvente', +'File': 'Fișier', 'file "%(filename)s" created': 'fișier "%(filename)s" creat', 'file "%(filename)s" deleted': 'fișier "%(filename)s" șters', 'file "%(filename)s" uploaded': 'fișier "%(filename)s" încărcat', @@ -368,92 +286,503 @@ 'file "%s" of %s restored': 'fișier "%s" de %s restaurat', 'file changed on disk': 'fișier modificat pe disc', 'file does not exist': 'fișier inexistent', +'file not found': 'file not found', 'file saved on %(time)s': 'fișier salvat %(time)s', 'file saved on %s': 'fișier salvat pe %s', +'filename': 'filename', +'Filename': 'Filename', +'Files added': 'Files added', 'filter': 'filtru', +'Find Next': 'Find Next', +'Find Previous': 'Find Previous', +'First name': 'Prenume', +'Forbidden': 'Interzis', +'Form has errors': 'Form has errors', +'Forms and Validators': 'Formulare și validatori', +'Frames': 'Frames', +'Free Applications': 'Aplicații gratuite', +'Functions with no doctests will result in [passed] tests.': 'Funcțiile fără doctests vor genera teste [trecute].', +'GAE Email': 'GAE Email', +'GAE Output': 'GAE Output', +'GAE Password': 'GAE Password', +'Generate': 'Generate', +'Get from URL:': 'Obține de la adresa:', +'Git Pull': 'Git Pull', +'Git Push': 'Git Push', +'Globals##debug': 'Globals##debug', +'Go to Matching Pair': 'Mergi la perechea care se potrivește', +'go!': 'go!', +'Google App Engine Deployment Interface': 'Google App Engine Deployment Interface', +'Google Application Id': 'Google Application Id', +'Goto': 'Goto', +'graph model': 'graph model', +'Graph Model': 'Graph Model', +'Group %(group_id)s created': 'Grup %(group_id)s creat', +'Group ID': 'ID grup', +'Group uniquely assigned to user %(id)s': 'Grup asociat în mod unic utilizatorului %(id)s', +'Groups': 'Grupuri', +'Hello World': 'Salutare lume', 'help': 'ajutor', +'Help': 'Ajutor', +'here': 'here', +'Hide/Show Translated strings': 'Hide/Show Translated strings', +'Highlight current line': 'Highlight current line', +'Hits': 'Hits', +'Home': 'Acasă', +'honored only if the expression evaluates to true': 'honored only if the expression evaluates to true', +'How did you get here?': 'Cum ați ajuns aici?', 'htmledit': 'editare html', +'If start the downgrade, be patient, it may take a while to rollback': 'If start the downgrade, be patient, it may take a while to rollback', +'If start the upgrade, be patient, it may take a while to download': 'If start the upgrade, be patient, it may take a while to download', +'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\n\t\tA green title indicates that all tests (if defined) passed. In this case test results are not shown.': 'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\n\t\tA green title indicates that all tests (if defined) passed. In this case test results are not shown.', +'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\nA green title indicates that all tests (if defined) passed. In this case test results are not shown.': 'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\nA green title indicates that all tests (if defined) passed. In this case test results are not shown.', +'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\r\nA green title indicates that all tests (if defined) passed. In this case test results are not shown.': 'Dacă raportul de deasupra conține un număr de tichet, asta indică un eșec în executarea controlorului, înainte de orice încercare de a executa doctests-urile. Aceasta se întâmplă de obicei din cauza unei erori de identare sau a unei erori din afara corpului funcției.\r\nUn titlu în verde arată ca toate testele (dacă definite) au fost trecute. În acest caz rezultatele testelor nu sunt arătate.', +'if your application uses a database other than sqlite you will then have to configure its DAL in pythonanywhere.': 'if your application uses a database other than sqlite you will then have to configure its DAL in pythonanywhere.', +'import': 'import', +'Import/Export': 'Import/Export', +'In development, use the default Rocket webserver that is currently supported by this debugger.': 'In development, use the default Rocket webserver that is currently supported by this debugger.', 'includes': 'include', +'Indent with tabs': 'Indent with tabs', +'Index': 'Index', 'index': 'index', 'insert new': 'adaugă nou', 'insert new %s': 'adaugă nou %s', 'inspect attributes': 'inspectare atribute', +'Install': 'Instalează', +'Installation of %(plugin)s for %(app)s': 'Installation of %(plugin)s for %(app)s', +'Installed applications': 'Aplicații instalate', +'Interaction at %s line %s': 'Interaction at %s line %s', +'Interactive console': 'Interactive console', 'internal error': 'eroare internă', +'internal error: %s': 'internal error: %s', +'Internal State': 'Stare internă', +'Introduction': 'Introducere', +'Invalid action': 'Acțiune invalidă', +'Invalid application name': 'Invalid application name', +'invalid circular reference': 'invalid circular reference', +'Invalid email': 'E-mail invalid', +'Invalid git repository specified.': 'Invalid git repository specified.', 'invalid password': 'parolă invalidă', +'Invalid password': 'Parolă invalidă', +'invalid password.': 'invalid password.', +'Invalid Query': 'Interogare invalidă', 'invalid request': 'cerere invalidă', +'Invalid request': 'Invalid request', +'invalid table names (auth_* tables already defined)': 'invalid table names (auth_* tables already defined)', 'invalid ticket': 'tichet invalid', +'Key': 'Key', +'Key bindings': 'Combinație taste', +'Key bindings for ZenCoding Plugin': 'Key bindings for ZenCoding Plugin', +'Keyboard shortcuts': 'Keyboard shortcuts', +'kill process': 'kill process', 'language file "%(filename)s" created/updated': 'fișier de limbă "%(filename)s" creat/actualizat', +'Language files (static strings) updated': 'Fișierele de limbă (șirurile statice de caractere) actualizate', 'languages': 'limbi', +'Languages': 'Limbi', 'languages updated': 'limbi actualizate', +'Last name': 'Nume', +'Last Revision': 'Last Revision', +'Last saved on:': 'Ultima salvare:', +'Layout': 'Șablon', +'Layout Plugins': 'Șablon plugin-uri', +'Layouts': 'Șabloane', +'License for': 'Licență pentru', +'License:': 'License:', +'Line Nr': 'Line Nr', +'Line number': 'Line number', +'lists by exception': 'lists by exception', +'lists by ticket': 'lists by ticket', +'Live Chat': 'Chat live', +'Loading...': 'Loading...', 'loading...': 'încarc...', +'Local Apps': 'Local Apps', 'locals': 'localizare', +'Locals##debug': 'Locals##debug', 'located in the file': 'prezentă în fișierul', +'Logged in': 'Logat', +'Logged out': 'Delogat', 'login': 'autentificare', +'Login': 'Autentificare', +'Login successful': 'Login successful', +'Login to the Administrative Interface': 'Logare interfață de administrare', +'Login/Register': 'Login/Register', 'logout': 'ieșire', +'Logout': 'Ieșire', +'Lost Password': 'Parolă pierdută', +'lost password': 'lost password', +'Lost password?': 'Parolă pierdută?', +'Main Menu': 'Meniu principal', +'Manage': 'Manage', +'Manage %(action)s': 'Manage %(action)s', +'Manage Access Control': 'Manage Access Control', +'Manage Admin Users/Students': 'Manage Admin Users/Students', +'Manage Cache': 'Manage Cache', +'Manage Students': 'Manage Students', +'Match Pair': 'Potrivește pereche', +'Memberships': 'Memberships', +'Menu Model': 'Model meniu', 'merge': 'unește', +'Merge Lines': 'Unește linii', +'Models': 'Modele', 'models': 'modele', +'Modified On': 'Modified On', +'Modules': 'Module', 'modules': 'module', +'Multi User Mode': 'Multi User Mode', +'My Sites': 'Site-urile mele', +'Name': 'Nume', +'New': 'Nou', 'new application "%s" created': 'aplicația nouă "%s" a fost creată', +'new application "%s" imported': 'new application "%s" imported', +'New Application Wizard': 'New Application Wizard', +'New application wizard': 'Magician aplicație nouă', +'New password': 'Parola nouă', +'new plugin installed': 'new plugin installed', +'New plugin installed: %s': 'New plugin installed: %s', +'New Record': 'Înregistrare nouă', 'new record inserted': 'înregistrare nouă adăugată', +'New simple application': 'O nouă aplicație simplă', +'next': 'next', +'next %s rows': 'next %s rows', 'next 100 rows': 'următoarele 100 de linii', +'Next Edit Point': 'Următorul punct de editare', +'NO': 'NU', +'no changes': 'no changes', +'No databases in this application': 'Aplicație fără bază de date', +'No Interaction yet': 'No Interaction yet', +'no match': 'no match', +'no package selected': 'no package selected', +'no permission to uninstall "%s"': 'no permission to uninstall "%s"', +'No ticket_storage.txt found under /private folder': 'No ticket_storage.txt found under /private folder', +'Node:': 'Node:', +'Not Authorized': 'Not Authorized', +'Not supported': 'Not supported', +'Note: If you receive an error with github status code of 128, ensure the system and account you are deploying from has a cooresponding ssh key configured in the openshift account.': 'Note: If you receive an error with github status code of 128, ensure the system and account you are deploying from has a cooresponding ssh key configured in the openshift account.', +'Object or table name': 'Obiect sau nume de tabel', +'Old password': 'Parola veche', +"On production, you'll have to configure your webserver to use one process and multiple threads to use this debugger.": "On production, you'll have to configure your webserver to use one process and multiple threads to use this debugger.", 'online designer': 'designer online', +'Online examples': 'Exemple online', +'Open new app in new window': 'Open new app in new window', +'OpenShift Deployment Interface': 'OpenShift Deployment Interface', +'OpenShift Output': 'OpenShift Output', +'Or': 'Sau', +'OR': 'SAU', +'or alternatively': 'or alternatively', +'Or Get from URL:': 'Or Get from URL:', 'or import from csv file': 'sau importă din fișier csv', 'or provide application url:': 'sau furnizează adresă url:', +'Origin': 'Origine', +'Original/Translation': 'Original/Traducere', +'Other Plugins': 'Alte plugin-uri', +'Other Recipes': 'Alte rețete', +'Overview': 'Prezentare de ansamblu', +'Overwrite installed app': 'Suprascrie aplicație instalată', 'pack all': 'împachetează toate', +'Pack all': 'Împachetează tot', +'Pack compiled': 'Pack compiled', 'pack compiled': 'împachetează ce e compilat', +'Pack custom': 'Pack custom', +'pack plugin': 'pack plugin', +'Password': 'Parola', +'password changed': 'password changed', +"Password fields don't match": 'Câmpurile de parolă nu se potrivesc', +'Past revisions': 'Past revisions', +'Path to appcfg.py': 'Path to appcfg.py', +'Path to local openshift repo root.': 'Path to local openshift repo root.', +'Peeking at file': 'Vizualizare fișier', +'Permission': 'Permission', +'Permissions': 'Permissions', +'Please': 'Please', 'please input your password again': 'introduceți parola din nou', +'Please wait, giving pythonanywhere a moment...': 'Please wait, giving pythonanywhere a moment...', +'plugin "%(plugin)s" deleted': 'plugin "%(plugin)s" deleted', +'Plugin "%s" in application': 'Plugin "%s" in application', +'plugin not specified': 'plugin not specified', +'Plugin page': 'Plugin page', 'plugins': 'plugin-uri', +'Plugins': 'Plugin-uri', +'Plural Form #%s': 'Plural Form #%s', +'Plural-Forms:': 'Plural-Forms:', +'Powered by': 'Pus în mișcare de', +'Preface': 'Prefață', +'Preferences saved correctly': 'Preferences saved correctly', +'Preferences saved on session only': 'Preferences saved on session only', +'previous %s rows': 'previous %s rows', 'previous 100 rows': '100 de linii anterioare', +'Previous Edit Point': 'Punct de editare anterior', +'Private files': 'Private files', +'private files': 'private files', +'Profile': 'Profil', +'Project Progress': 'Progres proiect', +'Pull': 'Pull', +'Pull failed, certain files could not be checked out. Check logs for details.': 'Pull failed, certain files could not be checked out. Check logs for details.', +'Pull is not possible because you have unmerged files. Fix them up in the work tree, and then try again.': 'Pull is not possible because you have unmerged files. Fix them up in the work tree, and then try again.', +'Push': 'Push', +'Push failed, there are unmerged entries in the cache. Resolve merge issues manually and try again.': 'Push failed, there are unmerged entries in the cache. Resolve merge issues manually and try again.', +'pygraphviz library not found': 'pygraphviz library not found', +'Python': 'Python', +'PythonAnywhere Apps': 'PythonAnywhere Apps', +'PythonAnywhere Password': 'PythonAnywhere Password', +'Query': 'Interogare', +'Query:': 'Interogare:', +'Quick Examples': 'Exemple rapide', +'RAM': 'RAM', +'RAM Cache Keys': 'Chei cache RAM', +'Ram Cleared': 'Ram Cleared', +'Rapid Search': 'Rapid Search', +'Recipes': 'Rețete', +'Record': 'Record', 'record': 'înregistrare', 'record does not exist': 'înregistrare inexistentă', 'record id': 'id înregistrare', +'Record ID': 'ID înregistrare', +'Record id': 'Record id', +'refresh': 'refresh', 'register': 'înregistrare', +'Register': 'Înregistrare', +'Registration identifier': 'Identificator de autentificare', +'Registration key': 'Cheie înregistrare', +'Registration successful': 'Autentificare reușită', +'Reload routes': 'Reîncarcare rute', +'Remember me (for 30 days)': 'Ține-mă minte (timp de 30 de zile)', +'Remove compiled': 'Remove compiled', 'remove compiled': 'șterge compilate', +'Removed Breakpoint on %s at line %s': 'Removed Breakpoint on %s at line %s', +'Replace': 'Replace', +'Replace All': 'Replace All', +'Repository (%s)': 'Repository (%s)', 'request': 'cerere', +'Request reset password': 'Cerere resetare parolă', +'requires distutils, but not installed': 'requires distutils, but not installed', +'requires python-git, but not installed': 'requires python-git, but not installed', +'Reset Password key': 'Cheie resetare parolă', +'Resolve Conflict file': 'Rezolvă conflict fișier', 'response': 'răspuns', +'restart': 'restart', 'restore': 'restaurare', +'return': 'return', +'Revert': 'Revert', 'revert': 'revenire', +'reverted to revision %s': 'reverted to revision %s', +'Revision %s': 'Revision %s', +'Revision:': 'Revision:', +'Role': 'Rol', +'Roles': 'Roles', +'Rows in Table': 'Rows in Table', +'Rows in table': 'Linii în tabel', +'Rows selected': 'Linii selectate', +'rules are not defined': 'rules are not defined', +'Run tests': 'Run tests', +'Run tests in this file': 'Run tests in this file', +"Run tests in this file (to run all files, you may also use the button labelled 'test')": "Run tests in this file (to run all files, you may also use the button labelled 'test')", +'Running on %s': 'Running on %s', +'Save': 'Salvează', 'save': 'salvare', +'Save file:': 'Save file:', +'Save file: %s': 'Save file: %s', +'Save model as...': 'Save model as...', +'Save profile': 'Salvează profil', +'Save via Ajax': 'Salvează utilizând Ajax', +'Saved file hash:': 'Hash fișier salvat:', +'Screenshot %s': 'Screenshot %s', +'Search': 'Căutare', +'Select Files to Package': 'Select Files to Package', 'selected': 'selectat', +'Semantic': 'Semantică', +'Services': 'Servicii', 'session': 'sesiune', 'session expired': 'sesiune expirată', +'Session saved correctly': 'Session saved correctly', +'Session saved on session only': 'Session saved on session only', +'Set Breakpoint on %s at line %s: %s': 'Set Breakpoint on %s at line %s: %s', 'shell': 'line de commandă', +'Showing %s to %s of %s %s found': 'Showing %s to %s of %s %s found', +'Singular Form': 'Singular Form', 'site': 'site', +'Site': 'Site', +'Size of cache:': 'Size of cache:', +'skip to generate': 'skip to generate', 'some files could not be removed': 'anumite fișiere n-au putut fi șterse', +'Something went wrong please wait a few minutes before retrying': 'Something went wrong please wait a few minutes before retrying', +'Sorry, could not find mercurial installed': 'Scuze, dar n-am gasit unde este instalat mercurial', +'source : db': 'source : db', +'source : filesystem': 'source : filesystem', +'Start a new app': 'Începe o nouă aplicație', +'Start searching': 'Start searching', +'Start wizard': 'Startează magician', 'starts with': 'începe cu', 'state': 'stare', +'Static': 'Static', 'static': 'static', +'Static files': 'Fișiere statice', +'Statistics': 'Statistics', +'Step': 'Step', +'step': 'step', +'stop': 'stop', +'Stylesheet': 'Foaie de stiluri', +'submit': 'submit', +'Submit': 'Înregistrează', 'successful': 'cu succes', +'Support': 'Suport', +'Sure you want to delete this object?': 'Sigur ștergeți acest obiect?', +'switch to : db': 'switch to : db', +'switch to : filesystem': 'switch to : filesystem', +'Tab width (# characters)': 'Tab width (# characters)', 'table': 'tabel', +'Table': 'Table', +'Table name': 'Nume tabel', +'Temporary': 'Temporary', 'test': 'test', +'Testing application': 'Testare aplicație', +'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.': '"Interogarea (query)" este o condiție de tipul "db.tabel1.câmp1==\'valoare\'". Ceva de genul "db.tabel1.câmp1==db.tabel2.câmp2" generează un JOIN SQL.', +'The app exists, was created by wizard, continue to overwrite!': 'The app exists, was created by wizard, continue to overwrite!', +'The app exists, was NOT created by wizard, continue to overwrite!': 'The app exists, was NOT created by wizard, continue to overwrite!', 'the application logic, each URL path is mapped in one exposed function in the controller': 'logica aplicației, fiecare rută URL este mapată într-o funcție expusă de controlor', +'The application logic, each URL path is mapped in one exposed function in the controller': 'Logica aplicației, fiecare rută URL este mapată într-o funcție expusă de controlor', +'The Core': 'Nucleul', 'the data representation, define database tables and sets': 'reprezentarea datelor, definește tabelele bazei de date și seturile (de date)', +'The data representation, define database tables and sets': 'Reprezentarea datelor, definește tabele și seturi de date', +'The output of the file is a dictionary that was rendered by the view': 'Fișierul produce un dicționar care a fost prelucrat de vederea', +'The presentations layer, views are also known as templates': 'Nivelul de prezentare, vederile sunt cunoscute de asemenea ca șabloane', 'the presentations layer, views are also known as templates': 'nivelul de prezentare, vederile sunt de asemenea numite și șabloane', +'The Views': 'Vederile', +'Theme': 'Theme', +'There are no controllers': 'Nu există controlori', +'There are no models': 'Nu există modele', +'There are no modules': 'Nu există module', +'There are no plugins': 'Nu există plugin-uri', +'There are no private files': 'There are no private files', +'There are no static files': 'Nu există fișiere statice', +'There are no translators': 'There are no translators', +'There are no translators, only default language is supported': 'Nu există traduceri, doar limba implicită este suportată', +'There are no views': 'Nu există vederi', +'These files are not served, they are only available from within your app': 'These files are not served, they are only available from within your app', +'These files are served without processing, your images go here': 'Aceste fișiere sunt servite fără procesare, fișierele imagine se pun aici', 'these files are served without processing, your images go here': 'aceste fișiere sunt servite fără procesare, imaginea se plasează acolo', +'This App': 'Această aplicație', +"This debugger may not work properly if you don't have a threaded webserver or you're using multiple daemon processes.": "This debugger may not work properly if you don't have a threaded webserver or you're using multiple daemon processes.", +'This is a copy of the scaffolding application': 'Aceasta este o copie a aplicației schelet', +'This is an experimental feature and it needs more testing. If you decide to downgrade you do it at your own risk': 'This is an experimental feature and it needs more testing. If you decide to downgrade you do it at your own risk', +'This is an experimental feature and it needs more testing. If you decide to upgrade you do it at your own risk': 'This is an experimental feature and it needs more testing. If you decide to upgrade you do it at your own risk', +'This is the %(filename)s template': 'Aceasta este șablonul fișierului %(filename)s', +"This page can commit your changes to an openshift app repo and push them to your cloud instance. This assumes that you've already created the application instance using the web2py skeleton and have that repo somewhere on a filesystem that this web2py instance can access. This functionality requires GitPython installed and on the python path of the runtime that web2py is operating in.": "This page can commit your changes to an openshift app repo and push them to your cloud instance. This assumes that you've already created the application instance using the web2py skeleton and have that repo somewhere on a filesystem that this web2py instance can access. This functionality requires GitPython installed and on the python path of the runtime that web2py is operating in.", +'This page can upload your application to the Google App Engine computing cloud. Mind that you must first create indexes locally and this is done by installing the Google appserver and running the app locally with it once, or there will be errors when selecting records. Attention: deployment may take long time, depending on the network speed. Attention: it will overwrite your app.yaml. DO NOT SUBMIT TWICE.': 'This page can upload your application to the Google App Engine computing cloud. Mind that you must first create indexes locally and this is done by installing the Google appserver and running the app locally with it once, or there will be errors when selecting records. Attention: deployment may take long time, depending on the network speed. Attention: it will overwrite your app.yaml. DO NOT SUBMIT TWICE.', +'this page to see if a breakpoint was hit and debug interaction is required.': 'this page to see if a breakpoint was hit and debug interaction is required.', +'This will pull changes from the remote repo for application "%s"?': 'This will pull changes from the remote repo for application "%s"?', +'This will push changes to the remote repo for application "%s".': 'This will push changes to the remote repo for application "%s".', +'Ticket': 'Tichet', +'Ticket ID': 'ID tichet', +'Ticket Missing': 'Ticket Missing', +'Time in Cache (h:m:s)': 'Time in Cache (h:m:s)', +'Timestamp': 'Moment în timp (timestamp)', 'to previous version.': 'la versiunea anterioară.', +'To create a plugin, name a file/folder plugin_[name]': 'Pentru a crea un plugin, numește un fișier/director plugin_[nume]', +'To emulate a breakpoint programatically, write:': 'To emulate a breakpoint programatically, write:', +'to use the debugger!': 'to use the debugger!', 'toggle breakpoint': 'comutare breakpoint', +'Toggle comment': 'Toggle comment', +'Toggle Fullscreen': 'Toggle Fullscreen', 'too short': 'prea scurt', +'Traceback': 'Trasabilitate', 'translation strings for the application': 'șiruri de caractere folosite la traducerea aplicației', +'Translation strings for the application': 'Șiruri de traducere pentru aplicație', +'True': 'Adevărat', 'try': 'încearcă', 'try something like': 'încearcă ceva de genul', +'Try the mobile interface': 'Try the mobile interface', +'try view': 'try view', +'Twitter': 'Twitter', +'Type PDB debugger command in here and hit Return (Enter) to execute it.': 'Type PDB debugger command in here and hit Return (Enter) to execute it.', +'Type some Python code in here and hit Return (Enter) to execute it.': 'Type some Python code in here and hit Return (Enter) to execute it.', +'Unable to check for upgrades': 'Imposibil de verificat dacă există actualizări', 'unable to create application "%s"': 'imposibil de creat aplicația "%s"', 'unable to delete file "%(filename)s"': 'imposibil de șters fișierul "%(filename)s"', +'unable to delete file plugin "%(plugin)s"': 'unable to delete file plugin "%(plugin)s"', +'Unable to determine the line number!': 'Unable to determine the line number!', +'Unable to download': 'Imposibil de descărcat', +'Unable to download app': 'Imposibil de descărcat aplicația', +'Unable to download app because:': 'Unable to download app because:', +'unable to download layout': 'unable to download layout', +'unable to download plugin: %s': 'unable to download plugin: %s', +'Unable to download the list of plugins': 'Unable to download the list of plugins', +'unable to install plugin "%s"': 'unable to install plugin "%s"', 'unable to parse csv file': 'imposibil de analizat fișierul csv', 'unable to uninstall "%s"': 'imposibil de dezinstalat "%s"', +'unable to upgrade because "%s"': 'unable to upgrade because "%s"', 'uncheck all': 'decoșează tot', 'uninstall': 'dezinstalează', +'Uninstall': 'Dezinstalează', +'Unsupported webserver working mode: %s': 'Unsupported webserver working mode: %s', 'update': 'actualizează', 'update all languages': 'actualizează toate limbile', +'Update:': 'Actualizare:', +'Upgrade': 'Upgrade', +'upgrade now to %s': 'upgrade now to %s', 'upload': 'încarcă', +'Upload': 'Upload', +'Upload a package:': 'Încarcă un pachet:', +'Upload and install packed application': 'Încarcă și instalează aplicație împachetată', 'upload application:': 'incarcă aplicația:', +'Upload existing application': 'Încarcă aplicația existentă', 'upload file:': 'încărcă fișier:', 'upload plugin file:': 'încarcă fișier plugin:', +'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Folosiți (...)&(...) pentru ȘI, (...)|(...) pentru SAU, și ~(...) pentru NEGARE, pentru a crea interogări complexe.', 'user': 'utilizator', +'User': 'User', +'User %(id)s Logged-in': 'Utilizator %(id)s autentificat', +'User %(id)s Logged-out': 'Utilizator %(id)s delogat', +'User %(id)s Password changed': 'Parola utilizatorului %(id)s a fost schimbată', +'User %(id)s Password reset': 'Resetare parola utilizator %(id)s', +'User %(id)s Profile updated': 'Profil utilizator %(id)s actualizat', +'User %(id)s Registered': 'Utilizator %(id)s înregistrat', +'User ID': 'ID utilizator', +'Username': 'Username', +'Users': 'Users', +'Using the shell may lock the database to other users of this app.': 'Using the shell may lock the database to other users of this app.', 'value already in database or empty': 'Valoare existentă în baza de date sau vidă', 'variables': 'variables', +'Verify Password': 'Verifică parola', +'VERSION': 'VERSIUNE', +'Version': 'Version', +'Version %s.%s.%s (%s) %s': 'Versiune %s.%s.%s (%s) %s', +'Versioning': 'Versiuni', 'versioning': 'versiuni', +'Videos': 'Video-uri', +'View': 'Vedere', 'view': 'vedere', +'Views': 'Vederi', 'views': 'vederi', -'web2py Recent Tweets': 'Ultimele tweet-uri web2py', +'Warning!': 'Warning!', +'WARNING:': 'WARNING:', +'WARNING: The following views could not be compiled:': 'WARNING: The following views could not be compiled:', +'Web Framework': 'Framework web', +'web2py Admin Password': 'web2py Admin Password', +'web2py apps to deploy': 'web2py apps to deploy', +'web2py Debugger': 'web2py Debugger', +'web2py downgrade': 'web2py downgrade', 'web2py is up to date': 'web2py este la zi', +'web2py online debugger': 'web2py online debugger', +'web2py Recent Tweets': 'Ultimele tweet-uri web2py', +'web2py upgrade': 'web2py upgrade', +'web2py upgraded; please restart it': 'web2py upgraded; please restart it', +'Welcome': 'Bine ați venit', +'Welcome %s': 'Bine ați venit %s', +'Welcome to web2py': 'Bun venit la web2py', +'Welcome to web2py!': 'Bun venit la web2py!', +'Which called the function': 'Care a apelat funcția', +'Working...': 'Working...', +'Wrap with Abbreviation': 'Încadrează cu abreviația', +'WSGI reference name': 'WSGI reference name', +'YES': 'DA', +'Yes': 'Yes', +'You are successfully running web2py': 'Rulați cu succes web2py', +'You can also set and remove breakpoint in the edit window, using the Toggle Breakpoint button': 'You can also set and remove breakpoint in the edit window, using the Toggle Breakpoint button', +'You can inspect variables using the console below': 'You can inspect variables using the console below', +'You can modify this application and adapt it to your needs': 'Puteți modifica și adapta aplicația nevoilor dvs.', +'You have one more login attempt before you are locked out': 'You have one more login attempt before you are locked out', +'You need to set up and reach a': 'You need to set up and reach a', +'You only need these if you have already registered': 'You only need these if you have already registered', +'You visited the url': 'Ați vizitat adresa', +'Your application will be blocked until you click an action button (next, step, continue, etc.)': 'Your application will be blocked until you click an action button (next, step, continue, etc.)', } diff --git a/applications/admin/languages/ru.py b/applications/admin/languages/ru.py index 04ad7ede..88f9d703 100755 --- a/applications/admin/languages/ru.py +++ b/applications/admin/languages/ru.py @@ -3,84 +3,148 @@ '!langcode!': 'ru', '!langname!': 'Русский', '"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN': '"Update" ist ein optionaler Ausdruck wie "Feld1 = \'newvalue". JOIN Ergebnisse können nicht aktualisiert oder gelöscht werden', +'"User Exception" debug mode. ': '"User Exception" debug mode. ', +'%s': '%s', '%s %%{row} deleted': '%s %%{строкa} %%{удаленa}', '%s %%{row} updated': '%s %%{строкa} %%{обновленa}', +'%s selected': '%s selected', +'%s students registered': '%s students registered', '%Y-%m-%d': '%Y-%m-%d', '%Y-%m-%d %H:%M:%S': '%Y-%m-%d %H:%M:%S', '(requires internet access)': '(требует подключения к интернету)', +'(requires internet access, experimental)': '(requires internet access, experimental)', '(something like "it-it")': '(наподобие "it-it")', +'(version %s)': '(version %s)', +'?': '?', '@markmin\x01Searching: **%s** %%{file}': 'Найдено: **%s** %%{файл}', 'A new version of web2py is available': 'Доступна новая версия web2py', 'A new version of web2py is available: %s': 'Доступна новая версия web2py: %s', 'Abort': 'Отмена', 'About': 'О', 'About application': 'О приложении', +'Accept Terms': 'Accept Terms', +'Add breakpoint': 'Add breakpoint', 'additional code for your application': 'добавочный код для вашего приложения', 'Additional code for your application': 'Допольнительный код для вашего приложения', +'Admin design page': 'Admin design page', 'admin disabled because no admin password': 'админка отключена, потому что отсутствует пароль администратора', +'admin disabled because not supported on google app engine': 'admin disabled because not supported on google app engine', 'admin disabled because not supported on google apps engine': 'админка отключена, т.к. не поддерживается на google app engine', +'admin disabled because too many invalid login attempts': 'admin disabled because too many invalid login attempts', 'admin disabled because unable to access password file': 'админка отключена, т.к. невозможно получить доступ к файлу с паролями ', 'Admin is disabled because insecure channel': 'Админпанель выключена из-за небезопасного соединения', 'Admin is disabled because unsecure channel': 'Админпанель выключен из-за небезопасного соединения', 'Admin language': 'Язык админпанели', +'Admin versioning page': 'Admin versioning page', 'administrative interface': 'интерфейс администратора', 'Administrator Password:': 'Пароль администратора:', 'and rename it (required):': 'и переименуйте его (необходимо):', 'and rename it:': ' и переименуйте его:', +'App does not exist or you are not authorized': 'App does not exist or you are not authorized', 'appadmin': 'appadmin', 'appadmin is disabled because insecure channel': 'Appadmin отключен, т.к. соединение не безопасно', +'Application': 'Application', 'application "%s" uninstalled': 'Приложение "%s" удалено', +'Application cannot be generated in demo mode': 'Application cannot be generated in demo mode', 'application compiled': 'Приложение скомпилировано', +'Application exists already': 'Application exists already', 'application is compiled and cannot be designed': 'Приложение скомпилировано и дизайн не может быть изменен', 'Application name:': 'Название приложения:', +'Application updated via git pull': 'Application updated via git pull', 'are not used': 'are not used', 'are not used yet': 'are not used yet', 'Are you sure you want to delete file "%s"?': 'Вы действительно хотите удалить файл "%s"?', +'Are you sure you want to delete plugin "%s"?': 'Are you sure you want to delete plugin "%s"?', 'Are you sure you want to delete this object?': 'Are you sure you want to delete this object?', 'Are you sure you want to uninstall application "%s"': 'Вы действительно хотите удалить приложение "%s"', 'Are you sure you want to uninstall application "%s"?': 'Вы действительно хотите удалить приложение "%s"?', 'Are you sure you want to upgrade web2py now?': 'Вы действительно хотите обновить web2py сейчас?', +'Are you sure?': 'Are you sure?', 'arguments': 'аргументы', +'at char %s': 'at char %s', +'at line %s': 'at line %s', +'ATTENTION:': 'ATTENTION:', 'ATTENTION: Login requires a secure (HTTPS) connection or running on localhost.': 'ВНИМАНИЕ: Для входа требуется бесопасное (HTTPS) соединение либо запуск на localhost.', 'ATTENTION: TESTING IS NOT THREAD SAFE SO DO NOT PERFORM MULTIPLE TESTS CONCURRENTLY.': 'ВНИМАНИЕ: Тестирование не потокобезопасно, поэтому не запускайте несколько тестов параллельно.', 'ATTENTION: This is an experimental feature and it needs more testing.': 'ВНИМАНИЕ: Это экспериментальная возможность и требует тестирования.', 'ATTENTION: you cannot edit the running application!': 'ВНИМАНИЕ: Вы не можете редактировать работающее приложение!', 'Authentication': 'Аутентификация', +'Autocomplete Python Code': 'Autocomplete Python Code', 'Available databases and tables': 'Доступные базы данных и таблицы', +'Available Databases and Tables': 'Available Databases and Tables', 'back': 'назад', +'Back to the plugins list': 'Back to the plugins list', +'Back to wizard': 'Back to wizard', +'Basics': 'Basics', 'beautify': 'Раскрасить', +'Begin': 'Begin', +'breakpoint': 'breakpoint', +'Breakpoints': 'Breakpoints', +'breakpoints': 'breakpoints', +'Bulk Register': 'Bulk Register', +'Bulk Student Registration': 'Bulk Student Registration', +'Cache': 'Cache', 'cache': 'кэш', +'Cache Cleared': 'Cache Cleared', +'Cache Keys': 'Cache Keys', 'cache, errors and sessions cleaned': 'Кэш, ошибки и сессии очищены', 'call': 'вызов', +'can be a git repo': 'can be a git repo', +'Cancel': 'Cancel', 'Cannot be empty': 'Не может быть пустым', 'Cannot compile: there are errors in your app. Debug it, correct errors and try again.': 'Невозможно компилировать: в приложении присутствуют ошибки. Отладьте его, исправьте ошибки и попробуйте заново.', +'Cannot compile: there are errors in your app:': 'Cannot compile: there are errors in your app:', 'cannot create file': 'Невозможно создать файл', 'cannot upload file "%(filename)s"': 'Невозможно загрузить файл "%(filename)s"', +'Change Admin Password': 'Change Admin Password', 'Change admin password': 'Изменить пароль администратора', +'change editor settings': 'change editor settings', 'Change Password': 'Изменить пароль', 'change password': 'изменить пароль', +'Changelog': 'Changelog', 'check all': 'проверить все', 'Check for upgrades': 'проверить обновления', 'Check to delete': 'Поставьте для удаления', 'Checking for upgrades...': 'Проверка обновлений...', 'Clean': 'Очистить', +'Clear': 'Clear', +'Clear CACHE?': 'Clear CACHE?', +'Clear DISK': 'Clear DISK', +'Clear RAM': 'Clear RAM', 'click here for online examples': 'нажмите здесь для онлайн примеров', 'click here for the administrative interface': 'нажмите здесь для интерфейса администратора', +'Click row to expand traceback': 'Click row to expand traceback', +'Click row to view a ticket': 'Click row to view a ticket', 'click to check for upgrades': 'нажмите для проверки обновления', 'Client IP': 'IP клиента', 'code': 'код', +'Code listing': 'Code listing', 'collapse/expand all': 'свернуть/развернуть все', +'Command': 'Command', +'Comment:': 'Comment:', +'Commit': 'Commit', +'Commit form': 'Commit form', +'Committed files': 'Committed files', 'Compile': 'Компилировать', +'Compile (all or nothing)': 'Compile (all or nothing)', +'Compile (skip failed views)': 'Compile (skip failed views)', 'compiled application removed': 'скомпилированное приложение удалено', +'Condition': 'Condition', +'continue': 'continue', 'Controller': 'Контроллер', 'Controllers': 'Контроллеры', 'controllers': 'контроллеры', 'Copyright': 'Copyright', +'Count': 'Count', 'Create': 'Создать', 'create file with filename:': 'Создать файл с названием:', 'create new application:': 'создать новое приложение:', 'Create new simple application': 'Создать новое простое приложение', +'Create/Upload': 'Create/Upload', 'created by': 'создано', +'Created by:': 'Created by:', +'Created On': 'Created On', +'Created on:': 'Created on:', 'crontab': 'crontab', 'Current request': 'Текущий запрос', 'Current response': 'Текущий ответ', @@ -91,8 +155,11 @@ 'data uploaded': 'дата загрузки', 'Database': 'База данных', 'database': 'база данных', +'Database %s select': 'Database %s select', 'database %s select': 'Выбор базы данных %s ', +'Database administration': 'Database administration', 'database administration': 'администрирование базы данных', +'Database Administration (appadmin)': 'Database Administration (appadmin)', 'Date and Time': 'Дата и время', 'db': 'бд', 'DB Model': 'Модель БД', @@ -104,47 +171,89 @@ 'delete plugin': 'удалить плагин', 'Delete this file (you will be asked to confirm deletion)': 'Delete this file (you will be asked to confirm deletion)', 'Delete:': 'Удалить:', +'deleted after first hit': 'deleted after first hit', +'Demo': 'Demo', 'Deploy': 'Развернуть', 'Deploy on Google App Engine': 'Развернуть на Google App Engine', 'Deploy to OpenShift': 'Deploy to OpenShift', +'Deploy to pythonanywhere': 'Deploy to pythonanywhere', +'Deploy to PythonAnywhere': 'Deploy to PythonAnywhere', +'Deployment form': 'Deployment form', +'Deployment Interface': 'Deployment Interface', 'Description': 'Описание', +'Description:': 'Description:', 'design': 'дизайн', 'DESIGN': 'ДИЗАЙН', 'Design for': 'Дизайн для', 'Detailed traceback description': 'Detailed traceback description', +'details': 'details', 'direction: ltr': 'направление: ltr', +'directory not found': 'directory not found', 'Disable': 'Disable', +'Disabled': 'Disabled', +'disabled in demo mode': 'disabled in demo mode', +'disabled in GAE mode': 'disabled in GAE mode', +'disabled in multi user mode': 'disabled in multi user mode', +'DISK': 'DISK', +'Disk Cache Keys': 'Disk Cache Keys', +'Disk Cleared': 'Disk Cleared', +'Display line numbers': 'Display line numbers', +'DO NOT use the "Pack compiled" feature.': 'DO NOT use the "Pack compiled" feature.', 'docs': 'docs', +'Docs': 'Docs', 'documentation': 'документация', 'done!': 'выполнено!', +'Downgrade': 'Downgrade', +'Download .w2p': 'Download .w2p', +'Download as .exe': 'Download as .exe', 'download layouts': 'загрузить шаблоны', +'Download layouts from repository': 'Download layouts from repository', 'download plugins': 'загрузить плагины', +'Download plugins from repository': 'Download plugins from repository', 'E-mail': 'E-mail', 'EDIT': 'ПРАВКА', 'Edit': 'Правка', +'edit all': 'edit all', 'Edit application': 'Правка приложения', 'edit controller': 'правка контроллера', +'edit controller:': 'edit controller:', 'Edit current record': 'Правка текущей записи', 'Edit Profile': 'Правка профиля', 'edit profile': 'правка профиля', 'Edit This App': 'Правка данного приложения', 'edit views:': 'правка видов:', +'Editing %s': 'Editing %s', 'Editing file': 'Правка файла', 'Editing file "%s"': 'Правка файла "%s"', 'Editing Language file': 'Правка языкового файла', 'Editing Plural Forms File': 'Editing Plural Forms File', +'Editor': 'Editor', +'Email Address': 'Email Address', +'Enable': 'Enable', +'Enable Close-Tag': 'Enable Close-Tag', +'Enable Code Folding': 'Enable Code Folding', 'Enterprise Web Framework': 'Enterprise Web Framework', +'Error': 'Error', 'Error logs for "%(app)s"': 'Журнал ошибок для "%(app)s"', 'Error snapshot': 'Error snapshot', 'Error ticket': 'Error ticket', 'Errors': 'Ошибка', 'escape': 'escape', +'Exception %(extype)s: %(exvalue)s': 'Exception %(extype)s: %(exvalue)s', +'Exception %s': 'Exception %s', 'Exception instance attributes': 'Атрибуты объекта исключения', +'Exit Fullscreen': 'Exit Fullscreen', 'Expand Abbreviation': 'Раскрыть аббревиатуру', +'Expand Abbreviation (html files only)': 'Expand Abbreviation (html files only)', 'export as csv file': 'Экспорт в CSV', +'Exports:': 'Exports:', 'exposes': 'открывает', +'exposes:': 'exposes:', 'extends': 'расширяет', +'failed to compile file because:': 'failed to compile file because:', 'failed to reload module': 'невозможно загрузить модуль', +'failed to reload module because:': 'failed to reload module because:', +'File': 'File', 'file "%(filename)s" created': 'файл "%(filename)s" создан', 'file "%(filename)s" deleted': 'файл "%(filename)s" удален', 'file "%(filename)s" uploaded': 'файл "%(filename)s" загружен', @@ -152,140 +261,308 @@ 'file "%s" of %s restored': 'файл "%s" из %s восстановлен', 'file changed on disk': 'файл изменился на диске', 'file does not exist': 'файл не существует', +'file not found': 'file not found', 'file saved on %(time)s': 'файл сохранен %(time)s', 'file saved on %s': 'файл сохранен %s', +'filename': 'filename', +'Filename': 'Filename', +'Files added': 'Files added', 'filter': 'фильтр', +'Find Next': 'Find Next', +'Find Previous': 'Find Previous', 'First name': 'Имя', +'Form has errors': 'Form has errors', 'Frames': 'Frames', 'Functions with no doctests will result in [passed] tests.': 'Функции без doctest будут давать [прошел] в тестах.', +'GAE Email': 'GAE Email', +'GAE Output': 'GAE Output', +'GAE Password': 'GAE Password', +'Generate': 'Generate', 'Get from URL:': 'Get from URL:', +'Git Pull': 'Git Pull', +'Git Push': 'Git Push', +'Globals##debug': 'Globals##debug', 'Go to Matching Pair': 'К подходящей паре', +'go!': 'go!', +'Google App Engine Deployment Interface': 'Google App Engine Deployment Interface', +'Google Application Id': 'Google Application Id', +'Goto': 'Goto', +'graph model': 'graph model', +'Graph Model': 'Graph Model', 'Group ID': 'ID группы', 'Hello World': 'Привет, Мир', 'Help': 'Помощь', +'here': 'here', 'Hide/Show Translated strings': 'Hide/Show Translated strings', +'Highlight current line': 'Highlight current line', +'Hits': 'Hits', +'Home': 'Home', +'honored only if the expression evaluates to true': 'honored only if the expression evaluates to true', 'htmledit': 'htmledit', +'If start the downgrade, be patient, it may take a while to rollback': 'If start the downgrade, be patient, it may take a while to rollback', +'If start the upgrade, be patient, it may take a while to download': 'If start the upgrade, be patient, it may take a while to download', +'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\n\t\tA green title indicates that all tests (if defined) passed. In this case test results are not shown.': 'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\n\t\tA green title indicates that all tests (if defined) passed. In this case test results are not shown.', 'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\nA green title indicates that all tests (if defined) passed. In this case test results are not shown.': 'Если отчет выше содержит номер ошибки, это указывает на ошибку при работе контроллера, до попытки выполнить doctest. Причиной чаще является неверные отступы или ошибки в коде вне функции. \nЗеленый заголовок указывает на успешное выполнение всех тестов. В этом случае результаты тестов не показываются.', 'If you answer "yes", be patient, it may take a while to download': 'Если вы ответили "Да", потерпите, загрузка может потребовать времени', 'If you answer yes, be patient, it may take a while to download': 'Если вы ответили "Да", потерпите, загрузка может потребовать времени', +'if your application uses a database other than sqlite you will then have to configure its DAL in pythonanywhere.': 'if your application uses a database other than sqlite you will then have to configure its DAL in pythonanywhere.', +'import': 'import', 'Import/Export': 'Импорт/Экспорт', +'In development, use the default Rocket webserver that is currently supported by this debugger.': 'In development, use the default Rocket webserver that is currently supported by this debugger.', 'includes': 'включает', +'Indent with tabs': 'Indent with tabs', 'Index': 'Индекс', 'index': 'index', 'insert new': 'вставить новый', 'insert new %s': 'вставить новый %s', 'inspect attributes': 'inspect attributes', 'Install': 'Установить', +'Installation of %(plugin)s for %(app)s': 'Installation of %(plugin)s for %(app)s', 'Installed applications': 'Установленные приложения', +'Interaction at %s line %s': 'Interaction at %s line %s', +'Interactive console': 'Interactive console', 'internal error': 'внутренняя ошибка', +'internal error: %s': 'internal error: %s', 'Internal State': 'Внутренний статус', 'Invalid action': 'Неверное действие', +'Invalid application name': 'Invalid application name', +'invalid circular reference': 'invalid circular reference', 'Invalid email': 'Неверный email', +'Invalid git repository specified.': 'Invalid git repository specified.', 'invalid password': 'неверный пароль', +'invalid password.': 'invalid password.', 'Invalid Query': 'Неверный запрос', 'invalid request': 'неверный запрос', +'Invalid request': 'Invalid request', +'invalid table names (auth_* tables already defined)': 'invalid table names (auth_* tables already defined)', 'invalid ticket': 'неверный тикет', +'Key': 'Key', 'Key bindings': 'Комбинации клавиш', 'Key bindings for ZenConding Plugin': 'Комбинации клавиш для плагина ZenConding', +'Keyboard shortcuts': 'Keyboard shortcuts', +'kill process': 'kill process', 'language file "%(filename)s" created/updated': 'Языковой файл "%(filename)s" создан/обновлен', 'Language files (static strings) updated': 'Языковые файлы (статичные строки) обновлены', 'languages': 'языки', 'Languages': 'Языки', 'languages updated': 'языки обновлены', 'Last name': 'Фамилия', +'Last Revision': 'Last Revision', 'Last saved on:': 'Последнее сохранение:', 'Layout': 'Верстка', 'License for': 'Лицензия для', +'License:': 'License:', +'Line Nr': 'Line Nr', +'Line number': 'Line number', +'lists by exception': 'lists by exception', +'lists by ticket': 'lists by ticket', +'Loading...': 'Loading...', 'loading...': 'загрузка...', +'Local Apps': 'Local Apps', 'locals': 'locals', +'Locals##debug': 'Locals##debug', 'located in the file': 'расположенный в файле', -'Login': 'Логин', 'login': 'логин', +'Login': 'Логин', +'Login successful': 'Login successful', 'Login to the Administrative Interface': 'Вход в интерфейс администратора', +'Login/Register': 'Login/Register', 'Logout': 'выход', 'Lost Password': 'Забыли пароль', +'lost password': 'lost password', 'lost password?': 'Пароль утерян?', 'Main Menu': 'Главное меню', +'Manage': 'Manage', +'Manage %(action)s': 'Manage %(action)s', +'Manage Access Control': 'Manage Access Control', +'Manage Admin Users/Students': 'Manage Admin Users/Students', +'Manage Cache': 'Manage Cache', +'Manage Students': 'Manage Students', 'Match Pair': 'Найти пару', +'Memberships': 'Memberships', 'Menu Model': 'Модель меню', 'merge': 'объединить', 'Merge Lines': 'Объединить линии', 'Models': 'Модели', 'models': 'модели', +'Modified On': 'Modified On', 'Modules': 'Модули', 'modules': 'модули', +'Multi User Mode': 'Multi User Mode', 'Name': 'Название', 'new application "%s" created': 'новое приложение "%s" создано', +'new application "%s" imported': 'new application "%s" imported', +'New Application Wizard': 'New Application Wizard', 'New application wizard': 'Мастер нового приложения', +'new plugin installed': 'new plugin installed', +'New plugin installed: %s': 'New plugin installed: %s', 'New Record': 'Новая запись', 'new record inserted': 'новая запись вставлена', 'New simple application': 'Новое простое приложение', +'next': 'next', +'next %s rows': 'next %s rows', 'next 100 rows': 'следующие 100 строк', 'Next Edit Point': 'Следующее место правки', 'NO': 'НЕТ', +'no changes': 'no changes', 'No databases in this application': 'В приложении нет базы данных', +'No Interaction yet': 'No Interaction yet', +'no match': 'no match', +'no package selected': 'no package selected', +'no permission to uninstall "%s"': 'no permission to uninstall "%s"', +'Node:': 'Node:', +'Not Authorized': 'Not Authorized', +'Not supported': 'Not supported', +'Note: If you receive an error with github status code of 128, ensure the system and account you are deploying from has a cooresponding ssh key configured in the openshift account.': 'Note: If you receive an error with github status code of 128, ensure the system and account you are deploying from has a cooresponding ssh key configured in the openshift account.', +"On production, you'll have to configure your webserver to use one process and multiple threads to use this debugger.": "On production, you'll have to configure your webserver to use one process and multiple threads to use this debugger.", +'Open new app in new window': 'Open new app in new window', +'OpenShift Deployment Interface': 'OpenShift Deployment Interface', +'OpenShift Output': 'OpenShift Output', +'or alternatively': 'or alternatively', +'Or Get from URL:': 'Or Get from URL:', 'or import from csv file': 'или испорт из cvs файла', 'or provide app url:': 'или URL приложения:', 'or provide application url:': 'или URL приложения:', 'Origin': 'Оригинал', 'Original/Translation': 'Оригинал/Перевод', +'Overview': 'Overview', 'Overwrite installed app': 'Переписать на установленное приложение', 'Pack all': 'упаковать все', 'Pack compiled': 'Архив скомпилирован', +'Pack custom': 'Pack custom', 'pack plugin': 'Упаковать плагин', 'Password': 'Пароль', +'password changed': 'password changed', +'Past revisions': 'Past revisions', +'Path to appcfg.py': 'Path to appcfg.py', +'Path to local openshift repo root.': 'Path to local openshift repo root.', 'Peeking at file': 'Просмотр', +'Permission': 'Permission', +'Permissions': 'Permissions', +'Please': 'Please', 'please wait!': 'подождите, пожалуйста!', +'Please wait, giving pythonanywhere a moment...': 'Please wait, giving pythonanywhere a moment...', +'plugin "%(plugin)s" deleted': 'plugin "%(plugin)s" deleted', 'Plugin "%s" in application': 'Плагин "%s" в приложении', +'plugin not specified': 'plugin not specified', +'Plugin page': 'Plugin page', 'plugins': 'плагины', 'Plugins': 'Плагины', 'Plural Form #%s': 'Plural Form #%s', 'Plural-Forms:': 'Plural-Forms:', 'Powered by': 'Обеспечен', +'Preferences saved correctly': 'Preferences saved correctly', +'Preferences saved on session only': 'Preferences saved on session only', +'previous %s rows': 'previous %s rows', 'previous 100 rows': 'предыдущие 100 строк', 'Previous Edit Point': 'Предыдущее место правки', +'Private files': 'Private files', +'private files': 'private files', +'Project Progress': 'Project Progress', +'Pull': 'Pull', +'Pull failed, certain files could not be checked out. Check logs for details.': 'Pull failed, certain files could not be checked out. Check logs for details.', +'Pull is not possible because you have unmerged files. Fix them up in the work tree, and then try again.': 'Pull is not possible because you have unmerged files. Fix them up in the work tree, and then try again.', +'Push': 'Push', +'Push failed, there are unmerged entries in the cache. Resolve merge issues manually and try again.': 'Push failed, there are unmerged entries in the cache. Resolve merge issues manually and try again.', +'pygraphviz library not found': 'pygraphviz library not found', +'PythonAnywhere Apps': 'PythonAnywhere Apps', +'PythonAnywhere Password': 'PythonAnywhere Password', 'Query:': 'Запрос:', +'RAM': 'RAM', +'RAM Cache Keys': 'RAM Cache Keys', +'Ram Cleared': 'Ram Cleared', +'Rapid Search': 'Rapid Search', +'Record': 'Record', 'record': 'запись', 'record does not exist': 'запись не существует', 'record id': 'id записи', 'Record ID': 'ID записи', -'register': 'зарегистрироваться', +'Record id': 'Record id', +'refresh': 'refresh', 'Register': 'Зарегистрироваться', +'register': 'зарегистрироваться', 'Registration key': 'Ключ регистрации', 'Reload routes': 'Reload routes', 'Remove compiled': 'Удалить скомпилированное', +'Removed Breakpoint on %s at line %s': 'Removed Breakpoint on %s at line %s', +'Replace': 'Replace', +'Replace All': 'Replace All', +'Repository (%s)': 'Repository (%s)', 'request': 'request', +'requires distutils, but not installed': 'requires distutils, but not installed', +'requires python-git, but not installed': 'requires python-git, but not installed', 'Reset Password key': 'Сброс пароля', 'Resolve Conflict file': 'Решить конфликт в файле', 'response': 'response', +'restart': 'restart', 'restore': 'восстановить', +'return': 'return', +'Revert': 'Revert', 'revert': 'откатиться', +'reverted to revision %s': 'reverted to revision %s', +'Revision %s': 'Revision %s', +'Revision:': 'Revision:', 'Role': 'Роль', +'Roles': 'Roles', 'Rows in table': 'Строк в таблице', +'Rows in Table': 'Rows in Table', 'Rows selected': 'Выбрано строк', +'rules are not defined': 'rules are not defined', 'rules:': 'rules:', +'Run tests': 'Run tests', +'Run tests in this file': 'Run tests in this file', "Run tests in this file (to run all files, you may also use the button labelled 'test')": "Run tests in this file (to run all files, you may also use the button labelled 'test')", 'Running on %s': 'Running on %s', 'Save': 'Save', 'save': 'сохранить', +'Save file:': 'Save file:', +'Save file: %s': 'Save file: %s', +'Save model as...': 'Save model as...', 'Save via Ajax': 'Сохранить через Ajax', 'Saved file hash:': 'Хэш сохраненного файла:', +'Screenshot %s': 'Screenshot %s', +'Search': 'Search', +'Select Files to Package': 'Select Files to Package', 'selected': 'выбрано', 'session': 'session', 'session expired': 'сессия истекла', +'Session saved correctly': 'Session saved correctly', +'Session saved on session only': 'Session saved on session only', +'Set Breakpoint on %s at line %s: %s': 'Set Breakpoint on %s at line %s: %s', 'shell': 'shell', +'Showing %s to %s of %s %s found': 'Showing %s to %s of %s %s found', 'Singular Form': 'Singular Form', 'Site': 'сайт', +'Size of cache:': 'Size of cache:', +'skip to generate': 'skip to generate', 'some files could not be removed': 'некоторые файлы нельзя удалить', +'Something went wrong please wait a few minutes before retrying': 'Something went wrong please wait a few minutes before retrying', +'Sorry, could not find mercurial installed': 'Sorry, could not find mercurial installed', +'source : db': 'source : db', +'source : filesystem': 'source : filesystem', +'Start a new app': 'Start a new app', +'Start searching': 'Start searching', 'Start wizard': 'запустить мастер', 'state': 'статус', +'Static': 'Static', 'static': 'статичные файлы', 'Static files': 'Статические файлы', +'Statistics': 'Statistics', +'Step': 'Step', +'step': 'step', +'stop': 'stop', 'Stylesheet': 'Таблицы стилей', 'submit': 'Отправить', +'Submit': 'Submit', +'successful': 'successful', 'Sure you want to delete this object?': 'Действительно хотите удалить данный объект?', +'switch to : db': 'switch to : db', +'switch to : filesystem': 'switch to : filesystem', +'Tab width (# characters)': 'Tab width (# characters)', 'table': 'таблица', +'Table': 'Table', 'Table name': 'Название таблицы', +'Temporary': 'Temporary', 'test': 'тест', 'test_def': 'test_def', 'test_for': 'test_for', @@ -294,6 +571,8 @@ 'Testing application': 'Тест приложения', 'Testing controller': 'Тест контроллера', 'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.': '"query" является условием вида "db.table1.field1 == \'значение\'". Что-либо типа "db.table1.field1 db.table2.field2 ==" ведет к SQL JOIN.', +'The app exists, was created by wizard, continue to overwrite!': 'The app exists, was created by wizard, continue to overwrite!', +'The app exists, was NOT created by wizard, continue to overwrite!': 'The app exists, was NOT created by wizard, continue to overwrite!', 'the application logic, each URL path is mapped in one exposed function in the controller': 'Логика приложения, каждый URL отображается в открытую функцию в контроллере', 'The application logic, each URL path is mapped in one exposed function in the controller': 'Логика приложения, каждый URL отображается к одной функции в контроллере', 'the data representation, define database tables and sets': 'представление данных, определить таблицы и наборы', @@ -301,43 +580,77 @@ 'The output of the file is a dictionary that was rendered by the view': 'Выводом файла является словарь, который создан в виде', 'The presentations layer, views are also known as templates': 'Слой презентации, виды так же известны, как шаблоны', 'the presentations layer, views are also known as templates': 'слой представления, виды известные так же как шаблоны', +'Theme': 'Theme', 'There are no controllers': 'Отсутствуют контроллеры', 'There are no models': 'Отсутствуют модели', 'There are no modules': 'Отсутствуют модули', 'There are no plugins': 'Отсутствуют плагины', +'There are no private files': 'There are no private files', 'There are no static files': 'Отсутствуют статичные файлы', +'There are no translators': 'There are no translators', 'There are no translators, only default language is supported': 'Отсутствуют переводчики, поддерживается только стандартный язык', 'There are no views': 'Отсутствуют виды', +'These files are not served, they are only available from within your app': 'These files are not served, they are only available from within your app', 'These files are served without processing, your images go here': 'Эти файлы обслуживаются без обработки, ваши изображения попадут сюда', 'these files are served without processing, your images go here': 'Эти файлы обслуживаются без обработки, ваши изображения попадут сюда', +"This debugger may not work properly if you don't have a threaded webserver or you're using multiple daemon processes.": "This debugger may not work properly if you don't have a threaded webserver or you're using multiple daemon processes.", 'This is a copy of the scaffolding application': 'Это копия сгенерированного приложения', +'This is an experimental feature and it needs more testing. If you decide to downgrade you do it at your own risk': 'This is an experimental feature and it needs more testing. If you decide to downgrade you do it at your own risk', +'This is an experimental feature and it needs more testing. If you decide to upgrade you do it at your own risk': 'This is an experimental feature and it needs more testing. If you decide to upgrade you do it at your own risk', 'This is the %(filename)s template': 'Это шаблон %(filename)s', +"This page can commit your changes to an openshift app repo and push them to your cloud instance. This assumes that you've already created the application instance using the web2py skeleton and have that repo somewhere on a filesystem that this web2py instance can access. This functionality requires GitPython installed and on the python path of the runtime that web2py is operating in.": "This page can commit your changes to an openshift app repo and push them to your cloud instance. This assumes that you've already created the application instance using the web2py skeleton and have that repo somewhere on a filesystem that this web2py instance can access. This functionality requires GitPython installed and on the python path of the runtime that web2py is operating in.", +'This page can upload your application to the Google App Engine computing cloud. Mind that you must first create indexes locally and this is done by installing the Google appserver and running the app locally with it once, or there will be errors when selecting records. Attention: deployment may take long time, depending on the network speed. Attention: it will overwrite your app.yaml. DO NOT SUBMIT TWICE.': 'This page can upload your application to the Google App Engine computing cloud. Mind that you must first create indexes locally and this is done by installing the Google appserver and running the app locally with it once, or there will be errors when selecting records. Attention: deployment may take long time, depending on the network speed. Attention: it will overwrite your app.yaml. DO NOT SUBMIT TWICE.', +'this page to see if a breakpoint was hit and debug interaction is required.': 'this page to see if a breakpoint was hit and debug interaction is required.', +'This will pull changes from the remote repo for application "%s"?': 'This will pull changes from the remote repo for application "%s"?', +'This will push changes to the remote repo for application "%s".': 'This will push changes to the remote repo for application "%s".', 'Ticket': 'Тикет', 'Ticket ID': 'Ticket ID', +'Ticket Missing': 'Ticket Missing', +'Time in Cache (h:m:s)': 'Time in Cache (h:m:s)', 'Timestamp': 'Время', 'TM': 'TM', 'to previous version.': 'на предыдущую версию.', 'To create a plugin, name a file/folder plugin_[name]': 'Для создания плагина назовите файл/папку plugin_[название]', +'To emulate a breakpoint programatically, write:': 'To emulate a breakpoint programatically, write:', +'to use the debugger!': 'to use the debugger!', 'toggle breakpoint': 'toggle breakpoint', +'Toggle comment': 'Toggle comment', +'Toggle Fullscreen': 'Toggle Fullscreen', 'Traceback': 'Traceback', 'translation strings for the application': 'строки перевода для приложения', 'Translation strings for the application': 'Строки перевода для приложения', 'try': 'try', 'try something like': 'попробовать что-либо вида', +'Try the mobile interface': 'Try the mobile interface', +'try view': 'try view', +'Type PDB debugger command in here and hit Return (Enter) to execute it.': 'Type PDB debugger command in here and hit Return (Enter) to execute it.', +'Type some Python code in here and hit Return (Enter) to execute it.': 'Type some Python code in here and hit Return (Enter) to execute it.', 'Unable to check for upgrades': 'Невозможно проверить обновления', 'unable to create application "%s"': 'невозможно создать приложение "%s" nicht möglich', 'unable to delete file "%(filename)s"': 'невозможно удалить файл "%(filename)s"', +'unable to delete file plugin "%(plugin)s"': 'unable to delete file plugin "%(plugin)s"', +'Unable to determine the line number!': 'Unable to determine the line number!', 'Unable to download': 'Невозможно загрузить', 'Unable to download app': 'Невозможно загрузить', +'Unable to download app because:': 'Unable to download app because:', +'unable to download layout': 'unable to download layout', +'unable to download plugin: %s': 'unable to download plugin: %s', +'Unable to download the list of plugins': 'Unable to download the list of plugins', +'unable to install plugin "%s"': 'unable to install plugin "%s"', 'unable to parse csv file': 'невозможно разобрать файл csv', 'unable to uninstall "%s"': 'невозможно удалить "%s"', +'unable to upgrade because "%s"': 'unable to upgrade because "%s"', 'uncheck all': 'снять выбор всего', 'Uninstall': 'Удалить', +'Unsupported webserver working mode: %s': 'Unsupported webserver working mode: %s', 'update': 'обновить', 'update all languages': 'обновить все языки', 'Update:': 'Обновить:', +'Upgrade': 'Upgrade', +'upgrade now to %s': 'upgrade now to %s', 'upgrade web2py now': 'обновить web2py сейчас', 'upload': 'загрузить', +'Upload': 'Upload', 'Upload & install packed application': 'Загрузить и установить приложение в архиве', 'Upload a package:': 'Загрузить пакет:', 'Upload and install packed application': 'Upload and install packed application', @@ -348,25 +661,48 @@ 'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Используйте (...)&(...) для AND, (...)|(...) для OR, и ~(...) для NOT при создании сложных запросов.', 'Use an url:': 'Используйте url:', 'user': 'пользователь', +'User': 'User', 'User ID': 'ID пользователя', +'Username': 'Username', +'Users': 'Users', +'Using the shell may lock the database to other users of this app.': 'Using the shell may lock the database to other users of this app.', 'variables': 'переменные', 'Version': 'Версия', -'versioning': 'версии', 'Versioning': 'Versioning', +'versioning': 'версии', 'View': 'Вид', 'view': 'вид', 'Views': 'Виды', 'views': 'виды', +'Warning!': 'Warning!', +'WARNING:': 'WARNING:', +'WARNING: The following views could not be compiled:': 'WARNING: The following views could not be compiled:', 'Web Framework': 'Web Framework', +'web2py Admin Password': 'web2py Admin Password', +'web2py apps to deploy': 'web2py apps to deploy', +'web2py Debugger': 'web2py Debugger', +'web2py downgrade': 'web2py downgrade', 'web2py is up to date': 'web2py обновлен', +'web2py online debugger': 'web2py online debugger', 'web2py Recent Tweets': 'последние твиты по web2py', +'web2py upgrade': 'web2py upgrade', +'web2py upgraded; please restart it': 'web2py upgraded; please restart it', 'Welcome %s': 'Добро пожаловать, %s', 'Welcome to web2py': 'Добро пожаловать в web2py', 'Which called the function': 'Который вызвал функцию', +'Working...': 'Working...', 'Wrap with Abbreviation': 'Заключить в аббревиатуру', +'WSGI reference name': 'WSGI reference name', 'xml': 'xml', 'YES': 'ДА', +'Yes': 'Yes', 'You are successfully running web2py': 'Вы успешно запустили web2by', +'You can also set and remove breakpoint in the edit window, using the Toggle Breakpoint button': 'You can also set and remove breakpoint in the edit window, using the Toggle Breakpoint button', +'You can inspect variables using the console below': 'You can inspect variables using the console below', 'You can modify this application and adapt it to your needs': 'Вы можете изменить это приложение и подогнать под свои нужды', +'You have one more login attempt before you are locked out': 'You have one more login attempt before you are locked out', +'You need to set up and reach a': 'You need to set up and reach a', +'You only need these if you have already registered': 'You only need these if you have already registered', 'You visited the url': 'Вы посетили URL', +'Your application will be blocked until you click an action button (next, step, continue, etc.)': 'Your application will be blocked until you click an action button (next, step, continue, etc.)', } diff --git a/applications/admin/languages/sl.py b/applications/admin/languages/sl.py index e4a1c1c6..c6767b97 100755 --- a/applications/admin/languages/sl.py +++ b/applications/admin/languages/sl.py @@ -3,276 +3,257 @@ '!langcode!': 'sl', '!langname!': 'Slovenski', '"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN': '"Popravi" je izbirni izraz kot npr.: "stolpec1 = \'novavrednost\'". Rezultatov JOIN operacije ne morete popravljati ali brisati', -'%Y-%m-%d': '%Y-%m-%d', -'%Y-%m-%d %H:%M:%S': '%Y-%m-%d %H:%M:%S', +'"User Exception" debug mode. ': '"User Exception" debug mode. ', +'%s': '%s', '%s %%{row} deleted': '%s vrstic izbrisanih', '%s %%{row} updated': '%s vrstic popravljeno', +'%s selected': '%s selected', +'%s students registered': '%s students registered', +'%Y-%m-%d': '%Y-%m-%d', +'%Y-%m-%d %H:%M:%S': '%Y-%m-%d %H:%M:%S', '(requires internet access)': '(zahteva internetni dostop)', +'(requires internet access, experimental)': '(requires internet access, experimental)', '(something like "it-it")': '(nekaj kot "sl-SI" ali samo "sl")', +'(version %s)': '(version %s)', +'?': '?', '@markmin\x01Searching: **%s** %%{file}': 'Iskanje: **%s** datoteke', 'A new version of web2py is available': 'Nova različica web2py je na voljo', 'A new version of web2py is available: %s': 'Nova različica web2py je na voljo: %s', -'ATTENTION: Login requires a secure (HTTPS) connection or running on localhost.': 'POZOR: Prijava zahteva varno povezavo (HTTPS) ali lokalni (localhost) dostop.', -'ATTENTION: TESTING IS NOT THREAD SAFE SO DO NOT PERFORM MULTIPLE TESTS CONCURRENTLY.': 'POZOR: Testiranje ni večopravilno, zato ne poganjajte več testov hkrati.', -'ATTENTION: This is an experimental feature and it needs more testing.': 'POZOR: To je preizkusni fazi in potrebuje več testiranja.', -'ATTENTION: you cannot edit the running application!': 'POZOR: Ne morete urejati aplikacije, ki že teče!', 'Abort': 'Preklic', 'About': 'Vizitka', 'About application': 'O aplikaciji', +'Accept Terms': 'Accept Terms', +'Add breakpoint': 'Add breakpoint', +'additional code for your application': 'dodatna koda za vašo aplikacijo', 'Additional code for your application': 'Dodatna koda za vašo aplikacijo', +'Admin design page': 'Admin design page', +'admin disabled because no admin password': 'skrbnik izključen, ker ni skrbniškega gesla', +'admin disabled because not supported on google app engine': 'admin disabled because not supported on google app engine', +'admin disabled because not supported on google apps engine': 'skrbnik izključen, ker ni podprt na Google App sistemu', +'admin disabled because too many invalid login attempts': 'admin disabled because too many invalid login attempts', +'admin disabled because unable to access password file': 'skrbnik izključen, ker ne morem dostopati do datoteke z gesli', 'Admin is disabled because insecure channel': 'Skrbnik je izključen zaradi nezavarovane povezave', 'Admin is disabled because unsecure channel': 'Skrbnik je izključen zaradi nezavarovane povezave', 'Admin language': 'Skrbniški jezik', +'Admin versioning page': 'Admin versioning page', +'administrative interface': 'skrbniški vmesnik', 'Administrator Password:': 'Skrbniško geslo:', +'and rename it (required):': 'in jo preimenujte (obvezno):', +'and rename it:': ' in jo preimenujte:', +'App does not exist or you are not authorized': 'App does not exist or you are not authorized', +'appadmin': 'appadmin', +'appadmin is disabled because insecure channel': 'Appadmin izključen, ker zahteva varno (HTTPS) povezavo', +'Application': 'Application', +'application "%s" uninstalled': 'Aplikacija "%s" odstranjena', +'Application cannot be generated in demo mode': 'Application cannot be generated in demo mode', +'application compiled': 'aplikacija prevedena', +'Application exists already': 'Application exists already', +'application is compiled and cannot be designed': 'aplikacija je prevedena in je ne morete popravljati', 'Application name:': 'Ime aplikacije:', +'Application updated via git pull': 'Application updated via git pull', +'are not used': 'are not used', +'are not used yet': 'are not used yet', 'Are you sure you want to delete file "%s"?': 'Ali res želite pobrisati datoteko "%s"?', +'Are you sure you want to delete plugin "%s"?': 'Are you sure you want to delete plugin "%s"?', 'Are you sure you want to delete this object?': 'Ali res želite izbrisati ta predmet?', 'Are you sure you want to uninstall application "%s"': 'Ali res želite odstraniti program "%s"', 'Are you sure you want to uninstall application "%s"?': 'Ali res želite odstraniti program "%s"?', 'Are you sure you want to upgrade web2py now?': 'Ali želite sedaj nadgraditi web2py?', +'Are you sure?': 'Are you sure?', +'arguments': 'argumenti', +'at char %s': 'at char %s', +'at line %s': 'at line %s', +'ATTENTION:': 'ATTENTION:', +'ATTENTION: Login requires a secure (HTTPS) connection or running on localhost.': 'POZOR: Prijava zahteva varno povezavo (HTTPS) ali lokalni (localhost) dostop.', +'ATTENTION: TESTING IS NOT THREAD SAFE SO DO NOT PERFORM MULTIPLE TESTS CONCURRENTLY.': 'POZOR: Testiranje ni večopravilno, zato ne poganjajte več testov hkrati.', +'ATTENTION: This is an experimental feature and it needs more testing.': 'POZOR: To je preizkusni fazi in potrebuje več testiranja.', +'ATTENTION: you cannot edit the running application!': 'POZOR: Ne morete urejati aplikacije, ki že teče!', 'Authentication': 'Avtentikacija', +'Autocomplete Python Code': 'Autocomplete Python Code', 'Available databases and tables': 'Podatkovne baze in tabele', +'Available Databases and Tables': 'Available Databases and Tables', +'back': 'nazaj', +'Back to the plugins list': 'Back to the plugins list', +'Back to wizard': 'Back to wizard', +'Basics': 'Basics', +'beautify': 'olepšaj', 'Begin': 'Začni', +'breakpoint': 'breakpoint', +'Breakpoints': 'Breakpoints', +'breakpoints': 'breakpoints', +'Bulk Register': 'Bulk Register', +'Bulk Student Registration': 'Bulk Student Registration', +'Cache': 'Cache', +'cache': 'predpomnilnik', +'Cache Cleared': 'Cache Cleared', +'Cache Keys': 'Cache Keys', +'cache, errors and sessions cleaned': 'Predpomnilnik, napake in seja so očiščeni', +'call': 'kliči', +'can be a git repo': 'can be a git repo', +'Cancel': 'Cancel', 'Cannot be empty': 'Ne sme biti prazno', 'Cannot compile: there are errors in your app. Debug it, correct errors and try again.': 'Nemogoče prevajanje: napake v programu. Odpravite napake in poskusite ponovno.', -'Change Password': 'Spremeni geslo', +'Cannot compile: there are errors in your app:': 'Cannot compile: there are errors in your app:', +'cannot create file': 'ne morem ustvariti datoteke', +'cannot upload file "%(filename)s"': 'ne morem naložiti datoteke "%(filename)s"', +'Change Admin Password': 'Change Admin Password', 'Change admin password': 'Spremenite skrbniško geslo', +'change editor settings': 'change editor settings', +'Change Password': 'Spremeni geslo', +'change password': 'spremeni geslo', +'Changelog': 'Changelog', +'check all': 'označi vse', 'Check for upgrades': 'Preveri za posodobitve', 'Check to delete': 'Odkljukajte, če želite izbrisati', 'Checking for upgrades...': 'Preverjam posodobitve...', 'Clean': 'Počisti', +'Clear': 'Clear', +'Clear CACHE?': 'Clear CACHE?', +'Clear DISK': 'Clear DISK', +'Clear RAM': 'Clear RAM', +'click here for online examples': 'kliknite za spletne primere', +'click here for the administrative interface': 'kliknite za skrbniški vmesnik', 'Click row to expand traceback': 'Kliknite vrstico da razširite sledenje', 'Click row to view a ticket': 'Kliknite vrstico za ogled listka', +'click to check for upgrades': 'kliknite za preverjanje nadgradenj', 'Client IP': 'IP klienta', +'code': 'koda', +'Code listing': 'Code listing', +'collapse/expand all': 'zapri/odpri vse', +'Command': 'Command', +'Comment:': 'Comment:', +'Commit': 'Commit', +'Commit form': 'Commit form', +'Committed files': 'Committed files', 'Compile': 'Prevedi', +'Compile (all or nothing)': 'Compile (all or nothing)', +'Compile (skip failed views)': 'Compile (skip failed views)', +'compiled application removed': 'prevedena aplikacija je odstranjena', +'Condition': 'Condition', +'continue': 'continue', 'Controller': 'Krmilnik', 'Controllers': 'Krmilniki', +'controllers': 'krmilniki', 'Copyright': 'Copyright', 'Count': 'Število', 'Create': 'Ustvari', +'create file with filename:': 'Ustvari datoteko z imenom:', +'create new application:': 'Ustvari novo aplikacijo:', 'Create new simple application': 'Ustvari novo enostavno aplikacijo', +'Create/Upload': 'Create/Upload', +'created by': 'ustvaril', +'Created by:': 'Created by:', +'Created On': 'Created On', +'Created on:': 'Created on:', +'crontab': 'crontab', 'Current request': 'Trenutna zahteva', 'Current response': 'Trenutni odgovor', 'Current session': 'Trenutna seja', -'DB Model': 'Podatkovni model', -'DESIGN': 'Izgled', +'currently running': 'trenutno teče', +'currently saved or': 'trenutno shranjeno ali', +'customize me!': 'Spremeni me!', +'data uploaded': 'podatki naloženi', 'Database': 'Podatkovna baza', +'database': 'podatkovna baza', +'Database %s select': 'Database %s select', +'database %s select': 'izberi podatkovno bazo %s ', +'Database administration': 'Database administration', +'database administration': 'upravljanje s podatkovno bazo', +'Database Administration (appadmin)': 'Database Administration (appadmin)', 'Date and Time': 'Datum in čas', +'db': 'db', +'DB Model': 'Podatkovni model', +'Debug': 'Debug', +'defines tables': 'definiraj tabele', 'Delete': 'Izbriši', +'delete': 'izbriši', +'delete all checked': 'izbriši vse označene', +'delete plugin': 'izbriši vtičnik', 'Delete this file (you will be asked to confirm deletion)': 'Izbriši to datoteko (izbris boste morali potrditi)', 'Delete:': 'Izbriši:', +'deleted after first hit': 'deleted after first hit', +'Demo': 'Demo', 'Deploy': 'Namesti', 'Deploy on Google App Engine': 'Prenesi na Google App sistem', +'Deploy to OpenShift': 'Deploy to OpenShift', +'Deploy to pythonanywhere': 'Deploy to pythonanywhere', +'Deploy to PythonAnywhere': 'Deploy to PythonAnywhere', +'Deployment form': 'Deployment form', +'Deployment Interface': 'Deployment Interface', 'Description': 'Opis', +'Description:': 'Description:', +'design': 'oblikuj', +'DESIGN': 'Izgled', 'Design for': 'Oblikuj za', 'Detailed traceback description': 'Natačen opis sledenja', +'details': 'podrobnosti', +'direction: ltr': 'smer: ltr', +'directory not found': 'directory not found', 'Disable': 'Izključi', +'Disabled': 'Disabled', +'disabled in demo mode': 'disabled in demo mode', +'disabled in GAE mode': 'disabled in GAE mode', +'disabled in multi user mode': 'disabled in multi user mode', +'DISK': 'DISK', +'Disk Cache Keys': 'Disk Cache Keys', +'Disk Cleared': 'Disk Cleared', +'Display line numbers': 'Display line numbers', +'DO NOT use the "Pack compiled" feature.': 'DO NOT use the "Pack compiled" feature.', +'docs': 'docs', +'Docs': 'Docs', +'documentation': 'dokumentacija', +'done!': 'Narejeno!', +'Downgrade': 'Downgrade', +'Download .w2p': 'Download .w2p', +'Download as .exe': 'Download as .exe', +'download layouts': 'prenesi postavitev', +'Download layouts from repository': 'Download layouts from repository', +'download plugins': 'prenesi vtičnik', +'Download plugins from repository': 'Download plugins from repository', 'E-mail': 'E-mail', 'EDIT': 'UREDI', 'Edit': 'Uredi', -'Edit Profile': 'Uredi profil', -'Edit This App': 'Uredi ta program', +'edit all': 'edit all', 'Edit application': 'Uredi program', +'edit controller': 'uredi krmilnik', +'edit controller:': 'edit controller:', 'Edit current record': 'Uredi trenutni zapis', -'Editing Language file': 'Uredi jezikovno datoteko', +'Edit Profile': 'Uredi profil', +'edit profile': 'uredi profil', +'Edit This App': 'Uredi ta program', +'edit views:': 'urejaj poglede:', +'Editing %s': 'Editing %s', 'Editing file': 'Urejanje datoteke', 'Editing file "%s"': 'Urejanje datoteke "%s"', +'Editing Language file': 'Uredi jezikovno datoteko', +'Editing Plural Forms File': 'Editing Plural Forms File', +'Editor': 'Editor', +'Email Address': 'Email Address', +'Enable': 'Enable', +'Enable Close-Tag': 'Enable Close-Tag', +'Enable Code Folding': 'Enable Code Folding', 'Enterprise Web Framework': 'Enterprise Web Framework', 'Error': 'Napaka', 'Error logs for "%(app)s"': 'Dnevnik napak za "%(app)s"', 'Error snapshot': 'Posnetek napake', 'Error ticket': 'Listek napake', 'Errors': 'Napake', -'Exception instance attributes': 'Lastnosti instance izjeme', -'Expand Abbreviation': 'Razširi okrajšave', -'File': 'Datoteka', -'First name': 'Ime', -'Frames': 'Okvirji', -'Functions with no doctests will result in [passed] tests.': 'Funkcije brez doctest bodo opravile teste brez preverjanja.', -'Get from URL:': 'Naloži iz URL:', -'Go to Matching Pair': 'Pojdi k ujemalnemu paru', -'Group ID': 'ID skupine', -'Hello World': 'Pozdravljen, Svet!', -'Help': 'Pomoč', -'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\nA green title indicates that all tests (if defined) passed. In this case test results are not shown.': 'Če poročilo zgoraj vsebuje številko listka to pomeni napako pri izvajanju krmilnika, še preden so se izvedli doctesti. To ponavadi pomeni napako pri zamiku programske vrstice ali izven funkcije.\nZelen naslov označuje, da so vsi testi opravljeni. V tem primeru testi niso prikazani.', -'If you answer "yes", be patient, it may take a while to download': 'Če odgovorite z "DA", potrpite. Prenos traja nekaj časa', -'If you answer yes, be patient, it may take a while to download': 'Če odgovorite z "DA", potrpite. Prenos traja nekaj časa', -'Import/Export': 'Uvoz/Izvoz', -'Index': 'Indeks', -'Install': 'Namesti', -'Installed applications': 'Nameščene aplikacije', -'Internal State': 'Notranje stanje', -'Invalid Query': 'Napačno povpraševanje', -'Invalid action': 'Napačno dejanje', -'Invalid email': 'Napačen e-naslov', -'Key bindings': 'Povezave tipk', -'Key bindings for ZenConding Plugin': 'Povezave tipk za ZenConding vtičnik', -'Language files (static strings) updated': 'Jezikovna datoteka (statično besedilo) posodobljeno', -'Languages': 'Jeziki', -'Last name': 'Priimek', -'Last saved on:': 'Zadnjič shranjeno:', -'Layout': 'Postavitev', -'License for': 'Licenca za', -'Login': 'Prijava', -'Login to the Administrative Interface': 'Prijava v skrbniški vmesnik', -'Logout': 'Odjava', -'Lost Password': 'Izgubljeno geslo', -'Main Menu': 'Glavni meni', -'Match Pair': 'Ujemalni par', -'Menu Model': 'Model menija', -'Merge Lines': 'Združi vrstice', -'Models': 'Modeli', -'Modules': 'Moduli', -'NO': 'NE', -'Name': 'Ime', -'New Application Wizard': 'Čarovnik za novo aplikacijo', -'New Record': 'Nov zapis', -'New application wizard': 'Čarovnik za novo aplikacijo', -'New simple application': 'Nova enostavna aplikacija', -'Next Edit Point': 'Naslednja točka urejanja', -'No databases in this application': 'V tem programu ni podatkovnih baz', -'Origin': 'Izvor', -'Original/Translation': 'Izvor/Prevod', -'Overwrite installed app': 'Prepiši obstoječi program', -'Pack all': 'Zapakiraj vse', -'Pack compiled': 'Paket preveden', -'Password': 'Geslo', -'Peeking at file': 'Vpogled v datoteko', -'Plugin "%s" in application': 'Vtičnik "%s" v aplikaciji', -'Plugins': 'Vtičniki', -'Powered by': 'Narejeno z', -'Previous Edit Point': 'Prejšnja točka urejanja', -'Query:': 'Vprašanje:', -'Record ID': 'ID zapisa', -'Register': 'Registracija', -'Registration key': 'Registracijski ključ', -'Reload routes': 'Ponovno naloži preusmeritve', -'Remove compiled': 'Odstrani prevedeno', -'Reset Password key': 'Ponastavi ključ gesla', -'Resolve Conflict file': 'Datoteka za razrešitev problemov', -'Role': 'Vloga', -'Rows in table': 'Vrstic v tabeli', -'Rows selected': 'Izbranih vrstic', -"Run tests in this file (to run all files, you may also use the button labelled 'test')": "Poženi teste v tej datoteki (za vse teste uporabite gumb 'test')", -'Save via Ajax': 'Shrani preko AJAX', -'Saved file hash:': 'Koda shranjene datoteke:', -'Site': 'Spletišče', -'Sorry, could not find mercurial installed': 'Oprostite. Mercurial ni nameščen.', -'Start a new app': 'Začnite z novo aplikacijo', -'Start wizard': 'Zaženi čarovnika', -'Static files': 'Statične datoteke', -'Stylesheet': 'CSS datoteka', -'Sure you want to delete this object?': 'Ali res želite izbrisati ta predmet?', -'TM': 'TM', -'Table name': 'Ime tabele', -'Testing application': 'Testiranje programa', -'Testing controller': 'Testiranje krmilnika', -'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.': '"vprašanje" je pogoj kot npr. "db.table1.field1 == \'vrednost\'". Nekaj kot "db.table1.field1 == db.table2.field2" izvede SQL operacijo JOIN.', -'The application logic, each URL path is mapped in one exposed function in the controller': 'Logika delovanja aplikacije. Vsak URL je povezan z eno objavljeno funkcijo v krmilniku', -'The data representation, define database tables and sets': 'Predstavitev podatkov. Definirajte podatkovne tabele in množice', -'The output of the file is a dictionary that was rendered by the view': 'Rezultat datoteke je slovar, ki ga predela pogled', -'The presentations layer, views are also known as templates': 'Predstavitveni nivo. Pogledi so znani tudi kot predloge', -'There are no controllers': 'Ni krmilnikov', -'There are no models': 'Ni modelov', -'There are no modules': 'Ni modulov', -'There are no plugins': 'Ni vtičnikov', -'There are no static files': 'Ni statičnih datotek', -'There are no translators, only default language is supported': 'Ni prevodov. Podprt je samo privzeti jezik', -'There are no views': 'Ni pogledov', -'These files are served without processing, your images go here': 'Te datoteke so poslane brez obdelave. Vaše slike shranite tu.', -'This is a copy of the scaffolding application': 'To je kopija okvirne aplikacije', -'This is the %(filename)s template': 'To je predloga %(filename)s', -'Ticket': 'Listek', -'Ticket ID': 'ID listka', -'Timestamp': 'Časovni žig', -'To create a plugin, name a file/folder plugin_[name]': 'Če želite ustvariti vtičnik, poimenujte datoteko/mapo plugin_[ime]', -'Traceback': 'Sledljivost', -'Translation strings for the application': 'Prevajalna besedila za aplikacijo', -'Unable to check for upgrades': 'Ne morem preveriti posodobitev', -'Unable to download': 'Ne morem prenesti datoteke', -'Unable to download app': 'Ne morem prenesti programa', -'Uninstall': 'Odstrani', -'Update:': 'Posodobitev:', -'Upload & install packed application': 'Naloži in namesti pakirano aplikacijo', -'Upload a package:': 'Naloži paket:', -'Upload and install packed application': 'Naloži in namesti pakirano aplikacijo', -'Upload existing application': 'Naloži obstoječo aplikacijo', -'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Uporabie (...)&(...) za AND, (...)|(...) za OR, in ~(...) za NOT pri gradnji kompleksnih povpraševanj.', -'Use an url:': 'Uporabite URL:', -'User ID': 'ID uporabnika', -'Version': 'Različica', -'Versioning': 'Versioning', -'View': 'Pogled', -'Views': 'Pogledi', -'Web Framework': 'Web Framework', -'Welcome %s': 'Dobrodošli, %s', -'Welcome to web2py': 'Dobrodošli v web2py', -'Which called the function': 'Ki je klical funkcijo', -'Wrap with Abbreviation': 'Ovij z okrajšavo', -'YES': 'DA', -'You are successfully running web2py': 'Uspešno ste pognali web2py', -'You can modify this application and adapt it to your needs': 'Lahko spremenite to aplikacijo in jo prilagodite vašim potrebam', -'You visited the url': 'Obiskali ste URL', -'additional code for your application': 'dodatna koda za vašo aplikacijo', -'admin disabled because no admin password': 'skrbnik izključen, ker ni skrbniškega gesla', -'admin disabled because not supported on google apps engine': 'skrbnik izključen, ker ni podprt na Google App sistemu', -'admin disabled because unable to access password file': 'skrbnik izključen, ker ne morem dostopati do datoteke z gesli', -'administrative interface': 'skrbniški vmesnik', -'and rename it (required):': 'in jo preimenujte (obvezno):', -'and rename it:': ' in jo preimenujte:', -'appadmin': 'appadmin', -'appadmin is disabled because insecure channel': 'Appadmin izključen, ker zahteva varno (HTTPS) povezavo', -'application "%s" uninstalled': 'Aplikacija "%s" odstranjena', -'application compiled': 'aplikacija prevedena', -'application is compiled and cannot be designed': 'aplikacija je prevedena in je ne morete popravljati', -'arguments': 'argumenti', -'back': 'nazaj', -'beautify': 'olepšaj', -'cache': 'predpomnilnik', -'cache, errors and sessions cleaned': 'Predpomnilnik, napake in seja so očiščeni', -'call': 'kliči', -'cannot create file': 'ne morem ustvariti datoteke', -'cannot upload file "%(filename)s"': 'ne morem naložiti datoteke "%(filename)s"', -'change password': 'spremeni geslo', -'check all': 'označi vse', -'click here for online examples': 'kliknite za spletne primere', -'click here for the administrative interface': 'kliknite za skrbniški vmesnik', -'click to check for upgrades': 'kliknite za preverjanje nadgradenj', -'code': 'koda', -'collapse/expand all': 'zapri/odpri vse', -'compiled application removed': 'prevedena aplikacija je odstranjena', -'controllers': 'krmilniki', -'create file with filename:': 'Ustvari datoteko z imenom:', -'create new application:': 'Ustvari novo aplikacijo:', -'created by': 'ustvaril', -'crontab': 'crontab', -'currently running': 'trenutno teče', -'currently saved or': 'trenutno shranjeno ali', -'customize me!': 'Spremeni me!', -'data uploaded': 'podatki naloženi', -'database': 'podatkovna baza', -'database %s select': 'izberi podatkovno bazo %s ', -'database administration': 'upravljanje s podatkovno bazo', -'db': 'db', -'defines tables': 'definiraj tabele', -'delete': 'izbriši', -'delete all checked': 'izbriši vse označene', -'delete plugin': 'izbriši vtičnik', -'design': 'oblikuj', -'details': 'podrobnosti', -'direction: ltr': 'smer: ltr', -'documentation': 'dokumentacija', -'done!': 'Narejeno!', -'download layouts': 'prenesi postavitev', -'download plugins': 'prenesi vtičnik', -'edit controller': 'uredi krmilnik', -'edit profile': 'uredi profil', -'edit views:': 'urejaj poglede:', 'escape': 'escape', +'Exception %(extype)s: %(exvalue)s': 'Exception %(extype)s: %(exvalue)s', +'Exception %s': 'Exception %s', +'Exception instance attributes': 'Lastnosti instance izjeme', +'Exit Fullscreen': 'Exit Fullscreen', +'Expand Abbreviation': 'Razširi okrajšave', +'Expand Abbreviation (html files only)': 'Expand Abbreviation (html files only)', 'export as csv file': 'izvozi kot CSV', +'Exports:': 'Exports:', 'exposes': 'objavlja', +'exposes:': 'exposes:', 'extends': 'razširja', +'failed to compile file because:': 'failed to compile file because:', 'failed to reload module': 'nisem uspel ponovno naložiti modula', +'failed to reload module because:': 'failed to reload module because:', +'File': 'Datoteka', 'file "%(filename)s" created': 'datoteka "%(filename)s" ustvarjena', 'file "%(filename)s" deleted': 'datoteka "%(filename)s" izbrisana', 'file "%(filename)s" uploaded': 'datoteka "%(filename)s" prenešena', @@ -280,89 +261,447 @@ 'file "%s" of %s restored': 'datoteka "%s" od %s obnovljena', 'file changed on disk': 'datoteka je bila spremenjena', 'file does not exist': 'datoteka ne obstaja', +'file not found': 'file not found', 'file saved on %(time)s': 'datoteka shranjena %(time)s', 'file saved on %s': 'datoteka shranjena %s', +'filename': 'filename', +'Filename': 'Filename', +'Files added': 'Files added', 'filter': 'fiter', +'Find Next': 'Find Next', +'Find Previous': 'Find Previous', +'First name': 'Ime', +'Form has errors': 'Form has errors', +'Frames': 'Okvirji', +'Functions with no doctests will result in [passed] tests.': 'Funkcije brez doctest bodo opravile teste brez preverjanja.', +'GAE Email': 'GAE Email', +'GAE Output': 'GAE Output', +'GAE Password': 'GAE Password', +'Generate': 'Generate', +'Get from URL:': 'Naloži iz URL:', +'Git Pull': 'Git Pull', +'Git Push': 'Git Push', +'Globals##debug': 'Globals##debug', +'Go to Matching Pair': 'Pojdi k ujemalnemu paru', +'go!': 'go!', +'Google App Engine Deployment Interface': 'Google App Engine Deployment Interface', +'Google Application Id': 'Google Application Id', +'Goto': 'Goto', +'graph model': 'graph model', +'Graph Model': 'Graph Model', +'Group ID': 'ID skupine', +'Hello World': 'Pozdravljen, Svet!', +'Help': 'Pomoč', +'here': 'here', +'Hide/Show Translated strings': 'Hide/Show Translated strings', +'Highlight current line': 'Highlight current line', +'Hits': 'Hits', +'Home': 'Home', +'honored only if the expression evaluates to true': 'honored only if the expression evaluates to true', 'htmledit': 'htmledit', +'If start the downgrade, be patient, it may take a while to rollback': 'If start the downgrade, be patient, it may take a while to rollback', +'If start the upgrade, be patient, it may take a while to download': 'If start the upgrade, be patient, it may take a while to download', +'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\n\t\tA green title indicates that all tests (if defined) passed. In this case test results are not shown.': 'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\n\t\tA green title indicates that all tests (if defined) passed. In this case test results are not shown.', +'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\nA green title indicates that all tests (if defined) passed. In this case test results are not shown.': 'Če poročilo zgoraj vsebuje številko listka to pomeni napako pri izvajanju krmilnika, še preden so se izvedli doctesti. To ponavadi pomeni napako pri zamiku programske vrstice ali izven funkcije.\nZelen naslov označuje, da so vsi testi opravljeni. V tem primeru testi niso prikazani.', +'If you answer "yes", be patient, it may take a while to download': 'Če odgovorite z "DA", potrpite. Prenos traja nekaj časa', +'If you answer yes, be patient, it may take a while to download': 'Če odgovorite z "DA", potrpite. Prenos traja nekaj časa', +'if your application uses a database other than sqlite you will then have to configure its DAL in pythonanywhere.': 'if your application uses a database other than sqlite you will then have to configure its DAL in pythonanywhere.', +'import': 'import', +'Import/Export': 'Uvoz/Izvoz', +'In development, use the default Rocket webserver that is currently supported by this debugger.': 'In development, use the default Rocket webserver that is currently supported by this debugger.', 'includes': 'vključuje', +'Indent with tabs': 'Indent with tabs', +'Index': 'Indeks', 'index': 'indeks', 'insert new': 'vstavi nov', 'insert new %s': 'vstavi nov %s', 'inspect attributes': 'pregled lastnosti', +'Install': 'Namesti', +'Installation of %(plugin)s for %(app)s': 'Installation of %(plugin)s for %(app)s', +'Installed applications': 'Nameščene aplikacije', +'Interaction at %s line %s': 'Interaction at %s line %s', +'Interactive console': 'Interactive console', 'internal error': 'notranja napaka', +'internal error: %s': 'internal error: %s', +'Internal State': 'Notranje stanje', +'Invalid action': 'Napačno dejanje', +'Invalid application name': 'Invalid application name', +'invalid circular reference': 'invalid circular reference', +'Invalid email': 'Napačen e-naslov', +'Invalid git repository specified.': 'Invalid git repository specified.', 'invalid password': 'napačno geslo', +'invalid password.': 'invalid password.', +'Invalid Query': 'Napačno povpraševanje', 'invalid request': 'napačna zahteva', +'Invalid request': 'Invalid request', +'invalid table names (auth_* tables already defined)': 'invalid table names (auth_* tables already defined)', 'invalid ticket': 'napačen kartonček', +'Key': 'Key', +'Key bindings': 'Povezave tipk', +'Key bindings for ZenConding Plugin': 'Povezave tipk za ZenConding vtičnik', +'Keyboard shortcuts': 'Keyboard shortcuts', +'kill process': 'kill process', 'language file "%(filename)s" created/updated': 'jezikovna datoteka "%(filename)s" ustvarjena/posodobljena', +'Language files (static strings) updated': 'Jezikovna datoteka (statično besedilo) posodobljeno', 'languages': 'jeziki', +'Languages': 'Jeziki', 'languages updated': 'jeziki posodobljeni', +'Last name': 'Priimek', +'Last Revision': 'Last Revision', +'Last saved on:': 'Zadnjič shranjeno:', +'Layout': 'Postavitev', +'License for': 'Licenca za', +'License:': 'License:', +'Line Nr': 'Line Nr', +'Line number': 'Line number', +'lists by exception': 'lists by exception', +'lists by ticket': 'lists by ticket', +'Loading...': 'Loading...', 'loading...': 'nalaganje...', +'Local Apps': 'Local Apps', 'locals': 'locals', +'Locals##debug': 'Locals##debug', 'located in the file': 'se nahaja v datoteki', 'login': 'prijava', +'Login': 'Prijava', +'Login successful': 'Login successful', +'Login to the Administrative Interface': 'Prijava v skrbniški vmesnik', +'Login/Register': 'Login/Register', +'Logout': 'Odjava', +'Lost Password': 'Izgubljeno geslo', +'lost password': 'lost password', 'lost password?': 'Izgubljeno geslo?', +'Main Menu': 'Glavni meni', +'Manage': 'Manage', +'Manage %(action)s': 'Manage %(action)s', +'Manage Access Control': 'Manage Access Control', +'Manage Admin Users/Students': 'Manage Admin Users/Students', +'Manage Cache': 'Manage Cache', +'Manage Students': 'Manage Students', +'Match Pair': 'Ujemalni par', +'Memberships': 'Memberships', +'Menu Model': 'Model menija', 'merge': 'združi', +'Merge Lines': 'Združi vrstice', +'Models': 'Modeli', 'models': 'modeli', +'Modified On': 'Modified On', +'Modules': 'Moduli', 'modules': 'moduli', +'Multi User Mode': 'Multi User Mode', +'Name': 'Ime', 'new application "%s" created': 'ustvarjen nov program "%s"', +'new application "%s" imported': 'new application "%s" imported', +'New Application Wizard': 'Čarovnik za novo aplikacijo', +'New application wizard': 'Čarovnik za novo aplikacijo', +'new plugin installed': 'new plugin installed', +'New plugin installed: %s': 'New plugin installed: %s', +'New Record': 'Nov zapis', 'new record inserted': 'vstavljen nov zapis', +'New simple application': 'Nova enostavna aplikacija', +'next': 'next', +'next %s rows': 'next %s rows', 'next 100 rows': 'naslednjih 100 zapisov', +'Next Edit Point': 'Naslednja točka urejanja', +'NO': 'NE', +'no changes': 'no changes', +'No databases in this application': 'V tem programu ni podatkovnih baz', +'No Interaction yet': 'No Interaction yet', +'no match': 'no match', +'no package selected': 'no package selected', +'no permission to uninstall "%s"': 'no permission to uninstall "%s"', +'Node:': 'Node:', +'Not Authorized': 'Not Authorized', +'Not supported': 'Not supported', +'Note: If you receive an error with github status code of 128, ensure the system and account you are deploying from has a cooresponding ssh key configured in the openshift account.': 'Note: If you receive an error with github status code of 128, ensure the system and account you are deploying from has a cooresponding ssh key configured in the openshift account.', +"On production, you'll have to configure your webserver to use one process and multiple threads to use this debugger.": "On production, you'll have to configure your webserver to use one process and multiple threads to use this debugger.", +'Open new app in new window': 'Open new app in new window', +'OpenShift Deployment Interface': 'OpenShift Deployment Interface', +'OpenShift Output': 'OpenShift Output', +'or alternatively': 'or alternatively', +'Or Get from URL:': 'Or Get from URL:', 'or import from csv file': 'ali uvozi iz CSV datoteke', 'or provide app url:': 'ali vpišite URL programa:', 'or provide application url:': 'ali vpišite URL programa:', +'Origin': 'Izvor', +'Original/Translation': 'Izvor/Prevod', +'Overview': 'Overview', +'Overwrite installed app': 'Prepiši obstoječi program', +'Pack all': 'Zapakiraj vse', +'Pack compiled': 'Paket preveden', +'Pack custom': 'Pack custom', 'pack plugin': 'zapakiraj vtičnik', +'Password': 'Geslo', +'password changed': 'password changed', +'Past revisions': 'Past revisions', +'Path to appcfg.py': 'Path to appcfg.py', +'Path to local openshift repo root.': 'Path to local openshift repo root.', +'Peeking at file': 'Vpogled v datoteko', +'Permission': 'Permission', +'Permissions': 'Permissions', +'Please': 'Please', 'please wait!': 'Prosim počakajte!', +'Please wait, giving pythonanywhere a moment...': 'Please wait, giving pythonanywhere a moment...', +'plugin "%(plugin)s" deleted': 'plugin "%(plugin)s" deleted', +'Plugin "%s" in application': 'Vtičnik "%s" v aplikaciji', +'plugin not specified': 'plugin not specified', +'Plugin page': 'Plugin page', 'plugins': 'vtičniki', +'Plugins': 'Vtičniki', +'Plural Form #%s': 'Plural Form #%s', +'Plural-Forms:': 'Plural-Forms:', +'Powered by': 'Narejeno z', +'Preferences saved correctly': 'Preferences saved correctly', +'Preferences saved on session only': 'Preferences saved on session only', +'previous %s rows': 'previous %s rows', 'previous 100 rows': 'prejšnjih 100 zapisov', +'Previous Edit Point': 'Prejšnja točka urejanja', +'Private files': 'Private files', +'private files': 'private files', +'Project Progress': 'Project Progress', +'Pull': 'Pull', +'Pull failed, certain files could not be checked out. Check logs for details.': 'Pull failed, certain files could not be checked out. Check logs for details.', +'Pull is not possible because you have unmerged files. Fix them up in the work tree, and then try again.': 'Pull is not possible because you have unmerged files. Fix them up in the work tree, and then try again.', +'Push': 'Push', +'Push failed, there are unmerged entries in the cache. Resolve merge issues manually and try again.': 'Push failed, there are unmerged entries in the cache. Resolve merge issues manually and try again.', +'pygraphviz library not found': 'pygraphviz library not found', +'PythonAnywhere Apps': 'PythonAnywhere Apps', +'PythonAnywhere Password': 'PythonAnywhere Password', +'Query:': 'Vprašanje:', +'RAM': 'RAM', +'RAM Cache Keys': 'RAM Cache Keys', +'Ram Cleared': 'Ram Cleared', +'Rapid Search': 'Rapid Search', +'Record': 'Record', 'record': 'zapis', 'record does not exist': 'zapis ne obstaja', 'record id': 'id zapisa', +'Record ID': 'ID zapisa', +'Record id': 'Record id', +'refresh': 'refresh', +'Register': 'Registracija', 'register': 'registracija', +'Registration key': 'Registracijski ključ', +'Reload routes': 'Ponovno naloži preusmeritve', +'Remove compiled': 'Odstrani prevedeno', +'Removed Breakpoint on %s at line %s': 'Removed Breakpoint on %s at line %s', +'Replace': 'Replace', +'Replace All': 'Replace All', +'Repository (%s)': 'Repository (%s)', 'request': 'zahteva', +'requires distutils, but not installed': 'requires distutils, but not installed', +'requires python-git, but not installed': 'requires python-git, but not installed', +'Reset Password key': 'Ponastavi ključ gesla', +'Resolve Conflict file': 'Datoteka za razrešitev problemov', 'response': 'odgovor', +'restart': 'restart', 'restore': 'obnovi', +'return': 'return', +'Revert': 'Revert', 'revert': 'povrni', +'reverted to revision %s': 'reverted to revision %s', +'Revision %s': 'Revision %s', +'Revision:': 'Revision:', +'Role': 'Vloga', +'Roles': 'Roles', +'Rows in table': 'Vrstic v tabeli', +'Rows in Table': 'Rows in Table', +'Rows selected': 'Izbranih vrstic', +'rules are not defined': 'rules are not defined', +'Run tests': 'Run tests', +'Run tests in this file': 'Run tests in this file', +"Run tests in this file (to run all files, you may also use the button labelled 'test')": "Poženi teste v tej datoteki (za vse teste uporabite gumb 'test')", +'Running on %s': 'Running on %s', +'Save': 'Save', 'save': 'shrani', +'Save file:': 'Save file:', +'Save file: %s': 'Save file: %s', +'Save model as...': 'Save model as...', +'Save via Ajax': 'Shrani preko AJAX', +'Saved file hash:': 'Koda shranjene datoteke:', +'Screenshot %s': 'Screenshot %s', +'Search': 'Search', +'Select Files to Package': 'Select Files to Package', 'selected': 'izbrano', 'session': 'seja', 'session expired': 'seja pretekla', +'Session saved correctly': 'Session saved correctly', +'Session saved on session only': 'Session saved on session only', +'Set Breakpoint on %s at line %s: %s': 'Set Breakpoint on %s at line %s: %s', 'shell': 'lupina', +'Showing %s to %s of %s %s found': 'Showing %s to %s of %s %s found', +'Singular Form': 'Singular Form', +'Site': 'Spletišče', +'Size of cache:': 'Size of cache:', +'skip to generate': 'skip to generate', 'some files could not be removed': 'nekaterih datotek se ni dalo izbrisati', +'Something went wrong please wait a few minutes before retrying': 'Something went wrong please wait a few minutes before retrying', +'Sorry, could not find mercurial installed': 'Oprostite. Mercurial ni nameščen.', +'source : db': 'source : db', +'source : filesystem': 'source : filesystem', +'Start a new app': 'Začnite z novo aplikacijo', +'Start searching': 'Start searching', +'Start wizard': 'Zaženi čarovnika', 'state': 'stanje', +'Static': 'Static', 'static': 'statično', +'Static files': 'Statične datoteke', +'Statistics': 'Statistics', +'Step': 'Step', +'step': 'step', +'stop': 'stop', +'Stylesheet': 'CSS datoteka', 'submit': 'pošlji', +'Submit': 'Submit', +'successful': 'successful', +'Sure you want to delete this object?': 'Ali res želite izbrisati ta predmet?', +'switch to : db': 'switch to : db', +'switch to : filesystem': 'switch to : filesystem', +'Tab width (# characters)': 'Tab width (# characters)', 'table': 'tabela', +'Table': 'Table', +'Table name': 'Ime tabele', +'Temporary': 'Temporary', 'test': 'test', 'test_def': 'test_def', 'test_for': 'test_for', 'test_if': 'test_if', 'test_try': 'test_try', +'Testing application': 'Testiranje programa', +'Testing controller': 'Testiranje krmilnika', +'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.': '"vprašanje" je pogoj kot npr. "db.table1.field1 == \'vrednost\'". Nekaj kot "db.table1.field1 == db.table2.field2" izvede SQL operacijo JOIN.', +'The app exists, was created by wizard, continue to overwrite!': 'The app exists, was created by wizard, continue to overwrite!', +'The app exists, was NOT created by wizard, continue to overwrite!': 'The app exists, was NOT created by wizard, continue to overwrite!', 'the application logic, each URL path is mapped in one exposed function in the controller': 'krmilna logika, vsaka URL pot je preslikana v eno funkcijo v krmilniku', +'The application logic, each URL path is mapped in one exposed function in the controller': 'Logika delovanja aplikacije. Vsak URL je povezan z eno objavljeno funkcijo v krmilniku', 'the data representation, define database tables and sets': 'podatkovna predstavitev, definirajte tabele in množice', +'The data representation, define database tables and sets': 'Predstavitev podatkov. Definirajte podatkovne tabele in množice', +'The output of the file is a dictionary that was rendered by the view': 'Rezultat datoteke je slovar, ki ga predela pogled', +'The presentations layer, views are also known as templates': 'Predstavitveni nivo. Pogledi so znani tudi kot predloge', 'the presentations layer, views are also known as templates': 'predstavitveni nivo, pogledi so tudi znani kot predloge', +'Theme': 'Theme', +'There are no controllers': 'Ni krmilnikov', +'There are no models': 'Ni modelov', +'There are no modules': 'Ni modulov', +'There are no plugins': 'Ni vtičnikov', +'There are no private files': 'There are no private files', +'There are no static files': 'Ni statičnih datotek', +'There are no translators': 'There are no translators', +'There are no translators, only default language is supported': 'Ni prevodov. Podprt je samo privzeti jezik', +'There are no views': 'Ni pogledov', +'These files are not served, they are only available from within your app': 'These files are not served, they are only available from within your app', +'These files are served without processing, your images go here': 'Te datoteke so poslane brez obdelave. Vaše slike shranite tu.', 'these files are served without processing, your images go here': 'te datoteke so poslane brez posredovanja in obdelave, svoje slike shranite tu', +"This debugger may not work properly if you don't have a threaded webserver or you're using multiple daemon processes.": "This debugger may not work properly if you don't have a threaded webserver or you're using multiple daemon processes.", +'This is a copy of the scaffolding application': 'To je kopija okvirne aplikacije', +'This is an experimental feature and it needs more testing. If you decide to downgrade you do it at your own risk': 'This is an experimental feature and it needs more testing. If you decide to downgrade you do it at your own risk', +'This is an experimental feature and it needs more testing. If you decide to upgrade you do it at your own risk': 'This is an experimental feature and it needs more testing. If you decide to upgrade you do it at your own risk', +'This is the %(filename)s template': 'To je predloga %(filename)s', +"This page can commit your changes to an openshift app repo and push them to your cloud instance. This assumes that you've already created the application instance using the web2py skeleton and have that repo somewhere on a filesystem that this web2py instance can access. This functionality requires GitPython installed and on the python path of the runtime that web2py is operating in.": "This page can commit your changes to an openshift app repo and push them to your cloud instance. This assumes that you've already created the application instance using the web2py skeleton and have that repo somewhere on a filesystem that this web2py instance can access. This functionality requires GitPython installed and on the python path of the runtime that web2py is operating in.", +'This page can upload your application to the Google App Engine computing cloud. Mind that you must first create indexes locally and this is done by installing the Google appserver and running the app locally with it once, or there will be errors when selecting records. Attention: deployment may take long time, depending on the network speed. Attention: it will overwrite your app.yaml. DO NOT SUBMIT TWICE.': 'This page can upload your application to the Google App Engine computing cloud. Mind that you must first create indexes locally and this is done by installing the Google appserver and running the app locally with it once, or there will be errors when selecting records. Attention: deployment may take long time, depending on the network speed. Attention: it will overwrite your app.yaml. DO NOT SUBMIT TWICE.', +'this page to see if a breakpoint was hit and debug interaction is required.': 'this page to see if a breakpoint was hit and debug interaction is required.', +'This will pull changes from the remote repo for application "%s"?': 'This will pull changes from the remote repo for application "%s"?', +'This will push changes to the remote repo for application "%s".': 'This will push changes to the remote repo for application "%s".', +'Ticket': 'Listek', +'Ticket ID': 'ID listka', +'Ticket Missing': 'Ticket Missing', +'Time in Cache (h:m:s)': 'Time in Cache (h:m:s)', +'Timestamp': 'Časovni žig', +'TM': 'TM', 'to previous version.': 'na prejšnjo različico.', +'To create a plugin, name a file/folder plugin_[name]': 'Če želite ustvariti vtičnik, poimenujte datoteko/mapo plugin_[ime]', +'To emulate a breakpoint programatically, write:': 'To emulate a breakpoint programatically, write:', +'to use the debugger!': 'to use the debugger!', +'toggle breakpoint': 'toggle breakpoint', +'Toggle comment': 'Toggle comment', +'Toggle Fullscreen': 'Toggle Fullscreen', +'Traceback': 'Sledljivost', 'translation strings for the application': 'prevodna besedila za program', +'Translation strings for the application': 'Prevajalna besedila za aplikacijo', 'try': 'poskusi', 'try something like': 'poskusite na primer', +'Try the mobile interface': 'Try the mobile interface', +'try view': 'try view', +'Type PDB debugger command in here and hit Return (Enter) to execute it.': 'Type PDB debugger command in here and hit Return (Enter) to execute it.', +'Type some Python code in here and hit Return (Enter) to execute it.': 'Type some Python code in here and hit Return (Enter) to execute it.', +'Unable to check for upgrades': 'Ne morem preveriti posodobitev', 'unable to create application "%s"': 'ne morem ustvariti programa "%s" ', 'unable to delete file "%(filename)s"': 'ne morem izbrisati datoteke "%(filename)s"', +'unable to delete file plugin "%(plugin)s"': 'unable to delete file plugin "%(plugin)s"', +'Unable to determine the line number!': 'Unable to determine the line number!', +'Unable to download': 'Ne morem prenesti datoteke', +'Unable to download app': 'Ne morem prenesti programa', +'Unable to download app because:': 'Unable to download app because:', +'unable to download layout': 'unable to download layout', +'unable to download plugin: %s': 'unable to download plugin: %s', +'Unable to download the list of plugins': 'Unable to download the list of plugins', +'unable to install plugin "%s"': 'unable to install plugin "%s"', 'unable to parse csv file': 'ne morem obdelati csv datoteke', 'unable to uninstall "%s"': 'ne morem odstraniti "%s"', +'unable to upgrade because "%s"': 'unable to upgrade because "%s"', 'uncheck all': 'odznači vse', +'Uninstall': 'Odstrani', +'Unsupported webserver working mode: %s': 'Unsupported webserver working mode: %s', 'update': 'posodobi', 'update all languages': 'posodobi vse jezike', +'Update:': 'Posodobitev:', +'Upgrade': 'Upgrade', +'upgrade now to %s': 'upgrade now to %s', 'upgrade web2py now': 'posodobi web2py', 'upload': 'naloži', +'Upload': 'Upload', +'Upload & install packed application': 'Naloži in namesti pakirano aplikacijo', +'Upload a package:': 'Naloži paket:', +'Upload and install packed application': 'Naloži in namesti pakirano aplikacijo', 'upload application:': 'naloži program:', +'Upload existing application': 'Naloži obstoječo aplikacijo', 'upload file:': 'naloži datoteko:', 'upload plugin file:': 'naloži vtičnik:', +'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Uporabie (...)&(...) za AND, (...)|(...) za OR, in ~(...) za NOT pri gradnji kompleksnih povpraševanj.', +'Use an url:': 'Uporabite URL:', 'user': 'uporabnik', +'User': 'User', +'User ID': 'ID uporabnika', +'Username': 'Username', +'Users': 'Users', +'Using the shell may lock the database to other users of this app.': 'Using the shell may lock the database to other users of this app.', 'variables': 'spremenljivke', +'Version': 'Različica', +'Versioning': 'Versioning', 'versioning': 'različice', +'View': 'Pogled', 'view': 'pogled', +'Views': 'Pogledi', 'views': 'pogledi', -'web2py Recent Tweets': 'zadnji tviti na web2py', +'Warning!': 'Warning!', +'WARNING:': 'WARNING:', +'WARNING: The following views could not be compiled:': 'WARNING: The following views could not be compiled:', +'Web Framework': 'Web Framework', +'web2py Admin Password': 'web2py Admin Password', +'web2py apps to deploy': 'web2py apps to deploy', +'web2py Debugger': 'web2py Debugger', +'web2py downgrade': 'web2py downgrade', 'web2py is up to date': 'web2py je ažuren', +'web2py online debugger': 'web2py online debugger', +'web2py Recent Tweets': 'zadnji tviti na web2py', +'web2py upgrade': 'web2py upgrade', +'web2py upgraded; please restart it': 'web2py upgraded; please restart it', +'Welcome %s': 'Dobrodošli, %s', +'Welcome to web2py': 'Dobrodošli v web2py', +'Which called the function': 'Ki je klical funkcijo', +'Working...': 'Working...', +'Wrap with Abbreviation': 'Ovij z okrajšavo', +'WSGI reference name': 'WSGI reference name', 'xml': 'xml', +'YES': 'DA', +'Yes': 'Yes', +'You are successfully running web2py': 'Uspešno ste pognali web2py', +'You can also set and remove breakpoint in the edit window, using the Toggle Breakpoint button': 'You can also set and remove breakpoint in the edit window, using the Toggle Breakpoint button', +'You can inspect variables using the console below': 'You can inspect variables using the console below', +'You can modify this application and adapt it to your needs': 'Lahko spremenite to aplikacijo in jo prilagodite vašim potrebam', +'You have one more login attempt before you are locked out': 'You have one more login attempt before you are locked out', +'You need to set up and reach a': 'You need to set up and reach a', +'You only need these if you have already registered': 'You only need these if you have already registered', +'You visited the url': 'Obiskali ste URL', +'Your application will be blocked until you click an action button (next, step, continue, etc.)': 'Your application will be blocked until you click an action button (next, step, continue, etc.)', } diff --git a/applications/admin/languages/sr-cr.py b/applications/admin/languages/sr-cr.py index 04ff676c..56a9a384 100755 --- a/applications/admin/languages/sr-cr.py +++ b/applications/admin/languages/sr-cr.py @@ -2,211 +2,594 @@ { '!langcode!': 'sr-cr', '!langname!': 'Српски (Ћирилица)', +'"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN': '"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN', +'"User Exception" debug mode. ': '"User Exception" debug mode. ', +'%s': '%s', +'%s %%{row} deleted': '%s %%{row} deleted', +'%s %%{row} updated': '%s %%{row} updated', +'%s selected': '%s selected', +'%s students registered': '%s students registered', '%Y-%m-%d': '%d-%m-%Y', '%Y-%m-%d %H:%M:%S': '%d-%m-%Y %H:%M:%S', '(requires internet access)': '(захтијева приступ интернету)', +'(requires internet access, experimental)': '(requires internet access, experimental)', '(something like "it-it")': '(нешто као "it-it")', +'(version %s)': '(version %s)', +'?': '?', '@markmin\x01(file **gluon/contrib/plural_rules/%s.py** is not found)': '(датотека **gluon/contrib/plural_rules/%s.py** није пронађена)', +'Abort': 'Abort', 'About': 'Информације', 'About application': 'О апликацији', +'Accept Terms': 'Accept Terms', +'Add breakpoint': 'Add breakpoint', 'Additional code for your application': 'Додатни код за апликацију', +'Admin design page': 'Admin design page', +'admin disabled because no admin password': 'admin disabled because no admin password', +'admin disabled because not supported on google app engine': 'admin disabled because not supported on google app engine', +'admin disabled because too many invalid login attempts': 'admin disabled because too many invalid login attempts', 'admin disabled because unable to access password file': 'администрација онемогућена јер не могу приступити датотеци са лозинком', +'Admin is disabled because insecure channel': 'Admin is disabled because insecure channel', 'Admin language': 'Језик администратора', +'Admin versioning page': 'Admin versioning page', 'administrative interface': 'административни интерфејс', 'Administrator Password:': 'Лозинка администратора:', 'and rename it:': 'и преименуј у:', +'App does not exist or you are not authorized': 'App does not exist or you are not authorized', +'appadmin': 'appadmin', +'appadmin is disabled because insecure channel': 'appadmin is disabled because insecure channel', +'Application': 'Application', +'application "%s" uninstalled': 'application "%s" uninstalled', +'Application cannot be generated in demo mode': 'Application cannot be generated in demo mode', +'application compiled': 'application compiled', +'Application exists already': 'Application exists already', +'application is compiled and cannot be designed': 'application is compiled and cannot be designed', 'Application name:': 'Назив апликације:', +'Application updated via git pull': 'Application updated via git pull', 'are not used': 'није кориштено', 'are not used yet': 'није још кориштено', +'Are you sure you want to delete file "%s"?': 'Are you sure you want to delete file "%s"?', +'Are you sure you want to delete plugin "%s"?': 'Are you sure you want to delete plugin "%s"?', 'Are you sure you want to delete this object?': 'Да ли сте сигурни да желите обрисати?', +'Are you sure you want to uninstall application "%s"?': 'Are you sure you want to uninstall application "%s"?', +'Are you sure?': 'Are you sure?', 'arguments': 'arguments', 'at char %s': 'код слова %s', 'at line %s': 'на линији %s', +'ATTENTION:': 'ATTENTION:', +'ATTENTION: Login requires a secure (HTTPS) connection or running on localhost.': 'ATTENTION: Login requires a secure (HTTPS) connection or running on localhost.', 'ATTENTION: TESTING IS NOT THREAD SAFE SO DO NOT PERFORM MULTIPLE TESTS CONCURRENTLY.': 'ATTENTION: TESTING IS NOT THREAD SAFE SO DO NOT PERFORM MULTIPLE TESTS CONCURRENTLY.', +'ATTENTION: you cannot edit the running application!': 'ATTENTION: you cannot edit the running application!', +'Autocomplete Python Code': 'Autocomplete Python Code', +'Available Databases and Tables': 'Available Databases and Tables', 'back': 'назад', +'Back to the plugins list': 'Back to the plugins list', +'Back to wizard': 'Back to wizard', 'Basics': 'Основе', 'Begin': 'Почетак', +'breakpoint': 'breakpoint', +'Breakpoints': 'Breakpoints', +'breakpoints': 'breakpoints', +'Bulk Register': 'Bulk Register', +'Bulk Student Registration': 'Bulk Student Registration', +'Cache': 'Cache', +'cache': 'cache', +'Cache Cleared': 'Cache Cleared', +'Cache Keys': 'Cache Keys', 'cache, errors and sessions cleaned': 'кеш, грешке и сесије су обрисани', 'can be a git repo': 'може бити git repo', +'Cancel': 'Cancel', +'Cannot be empty': 'Cannot be empty', +'Cannot compile: there are errors in your app:': 'Cannot compile: there are errors in your app:', +'cannot create file': 'cannot create file', 'cannot upload file "%(filename)s"': 'не мофу отпремити датотеку "%(filename)s"', +'Change Admin Password': 'Change Admin Password', 'Change admin password': 'Промијени лзинку администратора', +'change editor settings': 'change editor settings', +'Changelog': 'Changelog', 'check all': 'check all', 'Check for upgrades': 'Провјери могућност надоградње', +'Check to delete': 'Check to delete', 'Checking for upgrades...': 'Провјеравам могућност надоградње...', 'Clean': 'Прочисти', +'Clear': 'Clear', +'Clear CACHE?': 'Clear CACHE?', +'Clear DISK': 'Clear DISK', +'Clear RAM': 'Clear RAM', 'Click row to expand traceback': 'Click row to expand traceback', +'Click row to view a ticket': 'Click row to view a ticket', 'code': 'код', +'Code listing': 'Code listing', 'collapse/expand all': 'сакрити/приказати све', +'Command': 'Command', +'Comment:': 'Comment:', +'Commit': 'Commit', +'Commit form': 'Commit form', +'Committed files': 'Committed files', 'Compile': 'Компајлирај', +'Compile (all or nothing)': 'Compile (all or nothing)', +'Compile (skip failed views)': 'Compile (skip failed views)', +'compiled application removed': 'compiled application removed', +'Condition': 'Condition', +'continue': 'continue', 'Controllers': 'Контролери', 'controllers': 'контролери', 'Count': 'Count', 'Create': 'Креирај', 'create file with filename:': 'Креирај датотеку под називом:', 'Create rules': 'Креирај правила', +'Create/Upload': 'Create/Upload', 'created by': 'израдио', +'Created by:': 'Created by:', +'Created On': 'Created On', +'Created on:': 'Created on:', 'crontab': 'crontab', +'Current request': 'Current request', +'Current response': 'Current response', +'Current session': 'Current session', 'currently running': 'тренутно покренут', 'currently saved or': 'тренутно сачувано или', +'data uploaded': 'data uploaded', +'Database': 'Database', +'Database %s select': 'Database %s select', +'Database administration': 'Database administration', 'database administration': 'администрација базе података', +'Database Administration (appadmin)': 'Database Administration (appadmin)', +'Date and Time': 'Date and Time', +'db': 'db', 'Debug': 'Debug', 'defines tables': 'дефинише табеле', -'delete': 'обриши', 'Delete': 'Обриши', +'delete': 'обриши', 'delete all checked': 'delete all checked', +'delete plugin': 'delete plugin', 'Delete this file (you will be asked to confirm deletion)': 'Обриши ову даатотеку (бићете упитани за потврду брисања)', +'Delete:': 'Delete:', +'deleted after first hit': 'deleted after first hit', +'Demo': 'Demo', 'Deploy': 'Постави', 'Deploy on Google App Engine': 'Постави на Google App Engine', 'Deploy to OpenShift': 'Постави на OpenShift', +'Deploy to pythonanywhere': 'Deploy to pythonanywhere', +'Deploy to PythonAnywhere': 'Deploy to PythonAnywhere', +'Deployment form': 'Deployment form', +'Deployment Interface': 'Deployment Interface', +'Description:': 'Description:', +'design': 'design', 'Detailed traceback description': 'Detailed traceback description', +'details': 'details', 'direction: ltr': 'direction: ltr', +'directory not found': 'directory not found', 'Disable': 'Искључи', +'Disabled': 'Disabled', +'disabled in demo mode': 'disabled in demo mode', +'disabled in GAE mode': 'disabled in GAE mode', +'disabled in multi user mode': 'disabled in multi user mode', +'DISK': 'DISK', +'Disk Cache Keys': 'Disk Cache Keys', +'Disk Cleared': 'Disk Cleared', +'Display line numbers': 'Display line numbers', +'DO NOT use the "Pack compiled" feature.': 'DO NOT use the "Pack compiled" feature.', 'docs': 'документација', +'Docs': 'Docs', +'done!': 'done!', +'Downgrade': 'Downgrade', +'Download .w2p': 'Download .w2p', +'Download as .exe': 'Download as .exe', 'download layouts': 'преузми layouts', +'Download layouts from repository': 'Download layouts from repository', 'download plugins': 'преузми plugins', +'Download plugins from repository': 'Download plugins from repository', 'Edit': 'Уређивање', 'edit all': 'уреди све', 'Edit application': 'Уреди апликацију', 'edit controller': 'уреди контролер', +'edit controller:': 'edit controller:', +'Edit current record': 'Edit current record', 'edit views:': 'уреди views:', +'Editing %s': 'Editing %s', 'Editing file "%s"': 'Уређивање датотеке "%s"', 'Editing Language file': 'Уређивање језичке датотеке', +'Editing Plural Forms File': 'Editing Plural Forms File', +'Editor': 'Editor', +'Email Address': 'Email Address', +'Enable': 'Enable', +'Enable Close-Tag': 'Enable Close-Tag', +'Enable Code Folding': 'Enable Code Folding', 'Error': 'Грешка', 'Error logs for "%(app)s"': 'Преглед грешака за "%(app)s"', 'Error snapshot': 'Error snapshot', 'Error ticket': 'Error ticket', 'Errors': 'Грешке', +'Exception %(extype)s: %(exvalue)s': 'Exception %(extype)s: %(exvalue)s', +'Exception %s': 'Exception %s', 'Exception instance attributes': 'Exception instance attributes', +'Exit Fullscreen': 'Exit Fullscreen', 'Expand Abbreviation': 'Expand Abbreviation', +'Expand Abbreviation (html files only)': 'Expand Abbreviation (html files only)', +'export as csv file': 'export as csv file', +'Exports:': 'Exports:', 'exposes': 'exposes', 'exposes:': 'exposes:', 'extends': 'проширује', 'failed to compile file because:': 'нисам могао да компајлирам због:', +'failed to reload module because:': 'failed to reload module because:', 'File': 'Датотека', +'file "%(filename)s" created': 'file "%(filename)s" created', +'file "%(filename)s" deleted': 'file "%(filename)s" deleted', +'file "%(filename)s" uploaded': 'file "%(filename)s" uploaded', +'file "%s" of %s restored': 'file "%s" of %s restored', +'file changed on disk': 'file changed on disk', 'file does not exist': 'датотека не постоји', +'file not found': 'file not found', +'file saved on %(time)s': 'file saved on %(time)s', 'file saved on %s': 'датотека сачувана на %s', +'filename': 'filename', +'Filename': 'Filename', +'Files added': 'Files added', 'filter': 'филтер', 'Find Next': 'Пронађи сљедећи', 'Find Previous': 'Пронађи претходни', +'Form has errors': 'Form has errors', 'Frames': 'Frames', 'Functions with no doctests will result in [passed] tests.': 'Functions with no doctests will result in [passed] tests.', +'GAE Email': 'GAE Email', +'GAE Output': 'GAE Output', +'GAE Password': 'GAE Password', 'Generate': 'Generate', 'Get from URL:': 'Преузми са странице:', 'Git Pull': 'Git Pull', 'Git Push': 'Git Push', +'Globals##debug': 'Globals##debug', 'Go to Matching Pair': 'Go to Matching Pair', 'go!': 'крени!', +'Google App Engine Deployment Interface': 'Google App Engine Deployment Interface', +'Google Application Id': 'Google Application Id', +'Goto': 'Goto', +'graph model': 'graph model', +'Graph Model': 'Graph Model', 'Help': 'Помоћ', +'here': 'here', 'Hide/Show Translated strings': 'Сакрити/Приказати преведене ријечи', +'Highlight current line': 'Highlight current line', +'Hits': 'Hits', +'Home': 'Home', +'honored only if the expression evaluates to true': 'honored only if the expression evaluates to true', +'If start the downgrade, be patient, it may take a while to rollback': 'If start the downgrade, be patient, it may take a while to rollback', +'If start the upgrade, be patient, it may take a while to download': 'If start the upgrade, be patient, it may take a while to download', +'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\n\t\tA green title indicates that all tests (if defined) passed. In this case test results are not shown.': 'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\n\t\tA green title indicates that all tests (if defined) passed. In this case test results are not shown.', 'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\nA green title indicates that all tests (if defined) passed. In this case test results are not shown.': 'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\nA green title indicates that all tests (if defined) passed. In this case test results are not shown.', +'if your application uses a database other than sqlite you will then have to configure its DAL in pythonanywhere.': 'if your application uses a database other than sqlite you will then have to configure its DAL in pythonanywhere.', +'import': 'import', +'Import/Export': 'Import/Export', +'In development, use the default Rocket webserver that is currently supported by this debugger.': 'In development, use the default Rocket webserver that is currently supported by this debugger.', 'includes': 'укључује', +'Indent with tabs': 'Indent with tabs', 'inspect attributes': 'inspect attributes', 'Install': 'Инсталирај', +'Installation of %(plugin)s for %(app)s': 'Installation of %(plugin)s for %(app)s', 'Installed applications': 'Инсталиране апликације', +'Interaction at %s line %s': 'Interaction at %s line %s', +'Interactive console': 'Interactive console', +'internal error': 'internal error', +'internal error: %s': 'internal error: %s', +'Internal State': 'Internal State', +'Invalid action': 'Invalid action', +'Invalid application name': 'Invalid application name', +'invalid circular reference': 'invalid circular reference', +'Invalid git repository specified.': 'Invalid git repository specified.', +'invalid password': 'invalid password', 'invalid password.': 'погрешна лозинка.', +'Invalid Query': 'Invalid Query', +'invalid request': 'invalid request', +'Invalid request': 'Invalid request', +'invalid table names (auth_* tables already defined)': 'invalid table names (auth_* tables already defined)', +'invalid ticket': 'invalid ticket', +'Key': 'Key', 'Key bindings': 'Пречице', 'Key bindings for ZenCoding Plugin': 'Пречице за ZenCoding Plugin', +'Keyboard shortcuts': 'Keyboard shortcuts', +'kill process': 'kill process', +'language file "%(filename)s" created/updated': 'language file "%(filename)s" created/updated', 'Language files (static strings) updated': 'Језичке датотеке су ажуриране', 'languages': 'језици', 'Languages': 'Језици', +'Last Revision': 'Last Revision', 'Last saved on:': 'Посљедња измјена:', 'License for': 'Лиценца за', +'License:': 'License:', +'Line Nr': 'Line Nr', +'Line number': 'Line number', +'lists by exception': 'lists by exception', +'lists by ticket': 'lists by ticket', +'Loading...': 'Loading...', 'loading...': 'преузимам...', +'Local Apps': 'Local Apps', 'locals': 'locals', +'Locals##debug': 'Locals##debug', 'Login': 'Пријава', +'Login successful': 'Login successful', 'Login to the Administrative Interface': 'Пријава за административни интерфејс', +'Login/Register': 'Login/Register', 'Logout': 'Излаз', +'lost password': 'lost password', +'Main Menu': 'Main Menu', +'Manage': 'Manage', +'Manage %(action)s': 'Manage %(action)s', +'Manage Access Control': 'Manage Access Control', +'Manage Admin Users/Students': 'Manage Admin Users/Students', +'Manage Cache': 'Manage Cache', +'Manage Students': 'Manage Students', 'Match Pair': 'Match Pair', +'Memberships': 'Memberships', +'merge': 'merge', 'Merge Lines': 'Споји линије', -'models': 'models', 'Models': 'Models', +'models': 'models', +'Modified On': 'Modified On', 'Modules': 'Modules', 'modules': 'modules', +'Multi User Mode': 'Multi User Mode', +'new application "%s" created': 'new application "%s" created', +'new application "%s" imported': 'new application "%s" imported', 'New Application Wizard': 'Чаробњак за нове апликације', 'New application wizard': 'Чаробњак за нове апликације', +'new plugin installed': 'new plugin installed', +'New plugin installed: %s': 'New plugin installed: %s', +'New Record': 'New Record', +'new record inserted': 'new record inserted', 'New simple application': 'Нова једноставна апликација', +'next': 'next', +'next %s rows': 'next %s rows', 'Next Edit Point': 'Next Edit Point', +'NO': 'NO', +'no changes': 'no changes', +'No databases in this application': 'No databases in this application', +'No Interaction yet': 'No Interaction yet', +'no match': 'no match', +'no package selected': 'no package selected', +'no permission to uninstall "%s"': 'no permission to uninstall "%s"', 'No ticket_storage.txt found under /private folder': 'No ticket_storage.txt found under /private folder', +'Node:': 'Node:', +'Not Authorized': 'Not Authorized', +'Not supported': 'Not supported', +'Note: If you receive an error with github status code of 128, ensure the system and account you are deploying from has a cooresponding ssh key configured in the openshift account.': 'Note: If you receive an error with github status code of 128, ensure the system and account you are deploying from has a cooresponding ssh key configured in the openshift account.', +"On production, you'll have to configure your webserver to use one process and multiple threads to use this debugger.": "On production, you'll have to configure your webserver to use one process and multiple threads to use this debugger.", 'online designer': 'онлајн дизајнер', +'Open new app in new window': 'Open new app in new window', +'OpenShift Deployment Interface': 'OpenShift Deployment Interface', +'OpenShift Output': 'OpenShift Output', +'or alternatively': 'or alternatively', +'Or Get from URL:': 'Or Get from URL:', +'or import from csv file': 'or import from csv file', 'Original/Translation': 'Оргинал/Превод', +'Overview': 'Overview', 'Overwrite installed app': 'Пребриши постојећу апликацију', 'Pack all': 'Запакуј све', +'Pack compiled': 'Pack compiled', +'Pack custom': 'Pack custom', +'pack plugin': 'pack plugin', +'password changed': 'password changed', +'Past revisions': 'Past revisions', +'Path to appcfg.py': 'Path to appcfg.py', +'Path to local openshift repo root.': 'Path to local openshift repo root.', 'Peeking at file': 'Peeking at file', -'Plugins': 'Plugins', +'Permission': 'Permission', +'Permissions': 'Permissions', +'Please': 'Please', +'Please wait, giving pythonanywhere a moment...': 'Please wait, giving pythonanywhere a moment...', +'plugin "%(plugin)s" deleted': 'plugin "%(plugin)s" deleted', +'Plugin "%s" in application': 'Plugin "%s" in application', +'plugin not specified': 'plugin not specified', +'Plugin page': 'Plugin page', 'plugins': 'plugins', +'Plugins': 'Plugins', +'Plural Form #%s': 'Plural Form #%s', 'Plural-Forms:': 'Plural-Forms:', 'Powered by': 'Омогућио', +'Preferences saved correctly': 'Preferences saved correctly', +'Preferences saved on session only': 'Preferences saved on session only', +'previous %s rows': 'previous %s rows', 'Previous Edit Point': 'Previous Edit Point', 'Private files': 'Private files', 'private files': 'private files', 'Project Progress': 'Напредак пројекта', +'Pull': 'Pull', +'Pull failed, certain files could not be checked out. Check logs for details.': 'Pull failed, certain files could not be checked out. Check logs for details.', +'Pull is not possible because you have unmerged files. Fix them up in the work tree, and then try again.': 'Pull is not possible because you have unmerged files. Fix them up in the work tree, and then try again.', +'Push': 'Push', +'Push failed, there are unmerged entries in the cache. Resolve merge issues manually and try again.': 'Push failed, there are unmerged entries in the cache. Resolve merge issues manually and try again.', +'pygraphviz library not found': 'pygraphviz library not found', +'PythonAnywhere Apps': 'PythonAnywhere Apps', +'PythonAnywhere Password': 'PythonAnywhere Password', +'Query:': 'Query:', +'RAM': 'RAM', +'RAM Cache Keys': 'RAM Cache Keys', +'Ram Cleared': 'Ram Cleared', +'Rapid Search': 'Rapid Search', +'Record': 'Record', +'record does not exist': 'record does not exist', +'Record id': 'Record id', +'refresh': 'refresh', +'register': 'register', 'Reload routes': 'Обнови преусмјерења', +'Remove compiled': 'Remove compiled', 'Removed Breakpoint on %s at line %s': 'Removed Breakpoint on %s at line %s', 'Replace': 'Замијени', 'Replace All': 'Замијени све', +'Repository (%s)': 'Repository (%s)', 'request': 'request', +'requires distutils, but not installed': 'requires distutils, but not installed', +'requires python-git, but not installed': 'requires python-git, but not installed', +'Resolve Conflict file': 'Resolve Conflict file', 'response': 'response', 'restart': 'restart', 'restore': 'restore', +'return': 'return', +'Revert': 'Revert', 'revert': 'revert', +'reverted to revision %s': 'reverted to revision %s', +'Revision %s': 'Revision %s', +'Revision:': 'Revision:', +'Role': 'Role', +'Roles': 'Roles', +'Rows in Table': 'Rows in Table', +'Rows selected': 'Rows selected', 'rules are not defined': 'правила нису дефинисана', 'rules:': 'правила:', +'Run tests': 'Run tests', +'Run tests in this file': 'Run tests in this file', "Run tests in this file (to run all files, you may also use the button labelled 'test')": "Run tests in this file (to run all files, you may also use the button labelled 'test')", 'Running on %s': 'Покренути на %s', 'Save': 'Сачувај', +'Save file:': 'Save file:', +'Save file: %s': 'Save file: %s', +'Save model as...': 'Save model as...', 'Save via Ajax': 'сачувај via Ajax', 'Saved file hash:': 'Сачувано као хаш:', +'Screenshot %s': 'Screenshot %s', +'Search': 'Search', +'Select Files to Package': 'Select Files to Package', 'session': 'сесија', 'session expired': 'сесија истекла', +'Session saved correctly': 'Session saved correctly', +'Session saved on session only': 'Session saved on session only', 'Set Breakpoint on %s at line %s: %s': 'Set Breakpoint on %s at line %s: %s', 'shell': 'shell', +'Showing %s to %s of %s %s found': 'Showing %s to %s of %s %s found', +'Singular Form': 'Singular Form', 'Site': 'Сајт', +'Size of cache:': 'Size of cache:', 'skip to generate': 'skip to generate', +'some files could not be removed': 'some files could not be removed', +'Something went wrong please wait a few minutes before retrying': 'Something went wrong please wait a few minutes before retrying', +'Sorry, could not find mercurial installed': 'Sorry, could not find mercurial installed', +'source : db': 'source : db', +'source : filesystem': 'source : filesystem', 'Start a new app': 'Покрени нову апликацију', 'Start searching': 'Покрени претрагу', 'Start wizard': 'Покрени чаробњака', +'state': 'state', +'Static': 'Static', 'static': 'static', 'Static files': 'Static files', +'Statistics': 'Statistics', 'Step': 'Корак', +'step': 'step', +'stop': 'stop', +'submit': 'submit', 'Submit': 'Прихвати', 'successful': 'успјешан', +'switch to : db': 'switch to : db', +'switch to : filesystem': 'switch to : filesystem', +'Tab width (# characters)': 'Tab width (# characters)', +'Table': 'Table', +'Temporary': 'Temporary', 'test': 'тест', 'Testing application': 'Тестирање апликације', +'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.': 'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.', +'The app exists, was created by wizard, continue to overwrite!': 'The app exists, was created by wizard, continue to overwrite!', +'The app exists, was NOT created by wizard, continue to overwrite!': 'The app exists, was NOT created by wizard, continue to overwrite!', 'The application logic, each URL path is mapped in one exposed function in the controller': 'The application logic, each URL path is mapped in one exposed function in the controller', 'The data representation, define database tables and sets': 'The data representation, define database tables and sets', 'The presentations layer, views are also known as templates': 'The presentations layer, views are also known as templates', +'Theme': 'Theme', +'There are no controllers': 'There are no controllers', 'There are no models': 'There are no models', +'There are no modules': 'There are no modules', 'There are no plugins': 'There are no plugins', 'There are no private files': 'There are no private files', +'There are no static files': 'There are no static files', +'There are no translators': 'There are no translators', +'There are no translators, only default language is supported': 'There are no translators, only default language is supported', +'There are no views': 'There are no views', 'These files are not served, they are only available from within your app': 'These files are not served, they are only available from within your app', 'These files are served without processing, your images go here': 'These files are served without processing, your images go here', +"This debugger may not work properly if you don't have a threaded webserver or you're using multiple daemon processes.": "This debugger may not work properly if you don't have a threaded webserver or you're using multiple daemon processes.", +'This is an experimental feature and it needs more testing. If you decide to downgrade you do it at your own risk': 'This is an experimental feature and it needs more testing. If you decide to downgrade you do it at your own risk', +'This is an experimental feature and it needs more testing. If you decide to upgrade you do it at your own risk': 'This is an experimental feature and it needs more testing. If you decide to upgrade you do it at your own risk', +"This page can commit your changes to an openshift app repo and push them to your cloud instance. This assumes that you've already created the application instance using the web2py skeleton and have that repo somewhere on a filesystem that this web2py instance can access. This functionality requires GitPython installed and on the python path of the runtime that web2py is operating in.": "This page can commit your changes to an openshift app repo and push them to your cloud instance. This assumes that you've already created the application instance using the web2py skeleton and have that repo somewhere on a filesystem that this web2py instance can access. This functionality requires GitPython installed and on the python path of the runtime that web2py is operating in.", +'This page can upload your application to the Google App Engine computing cloud. Mind that you must first create indexes locally and this is done by installing the Google appserver and running the app locally with it once, or there will be errors when selecting records. Attention: deployment may take long time, depending on the network speed. Attention: it will overwrite your app.yaml. DO NOT SUBMIT TWICE.': 'This page can upload your application to the Google App Engine computing cloud. Mind that you must first create indexes locally and this is done by installing the Google appserver and running the app locally with it once, or there will be errors when selecting records. Attention: deployment may take long time, depending on the network speed. Attention: it will overwrite your app.yaml. DO NOT SUBMIT TWICE.', +'this page to see if a breakpoint was hit and debug interaction is required.': 'this page to see if a breakpoint was hit and debug interaction is required.', +'This will pull changes from the remote repo for application "%s"?': 'This will pull changes from the remote repo for application "%s"?', +'This will push changes to the remote repo for application "%s".': 'This will push changes to the remote repo for application "%s".', +'Ticket': 'Ticket', 'Ticket ID': 'Ticket ID', 'Ticket Missing': 'Ticket nedostaje', +'Time in Cache (h:m:s)': 'Time in Cache (h:m:s)', 'to previous version.': 'на претходну верзију.', 'To create a plugin, name a file/folder plugin_[name]': 'To create a plugin, name a file/folder plugin_[name]', +'To emulate a breakpoint programatically, write:': 'To emulate a breakpoint programatically, write:', +'to use the debugger!': 'to use the debugger!', 'toggle breakpoint': 'toggle breakpoint', +'Toggle comment': 'Toggle comment', 'Toggle Fullscreen': 'Toggle Fullscreen', 'Traceback': 'Traceback', 'Translation strings for the application': 'Ријечи у апликацији које треба превести', +'try something like': 'try something like', 'Try the mobile interface': 'Пробај мобилни интерфејс', 'try view': 'try view', +'Type PDB debugger command in here and hit Return (Enter) to execute it.': 'Type PDB debugger command in here and hit Return (Enter) to execute it.', +'Type some Python code in here and hit Return (Enter) to execute it.': 'Type some Python code in here and hit Return (Enter) to execute it.', +'Unable to check for upgrades': 'Unable to check for upgrades', +'unable to create application "%s"': 'unable to create application "%s"', +'unable to delete file "%(filename)s"': 'unable to delete file "%(filename)s"', +'unable to delete file plugin "%(plugin)s"': 'unable to delete file plugin "%(plugin)s"', +'Unable to determine the line number!': 'Unable to determine the line number!', +'Unable to download app because:': 'Unable to download app because:', +'unable to download layout': 'unable to download layout', +'unable to download plugin: %s': 'unable to download plugin: %s', +'Unable to download the list of plugins': 'Unable to download the list of plugins', +'unable to install plugin "%s"': 'unable to install plugin "%s"', +'unable to parse csv file': 'unable to parse csv file', +'unable to uninstall "%s"': 'unable to uninstall "%s"', +'unable to upgrade because "%s"': 'unable to upgrade because "%s"', 'uncheck all': 'uncheck all', 'Uninstall': 'Деинсталирај', +'Unsupported webserver working mode: %s': 'Unsupported webserver working mode: %s', 'update': 'ажурирај', 'update all languages': 'ажурирај све језике', +'Update:': 'Update:', +'Upgrade': 'Upgrade', +'upgrade now to %s': 'upgrade now to %s', 'upload': 'Отпреми', +'Upload': 'Upload', 'Upload a package:': 'Преузми пакет:', 'Upload and install packed application': 'Преузми и инсталирај запаковану апликацију', 'upload file:': 'преузми датотеку:', 'upload plugin file:': 'преузми плагин датотеку:', +'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.', +'User': 'User', +'Username': 'Username', +'Users': 'Users', +'Using the shell may lock the database to other users of this app.': 'Using the shell may lock the database to other users of this app.', 'variables': 'variables', 'Version': 'Верзија', 'Version %s.%s.%s (%s) %s': 'Верзија %s.%s.%s (%s) %s', 'Versioning': 'Versioning', -'views': 'views', 'Views': 'Views', +'views': 'views', +'Warning!': 'Warning!', +'WARNING:': 'WARNING:', +'WARNING: The following views could not be compiled:': 'WARNING: The following views could not be compiled:', 'Web Framework': 'Web Framework', +'web2py Admin Password': 'web2py Admin Password', +'web2py apps to deploy': 'web2py apps to deploy', +'web2py Debugger': 'web2py Debugger', +'web2py downgrade': 'web2py downgrade', 'web2py is up to date': 'web2py је ажуран', +'web2py online debugger': 'web2py online debugger', 'web2py Recent Tweets': 'web2py Recent Tweets', +'web2py upgrade': 'web2py upgrade', +'web2py upgraded; please restart it': 'web2py upgraded; please restart it', +'Working...': 'Working...', 'Wrap with Abbreviation': 'Wrap with Abbreviation', +'WSGI reference name': 'WSGI reference name', +'YES': 'YES', +'Yes': 'Yes', +'You can also set and remove breakpoint in the edit window, using the Toggle Breakpoint button': 'You can also set and remove breakpoint in the edit window, using the Toggle Breakpoint button', +'You can inspect variables using the console below': 'You can inspect variables using the console below', +'You have one more login attempt before you are locked out': 'You have one more login attempt before you are locked out', +'You need to set up and reach a': 'You need to set up and reach a', +'You only need these if you have already registered': 'You only need these if you have already registered', +'Your application will be blocked until you click an action button (next, step, continue, etc.)': 'Your application will be blocked until you click an action button (next, step, continue, etc.)', } diff --git a/applications/admin/languages/sr-lt.py b/applications/admin/languages/sr-lt.py index 64f8eb7f..659cb84e 100755 --- a/applications/admin/languages/sr-lt.py +++ b/applications/admin/languages/sr-lt.py @@ -2,211 +2,594 @@ { '!langcode!': 'sr-lt', '!langname!': 'Srpski (Latinica)', +'"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN': '"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN', +'"User Exception" debug mode. ': '"User Exception" debug mode. ', +'%s': '%s', +'%s %%{row} deleted': '%s %%{row} deleted', +'%s %%{row} updated': '%s %%{row} updated', +'%s selected': '%s selected', +'%s students registered': '%s students registered', '%Y-%m-%d': '%d-%m-%Y', '%Y-%m-%d %H:%M:%S': '%d-%m-%Y %H:%M:%S', '(requires internet access)': '(zahtijeva pristup internetu)', +'(requires internet access, experimental)': '(requires internet access, experimental)', '(something like "it-it")': '(nešto kao "it-it")', +'(version %s)': '(version %s)', +'?': '?', '@markmin\x01(file **gluon/contrib/plural_rules/%s.py** is not found)': '(datoteka **gluon/contrib/plural_rules/%s.py** nije pronađena)', +'Abort': 'Abort', 'About': 'Informacije', 'About application': 'O aplikaciji', +'Accept Terms': 'Accept Terms', +'Add breakpoint': 'Add breakpoint', 'Additional code for your application': 'Dodatni kod za aplikaciju', +'Admin design page': 'Admin design page', +'admin disabled because no admin password': 'admin disabled because no admin password', +'admin disabled because not supported on google app engine': 'admin disabled because not supported on google app engine', +'admin disabled because too many invalid login attempts': 'admin disabled because too many invalid login attempts', 'admin disabled because unable to access password file': 'administracija onemogućena jer ne mogu pristupiti datoteci sa lozinkom', +'Admin is disabled because insecure channel': 'Admin is disabled because insecure channel', 'Admin language': 'Jezik administratora', +'Admin versioning page': 'Admin versioning page', 'administrative interface': 'administrativni interfejs', 'Administrator Password:': 'Lozinka administratora:', 'and rename it:': 'i preimenuj u:', +'App does not exist or you are not authorized': 'App does not exist or you are not authorized', +'appadmin': 'appadmin', +'appadmin is disabled because insecure channel': 'appadmin is disabled because insecure channel', +'Application': 'Application', +'application "%s" uninstalled': 'application "%s" uninstalled', +'Application cannot be generated in demo mode': 'Application cannot be generated in demo mode', +'application compiled': 'application compiled', +'Application exists already': 'Application exists already', +'application is compiled and cannot be designed': 'application is compiled and cannot be designed', 'Application name:': 'Naziv aplikacije:', +'Application updated via git pull': 'Application updated via git pull', 'are not used': 'nije korišteno', 'are not used yet': 'nije još korišteno', +'Are you sure you want to delete file "%s"?': 'Are you sure you want to delete file "%s"?', +'Are you sure you want to delete plugin "%s"?': 'Are you sure you want to delete plugin "%s"?', 'Are you sure you want to delete this object?': 'Da li ste sigurni da želite obrisati?', +'Are you sure you want to uninstall application "%s"?': 'Are you sure you want to uninstall application "%s"?', +'Are you sure?': 'Are you sure?', 'arguments': 'arguments', 'at char %s': 'kod slova %s', 'at line %s': 'na liniji %s', +'ATTENTION:': 'ATTENTION:', +'ATTENTION: Login requires a secure (HTTPS) connection or running on localhost.': 'ATTENTION: Login requires a secure (HTTPS) connection or running on localhost.', 'ATTENTION: TESTING IS NOT THREAD SAFE SO DO NOT PERFORM MULTIPLE TESTS CONCURRENTLY.': 'ATTENTION: TESTING IS NOT THREAD SAFE SO DO NOT PERFORM MULTIPLE TESTS CONCURRENTLY.', +'ATTENTION: you cannot edit the running application!': 'ATTENTION: you cannot edit the running application!', +'Autocomplete Python Code': 'Autocomplete Python Code', +'Available Databases and Tables': 'Available Databases and Tables', 'back': 'nazad', +'Back to the plugins list': 'Back to the plugins list', +'Back to wizard': 'Back to wizard', 'Basics': 'Osnove', 'Begin': 'Početak', +'breakpoint': 'breakpoint', +'Breakpoints': 'Breakpoints', +'breakpoints': 'breakpoints', +'Bulk Register': 'Bulk Register', +'Bulk Student Registration': 'Bulk Student Registration', +'Cache': 'Cache', +'cache': 'cache', +'Cache Cleared': 'Cache Cleared', +'Cache Keys': 'Cache Keys', 'cache, errors and sessions cleaned': 'keš, greške i sesije su obrisani', 'can be a git repo': 'može biti git repo', +'Cancel': 'Cancel', +'Cannot be empty': 'Cannot be empty', +'Cannot compile: there are errors in your app:': 'Cannot compile: there are errors in your app:', +'cannot create file': 'cannot create file', 'cannot upload file "%(filename)s"': 'ne mogu otpremiti datoteku "%(filename)s"', +'Change Admin Password': 'Change Admin Password', 'Change admin password': 'Promijeni lozinku administratora', +'change editor settings': 'change editor settings', +'Changelog': 'Changelog', 'check all': 'check all', 'Check for upgrades': 'Provjeri mogućnost nadogradnje', +'Check to delete': 'Check to delete', 'Checking for upgrades...': 'Provjeravam mogućnost nadogradnje...', 'Clean': 'Pročisti', +'Clear': 'Clear', +'Clear CACHE?': 'Clear CACHE?', +'Clear DISK': 'Clear DISK', +'Clear RAM': 'Clear RAM', 'Click row to expand traceback': 'Click row to expand traceback', +'Click row to view a ticket': 'Click row to view a ticket', 'code': 'kod', +'Code listing': 'Code listing', 'collapse/expand all': 'sakriti/prikazati sve', +'Command': 'Command', +'Comment:': 'Comment:', +'Commit': 'Commit', +'Commit form': 'Commit form', +'Committed files': 'Committed files', 'Compile': 'Kompajliraj', +'Compile (all or nothing)': 'Compile (all or nothing)', +'Compile (skip failed views)': 'Compile (skip failed views)', +'compiled application removed': 'compiled application removed', +'Condition': 'Condition', +'continue': 'continue', 'Controllers': 'Kontroleri', 'controllers': 'kontroleri', 'Count': 'Count', 'Create': 'Kreiraj', 'create file with filename:': 'Kreiraj datoteku pod nazivom:', 'Create rules': 'Kreiraj pravila', +'Create/Upload': 'Create/Upload', 'created by': 'izradio', +'Created by:': 'Created by:', +'Created On': 'Created On', +'Created on:': 'Created on:', 'crontab': 'crontab', +'Current request': 'Current request', +'Current response': 'Current response', +'Current session': 'Current session', 'currently running': 'trenutno pokrenut', 'currently saved or': 'trenutno sačuvano ili', +'data uploaded': 'data uploaded', +'Database': 'Database', +'Database %s select': 'Database %s select', +'Database administration': 'Database administration', 'database administration': 'administracija baze podataka', +'Database Administration (appadmin)': 'Database Administration (appadmin)', +'Date and Time': 'Date and Time', +'db': 'db', 'Debug': 'Debug', 'defines tables': 'definiše tabele', -'delete': 'obriši', 'Delete': 'Obriši', +'delete': 'obriši', 'delete all checked': 'delete all checked', +'delete plugin': 'delete plugin', 'Delete this file (you will be asked to confirm deletion)': 'Obriši ovu datoteku (bićete upitani za potvrdu brisanja)', +'Delete:': 'Delete:', +'deleted after first hit': 'deleted after first hit', +'Demo': 'Demo', 'Deploy': 'Postavi', 'Deploy on Google App Engine': 'Postavi na Google App Engine', 'Deploy to OpenShift': 'Postavi na OpenShift', +'Deploy to pythonanywhere': 'Deploy to pythonanywhere', +'Deploy to PythonAnywhere': 'Deploy to PythonAnywhere', +'Deployment form': 'Deployment form', +'Deployment Interface': 'Deployment Interface', +'Description:': 'Description:', +'design': 'design', 'Detailed traceback description': 'Detailed traceback description', +'details': 'details', 'direction: ltr': 'direction: ltr', +'directory not found': 'directory not found', 'Disable': 'Isključi', +'Disabled': 'Disabled', +'disabled in demo mode': 'disabled in demo mode', +'disabled in GAE mode': 'disabled in GAE mode', +'disabled in multi user mode': 'disabled in multi user mode', +'DISK': 'DISK', +'Disk Cache Keys': 'Disk Cache Keys', +'Disk Cleared': 'Disk Cleared', +'Display line numbers': 'Display line numbers', +'DO NOT use the "Pack compiled" feature.': 'DO NOT use the "Pack compiled" feature.', 'docs': 'dokumentacija', +'Docs': 'Docs', +'done!': 'done!', +'Downgrade': 'Downgrade', +'Download .w2p': 'Download .w2p', +'Download as .exe': 'Download as .exe', 'download layouts': 'preuzmi layouts', +'Download layouts from repository': 'Download layouts from repository', 'download plugins': 'preuzmi plugins', +'Download plugins from repository': 'Download plugins from repository', 'Edit': 'Uređivanje', 'edit all': 'uredi sve', 'Edit application': 'Uredi aplikaciju', 'edit controller': 'uredi controller', +'edit controller:': 'edit controller:', +'Edit current record': 'Edit current record', 'edit views:': 'uredi views:', +'Editing %s': 'Editing %s', 'Editing file "%s"': 'Uređivanje datoteke "%s"', 'Editing Language file': 'Uređivanje jezičke datoteke', +'Editing Plural Forms File': 'Editing Plural Forms File', +'Editor': 'Editor', +'Email Address': 'Email Address', +'Enable': 'Enable', +'Enable Close-Tag': 'Enable Close-Tag', +'Enable Code Folding': 'Enable Code Folding', 'Error': 'Greška', 'Error logs for "%(app)s"': 'Pregled grešaka za "%(app)s"', 'Error snapshot': 'Error snapshot', 'Error ticket': 'Error ticket', 'Errors': 'Greške', +'Exception %(extype)s: %(exvalue)s': 'Exception %(extype)s: %(exvalue)s', +'Exception %s': 'Exception %s', 'Exception instance attributes': 'Exception instance attributes', +'Exit Fullscreen': 'Exit Fullscreen', 'Expand Abbreviation': 'Expand Abbreviation', +'Expand Abbreviation (html files only)': 'Expand Abbreviation (html files only)', +'export as csv file': 'export as csv file', +'Exports:': 'Exports:', 'exposes': 'exposes', 'exposes:': 'exposes:', 'extends': 'proširuje', 'failed to compile file because:': 'nisam mogao da kompajliram zbog:', +'failed to reload module because:': 'failed to reload module because:', 'File': 'Datoteka', +'file "%(filename)s" created': 'file "%(filename)s" created', +'file "%(filename)s" deleted': 'file "%(filename)s" deleted', +'file "%(filename)s" uploaded': 'file "%(filename)s" uploaded', +'file "%s" of %s restored': 'file "%s" of %s restored', +'file changed on disk': 'file changed on disk', 'file does not exist': 'datoteka ne postoji', +'file not found': 'file not found', +'file saved on %(time)s': 'file saved on %(time)s', 'file saved on %s': 'datoteka sačuvana na %s', +'filename': 'filename', +'Filename': 'Filename', +'Files added': 'Files added', 'filter': 'filter', 'Find Next': 'Pronađi sljedeći', 'Find Previous': 'Pronađi prethodni', +'Form has errors': 'Form has errors', 'Frames': 'Frames', 'Functions with no doctests will result in [passed] tests.': 'Functions with no doctests will result in [passed] tests.', +'GAE Email': 'GAE Email', +'GAE Output': 'GAE Output', +'GAE Password': 'GAE Password', 'Generate': 'Generate', 'Get from URL:': 'Preuzmi sa stranice:', 'Git Pull': 'Git Pull', 'Git Push': 'Git Push', +'Globals##debug': 'Globals##debug', 'Go to Matching Pair': 'Go to Matching Pair', 'go!': 'kreni!', +'Google App Engine Deployment Interface': 'Google App Engine Deployment Interface', +'Google Application Id': 'Google Application Id', +'Goto': 'Goto', +'graph model': 'graph model', +'Graph Model': 'Graph Model', 'Help': 'Pomoć', +'here': 'here', 'Hide/Show Translated strings': 'Sakriti/Prikazati prevedene riječi', +'Highlight current line': 'Highlight current line', +'Hits': 'Hits', +'Home': 'Home', +'honored only if the expression evaluates to true': 'honored only if the expression evaluates to true', +'If start the downgrade, be patient, it may take a while to rollback': 'If start the downgrade, be patient, it may take a while to rollback', +'If start the upgrade, be patient, it may take a while to download': 'If start the upgrade, be patient, it may take a while to download', +'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\n\t\tA green title indicates that all tests (if defined) passed. In this case test results are not shown.': 'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\n\t\tA green title indicates that all tests (if defined) passed. In this case test results are not shown.', 'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\nA green title indicates that all tests (if defined) passed. In this case test results are not shown.': 'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\nA green title indicates that all tests (if defined) passed. In this case test results are not shown.', +'if your application uses a database other than sqlite you will then have to configure its DAL in pythonanywhere.': 'if your application uses a database other than sqlite you will then have to configure its DAL in pythonanywhere.', +'import': 'import', +'Import/Export': 'Import/Export', +'In development, use the default Rocket webserver that is currently supported by this debugger.': 'In development, use the default Rocket webserver that is currently supported by this debugger.', 'includes': 'uključuje', +'Indent with tabs': 'Indent with tabs', 'inspect attributes': 'inspect attributes', 'Install': 'Instaliraj', +'Installation of %(plugin)s for %(app)s': 'Installation of %(plugin)s for %(app)s', 'Installed applications': 'Instalirane aplikacije', +'Interaction at %s line %s': 'Interaction at %s line %s', +'Interactive console': 'Interactive console', +'internal error': 'internal error', +'internal error: %s': 'internal error: %s', +'Internal State': 'Internal State', +'Invalid action': 'Invalid action', +'Invalid application name': 'Invalid application name', +'invalid circular reference': 'invalid circular reference', +'Invalid git repository specified.': 'Invalid git repository specified.', +'invalid password': 'invalid password', 'invalid password.': 'pogrešna lozinka.', +'Invalid Query': 'Invalid Query', +'invalid request': 'invalid request', +'Invalid request': 'Invalid request', +'invalid table names (auth_* tables already defined)': 'invalid table names (auth_* tables already defined)', +'invalid ticket': 'invalid ticket', +'Key': 'Key', 'Key bindings': 'Prečice', 'Key bindings for ZenCoding Plugin': 'Prečice za for ZenCoding Plugin', +'Keyboard shortcuts': 'Keyboard shortcuts', +'kill process': 'kill process', +'language file "%(filename)s" created/updated': 'language file "%(filename)s" created/updated', 'Language files (static strings) updated': 'Jezičke datoteke su ažurirane', 'languages': 'jezici', 'Languages': 'Jezici', +'Last Revision': 'Last Revision', 'Last saved on:': 'Posljednja izmjena:', 'License for': 'Licenca za', +'License:': 'License:', +'Line Nr': 'Line Nr', +'Line number': 'Line number', +'lists by exception': 'lists by exception', +'lists by ticket': 'lists by ticket', +'Loading...': 'Loading...', 'loading...': 'preuzimam...', +'Local Apps': 'Local Apps', 'locals': 'locals', +'Locals##debug': 'Locals##debug', 'Login': 'Prijava', +'Login successful': 'Login successful', 'Login to the Administrative Interface': 'Prijava za administrativni interfejs', +'Login/Register': 'Login/Register', 'Logout': 'Izlaz', +'lost password': 'lost password', +'Main Menu': 'Main Menu', +'Manage': 'Manage', +'Manage %(action)s': 'Manage %(action)s', +'Manage Access Control': 'Manage Access Control', +'Manage Admin Users/Students': 'Manage Admin Users/Students', +'Manage Cache': 'Manage Cache', +'Manage Students': 'Manage Students', 'Match Pair': 'Match Pair', +'Memberships': 'Memberships', +'merge': 'merge', 'Merge Lines': 'Spoji linije', -'models': 'models', 'Models': 'Models', +'models': 'models', +'Modified On': 'Modified On', 'Modules': 'Modules', 'modules': 'modules', +'Multi User Mode': 'Multi User Mode', +'new application "%s" created': 'new application "%s" created', +'new application "%s" imported': 'new application "%s" imported', 'New Application Wizard': 'Čarobnjak za nove aplikacije', 'New application wizard': 'Čarobnjak za nove aplikacije', +'new plugin installed': 'new plugin installed', +'New plugin installed: %s': 'New plugin installed: %s', +'New Record': 'New Record', +'new record inserted': 'new record inserted', 'New simple application': 'Nova jednostavna aplikacija', +'next': 'next', +'next %s rows': 'next %s rows', 'Next Edit Point': 'Next Edit Point', +'NO': 'NO', +'no changes': 'no changes', +'No databases in this application': 'No databases in this application', +'No Interaction yet': 'No Interaction yet', +'no match': 'no match', +'no package selected': 'no package selected', +'no permission to uninstall "%s"': 'no permission to uninstall "%s"', 'No ticket_storage.txt found under /private folder': 'No ticket_storage.txt found under /private folder', +'Node:': 'Node:', +'Not Authorized': 'Not Authorized', +'Not supported': 'Not supported', +'Note: If you receive an error with github status code of 128, ensure the system and account you are deploying from has a cooresponding ssh key configured in the openshift account.': 'Note: If you receive an error with github status code of 128, ensure the system and account you are deploying from has a cooresponding ssh key configured in the openshift account.', +"On production, you'll have to configure your webserver to use one process and multiple threads to use this debugger.": "On production, you'll have to configure your webserver to use one process and multiple threads to use this debugger.", 'online designer': 'onlajn dizajner', +'Open new app in new window': 'Open new app in new window', +'OpenShift Deployment Interface': 'OpenShift Deployment Interface', +'OpenShift Output': 'OpenShift Output', +'or alternatively': 'or alternatively', +'Or Get from URL:': 'Or Get from URL:', +'or import from csv file': 'or import from csv file', 'Original/Translation': 'Original/Prevod', +'Overview': 'Overview', 'Overwrite installed app': 'Prebriši postojeću aplikaciju', 'Pack all': 'Zapakuj sve', +'Pack compiled': 'Pack compiled', +'Pack custom': 'Pack custom', +'pack plugin': 'pack plugin', +'password changed': 'password changed', +'Past revisions': 'Past revisions', +'Path to appcfg.py': 'Path to appcfg.py', +'Path to local openshift repo root.': 'Path to local openshift repo root.', 'Peeking at file': 'Peeking at file', -'Plugins': 'Plugins', +'Permission': 'Permission', +'Permissions': 'Permissions', +'Please': 'Please', +'Please wait, giving pythonanywhere a moment...': 'Please wait, giving pythonanywhere a moment...', +'plugin "%(plugin)s" deleted': 'plugin "%(plugin)s" deleted', +'Plugin "%s" in application': 'Plugin "%s" in application', +'plugin not specified': 'plugin not specified', +'Plugin page': 'Plugin page', 'plugins': 'plugins', +'Plugins': 'Plugins', +'Plural Form #%s': 'Plural Form #%s', 'Plural-Forms:': 'Plural-Forms:', 'Powered by': 'Omogućio', +'Preferences saved correctly': 'Preferences saved correctly', +'Preferences saved on session only': 'Preferences saved on session only', +'previous %s rows': 'previous %s rows', 'Previous Edit Point': 'Previous Edit Point', 'Private files': 'Private files', 'private files': 'private files', 'Project Progress': 'Napredak projekta', +'Pull': 'Pull', +'Pull failed, certain files could not be checked out. Check logs for details.': 'Pull failed, certain files could not be checked out. Check logs for details.', +'Pull is not possible because you have unmerged files. Fix them up in the work tree, and then try again.': 'Pull is not possible because you have unmerged files. Fix them up in the work tree, and then try again.', +'Push': 'Push', +'Push failed, there are unmerged entries in the cache. Resolve merge issues manually and try again.': 'Push failed, there are unmerged entries in the cache. Resolve merge issues manually and try again.', +'pygraphviz library not found': 'pygraphviz library not found', +'PythonAnywhere Apps': 'PythonAnywhere Apps', +'PythonAnywhere Password': 'PythonAnywhere Password', +'Query:': 'Query:', +'RAM': 'RAM', +'RAM Cache Keys': 'RAM Cache Keys', +'Ram Cleared': 'Ram Cleared', +'Rapid Search': 'Rapid Search', +'Record': 'Record', +'record does not exist': 'record does not exist', +'Record id': 'Record id', +'refresh': 'refresh', +'register': 'register', 'Reload routes': 'Obnovi preusmjerenja', +'Remove compiled': 'Remove compiled', 'Removed Breakpoint on %s at line %s': 'Removed Breakpoint on %s at line %s', 'Replace': 'Zamijeni', 'Replace All': 'Zamijeni sve', +'Repository (%s)': 'Repository (%s)', 'request': 'request', +'requires distutils, but not installed': 'requires distutils, but not installed', +'requires python-git, but not installed': 'requires python-git, but not installed', +'Resolve Conflict file': 'Resolve Conflict file', 'response': 'response', 'restart': 'restart', 'restore': 'restore', +'return': 'return', +'Revert': 'Revert', 'revert': 'revert', +'reverted to revision %s': 'reverted to revision %s', +'Revision %s': 'Revision %s', +'Revision:': 'Revision:', +'Role': 'Role', +'Roles': 'Roles', +'Rows in Table': 'Rows in Table', +'Rows selected': 'Rows selected', 'rules are not defined': 'pravila nisu definisana', 'rules:': 'pravila:', +'Run tests': 'Run tests', +'Run tests in this file': 'Run tests in this file', "Run tests in this file (to run all files, you may also use the button labelled 'test')": "Run tests in this file (to run all files, you may also use the button labelled 'test')", 'Running on %s': 'Pokrenuto na %s', 'Save': 'Sačuvaj', +'Save file:': 'Save file:', +'Save file: %s': 'Save file: %s', +'Save model as...': 'Save model as...', 'Save via Ajax': 'Sačuvaj via Ajax', 'Saved file hash:': 'Sačuvano kao haš:', +'Screenshot %s': 'Screenshot %s', +'Search': 'Search', +'Select Files to Package': 'Select Files to Package', 'session': 'sesija', 'session expired': 'sesija istekla', +'Session saved correctly': 'Session saved correctly', +'Session saved on session only': 'Session saved on session only', 'Set Breakpoint on %s at line %s: %s': 'Set Breakpoint on %s at line %s: %s', 'shell': 'shell', +'Showing %s to %s of %s %s found': 'Showing %s to %s of %s %s found', +'Singular Form': 'Singular Form', 'Site': 'Sajt', +'Size of cache:': 'Size of cache:', 'skip to generate': 'skip to generate', +'some files could not be removed': 'some files could not be removed', +'Something went wrong please wait a few minutes before retrying': 'Something went wrong please wait a few minutes before retrying', +'Sorry, could not find mercurial installed': 'Sorry, could not find mercurial installed', +'source : db': 'source : db', +'source : filesystem': 'source : filesystem', 'Start a new app': 'Pokreni novu aplikaciju', 'Start searching': 'Pokreni pretragu', 'Start wizard': 'Pokreni čarobnjaka', +'state': 'state', +'Static': 'Static', 'static': 'static', 'Static files': 'Static files', +'Statistics': 'Statistics', 'Step': 'Korak', +'step': 'step', +'stop': 'stop', +'submit': 'submit', 'Submit': 'Prihvati', 'successful': 'uspješan', +'switch to : db': 'switch to : db', +'switch to : filesystem': 'switch to : filesystem', +'Tab width (# characters)': 'Tab width (# characters)', +'Table': 'Table', +'Temporary': 'Temporary', 'test': 'test', 'Testing application': 'Testing application', +'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.': 'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.', +'The app exists, was created by wizard, continue to overwrite!': 'The app exists, was created by wizard, continue to overwrite!', +'The app exists, was NOT created by wizard, continue to overwrite!': 'The app exists, was NOT created by wizard, continue to overwrite!', 'The application logic, each URL path is mapped in one exposed function in the controller': 'The application logic, each URL path is mapped in one exposed function in the controller', 'The data representation, define database tables and sets': 'The data representation, define database tables and sets', 'The presentations layer, views are also known as templates': 'The presentations layer, views are also known as templates', +'Theme': 'Theme', +'There are no controllers': 'There are no controllers', 'There are no models': 'There are no models', +'There are no modules': 'There are no modules', 'There are no plugins': 'There are no plugins', 'There are no private files': 'There are no private files', +'There are no static files': 'There are no static files', +'There are no translators': 'There are no translators', +'There are no translators, only default language is supported': 'There are no translators, only default language is supported', +'There are no views': 'There are no views', 'These files are not served, they are only available from within your app': 'These files are not served, they are only available from within your app', 'These files are served without processing, your images go here': 'These files are served without processing, your images go here', +"This debugger may not work properly if you don't have a threaded webserver or you're using multiple daemon processes.": "This debugger may not work properly if you don't have a threaded webserver or you're using multiple daemon processes.", +'This is an experimental feature and it needs more testing. If you decide to downgrade you do it at your own risk': 'This is an experimental feature and it needs more testing. If you decide to downgrade you do it at your own risk', +'This is an experimental feature and it needs more testing. If you decide to upgrade you do it at your own risk': 'This is an experimental feature and it needs more testing. If you decide to upgrade you do it at your own risk', +"This page can commit your changes to an openshift app repo and push them to your cloud instance. This assumes that you've already created the application instance using the web2py skeleton and have that repo somewhere on a filesystem that this web2py instance can access. This functionality requires GitPython installed and on the python path of the runtime that web2py is operating in.": "This page can commit your changes to an openshift app repo and push them to your cloud instance. This assumes that you've already created the application instance using the web2py skeleton and have that repo somewhere on a filesystem that this web2py instance can access. This functionality requires GitPython installed and on the python path of the runtime that web2py is operating in.", +'This page can upload your application to the Google App Engine computing cloud. Mind that you must first create indexes locally and this is done by installing the Google appserver and running the app locally with it once, or there will be errors when selecting records. Attention: deployment may take long time, depending on the network speed. Attention: it will overwrite your app.yaml. DO NOT SUBMIT TWICE.': 'This page can upload your application to the Google App Engine computing cloud. Mind that you must first create indexes locally and this is done by installing the Google appserver and running the app locally with it once, or there will be errors when selecting records. Attention: deployment may take long time, depending on the network speed. Attention: it will overwrite your app.yaml. DO NOT SUBMIT TWICE.', +'this page to see if a breakpoint was hit and debug interaction is required.': 'this page to see if a breakpoint was hit and debug interaction is required.', +'This will pull changes from the remote repo for application "%s"?': 'This will pull changes from the remote repo for application "%s"?', +'This will push changes to the remote repo for application "%s".': 'This will push changes to the remote repo for application "%s".', +'Ticket': 'Ticket', 'Ticket ID': 'Ticket ID', 'Ticket Missing': 'Ticket nedostaje', +'Time in Cache (h:m:s)': 'Time in Cache (h:m:s)', 'to previous version.': 'na prethodnu verziju.', 'To create a plugin, name a file/folder plugin_[name]': 'To create a plugin, name a file/folder plugin_[name]', +'To emulate a breakpoint programatically, write:': 'To emulate a breakpoint programatically, write:', +'to use the debugger!': 'to use the debugger!', 'toggle breakpoint': 'toggle breakpoint', +'Toggle comment': 'Toggle comment', 'Toggle Fullscreen': 'Toggle Fullscreen', 'Traceback': 'Traceback', 'Translation strings for the application': 'Riječi u aplikaciji koje treba prevesti', +'try something like': 'try something like', 'Try the mobile interface': 'Probaj mobilni interfejs', 'try view': 'try view', +'Type PDB debugger command in here and hit Return (Enter) to execute it.': 'Type PDB debugger command in here and hit Return (Enter) to execute it.', +'Type some Python code in here and hit Return (Enter) to execute it.': 'Type some Python code in here and hit Return (Enter) to execute it.', +'Unable to check for upgrades': 'Unable to check for upgrades', +'unable to create application "%s"': 'unable to create application "%s"', +'unable to delete file "%(filename)s"': 'unable to delete file "%(filename)s"', +'unable to delete file plugin "%(plugin)s"': 'unable to delete file plugin "%(plugin)s"', +'Unable to determine the line number!': 'Unable to determine the line number!', +'Unable to download app because:': 'Unable to download app because:', +'unable to download layout': 'unable to download layout', +'unable to download plugin: %s': 'unable to download plugin: %s', +'Unable to download the list of plugins': 'Unable to download the list of plugins', +'unable to install plugin "%s"': 'unable to install plugin "%s"', +'unable to parse csv file': 'unable to parse csv file', +'unable to uninstall "%s"': 'unable to uninstall "%s"', +'unable to upgrade because "%s"': 'unable to upgrade because "%s"', 'uncheck all': 'uncheck all', 'Uninstall': 'Deinstaliraj', +'Unsupported webserver working mode: %s': 'Unsupported webserver working mode: %s', 'update': 'ažuriraj', 'update all languages': 'ažuriraj sve jezike', +'Update:': 'Update:', +'Upgrade': 'Upgrade', +'upgrade now to %s': 'upgrade now to %s', 'upload': 'Otpremi', +'Upload': 'Upload', 'Upload a package:': 'Preuzmi paket:', 'Upload and install packed application': 'Preuzmi i instaliraj zapakovanu aplikaciju', 'upload file:': 'preuzmi datoteku:', 'upload plugin file:': 'preuzmi plugin datoteku:', +'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.', +'User': 'User', +'Username': 'Username', +'Users': 'Users', +'Using the shell may lock the database to other users of this app.': 'Using the shell may lock the database to other users of this app.', 'variables': 'variables', 'Version': 'Verzija', 'Version %s.%s.%s (%s) %s': 'Verzija %s.%s.%s (%s) %s', 'Versioning': 'Versioning', -'views': 'views', 'Views': 'Views', +'views': 'views', +'Warning!': 'Warning!', +'WARNING:': 'WARNING:', +'WARNING: The following views could not be compiled:': 'WARNING: The following views could not be compiled:', 'Web Framework': 'Web Framework', +'web2py Admin Password': 'web2py Admin Password', +'web2py apps to deploy': 'web2py apps to deploy', +'web2py Debugger': 'web2py Debugger', +'web2py downgrade': 'web2py downgrade', 'web2py is up to date': 'web2py je ažuran', +'web2py online debugger': 'web2py online debugger', 'web2py Recent Tweets': 'web2py Recent Tweets', +'web2py upgrade': 'web2py upgrade', +'web2py upgraded; please restart it': 'web2py upgraded; please restart it', +'Working...': 'Working...', 'Wrap with Abbreviation': 'Wrap with Abbreviation', +'WSGI reference name': 'WSGI reference name', +'YES': 'YES', +'Yes': 'Yes', +'You can also set and remove breakpoint in the edit window, using the Toggle Breakpoint button': 'You can also set and remove breakpoint in the edit window, using the Toggle Breakpoint button', +'You can inspect variables using the console below': 'You can inspect variables using the console below', +'You have one more login attempt before you are locked out': 'You have one more login attempt before you are locked out', +'You need to set up and reach a': 'You need to set up and reach a', +'You only need these if you have already registered': 'You only need these if you have already registered', +'Your application will be blocked until you click an action button (next, step, continue, etc.)': 'Your application will be blocked until you click an action button (next, step, continue, etc.)', } diff --git a/applications/admin/languages/tr.py b/applications/admin/languages/tr.py index b31e25cd..50e52d8e 100755 --- a/applications/admin/languages/tr.py +++ b/applications/admin/languages/tr.py @@ -1,29 +1,38 @@ -# coding: utf-8 +# -*- coding: utf-8 -*- { '!langcode!': 'tr', '!langname!': 'Türkçe', '"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN': '"güncelleme" ("update") "field1 = \'yenideğer\'" gibi seçeneğe bağlı bir ifadedir. JOIN sonuçlarını silemez veya silemezsiniz.', +'"User Exception" debug mode. ': '"User Exception" debug mode. ', +'%s': '%s', '%s %%{row} deleted': '%s %%{row} silindi', '%s %%{row} updated': '%s %%{row} güncellendi', +'%s selected': '%s selected', +'%s students registered': '%s students registered', '%Y-%m-%d': '%d-%m-%Y', '%Y-%m-%d %H:%M:%S': '%d-%m-%Y %H:%M:%S', '(requires internet access)': '(Internet erişimi gerekir)', '(requires internet access, experimental)': '(internet erişimi gerekir, deneysel)', '(something like "it-it")': '("it-it" şeklinde birşeyler) ', +'(version %s)': '(version %s)', '1: Setting Parameters': '1: Parametrelerin Yapılandırılması', +'?': '?', '@markmin\x01An error occured, please [[reload %s]] the page': '@markmin\x01Bir hata oluştu, lütfen sayfayı [[reload %s]]', "@markmin\x01Mercurial Version Control System Interface[[NEWLINE]]for application '%s'": "'%s' uygulaması için[[NEWLINE]]Mercurial Sürüm Kontrol Sistemi Arayüzü", '@markmin\x01Searching: **%s** %%{file}': '@markmin\x01Aranıyor: **%s** %%{file}', 'A new version of web2py is available: %s': "web2py'nin yeni sürümü mevcut: %s ", 'A new version of web2py is available: Version 1.68.2 (2009-10-21 09:59:29)\n': "web2py'nin yeni sürümü mevcut: Sürüm 1.68.2 (2009-10-21 09:59:29)\r\n", +'Abort': 'Abort', 'About': 'Hakkında', 'About application': 'Uygulama hakkında', +'Accept Terms': 'Accept Terms', 'Add breakpoint': 'Kesme noktası ekle', 'additional code for your application': 'uygulamanız için fazladan kod', 'Additional code for your application': 'Uygulamanız için fazladan kod', 'Admin design page': 'Yönetici tasarım sayfası', 'admin disabled because no admin password': 'yönetici parolası olmadığından admin etkinsiz', 'admin disabled because not supported on google app engine': 'Google App Motoru tafaından desteklenmediğinden admin etkinsizleştirildi', +'admin disabled because too many invalid login attempts': 'admin disabled because too many invalid login attempts', 'admin disabled because unable to access password file': 'parola dosyasına erişielemdiğinden admin etkinsizleştirildi', 'Admin is disabled because insecure channel': 'güvenzis kanal olduğundan admin etkinsizleştirildi', 'Admin language': 'Admin dilleri', @@ -32,14 +41,18 @@ 'Administrator Password:': 'Yönetici Parolası:', 'and rename it (required):': 've yeniden adlandır (gerekli):', 'and rename it:': 'yeniden adlandır:', +'App does not exist or you are not authorized': 'App does not exist or you are not authorized', 'appadmin': 'appadmin', 'appadmin is disabled because insecure channel': 'güvenzis kanal olduğundan admin etkinsizleştirildi', 'Application': 'Uygulama', 'application "%s" uninstalled': '"%s" uygulaması kaldırıldı', 'application %(appname)s installed with md5sum: %(digest)s': '%(appname)s uygulaması md5sum %(digest)s ile kuruldu', +'Application cannot be generated in demo mode': 'Application cannot be generated in demo mode', 'application compiled': 'uygulama derlendi', +'Application exists already': 'Application exists already', 'application is compiled and cannot be designed': 'uygulama derlenmiş ve tasarlanamaz', 'Application name:': 'Uygulama adı:', +'Application updated via git pull': 'Application updated via git pull', 'are not used': 'kullanılamıyor', 'are not used yet': 'şimdilik kullanılamıyor', 'Are you sure you want to delete file "%s"?': '«%s» dosyasını silmek istediğinize emin misiniz?', @@ -47,20 +60,31 @@ 'Are you sure you want to delete this object?': 'Bu nesneyi silmek istediğinizden emin misiniz?', 'Are you sure you want to uninstall application "%s"?': '«%s» uygulamasını kaldırmak istediğinizden emin misiniz?', 'Are you sure you want to upgrade web2py now?': "web2py'yi güncellemek istediğinizden emin misiniz?", +'Are you sure?': 'Are you sure?', 'arguments': 'argümanlar', +'at char %s': 'at char %s', +'at line %s': 'at line %s', +'ATTENTION:': 'ATTENTION:', 'ATTENTION: Login requires a secure (HTTPS) connection or running on localhost.': 'UYARI: Giriş günceli bağlantı (HTTPS) gerektirmekte veya yerel makinada çalışılmalıdır.', 'ATTENTION: TESTING IS NOT THREAD SAFE SO DO NOT PERFORM MULTIPLE TESTS CONCURRENTLY.': 'UYARI: ÇOKLU TEST GÜVENLİ DEĞİL. BİRDEN ÇOK TESTİ AYNI ANDA YAPMAYIN.', 'ATTENTION: you cannot edit the running application!': 'UYARI: çalışan uygulamayı düzenleyemezsiniz!', 'Autocomplete Python Code': 'Python Kodlarını Otomatik Tamamla', 'Available databases and tables': 'Kullanılabilir veritabanları ve tablolar', +'Available Databases and Tables': 'Available Databases and Tables', 'back': 'geri', +'Back to the plugins list': 'Back to the plugins list', 'Back to wizard': 'Sihirbaza geri dön', 'Basics': 'Temeller', 'Begin': 'Başla', 'breakpoint': 'kesme noktası', -'Breakpoints': 'Kesme Noktaları', 'breakpoints': 'kesme noktaları', +'Breakpoints': 'Kesme Noktaları', +'Bulk Register': 'Bulk Register', +'Bulk Student Registration': 'Bulk Student Registration', +'Cache': 'Cache', 'cache': 'zula', +'Cache Cleared': 'Cache Cleared', +'Cache Keys': 'Cache Keys', 'cache, errors and sessions cleaned': 'zula, hatalar ve oturumlar temizlendi', 'can be a git repo': 'git deposu olabilir', 'Cancel': 'Vazgeç', @@ -69,23 +93,36 @@ 'Cannot compile: there are errors in your app:': 'Derlenemiyor: uygulamanızda hata(lar) var:', 'cannot create file': 'dosya oluşturulamıyor', 'cannot upload file "%(filename)s"': '"%(filename)s" dosyalarını yükleyemiyor', +'Change Admin Password': 'Change Admin Password', 'Change admin password': 'admin parolasını değiştir', 'change editor settings': 'düzenleyici ayarlarını değiştir', +'Changelog': 'Changelog', 'check all': 'tümünü kontrol et', 'Check for upgrades': 'Güncellemeleri kontrol et', 'Check to delete': 'Silmek için kontrok et', 'Checking for upgrades...': 'Güncellemeler denetleniyor ... ', 'Clean': 'Temizle', +'Clear': 'Clear', +'Clear CACHE?': 'Clear CACHE?', +'Clear DISK': 'Clear DISK', +'Clear RAM': 'Clear RAM', 'Click row to expand traceback': 'Takibi genişletmek için satır üzerine tıkla', +'Click row to view a ticket': 'Click row to view a ticket', 'click to check for upgrades': 'güncellemeleri denetlemek için tıklayın', 'code': 'kod', +'Code listing': 'Code listing', 'collapse/expand all': 'sıkıştır/tümünü aç', +'Command': 'Command', 'Comment:': 'Yorum:', 'Commit': 'Öneri', 'Commit form': 'Tarafından öneri', +'Committed files': 'Committed files', 'Compile': 'Derle', +'Compile (all or nothing)': 'Compile (all or nothing)', +'Compile (skip failed views)': 'Compile (skip failed views)', 'compiled application removed': 'derlenmiş uygulama kaldırıldı', 'Condition': 'Durum', +'continue': 'continue', 'Controllers': 'Denetçiler', 'controllers': 'denetçiler', 'Count': 'Sayı', @@ -95,6 +132,9 @@ 'Create new simple application': 'Yeni basit uygulama oluştur', 'Create/Upload': 'Oluştur/Yükle', 'created by': 'yazan:', +'Created by:': 'Created by:', +'Created On': 'Created On', +'Created on:': 'Created on:', 'crontab': 'krontab', 'Current request': 'Şimdiki istek', 'Current response': 'Şimdiki yanıt', @@ -102,10 +142,13 @@ 'currently running': 'şimdiki çalışan', 'currently saved or': 'şimdiki kaydedilen veya', 'data uploaded': 'veri yüklendi', +'Database': 'Database', 'database': 'veritabı', +'Database %s select': 'Database %s select', 'database %s select': '%s veritabanı seçildi', 'Database administration': 'Veritabanı yönetimi', 'database administration': 'veritabı yönetimi', +'Database Administration (appadmin)': 'Database Administration (appadmin)', 'Date and Time': 'Tarih ve Zaman', 'db': 'db', 'Debug': 'Hata Ayıkla', @@ -117,19 +160,40 @@ 'Delete this file (you will be asked to confirm deletion)': 'Bu dosyayı sil (silmek için onay istenecek)', 'Delete:': 'Sil:', 'deleted after first hit': 'ilk vuruşta silinir', +'Demo': 'Demo', 'Deploy': 'Yayımla', 'Deploy on Google App Engine': 'Google App Motorunda Yayınla', 'Deploy to OpenShift': "OpenShift'e Yayınla ", +'Deploy to pythonanywhere': 'Deploy to pythonanywhere', +'Deploy to PythonAnywhere': 'Deploy to PythonAnywhere', 'Deployment form': 'Yayınlama formu', +'Deployment Interface': 'Deployment Interface', +'Description:': 'Description:', 'design': 'tadarla', 'Detailed traceback description': 'Ayrıntılı nedenin bulma tanımı', +'details': 'details', 'direction: ltr': 'yön: ltr', +'directory not found': 'directory not found', 'Disable': 'Devre Dışı', +'Disabled': 'Disabled', +'disabled in demo mode': 'disabled in demo mode', +'disabled in GAE mode': 'disabled in GAE mode', +'disabled in multi user mode': 'disabled in multi user mode', +'DISK': 'DISK', +'Disk Cache Keys': 'Disk Cache Keys', +'Disk Cleared': 'Disk Cleared', +'Display line numbers': 'Display line numbers', +'DO NOT use the "Pack compiled" feature.': 'DO NOT use the "Pack compiled" feature.', 'docs': 'dokümanlar', +'Docs': 'Docs', 'done!': 'bitti!', +'Downgrade': 'Downgrade', 'Download .w2p': '.w2p İndir', +'Download as .exe': 'Download as .exe', 'download layouts': 'düzenleri indir', +'Download layouts from repository': 'Download layouts from repository', 'download plugins': 'eklentileri indir', +'Download plugins from repository': 'Download plugins from repository', 'EDIT': 'DÜZENLE', 'Edit': 'Düzenle', 'edit all': 'tümünü düzenle', @@ -142,7 +206,12 @@ 'Editing file': 'Dosya düzenleniyor', 'Editing file "%s"': '"%s" dosyası düzenleniyor ', 'Editing Language file': 'Dil dosyası düzenleniyor', +'Editing Plural Forms File': 'Editing Plural Forms File', +'Editor': 'Editor', +'Email Address': 'Email Address', 'Enable': 'Etkinleştir', +'Enable Close-Tag': 'Enable Close-Tag', +'Enable Code Folding': 'Enable Code Folding', 'enter a valid email address': 'geçerli e-posta adresi girin', 'enter a value': 'bir değer girin', 'enter only letters, numbers, and underscore': 'sadece harf, sayı ve alt çizgi giriniz', @@ -152,13 +221,18 @@ 'Error snapshot': 'Hata resmi', 'Error ticket': 'Hata bileti', 'Errors': 'Hatalar', +'Exception %(extype)s: %(exvalue)s': 'Exception %(extype)s: %(exvalue)s', +'Exception %s': 'Exception %s', 'Exception instance attributes': 'Hata durumu özellikleri', 'Exit Fullscreen': 'Tam Ekrandan Çık', 'Expand Abbreviation': 'Kısıtlamayı Aç', +'Expand Abbreviation (html files only)': 'Expand Abbreviation (html files only)', 'export as csv file': 'CSV olarak dışa ver', +'Exports:': 'Exports:', 'exposes': 'sergileniyor', 'exposes:': 'sergile:', 'extends': 'genişlet', +'failed to compile file because:': 'failed to compile file because:', 'failed to reload module': 'modül yüklenemedi', 'failed to reload module because:': 'modü yüklenemedi çünkü:', 'File': 'Dosya', @@ -171,13 +245,17 @@ 'file not found': 'dosya bulanamadı', 'file saved on %(time)s': 'dosyası %(time)s zamanında kaydedildi', 'file saved on %s': 'dosyası kaydedildi: %s', +'filename': 'filename', 'Filename': 'Dosya adı', +'Files added': 'Files added', 'filter': 'filtre', 'Find Next': 'Sonrakini Bul', 'Find Previous': 'Öncekini Bul', +'Form has errors': 'Form has errors', 'Frames': 'Çerçeveler', 'Functions with no doctests will result in [passed] tests.': '[passed] testlerdeki işlevlerde doctest yok', 'GAE Email': 'GAE E-postası', +'GAE Output': 'GAE Output', 'GAE Password': 'GAE Parolası', 'Generate': 'Oluştur', 'Git Pull': 'Git Çek', @@ -188,79 +266,129 @@ 'Google Application Id': 'Google Uygulama Id', 'Goto': 'Git', 'graph model': 'grafik modeli', +'Graph Model': 'Graph Model', 'Help': 'Yardım', +'here': 'here', 'Hide/Show Translated strings': 'Çevrilmiş cümleleri Gizle/Görüntüle', +'Highlight current line': 'Highlight current line', 'Hits': 'Vuruşlar', 'Home': 'Anasayfa', 'honored only if the expression evaluates to true': 'sadece deyim doğru sonucunu verirse', 'htmledit': 'html dğzenleyici', +'If start the downgrade, be patient, it may take a while to rollback': 'If start the downgrade, be patient, it may take a while to rollback', +'If start the upgrade, be patient, it may take a while to download': 'If start the upgrade, be patient, it may take a while to download', +'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\n\t\tA green title indicates that all tests (if defined) passed. In this case test results are not shown.': 'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\n\t\tA green title indicates that all tests (if defined) passed. In this case test results are not shown.', 'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\nA green title indicates that all tests (if defined) passed. In this case test results are not shown.': 'Doküman testi yapılmadan önce, eğer yukarıdaki rapor bir bilet numarası içeriyorsa bu denetleyici çalıştırılırken bir hata oluşturğunu gösterir. Bu genellikle girinti/çıkıntı (indentation) hatası veya işlev dışındaki bir hatadan kaynaklanır.\nYeşil başlık geçilen tüm testleri (eğer tanımlanmışsa) gösterir. Bu durumda test sonuçları görüntülenmez.', +'if your application uses a database other than sqlite you will then have to configure its DAL in pythonanywhere.': 'if your application uses a database other than sqlite you will then have to configure its DAL in pythonanywhere.', +'import': 'import', 'Import/Export': 'İçe/Dışa Aktarıcı', +'In development, use the default Rocket webserver that is currently supported by this debugger.': 'In development, use the default Rocket webserver that is currently supported by this debugger.', 'includes': 'içerir', +'Indent with tabs': 'Indent with tabs', 'index': 'indeks', 'insert new': 'yeni ekle', 'insert new %s': '%s yeni ekle', 'inspect attributes': 'özellikleri denetleyin', 'Install': 'Kurucu', +'Installation of %(plugin)s for %(app)s': 'Installation of %(plugin)s for %(app)s', 'Installed applications': 'Kurulu uygulamalar', +'Interaction at %s line %s': 'Interaction at %s line %s', +'Interactive console': 'Interactive console', 'internal error': 'dahili hata', +'internal error: %s': 'internal error: %s', 'Internal State': 'Dahili Durum', 'Invalid action': 'Geçersiz eylem', +'Invalid application name': 'Invalid application name', +'invalid circular reference': 'invalid circular reference', 'invalid expression': 'geçersiz ifade', +'Invalid git repository specified.': 'Invalid git repository specified.', 'invalid password': 'Parola geçersiz', 'invalid password.': 'geçersiz parola.', 'Invalid Query': 'Geçersiz Sorgu', 'invalid request': 'geçersiz istek', +'Invalid request': 'Invalid request', +'invalid table names (auth_* tables already defined)': 'invalid table names (auth_* tables already defined)', 'invalid ticket': 'geçersiz bilet', +'Key': 'Key', 'Key bindings': 'Anahtarlar', 'Key bindings for ZenCoding Plugin': 'ZenCoding Eklentisi için anahtarlar', +'Keyboard shortcuts': 'Keyboard shortcuts', +'kill process': 'kill process', 'language file "%(filename)s" created/updated': '"%(filename)s" dil dosyası/dosyaları güncellendi', 'Language files (static strings) updated': 'Dil dosyası (statik cümleler) güncellendi', 'languages': 'diller', 'Languages': 'Diller', +'Last Revision': 'Last Revision', 'Last saved on:': 'Son kaydedilme:', 'License for': 'için lisanslanmış', +'License:': 'License:', 'Line Nr': 'Satır Nr', 'Line number': 'Satır numarası', 'lists by exception': 'istisnaya göre sırala', 'lists by ticket': 'bilete göre sırala', +'Loading...': 'Loading...', 'loading...': 'yükleniyor ...', +'Local Apps': 'Local Apps', 'locals': 'yereller', 'Locals##debug': 'Yereller', 'Login': 'Giriş', 'login': 'giriş', +'Login successful': 'Login successful', 'Login to the Administrative Interface': 'Yönetsel Arayüze Giriş\t', +'Login/Register': 'Login/Register', 'Logout': 'Çıkış', +'lost password': 'lost password', +'Main Menu': 'Main Menu', 'Manage': 'Yönet', +'Manage %(action)s': 'Manage %(action)s', +'Manage Access Control': 'Manage Access Control', +'Manage Admin Users/Students': 'Manage Admin Users/Students', +'Manage Cache': 'Manage Cache', +'Manage Students': 'Manage Students', +'Memberships': 'Memberships', 'merge': 'birleştir', 'Models': 'Modeller', 'models': 'modeller', +'Modified On': 'Modified On', 'Modules': 'Modüller', 'modules': 'modüller', +'Multi User Mode': 'Multi User Mode', 'new application "%s" created': 'yeni uygulama "%s" oluşturuldu', +'new application "%s" imported': 'new application "%s" imported', 'New Application Wizard': 'Yeni Uygulama Sihirbazı', 'New application wizard': 'Yeni uygulama sihirbazı', 'new plugin installed': 'yeni eklenti kuruldu', +'New plugin installed: %s': 'New plugin installed: %s', 'New Record': 'Yeni Kayıt', 'new record inserted': 'yeni kayıt eklendi', 'New simple application': 'Yeni basit uygulama', +'next': 'next', +'next %s rows': 'next %s rows', 'next 100 rows': 'sonraki 100 satır', 'NO': 'HAYIR', +'no changes': 'no changes', 'No databases in this application': 'Bu uygulamada veritabanı yok', 'No Interaction yet': 'Henüz etkileşim yok', 'no match': 'eşlenen yok', 'no package selected': 'hiç paket seçilmemiş', +'no permission to uninstall "%s"': 'no permission to uninstall "%s"', 'No ticket_storage.txt found under /private folder': '/private dizininde ticket_storage.txt dosyası bulunamadı', +'Node:': 'Node:', +'Not Authorized': 'Not Authorized', +'Not supported': 'Not supported', 'Note: If you receive an error with github status code of 128, ensure the system and account you are deploying from has a cooresponding ssh key configured in the openshift account.': 'Not: Eğer github hata kodu 128 durumunu bildiren bir ileti alırsanız, OpenShift hesabınızı ait ssh anahtarının doğru yapılandırıldığından emin olun.', +"On production, you'll have to configure your webserver to use one process and multiple threads to use this debugger.": "On production, you'll have to configure your webserver to use one process and multiple threads to use this debugger.", 'online designer': 'çevirimiçi tasarlayıcı', 'Open new app in new window': 'Yeni pencerede yeni uygualama aç', 'OpenShift Deployment Interface': 'OpenShift Yayınlama Arayüzü', +'OpenShift Output': 'OpenShift Output', 'or alternatively': 'veya seçenek olarak', 'Or Get from URL:': 'Veya şu URL den alın:', 'or import from csv file': 'veya CSV dsoyasından içerin', 'or provide app url:': "veya uygulama URL'si verin:", 'or provide application url:': "veya uygulama URL'si verin:", 'Original/Translation': 'Orjinal / Çeviri', +'Overview': 'Overview', 'Overwrite installed app': 'Kurulu uygulama üzerine yaz', 'Pack all': 'Tümünü paketle', 'Pack compiled': 'Derlenenleri paketle', @@ -268,106 +396,171 @@ 'pack plugin': 'eklentiyi paketle', 'PAM authenticated user, cannot change password here': 'PAM onaylı kullanıcı, parola buradan değiştirilemiyor', 'password changed': 'parola değiştirilidi', +'Past revisions': 'Past revisions', 'Path to appcfg.py': 'appcfg.py dosyasının patikası', 'Path to local openshift repo root.': 'Yerel openshift repo kökünün patikası.', 'Peeking at file': 'Dosya gözetleniyor', +'Permission': 'Permission', +'Permissions': 'Permissions', 'Please': 'Lütfen', +'Please wait, giving pythonanywhere a moment...': 'Please wait, giving pythonanywhere a moment...', 'plugin "%(plugin)s" deleted': '"%(plugin)s" eklentisi silindi', 'Plugin "%s" in application': '"%s" uygulamasında eklenti', +'plugin not specified': 'plugin not specified', +'Plugin page': 'Plugin page', 'plugins': 'eklentiler', 'Plugins': 'Eklentiler', +'Plural Form #%s': 'Plural Form #%s', 'Plural-Forms:': 'Çoğul-Kipler:', 'Powered by': 'Yazılım Temeli:', +'Preferences saved correctly': 'Preferences saved correctly', +'Preferences saved on session only': 'Preferences saved on session only', +'previous %s rows': 'previous %s rows', 'previous 100 rows': 'önceki 100 satır', 'Private files': 'Özel dosyalar', 'private files': 'özel dosyalar', 'Project Progress': 'Proje İlerlemesi', +'Pull': 'Pull', +'Pull failed, certain files could not be checked out. Check logs for details.': 'Pull failed, certain files could not be checked out. Check logs for details.', +'Pull is not possible because you have unmerged files. Fix them up in the work tree, and then try again.': 'Pull is not possible because you have unmerged files. Fix them up in the work tree, and then try again.', +'Push': 'Push', +'Push failed, there are unmerged entries in the cache. Resolve merge issues manually and try again.': 'Push failed, there are unmerged entries in the cache. Resolve merge issues manually and try again.', 'pygraphviz library not found': 'pygraphviz kütüphanesi yok', +'PythonAnywhere Apps': 'PythonAnywhere Apps', +'PythonAnywhere Password': 'PythonAnywhere Password', 'Query:': 'Sorgu: ', +'RAM': 'RAM', +'RAM Cache Keys': 'RAM Cache Keys', +'Ram Cleared': 'Ram Cleared', 'Rapid Search': 'Hızlı Arama', +'Record': 'Record', 'record': 'kayıt', 'record does not exist': 'kayıt bulunamıyor', 'record id': 'kayıt id', +'Record id': 'Record id', 'refresh': 'yeniden yükle', +'register': 'register', 'Reload routes': 'Yönelendirmeyi yeniden yükle', 'Remove compiled': 'Derlemeyi kaldır', 'Removed Breakpoint on %s at line %s': ' %s üzerindeki kesme noktası %s satırında değiştrildi.', 'Replace': 'Değiştir', 'Replace All': 'Tümünü değiştir', +'Repository (%s)': 'Repository (%s)', 'request': 'istek', +'requires distutils, but not installed': 'requires distutils, but not installed', 'requires python-git, but not installed': 'python-git gerekyior, fakat kurulu değil', 'Resolve Conflict file': 'Dosyadaki çakışmayı çöz', 'response': 'tepki', 'restart': 'yeniden başla', 'restore': 'geri al', +'return': 'return', +'Revert': 'Revert', 'revert': 'geri al', +'reverted to revision %s': 'reverted to revision %s', +'Revision %s': 'Revision %s', +'Revision:': 'Revision:', +'Role': 'Role', +'Roles': 'Roles', +'Rows in Table': 'Rows in Table', 'Rows in table': 'Tablosundaki satırlar', 'Rows selected': 'Seçilen satırlar', +'rules are not defined': 'rules are not defined', +'Run tests': 'Run tests', +'Run tests in this file': 'Run tests in this file', "Run tests in this file (to run all files, you may also use the button labelled 'test')": "Bu dosyadaki testleri çalıştırır (tüm dosyaları çalıştırmak için, 'test' etiketli düğmeyi kullanabilirsiniz)", 'Running on %s': '%s üzerinde çalışıyor', 'Save': 'Kaydet', 'save': 'kaydet', 'Save file:': 'Dosyayı kaydet:', 'Save file: %s': 'Dosyayı farklı kaydet: %s', +'Save model as...': 'Save model as...', 'Save via Ajax': 'Ajax üzerinden kaydet', 'Saved file hash:': 'Kaydedilen dosyanın parmak izi:', +'Screenshot %s': 'Screenshot %s', +'Search': 'Search', 'Select Files to Package': 'Paketlenecek Dosyaları Seç', 'selected': 'seçildi', 'session': 'oturum', 'session expired': 'oturum zamanaşımına uğradı', +'Session saved correctly': 'Session saved correctly', +'Session saved on session only': 'Session saved on session only', 'Set Breakpoint on %s at line %s: %s': "%s'nin %s satırındaki kesme noktasını: %s yap", 'shell': 'kabuk', +'Showing %s to %s of %s %s found': 'Showing %s to %s of %s %s found', +'Singular Form': 'Singular Form', 'Site': 'Site', +'Size of cache:': 'Size of cache:', 'skip to generate': 'oluşturmak için atla', 'some files could not be removed': 'bazı dosyalar kaldırılamadı', +'Something went wrong please wait a few minutes before retrying': 'Something went wrong please wait a few minutes before retrying', +'Sorry, could not find mercurial installed': 'Sorry, could not find mercurial installed', +'source : db': 'source : db', 'source : filesystem': 'kaynak : dosyasistemi', 'Start a new app': 'Yeni uygualama başla', 'Start searching': 'Aramaya başla', 'Start wizard': 'Başlatma sihirbazı', 'state': 'durum', -'static': 'statik', 'Static': 'Statik', +'static': 'statik', 'Static files': 'Statik dosyalar', +'Statistics': 'Statistics', 'Step': 'Basamak', -'Submit': 'Gönder', +'step': 'step', +'stop': 'stop', 'submit': 'gönder', +'Submit': 'Gönder', 'successful': 'başarılı', 'Sure you want to delete this object?': 'Bu nesneyi silmek istediğinizden emin misiniz? ', 'switch to : db': 'geç : db', +'switch to : filesystem': 'switch to : filesystem', +'Tab width (# characters)': 'Tab width (# characters)', 'table': 'tablo', +'Table': 'Table', 'Temporary': 'Geçici', 'test': 'test', 'Testing application': 'Uygulama test ediliyor', 'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.': '"sorgulama" "db.table1.field1==\'değer\'" şeklinde bir durumu ifade eder. SQL birleştirmede (JOIN) "db.table1.field1==db.table2.field2" şeklindedir.', +'The app exists, was created by wizard, continue to overwrite!': 'The app exists, was created by wizard, continue to overwrite!', +'The app exists, was NOT created by wizard, continue to overwrite!': 'The app exists, was NOT created by wizard, continue to overwrite!', 'the application logic, each URL path is mapped in one exposed function in the controller': 'uygulama mantığı: her URL denetleyicideki bir işleve eşlenir', 'The application logic, each URL path is mapped in one exposed function in the controller': 'Uygulama mantığı: her URL denetleyicideki bir işleve eşlenir', 'the data representation, define database tables and sets': 'veri gösterimi, veritabanı tablolarını ve setlerini tanımla', 'The data representation, define database tables and sets': 'Veri gösterimi, veritabanı tablolarını ve setlerini tanımla', 'The presentations layer, views are also known as templates': 'Sunum katmanı, görünümler şablon olarakda biliniyor.', 'the presentations layer, views are also known as templates': 'sunum katmanı, görünümler şablon olarakda biliniyor.', +'Theme': 'Theme', 'There are no controllers': 'Denetçiler yok', 'There are no models': 'Modeller yok', 'There are no modules': 'Modüller yok', 'There are no plugins': 'Eklentiler yok', 'There are no private files': 'Özel dosyalar yok', 'There are no static files': 'Statik dosyalar yok', +'There are no translators': 'There are no translators', 'There are no translators, only default language is supported': 'Çeviriler, sadeceön tanmlı dil destekleniyor.', 'There are no views': 'Görünümler yok', 'These files are not served, they are only available from within your app': 'Bu dosyalar servis yapılmıyor, bunlar sadece uygulamanız içerisinden erişilebilir.', 'These files are served without processing, your images go here': 'Bu dosyalarda işlem yapılmadan kaydedildi, resimler buraya gidiyor:', 'these files are served without processing, your images go here': 'bu dosyalarda işlem yapılmadan kaydedildi, resimler buraya gidiyor:', +"This debugger may not work properly if you don't have a threaded webserver or you're using multiple daemon processes.": "This debugger may not work properly if you don't have a threaded webserver or you're using multiple daemon processes.", +'This is an experimental feature and it needs more testing. If you decide to downgrade you do it at your own risk': 'This is an experimental feature and it needs more testing. If you decide to downgrade you do it at your own risk', +'This is an experimental feature and it needs more testing. If you decide to upgrade you do it at your own risk': 'This is an experimental feature and it needs more testing. If you decide to upgrade you do it at your own risk', 'This is the %(filename)s template': 'Bu şablonlar %(filename)s: ', "This page can commit your changes to an openshift app repo and push them to your cloud instance. This assumes that you've already created the application instance using the web2py skeleton and have that repo somewhere on a filesystem that this web2py instance can access. This functionality requires GitPython installed and on the python path of the runtime that web2py is operating in.": "Bu sayfa uygulamanızı OpenShif uygulama reposuna koyar. Uygulamanızın web2py iskeleti ile oluşturulduğunuz ve web2py dosya sisteminizdeki ropoya erişilebileceği varsayılmıştır. Bu işlev web2py'nin çalıştığı ortamda GitPython'e ihtiyaç duyar.", 'This page can upload your application to the Google App Engine computing cloud. Mind that you must first create indexes locally and this is done by installing the Google appserver and running the app locally with it once, or there will be errors when selecting records. Attention: deployment may take long time, depending on the network speed. Attention: it will overwrite your app.yaml. DO NOT SUBMIT TWICE.': 'Bu sayfa uygulamanızı Google App Motoru bilişim bulutuna yükleyecektir. İndeksleri yerel olarak oluştırmanız gerektiğini aklınızda tutun, Google uygulama sunucusunu yerel olarak kurup çalıştırın, aksi halde bazı kayıtlarda hatalar olacaktır. Uyarı: yayınlama ağ hızınıza bağlı olarak uzun zaman alabilir. Uyarı: bu sizin app.yaml dosyasını yeniden yazar. LÜTFEN BİRDEN FAZLA GÖNDERMEYİN.', 'this page to see if a breakpoint was hit and debug interaction is required.': 'bu sayfayı, kesme noktasına geldiğini görmek için ve hata ayıklama etkileşmesi gerekiyor..', +'This will pull changes from the remote repo for application "%s"?': 'This will pull changes from the remote repo for application "%s"?', +'This will push changes to the remote repo for application "%s".': 'This will push changes to the remote repo for application "%s".', 'Ticket': 'Bilet', -'Ticket ID': 'Bile ID\'si', +'Ticket ID': "Bile ID'si", +'Ticket Missing': 'Ticket Missing', +'Time in Cache (h:m:s)': 'Time in Cache (h:m:s)', 'TM': 'TM', 'to previous version.': 'önceki sürüme.', 'To create a plugin, name a file/folder plugin_[name]': 'Eklenti oluşturmak için dosyayı dosya/klasör plugin_[isim] şeklinde isimlendir. ', 'To emulate a breakpoint programatically, write:': 'Program ile kesme noktasını öykünmek için, yazın:', 'to use the debugger!': 'hata ayıklayıcısını kullanmak için!', 'toggle breakpoint': 'kesme noktasını değiştir', +'Toggle comment': 'Toggle comment', 'Toggle Fullscreen': 'Tam Ekrana Geç', 'Traceback': 'Nedenin bul', 'translation strings for the application': 'uygulama için çeviri cümleleri', @@ -376,23 +569,33 @@ 'try something like': 'gibi birşey dene', 'Try the mobile interface': 'Mobil arayüzü dene', 'try view': 'görünümü dene', +'Type PDB debugger command in here and hit Return (Enter) to execute it.': 'Type PDB debugger command in here and hit Return (Enter) to execute it.', +'Type some Python code in here and hit Return (Enter) to execute it.': 'Type some Python code in here and hit Return (Enter) to execute it.', 'Unable to check for upgrades': 'Güncellemeler denetlenemiyor', 'unable to create application "%s"': '"%s" uygulaması oluşturulamıyor', 'unable to delete file "%(filename)s"': '"%(filename)s" dosylaları silinemiyor', 'unable to delete file plugin "%(plugin)s"': '"%(plugin)s" eklenti dosyasyaları silenemiyor', +'Unable to determine the line number!': 'Unable to determine the line number!', 'Unable to download': 'İndirilemiyor', 'Unable to download app': 'Uygulamanız indirilemiyor', 'Unable to download app because:': 'Uygulamanız indirilemiyor çünkü:', 'Unable to download because': 'İndirilemiyor çünkü:', +'unable to download layout': 'unable to download layout', +'unable to download plugin: %s': 'unable to download plugin: %s', +'Unable to download the list of plugins': 'Unable to download the list of plugins', +'unable to install plugin "%s"': 'unable to install plugin "%s"', 'unable to parse csv file': "impossible d'analyser les fichiers CSV", 'unable to uninstall "%s"': 'kladıramıyor çünkü "%s"', 'unable to upgrade because "%s"': 'güncelleyemiyor çünkü "%s"', 'uncheck all': 'tümünü kladır', 'Uninstall': 'Kaldır', +'Unsupported webserver working mode: %s': 'Unsupported webserver working mode: %s', 'update': 'güncelle', 'update all languages': 'tüm delleri yükle', 'Update:': 'Güncelle:', +'Upgrade': 'Upgrade', 'upgrade now': 'şimdi güncelle', +'upgrade now to %s': 'upgrade now to %s', 'upgrade web2py now': "web2py'yi güncelle", 'upload': 'yükle', 'Upload': 'Yükle', @@ -406,21 +609,38 @@ 'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Karmaşık sorgularda Ve (AND) için (...)&(...) kullanın, Veya (OR) için (...)|(...) kullanın ve DEĞİL (NOT) için ~(...) kullanın. ', 'Use an url:': "Url'yi kullan:", 'user': 'kullanıcı', +'User': 'User', +'Username': 'Username', +'Users': 'Users', +'Using the shell may lock the database to other users of this app.': 'Using the shell may lock the database to other users of this app.', 'variables': 'değişkenler', 'Version': 'Sürüm', -'versioning': 'sürümleme', 'Versioning': 'Sürümleme', +'versioning': 'sürümleme', 'view': 'görüntü', 'Views': 'Görüntüler', 'views': 'görüntüler', +'Warning!': 'Warning!', +'WARNING:': 'WARNING:', +'WARNING: The following views could not be compiled:': 'WARNING: The following views could not be compiled:', 'Web Framework': 'Web Çatısı', +'web2py Admin Password': 'web2py Admin Password', 'web2py apps to deploy': 'Yayınlanacak web2py uygulaması', +'web2py Debugger': 'web2py Debugger', +'web2py downgrade': 'web2py downgrade', 'web2py is up to date': 'web2py güncel', 'web2py online debugger': 'çevirimiçi web2py hata ayıklayıcı', 'web2py Recent Tweets': 'web2py Son Twitler', +'web2py upgrade': 'web2py upgrade', 'web2py upgraded; please restart it': 'web2py güncellendi, lütfen yeniden başlatın', +'Working...': 'Working...', 'WSGI reference name': 'WSGI referans ismi', 'YES': 'EVET', +'Yes': 'Yes', 'You can also set and remove breakpoint in the edit window, using the Toggle Breakpoint button': '"kesme noktaları" düğmesini kullanarak düzenleme penceresine geçebilir ve kesme nokatalarını hem ekeleyebilir hemde kaldırabilirsiniz', +'You can inspect variables using the console below': 'You can inspect variables using the console below', +'You have one more login attempt before you are locked out': 'You have one more login attempt before you are locked out', 'You need to set up and reach a': 'Gelinceye kadar kurmalısınız', +'You only need these if you have already registered': 'You only need these if you have already registered', +'Your application will be blocked until you click an action button (next, step, continue, etc.)': 'Your application will be blocked until you click an action button (next, step, continue, etc.)', } diff --git a/applications/admin/languages/uk.py b/applications/admin/languages/uk.py index ca54e12c..a45124c6 100755 --- a/applications/admin/languages/uk.py +++ b/applications/admin/languages/uk.py @@ -9,12 +9,15 @@ '%s %%{row} deleted': 'Вилучено %s %%{рядок}', '%s %%{row} updated': 'Вилучено %s %%{рядок}', '%s Recent Tweets': '%s %%{останній} %%{твіт}', +'%s selected': '%s selected', '%s students registered': '%s студентів зареєстровано', '%Y-%m-%d': '%Y/%m/%d', '%Y-%m-%d %H:%M:%S': '%Y/%m/%d %H:%M:%S', '(requires internet access)': '(потрібно мати доступ в інтернет)', '(requires internet access, experimental)': '(потрібно мати доступ в інтернет, експериментально)', '(something like "it-it")': '(щось схоже на "uk-ua")', +'(version %s)': '(version %s)', +'?': '?', '@markmin\x01(file **gluon/contrib/plural_rules/%s.py** is not found)': '(не існує файлу **gluon/contrib/plural_rules/%s.py**)', '@markmin\x01An error occured, please [[reload %s]] the page': 'Сталась помилка, будь-ласка [[переватажте %s]] сторінку', "@markmin\x01Mercurial Version Control System Interface[[NEWLINE]]for application '%s'": "Інтерфейс системи контролю версій Mercurial[[NEWLINE]]для додатку '%s'", @@ -23,17 +26,21 @@ 'About': 'Про', 'about': 'про', 'About application': 'Про додаток', +'Accept Terms': 'Accept Terms', 'Add breakpoint': 'Додати точку зупинки', 'Additional code for your application': 'Додатковий код для вашого додатку', +'Admin design page': 'Admin design page', 'admin disabled because no admin password': 'адмін.інтерфейс відключено, бо не вказано пароль адміністратора', 'admin disabled because not supported on google app engine': 'адмін.інтерфейс відключено через те, що Google Application Engine його не підтримує', 'admin disabled because too many invalid login attempts': 'адмін.інтерфейс заблоковано, бо кількість хибних спроб входу перевищило граничний рівень', 'admin disabled because unable to access password file': 'адмін.інтерфейс відключено через відсутність доступу до файлу паролів', 'Admin is disabled because insecure channel': "Адмін.інтерфейс відключено через використання ненадійного каналу звя'зку", 'Admin language': 'Мова інтерфейсу:', +'Admin versioning page': 'Admin versioning page', 'administrative interface': 'інтерфейс адміністратора', 'Administrator Password:': 'Пароль адміністратора:', 'and rename it:': 'i змінити назву на:', +'App does not exist or you are not authorized': 'App does not exist or you are not authorized', 'App does not exist or your are not authorized': 'Додаток не існує, або ви не авторизовані', 'appadmin': 'Aдм.панель', 'appadmin is disabled because insecure channel': "адмін.панель відключено через використання ненадійного каналу зв'язку", @@ -45,12 +52,14 @@ 'Application exists already': 'Додаток вже існує', 'application is compiled and cannot be designed': 'додаток скомпільований. налаштування змінювати не можна', 'Application name:': 'Назва додатку:', +'Application updated via git pull': 'Application updated via git pull', 'are not used': 'не використовуються', 'are not used yet': 'поки що не використовуються', 'Are you sure you want to delete file "%s"?': 'Ви впевнені, що хочете вилучити файл "%s"?', 'Are you sure you want to delete plugin "%s"?': 'Ви впевнені, що хочете вилучити втулку "%s"?"', 'Are you sure you want to delete this object?': "Ви впевнені, що хочете вилучити цей об'єкт?", 'Are you sure you want to uninstall application "%s"?': 'Ви впевнені, що хочете вилучити (uninstall) додаток "%s"?', +'Are you sure?': 'Are you sure?', 'arguments': 'аргументи', 'at char %s': 'на символі %s', 'at line %s': 'в рядку %s', @@ -60,7 +69,10 @@ 'ATTENTION: you cannot edit the running application!': 'УВАГА: Ви не можете редагувати додаток, який зараз виконуєте!', 'Autocomplete Python Code': 'Автозавершення коду на Python', 'Available databases and tables': 'Доступні бази даних та таблиці', +'Available Databases and Tables': 'Available Databases and Tables', 'back': '<< назад', +'Back to the plugins list': 'Back to the plugins list', +'Back to wizard': 'Back to wizard', 'bad_resource': 'поганий_ресурс', 'Basics': 'Початок', 'Begin': 'Початок', @@ -69,7 +81,9 @@ 'breakpoints': 'точки зупинок', 'Bulk Register': 'Масова реєстрація', 'Bulk Student Registration': 'Масова реєстрація студентів', +'Cache': 'Cache', 'cache': 'кеш', +'Cache Cleared': 'Cache Cleared', 'Cache Keys': 'Ключі кешу', 'cache, errors and sessions cleaned': 'кеш, список зареєстрованих помилок та сесії очищенні', 'can be a git repo': 'може бути git-репозитарієм', @@ -78,13 +92,16 @@ 'Cannot compile: there are errors in your app:': 'Не вдається скомпілювати: є помилки у вашому додатку:', 'cannot create file': 'не можу створити файл', 'cannot upload file "%(filename)s"': 'не можу завантажити файл "%(filename)s"', +'Change Admin Password': 'Change Admin Password', 'Change admin password': 'Змінити пароль адміністратора', 'change editor settings': 'змінити налаштування редактора', +'Changelog': 'Changelog', 'check all': 'відмітити всі', 'Check for upgrades': 'Перевірити оновлення', 'Check to delete': 'Помітити на вилучення', 'Checking for upgrades...': 'Відбувається пошук оновлень...', 'Clean': 'Очистити', +'Clear': 'Clear', 'Clear CACHE?': 'Очистити ВЕСЬ кеш?', 'Clear DISK': 'Очистити ДИСКОВИЙ КЕШ', 'Clear RAM': "Очистити КЕШ В ПАМ'ЯТІ", @@ -97,7 +114,10 @@ 'Comment:': 'Пояснення:', 'Commit': 'Комміт', 'Commit form': 'Commit form', +'Committed files': 'Committed files', 'Compile': 'Компілювати', +'Compile (all or nothing)': 'Compile (all or nothing)', +'Compile (skip failed views)': 'Compile (skip failed views)', 'compiled application removed': 'скомпільований додаток вилучено', 'Condition': 'Умова', 'contact_admin': "зв'язатись_з_адміністратором", @@ -112,7 +132,9 @@ 'Create rules': 'Створити правила', 'Create/Upload': 'Створити/Завантажити', 'created by': 'Автор:', +'Created by:': 'Created by:', 'Created On': 'Створено в', +'Created on:': 'Created on:', 'crontab': 'таблиця cron', 'Current request': 'Поточний запит', 'Current response': 'Поточна відповідь', @@ -120,9 +142,13 @@ 'currently running': 'наразі, активний додаток', 'currently saved or': 'останній збережений, або', 'data uploaded': 'дані завантажено', +'Database': 'Database', 'database': 'база даних', +'Database %s select': 'Database %s select', 'database %s select': 'Вибірка з бази даних %s', +'Database administration': 'Database administration', 'database administration': 'адміністрування бази даних', +'Database Administration (appadmin)': 'Database Administration (appadmin)', 'Date and Time': 'Дата і час', 'db': 'база даних', 'Debug': 'Ладнати (Debug)', @@ -134,10 +160,15 @@ 'Delete this file (you will be asked to confirm deletion)': 'Вилучити цей файл (буде відображено запит на підтвердження операції)', 'Delete:': 'Вилучити:', 'deleted after first hit': 'автоматично вилучається після першого спрацювання', +'Demo': 'Demo', 'Deploy': 'Розгорнути', 'Deploy on Google App Engine': 'Розгорнути на Google App Engine (GAE)', 'Deploy to OpenShift': 'Розгорнути на OpenShift', +'Deploy to pythonanywhere': 'Deploy to pythonanywhere', +'Deploy to PythonAnywhere': 'Deploy to PythonAnywhere', 'Deployment form': 'Форма розгортання (deployment form)', +'Deployment Interface': 'Deployment Interface', +'Description:': 'Description:', 'design': 'налаштування', 'Detailed traceback description': 'Детальний опис стеку викликів (traceback)', 'details': 'детальніше', @@ -146,14 +177,23 @@ 'Disable': 'Вимкнути', 'Disabled': 'Вимкнено', 'disabled in demo mode': 'відключено в демо-режимі', +'disabled in GAE mode': 'disabled in GAE mode', 'disabled in multi user mode': 'відключено в багато-користувацькому режимі', +'DISK': 'DISK', 'Disk Cache Keys': 'Ключі дискового кешу', 'Disk Cleared': 'Дисковий кеш очищено', +'Display line numbers': 'Display line numbers', +'DO NOT use the "Pack compiled" feature.': 'DO NOT use the "Pack compiled" feature.', 'docs': 'док.', +'Docs': 'Docs', 'done!': 'зроблено!', 'Downgrade': 'Повернути попередню версію', +'Download .w2p': 'Download .w2p', +'Download as .exe': 'Download as .exe', 'download layouts': 'завантажити макет (layout)', +'Download layouts from repository': 'Download layouts from repository', 'download plugins': 'завантажити втулки', +'Download plugins from repository': 'Download plugins from repository', 'Edit': 'Редагувати', 'edit all': 'редагувати всі', 'Edit application': 'Налаштування додатку', @@ -165,7 +205,11 @@ 'Editing file "%s"': 'Редагується файл "%s"', 'Editing Language file': 'Редагується файл перекладу', 'Editing Plural Forms File': 'Редагується файл форм множини', +'Editor': 'Editor', +'Email Address': 'Email Address', 'Enable': 'Увімкнути', +'Enable Close-Tag': 'Enable Close-Tag', +'Enable Code Folding': 'Enable Code Folding', 'enter a value': 'введіть значення', 'Error': 'Помилка', 'Error logs for "%(app)s"': 'Список зареєстрованих помилок додатку "%(app)s"', @@ -178,7 +222,9 @@ 'Exception instance attributes': 'Атрибути примірника класу Exception (виключення)', 'Exit Fullscreen': 'Вийти з повноекранного режиму', 'Expand Abbreviation': 'Розгорнути абревіатуру', +'Expand Abbreviation (html files only)': 'Expand Abbreviation (html files only)', 'export as csv file': 'експортувати як файл csv', +'Exports:': 'Exports:', 'exposes': 'обслуговує', 'exposes:': 'обслуговує:', 'extends': 'розширює', @@ -195,10 +241,13 @@ 'file not found': 'файл не знайдено', 'file saved on %(time)s': 'файл збережено в %(time)s', 'file saved on %s': 'файл збережено в %s', +'filename': 'filename', 'Filename': "Ім'я файлу", +'Files added': 'Files added', 'filter': 'фільтр', 'Find Next': 'Шукати наступний', 'Find Previous': 'Шукати попередній', +'Form has errors': 'Form has errors', 'Frames': 'Стек викликів', 'Functions with no doctests will result in [passed] tests.': 'Функції, в яких відсутні док-тести відносяться до функцій, які успішно пройшли тести.', 'GAE Email': 'Ел.пошта GAE', @@ -215,22 +264,30 @@ 'Google Application Id': 'Ідентифікатор Google Application', 'Goto': 'Перейти до', 'graph model': 'графова модель', +'Graph Model': 'Graph Model', 'Help': 'Допомога', +'here': 'here', 'Hide/Show Translated strings': 'Сховати/показати ВЖЕ ПЕРЕКЛАДЕНІ рядки', +'Highlight current line': 'Highlight current line', 'Hits': 'Спрацьовувань', 'Home': 'Домівка', 'honored only if the expression evaluates to true': 'точка зупинки активується тільки за істинності умови', 'If start the downgrade, be patient, it may take a while to rollback': 'Запустивши повернення на попередню версію, будьте терплячими, це може зайняти трохи часу', 'If start the upgrade, be patient, it may take a while to download': 'Запустивши оновлення, будьте терплячими, потрібен час для завантаження необхідних даних', 'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\n\t\tA green title indicates that all tests (if defined) passed. In this case test results are not shown.': 'Якщо в наданому вище звіті присутня позначка про помилку (ticket number), то це вказує на збій у виконанні контролера ще до початку запуску док-тестів. Це, зазвичай, сигналізує про помилку вирівнювання тексту програми (indention error) або помилку за межами функції (error outside function code).\n\t\tЗелений заголовок сигналізує, що всі тести (з наявних) пройшли успішно. В цьому випадку результат тестів показано не буде.', +'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\nA green title indicates that all tests (if defined) passed. In this case test results are not shown.': 'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\nA green title indicates that all tests (if defined) passed. In this case test results are not shown.', +'if your application uses a database other than sqlite you will then have to configure its DAL in pythonanywhere.': 'if your application uses a database other than sqlite you will then have to configure its DAL in pythonanywhere.', +'import': 'import', 'Import/Export': 'Імпорт/Експорт', 'In development, use the default Rocket webserver that is currently supported by this debugger.': 'Під час розробки , використовуйте вбудований веб-сервер Rocket, він найкраще налаштований на спільну роботу з інтерактивним ладначем.', 'includes': 'включає', +'Indent with tabs': 'Indent with tabs', 'index': 'індекс', 'insert new': 'вставити новий', 'insert new %s': 'вставити новий %s', 'inspect attributes': 'інспектувати атрибути', 'Install': 'Встановлення', +'Installation of %(plugin)s for %(app)s': 'Installation of %(plugin)s for %(app)s', 'Installed applications': 'Встановлені додатки (applications)', 'Interaction at %s line %s': 'Виконується %s рядок %s', 'Interactive console': 'Інтерактивна консоль', @@ -238,41 +295,57 @@ 'internal error: %s': 'внутрішня помилка: %s', 'Internal State': 'Внутрішній стан', 'Invalid action': 'Помилкова дія', +'Invalid application name': 'Invalid application name', 'invalid circual reference': 'помилкове циклічне посилання', 'invalid circular reference': 'помилкове циклічне посилання', +'Invalid git repository specified.': 'Invalid git repository specified.', 'invalid password': 'неправильний пароль', 'invalid password.': 'неправильний пароль.', 'Invalid Query': 'Помилковий запит', 'invalid request': 'хибний запит', +'Invalid request': 'Invalid request', 'invalid request ': 'Хибний запит', 'invalid table names (auth_* tables already defined)': 'хибна назва таблиці (таблиці auth_* вже оголошено)', 'invalid ticket': 'недійсна позначка про помилку (ticket)', 'Key': 'Ключ', 'Key bindings': 'Клавіатурні скорочення:', 'Key bindings for ZenCoding Plugin': 'Клавіатурні скорочення для втулки ZenCoding plugin', +'Keyboard shortcuts': 'Keyboard shortcuts', 'kill process': 'вбити процес', 'language file "%(filename)s" created/updated': 'Файл перекладу "%(filename)s" створено/оновлено', 'Language files (static strings) updated': 'Файли перекладів (із статичних рядків в першоджерелах) оновлено', 'languages': 'переклади', 'Languages': 'Переклади', +'Last Revision': 'Last Revision', 'Last saved on:': 'Востаннє збережено:', 'License for': 'Ліцензія додатку', +'License:': 'License:', +'Line Nr': 'Line Nr', 'Line number': '№ рядка', 'LineNo': '№ рядка', 'lists by exception': 'список виключень (exceptions)', 'lists by ticket': 'список позначок (tickets)', +'Loading...': 'Loading...', 'loading...': 'завантаження...', +'Local Apps': 'Local Apps', 'locals': 'локальні', 'Locals##debug': 'Локальні змінні', 'Login': 'Вхід', 'login': 'вхід', +'Login successful': 'Login successful', 'Login to the Administrative Interface': 'Вхід в адміністративний інтерфейс', +'Login/Register': 'Login/Register', 'Logout': 'Вихід', +'lost password': 'lost password', 'Main Menu': 'Основне меню', 'Manage': 'Керувати', +'Manage %(action)s': 'Manage %(action)s', +'Manage Access Control': 'Manage Access Control', 'Manage Admin Users/Students': 'Адміністратор керування користувачами/студентами', +'Manage Cache': 'Manage Cache', 'Manage Students': 'Керувати студентами', 'Match Pair': 'Знайти пару', +'Memberships': 'Memberships', 'merge': "з'єднати", 'Merge Lines': "З'єднати рядки", 'Minimum length is %s': 'Мінімальна довжина становить %s', @@ -281,37 +354,46 @@ 'Modified On': 'Змінено в', 'Modules': 'Модулі', 'modules': 'модулі', +'Multi User Mode': 'Multi User Mode', 'Must include at least %s %s': 'Має вміщувати щонайменше %s %s', 'Must include at least %s lower case': 'Повинен включати щонайменше %s малих букв', 'Must include at least %s of the following : %s': 'Має включати не менше %s таких символів : %s', 'Must include at least %s upper case': 'Повинен включати щонайменше %s великих букв', 'new application "%s" created': 'новий додаток "%s" створено', +'new application "%s" imported': 'new application "%s" imported', 'New Application Wizard': 'Майстер створення нового додатку', 'New application wizard': 'Майстер створення нового додатку', 'new plugin installed': 'нова втулка (plugin) встановлена', +'New plugin installed: %s': 'New plugin installed: %s', 'New Record': 'Новий запис', 'new record inserted': 'новий рядок додано', 'New simple application': 'Новий простий додаток', 'next': 'наступний', +'next %s rows': 'next %s rows', 'next 100 rows': 'наступні 100 рядків', 'Next Edit Point': 'Наступне місце редагування', 'NO': 'НІ', +'no changes': 'no changes', 'No databases in this application': 'Даний додаток не використовує бази даних', 'No Interaction yet': 'Ладнач не активовано', 'no match': 'співпадань нема', 'no package selected': 'пакет не вибрано', 'no permission to uninstall "%s"': 'нема прав на вилучення (uninstall) "%s"', 'No ticket_storage.txt found under /private folder': 'В каталозі /private відсутній файл ticket_storage.txt', +'Node:': 'Node:', 'Not Authorized': 'Не дозволено', +'Not supported': 'Not supported', 'Note: If you receive an error with github status code of 128, ensure the system and account you are deploying from has a cooresponding ssh key configured in the openshift account.': 'Примітка: Якщо ви отримали повідомлення про помилку з кодом стану github рівним 128, переконайтесь, що система та обліковий запис, з якого відбувається розгортання використовують відповідний ключ ssh, налаштований в обліковому записі openshift.', "On production, you'll have to configure your webserver to use one process and multiple threads to use this debugger.": 'У промисловій експлуатації, ви повинні налаштувати ваш веб-сервер на використання одного процесу та багатьох потоків, якщо бажаєте скористатись цим ладначем.', 'online designer': 'дизайнер БД', +'Open new app in new window': 'Open new app in new window', 'OpenShift Deployment Interface': 'OpenShift: Інтерфейс розгортання', 'OpenShift Output': 'Вивід OpenShift', 'or alternatively': 'або альтернативно', 'Or Get from URL:': 'Або Отримати з мережі (ч/з URL):', 'or import from csv file': 'або імпортувати через csv-файл', 'Original/Translation': 'Оригінал/переклад', +'Overview': 'Overview', 'Overwrite installed app': 'Перезаписати встановлений додаток', 'Pack all': 'Пакувати все', 'Pack compiled': 'Пакувати зкомпільоване', @@ -319,42 +401,62 @@ 'pack plugin': 'запакувати втулку', 'PAM authenticated user, cannot change password here': 'Ввімкнена система ідентифікації користувачів PAM. Для зміни паролю скористайтесь командами вашої ОС ', 'password changed': 'пароль змінено', +'Past revisions': 'Past revisions', 'Path to appcfg.py': 'Шлях до appcfg.py', 'Path to local openshift repo root.': 'Шлях до локального корня репозитарія openshift.', 'peek': 'глянути', 'Peeking at file': 'Перегляд файлу', +'Permission': 'Permission', +'Permissions': 'Permissions', 'Please': 'Будь-ласка', +'Please wait, giving pythonanywhere a moment...': 'Please wait, giving pythonanywhere a moment...', 'plugin': 'втулка', 'plugin "%(plugin)s" deleted': 'втулку "%(plugin)s" вилучено', 'Plugin "%s" in application': 'Втулка "%s" в додатку', 'plugin not specified': 'втулку не визначено', +'Plugin page': 'Plugin page', 'plugins': 'втулки (plugins)', 'Plugins': 'Втулки (Plugins)', 'Plural Form #%s': 'Форма множини #%s', 'Plural-Forms:': 'Форми множини:', 'Powered by': 'Працює на', +'Preferences saved correctly': 'Preferences saved correctly', +'Preferences saved on session only': 'Preferences saved on session only', +'previous %s rows': 'previous %s rows', 'previous 100 rows': 'попередні 100 рядків', 'Previous Edit Point': 'Попереднє місце редагування', 'Private files': 'Приватні файли', 'private files': 'приватні файли', 'Project Progress': 'Поступ проекту', 'Pull': 'Втягнути', +'Pull failed, certain files could not be checked out. Check logs for details.': 'Pull failed, certain files could not be checked out. Check logs for details.', +'Pull is not possible because you have unmerged files. Fix them up in the work tree, and then try again.': 'Pull is not possible because you have unmerged files. Fix them up in the work tree, and then try again.', 'Push': 'Проштовхнути', +'Push failed, there are unmerged entries in the cache. Resolve merge issues manually and try again.': 'Push failed, there are unmerged entries in the cache. Resolve merge issues manually and try again.', +'pygraphviz library not found': 'pygraphviz library not found', +'PythonAnywhere Apps': 'PythonAnywhere Apps', +'PythonAnywhere Password': 'PythonAnywhere Password', 'Query:': 'Запит:', +'RAM': 'RAM', 'RAM Cache Keys': 'Ключ ОЗП-кешу (RAM Cache)', 'Ram Cleared': "Кеш в пам'яті очищено", 'Rapid Search': 'Миттєвий пошук', +'Record': 'Record', 'record': 'запис', 'record does not exist': 'запису не існує', 'record id': 'Ід.запису', +'Record id': 'Record id', 'refresh': 'оновіть', +'register': 'register', 'reload': 'перевантажити', 'Reload routes': 'Перезавантажити маршрути', 'Remove compiled': 'Вилуч.компл', 'Removed Breakpoint on %s at line %s': 'Вилучено точку зупинки у %s в рядку %s', 'Replace': 'Замінити', 'Replace All': 'Замінити все', +'Repository (%s)': 'Repository (%s)', 'request': 'запит', +'requires distutils, but not installed': 'requires distutils, but not installed', 'requires python-git, but not installed': 'Для розгортання необхідний пакет python-git, але він не встановлений', 'resolve': "розв'язати", 'Resolve Conflict file': "Файл розв'язування конфлікту", @@ -362,7 +464,14 @@ 'restart': 'перезапустити майстра', 'restore': 'повернути', 'return': 'повернутись', +'Revert': 'Revert', 'revert': 'відновитись', +'reverted to revision %s': 'reverted to revision %s', +'Revision %s': 'Revision %s', +'Revision:': 'Revision:', +'Role': 'Role', +'Roles': 'Roles', +'Rows in Table': 'Rows in Table', 'Rows in table': 'Рядків у таблиці', 'Rows selected': 'Рядків вибрано', 'rules are not defined': 'правила не визначені', @@ -376,22 +485,33 @@ 'Save': 'Зберегти', 'Save file:': 'Зберегти файл:', 'Save file: %s': 'Зберегти файл: %s', +'Save model as...': 'Save model as...', 'Save via Ajax': 'зберегти через Ajax', 'Saved file hash:': 'Хеш збереженого файлу:', +'Screenshot %s': 'Screenshot %s', 'search': 'пошук', +'Search': 'Search', +'Select Files to Package': 'Select Files to Package', 'selected': 'відмічено', 'session': 'сесія', 'session expired': 'час даної сесії вичерпано', +'Session saved correctly': 'Session saved correctly', +'Session saved on session only': 'Session saved on session only', 'Set Breakpoint on %s at line %s: %s': 'Додано точку зупинки в %s на рядок %s: %s', 'shell': 'консоль', +'Showing %s to %s of %s %s found': 'Showing %s to %s of %s %s found', 'signup': 'підписатись', 'signup_requested': 'необхідна_реєстрація', 'Singular Form': 'Форма однини', 'site': 'сайт', 'Site': 'Сайт', +'Size of cache:': 'Size of cache:', 'skip to generate': 'перейти до генерування результату', 'some files could not be removed': 'деякі файли не можна вилучити', +'Something went wrong please wait a few minutes before retrying': 'Something went wrong please wait a few minutes before retrying', 'Sorry, could not find mercurial installed': 'Не вдалось виявити встановлену систему контролю версій Mercurial', +'source : db': 'source : db', +'source : filesystem': 'source : filesystem', 'Start a new app': 'Створюється новий додаток', 'Start searching': 'Розпочати пошук', 'Start wizard': 'Активувати майстра', @@ -399,6 +519,7 @@ 'Static': 'Статичні', 'static': 'статичні', 'Static files': 'Статичні файли', +'Statistics': 'Statistics', 'Step': 'Крок', 'step': 'крок', 'stop': 'зупинити', @@ -406,7 +527,10 @@ 'Submit': 'Застосувати', 'successful': 'успішно', 'switch to : db': 'перемкнути на : БД', +'switch to : filesystem': 'switch to : filesystem', +'Tab width (# characters)': 'Tab width (# characters)', 'table': 'таблиця', +'Table': 'Table', 'tags': 'мітки (tags)', 'Temporary': 'Тимчасово', 'test': 'тестувати всі', @@ -417,6 +541,7 @@ 'The application logic, each URL path is mapped in one exposed function in the controller': 'Логіка додатку, кожний шлях URL проектується на одну з функцій обслуговування в контролері', 'The data representation, define database tables and sets': 'Представлення даних, опис таблиць БД та наборів', 'The presentations layer, views are also known as templates': 'Презентаційний рівень, відображення, відомі також як шаблони', +'Theme': 'Theme', 'There are no controllers': 'Жодного контролера, наразі, не існує', 'There are no models': 'Моделей, наразі, нема', 'There are no modules': 'Модулів поки що нема', @@ -448,6 +573,7 @@ 'To emulate a breakpoint programatically, write:': 'Для встановлення точки зупинки програмним чином напишіть:', 'to use the debugger!': 'щоб активувати ладнач!', 'toggle breakpoint': '+/- точку зупинки', +'Toggle comment': 'Toggle comment', 'Toggle Fullscreen': 'Перемкнути на весь екран', 'Traceback': 'Стек викликів (Traceback)', 'Translation strings for the application': 'Пари рядків <оригінал>:<переклад> для вибраної мови', @@ -456,6 +582,7 @@ 'try view': 'дивитись результат', 'Type PDB debugger command in here and hit Return (Enter) to execute it.': 'наберіть тут будь-які команди ладнача PDB і натисніть клавішу [Return] ([Enter]), щоб запустити їх на виконання.', 'Type python statement in here and hit Return (Enter) to execute it.': 'Наберіть тут будь-які вирази Python і натисніть клавішу [Return] ([Enter]), щоб запустити їх на виконання.', +'Type some Python code in here and hit Return (Enter) to execute it.': 'Type some Python code in here and hit Return (Enter) to execute it.', 'Unable to check for upgrades': 'Неможливо перевірити оновлення', 'unable to create application "%s"': 'не можу створити додаток "%s"', 'unable to create application "%s" (it may exist already)': 'не можу створити додаток "%s" (можливо його вже створено)', @@ -466,7 +593,9 @@ 'Unable to download because:': 'Неможливо завантажити через:', 'unable to download layout': 'не вдається завантажити макет', 'unable to download plugin: %s': 'не вдається завантажити втулку: %s', +'Unable to download the list of plugins': 'Unable to download the list of plugins', 'unable to install application "%(appname)s"': 'не вдається встановити додаток "%(appname)s"', +'unable to install plugin "%s"': 'unable to install plugin "%s"', 'unable to parse csv file': 'не вдається розібрати csv-файл', 'unable to uninstall "%s"': 'не вдається вилучити "%s"', 'unable to upgrade because "%s"': 'не вдається оновити, тому що "%s"', @@ -490,6 +619,9 @@ 'upload plugin file:': 'завантажити файл втулки:', 'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Для створення складних запитів використовуйте (...)&(...) замість AND, (...)|(...) замість OR, та ~(...) замість NOT.', 'user': 'користувач', +'User': 'User', +'Username': 'Username', +'Users': 'Users', 'Using the shell may lock the database to other users of this app.': 'Використання оболонки може заблокувати базу даних від сумісного використання іншими користувачами цього додатку.', 'value not allowed': 'недопустиме значення', 'variables': 'змінні', @@ -499,8 +631,11 @@ 'view': 'перегляд', 'Views': 'Відображення (Views)', 'views': 'відображення', +'Warning!': 'Warning!', 'WARNING:': 'ПОПЕРЕДЖЕННЯ:', +'WARNING: The following views could not be compiled:': 'WARNING: The following views could not be compiled:', 'Web Framework': 'Веб-каркас (Web Framework)', +'web2py Admin Password': 'web2py Admin Password', 'web2py apps to deploy': 'Готові до розгортання додатки web2py', 'web2py Debugger': 'Ладнач web2py', 'web2py downgrade': 'повернення на попередню версію web2py', @@ -509,13 +644,17 @@ 'web2py Recent Tweets': 'Останні твіти web2py', 'web2py upgrade': 'оновлення web2py', 'web2py upgraded; please restart it': 'web2py оновлено; будь-ласка перезапустіть його', +'Working...': 'Working...', 'Wrap with Abbreviation': 'Загорнути з абревіатурою', 'WSGI reference name': "ім'я посилання WSGI", 'YES': 'ТАК', +'Yes': 'Yes', 'You can also set and remove breakpoint in the edit window, using the Toggle Breakpoint button': 'Ви також можете встановлювати/вилучати точки зупинок під час редагування першоджерел (sources), використовуючи кнопку "+/- точку зупинки"', +'You can inspect variables using the console bellow': 'Ви можете досліджувати змінні, використовуючи інтерактивну консоль', +'You can inspect variables using the console below': 'You can inspect variables using the console below', 'You have one more login attempt before you are locked out': 'У вас є ще одна спроба перед тим, як вхід буде заблоковано', 'you must specify a name for the uploaded application': "ви повинні вказати ім'я додатка, перед ти, як завантажити його", 'You need to set up and reach a': 'Треба встановити та досягнути', +'You only need these if you have already registered': 'You only need these if you have already registered', 'Your application will be blocked until you click an action button (next, step, continue, etc.)': 'Ваш додаток буде заблоковано, поки ви не клацнете по одній з кнопок керування ("наступний", "крок", "продовжити", та ін.)', -'You can inspect variables using the console bellow': 'Ви можете досліджувати змінні, використовуючи інтерактивну консоль', } diff --git a/applications/admin/languages/zh-tw.py b/applications/admin/languages/zh-tw.py index 79cb4183..b8d564fc 100755 --- a/applications/admin/languages/zh-tw.py +++ b/applications/admin/languages/zh-tw.py @@ -3,300 +3,680 @@ '!langcode!': 'zh-tw', '!langname!': '台灣中文', '"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN': '"更新" 是選擇性的條件式, 格式就像 "欄位1=\'值\'". 但是 JOIN 的資料不可以使用 update 或是 delete"', -'%Y-%m-%d': '%Y-%m-%d', -'%Y-%m-%d %H:%M:%S': '%Y-%m-%d %H:%M:%S', +'"User Exception" debug mode. ': '"User Exception" debug mode. ', +'%s': '%s', '%s %%{row} deleted': '已刪除 %s 筆', '%s %%{row} updated': '已更新 %s 筆', +'%s selected': '%s selected', +'%s students registered': '%s students registered', +'%Y-%m-%d': '%Y-%m-%d', +'%Y-%m-%d %H:%M:%S': '%Y-%m-%d %H:%M:%S', +'(requires internet access, experimental)': '(requires internet access, experimental)', '(something like "it-it")': '(格式類似 "zh-tw")', +'(version %s)': '(version %s)', +'?': '?', '@markmin\x01Searching: **%s** %%{file}': 'Searching: **%s** files', 'A new version of web2py is available': '新版的 web2py 已發行', 'A new version of web2py is available: %s': '新版的 web2py 已發行: %s', -'ATTENTION: Login requires a secure (HTTPS) connection or running on localhost.': '注意: 登入管理帳號需要安全連線(HTTPS)或是在本機連線(localhost).', -'ATTENTION: TESTING IS NOT THREAD SAFE SO DO NOT PERFORM MULTIPLE TESTS CONCURRENTLY.': '注意: 因為在測試模式不保證多執行緒安全性,也就是說不可以同時執行多個測試案例', -'ATTENTION: you cannot edit the running application!': '注意:不可編輯正在執行的應用程式!', +'Abort': 'Abort', 'About': '關於', 'About application': '關於本應用程式', +'Accept Terms': 'Accept Terms', +'Add breakpoint': 'Add breakpoint', +'additional code for your application': '應用程式額外的程式碼', +'Additional code for your application': 'Additional code for your application', +'Admin design page': 'Admin design page', +'admin disabled because no admin password': '管理介面關閉原因是沒有設定管理員密碼 ', +'admin disabled because not supported on google app engine': '管理介面關閉原因是不支援在google apps engine環境下運作', +'admin disabled because too many invalid login attempts': 'admin disabled because too many invalid login attempts', +'admin disabled because unable to access password file': '管理介面關閉原因是無法存取密碼檔', 'Admin is disabled because insecure channel': '管理功能(Admin)在不安全連線環境下自動關閉', 'Admin is disabled because unsecure channel': '管理功能(Admin)在不安全連線環境下自動關閉', +'Admin language': 'Admin language', +'Admin versioning page': 'Admin versioning page', +'administrative interface': 'administrative interface', 'Administrator Password:': '管理員密碼:', +'amy_ajax': 'amy_ajax', +'and rename it (required):': '同時更名為(必要的):', +'and rename it:': '同時更名為:', +'App does not exist or you are not authorized': 'App does not exist or you are not authorized', +'appadmin': '應用程式管理員', +'appadmin is disabled because insecure channel': '管理介面關閉理由是連線方式不安全', +'Application': 'Application', +'application "%s" uninstalled': '已移除應用程式 "%s"', +'Application cannot be generated in demo mode': 'Application cannot be generated in demo mode', +'application compiled': '已編譯應用程式', +'Application exists already': 'Application exists already', +'application is compiled and cannot be designed': '應用程式已經編譯無法重新設計', +'Application name:': 'Application name:', +'Application updated via git pull': 'Application updated via git pull', +'are not used': 'are not used', +'are not used yet': 'are not used yet', 'Are you sure you want to delete file "%s"?': '確定要刪除檔案"%s"?', 'Are you sure you want to delete plugin "%s"?': '確定要刪除插件 "%s"?', +'Are you sure you want to delete this object?': 'Are you sure you want to delete this object?', 'Are you sure you want to uninstall application "%s"': '確定要移除應用程式 "%s"', 'Are you sure you want to uninstall application "%s"?': '確定要移除應用程式 "%s"', 'Are you sure you want to upgrade web2py now?': '確定現在要升級 web2py?', +'Are you sure?': 'Are you sure?', +'arguments': 'arguments', +'at char %s': 'at char %s', +'at line %s': 'at line %s', +'ATTENTION:': 'ATTENTION:', +'ATTENTION: Login requires a secure (HTTPS) connection or running on localhost.': '注意: 登入管理帳號需要安全連線(HTTPS)或是在本機連線(localhost).', +'ATTENTION: TESTING IS NOT THREAD SAFE SO DO NOT PERFORM MULTIPLE TESTS CONCURRENTLY.': '注意: 因為在測試模式不保證多執行緒安全性,也就是說不可以同時執行多個測試案例', +'ATTENTION: you cannot edit the running application!': '注意:不可編輯正在執行的應用程式!', 'Authentication': '驗證', +'Autocomplete Python Code': 'Autocomplete Python Code', 'Available databases and tables': '可提供的資料庫和資料表', +'Available Databases and Tables': 'Available Databases and Tables', +'back': '回復(back)', +'Back to the plugins list': 'Back to the plugins list', +'Back to wizard': 'Back to wizard', +'Basics': 'Basics', +'Begin': 'Begin', +'breakpoint': 'breakpoint', +'Breakpoints': 'Breakpoints', +'breakpoints': 'breakpoints', +'Bulk Register': 'Bulk Register', +'Bulk Student Registration': 'Bulk Student Registration', +'Cache': 'Cache', +'cache': '快取記憶體', +'Cache Cleared': 'Cache Cleared', +'Cache Keys': 'Cache Keys', +'cache, errors and sessions cleaned': '快取記憶體,錯誤紀錄,連線紀錄已清除', +'can be a git repo': 'can be a git repo', +'Cancel': 'Cancel', 'Cannot be empty': '不可空白', 'Cannot compile: there are errors in your app. Debug it, correct errors and try again.': '無法編譯:應用程式中含有錯誤,請除錯後再試一次.', 'Cannot compile: there are errors in your app:': '無法編譯: 在你的應用程式存在錯誤:', -'Change Password': '變更密碼', +'cannot create file': '無法創建檔案', +'cannot upload file "%(filename)s"': '無法上傳檔案 "%(filename)s"', +'Change Admin Password': 'Change Admin Password', 'Change admin password': 'change admin password', +'change editor settings': 'change editor settings', +'Change Password': '變更密碼', +'change_password': '變更密碼', +'Changelog': 'Changelog', +'check all': '全選', +'Check for upgrades': 'Check for upgrades', 'Check to delete': '打勾代表刪除', 'Check to delete:': '打勾代表刪除:', 'Checking for upgrades...': '檢查新版本中...', 'Clean': '清除', +'Clear': 'Clear', +'Clear CACHE?': 'Clear CACHE?', +'Clear DISK': 'Clear DISK', +'Clear RAM': 'Clear RAM', +'click here for online examples': '點此處進入線上範例', +'click here for the administrative interface': '點此處進入管理介面', +'Click row to expand traceback': 'Click row to expand traceback', +'Click row to view a ticket': 'Click row to view a ticket', +'click to check for upgrades': '點擊打勾以便升級', 'Client IP': '客戶端網址(IP)', +'code': 'code', +'Code listing': 'Code listing', +'collapse/expand all': 'collapse/expand all', +'Command': 'Command', +'Comment:': 'Comment:', +'Commit': 'Commit', +'Commit form': 'Commit form', +'Committed files': 'Committed files', 'Compile': '編譯', +'Compile (all or nothing)': 'Compile (all or nothing)', +'Compile (skip failed views)': 'Compile (skip failed views)', +'compiled application removed': '已移除已編譯的應用程式', +'Condition': 'Condition', +'continue': 'continue', 'Controller': '控件', 'Controllers': '控件', +'controllers': '控件', 'Copyright': '版權所有', +'Count': 'Count', 'Create': '創建', +'create file with filename:': '創建檔案:', +'create new application:': '創建新應用程式:', 'Create new simple application': '創建應用程式', +'Create/Upload': 'Create/Upload', +'created by': '創建自', +'Created by:': 'Created by:', +'Created On': 'Created On', +'Created on:': 'Created on:', +'crontab': '定時執行表', 'Current request': '目前網路資料要求(request)', 'Current response': '目前網路資料回應(response)', 'Current session': '目前網路連線資訊(session)', -'DB Model': '資料庫模組', -'DESIGN': '設計', -'Database': '資料庫', -'Date and Time': '日期和時間', -'Delete': '刪除', -'Delete:': '刪除:', -'Deploy on Google App Engine': '配置到 Google App Engine', -'Description': '描述', -'Design for': '設計為了', -'E-mail': '電子郵件', -'EDIT': '編輯', -'Edit': '編輯', -'Edit Profile': '編輯設定檔', -'Edit This App': '編輯本應用程式', -'Edit application': '編輯應用程式', -'Edit current record': '編輯當前紀錄', -'Editing Language file': '編輯語言檔案', -'Editing file': '編輯檔案', -'Editing file "%s"': '編輯檔案"%s"', -'Enterprise Web Framework': '企業網站平台', -'Error logs for "%(app)s"': '"%(app)s"的錯誤紀錄', -'Errors': '錯誤紀錄', -'Exception instance attributes': 'Exception instance attributes', -'First name': '名', -'Functions with no doctests will result in [passed] tests.': '沒有 doctests 的函式會顯示 [passed].', -'Group ID': '群組編號', -'Hello World': '嗨! 世界', -'Help': '說明檔', -'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\nA green title indicates that all tests (if defined) passed. In this case test results are not shown.': 'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\nA green title indicates that all tests (if defined) passed. In this case test results are not shown.', -'Import/Export': '匯入/匯出', -'Index': '索引', -'Install': '安裝', -'Installed applications': '已安裝應用程式', -'Internal State': '內部狀態', -'Invalid Query': '不合法的查詢', -'Invalid action': '不合法的動作(action)', -'Invalid email': '不合法的電子郵件', -'Language files (static strings) updated': '語言檔已更新', -'Languages': '各國語言', -'Last name': '姓', -'Last saved on:': '最後儲存時間:', -'Layout': '網頁配置', -'License for': '許可證', -'Login': '登入', -'Login to the Administrative Interface': '登入到管理員介面', -'Logout': '登出', -'Lost Password': '密碼遺忘', -'Main Menu': '主選單', -'Menu Model': '選單模組(menu)', -'Models': '資料模組', -'Modules': '程式模組', -'NO': '否', -'Name': '名字', -'New Record': '新紀錄', -'No databases in this application': '這應用程式不含資料庫', -'Origin': '原文', -'Original/Translation': '原文/翻譯', -'Overwrite installed app': '覆蓋已安裝的應用程式', -'PAM authenticated user, cannot change password here': 'PAM 授權使用者, 無法在此變更密碼', -'Pack all': '全部打包', -'Pack compiled': '打包已編譯資料', -'Password': '密碼', -"Password fields don't match": '密碼欄不匹配', -'Peeking at file': '選個文件', -'Plugin "%s" in application': '在應用程式的插件 "%s"', -'Plugins': '插件', -'Powered by': '基於以下技術構建:', -'Query:': '查詢:', -'Record ID': '紀錄編號', -'Register': '註冊', -'Registration key': '註冊金鑰', -'Remember me (for 30 days)': '記住帳號(30 天)', -'Remove compiled': '編譯檔案已移除', -'Reset Password key': '重設密碼', -'Resolve Conflict file': '解決衝突檔案', -'Role': '角色', -'Rows in table': '在資料表裏的資料', -'Rows selected': '筆資料被選擇', -'Saved file hash:': '檔案雜湊值已紀錄:', -'Site': '網站', -'Static files': '靜態檔案', -'Stylesheet': '網頁風格檔', -'Submit': '傳送', -'Sure you want to delete this object?': '確定要刪除此物件?', -'TM': 'TM', -'Table name': '資料表名稱', -'Testing application': '測試中的應用程式', -'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.': '"查詢"是一個像 "db.表1.欄位1==\'值\'" 的條件式. 以"db.表1.欄位1==db.表2.欄位2"方式則相當於執行 JOIN SQL.', -'There are no controllers': '沒有控件(controllers)', -'There are no models': '沒有資料庫模組(models)', -'There are no modules': '沒有程式模組(modules)', -'There are no static files': '沒有靜態檔案', -'There are no translators, only default language is supported': '沒有翻譯檔,只支援原始語言', -'There are no views': '沒有視圖', -'This is the %(filename)s template': '這是%(filename)s檔案的樣板(template)', -'Ticket': '問題單', -'Timestamp': '時間標記', -'To create a plugin, name a file/folder plugin_[name]': '檔案或目錄名稱以 plugin_開頭來創建插件', -'Unable to check for upgrades': '無法做升級檢查', -'Unable to download': '無法下載', -'Unable to download app': '無法下載應用程式', -'Unable to download app because:': '無法下載應用程式因為:', -'Unable to download because': '因為下列原因無法下載:', -'Uninstall': '解除安裝', -'Update:': '更新:', -'Upload & install packed application': '上傳並安裝已打包的應用程式', -'Upload existing application': '更新存在的應用程式', -'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': '使用下列方式來組合更複雜的條件式, (...)&(...) 代表同時存在的條件, (...)|(...) 代表擇一的條件, ~(...)則代表反向條件.', -'User %(id)s Logged-in': '使用者 %(id)s 已登入', -'User %(id)s Registered': '使用者 %(id)s 已註冊', -'User ID': '使用者編號', -'Verify Password': '驗證密碼', -'Version': '版本', -'View': '視圖', -'Views': '視圖', -'Welcome %s': '歡迎 %s', -'Welcome to web2py': '歡迎使用 web2py', -'YES': '是', -'additional code for your application': '應用程式額外的程式碼', -'admin disabled because no admin password': '管理介面關閉原因是沒有設定管理員密碼 ', -'admin disabled because not supported on google app engine': '管理介面關閉原因是不支援在google apps engine環境下運作', -'admin disabled because unable to access password file': '管理介面關閉原因是無法存取密碼檔', -'amy_ajax': 'amy_ajax', -'and rename it (required):': '同時更名為(必要的):', -'and rename it:': '同時更名為:', -'appadmin': '應用程式管理員', -'appadmin is disabled because insecure channel': '管理介面關閉理由是連線方式不安全', -'application "%s" uninstalled': '已移除應用程式 "%s"', -'application compiled': '已編譯應用程式', -'application is compiled and cannot be designed': '應用程式已經編譯無法重新設計', -'arguments': 'arguments', -'back': '回復(back)', -'cache': '快取記憶體', -'cache, errors and sessions cleaned': '快取記憶體,錯誤紀錄,連線紀錄已清除', -'cannot create file': '無法創建檔案', -'cannot upload file "%(filename)s"': '無法上傳檔案 "%(filename)s"', -'change_password': '變更密碼', -'check all': '全選', -'click here for online examples': '點此處進入線上範例', -'click here for the administrative interface': '點此處進入管理介面', -'click to check for upgrades': '點擊打勾以便升級', -'code': 'code', -'compiled application removed': '已移除已編譯的應用程式', -'controllers': '控件', -'create file with filename:': '創建檔案:', -'create new application:': '創建新應用程式:', -'created by': '創建自', -'crontab': '定時執行表', +'currently running': 'currently running', 'currently saved or': '現在存檔或', 'customize me!': '請調整我!', 'data uploaded': '資料已上傳', +'Database': '資料庫', 'database': '資料庫', +'Database %s select': 'Database %s select', 'database %s select': '已選擇 %s 資料庫', +'Database administration': 'Database administration', 'database administration': '資料庫管理', +'Database Administration (appadmin)': 'Database Administration (appadmin)', +'Date and Time': '日期和時間', 'db': 'db', +'DB Model': '資料庫模組', +'Debug': 'Debug', 'defines tables': '定義資料表', +'Delete': '刪除', 'delete': '刪除', 'delete all checked': '刪除所有已選擇項目', 'delete plugin': '刪除插件', +'Delete this file (you will be asked to confirm deletion)': 'Delete this file (you will be asked to confirm deletion)', +'Delete:': '刪除:', 'delete_plugin': '刪除插件', +'deleted after first hit': 'deleted after first hit', +'Demo': 'Demo', +'Deploy': 'Deploy', +'Deploy on Google App Engine': '配置到 Google App Engine', +'Deploy to OpenShift': 'Deploy to OpenShift', +'Deploy to pythonanywhere': 'Deploy to pythonanywhere', +'Deploy to PythonAnywhere': 'Deploy to PythonAnywhere', +'Deployment form': 'Deployment form', +'Deployment Interface': 'Deployment Interface', +'Description': '描述', +'Description:': 'Description:', 'design': '設計', +'DESIGN': '設計', +'Design for': '設計為了', +'Detailed traceback description': 'Detailed traceback description', +'details': 'details', 'direction: ltr': 'direction: ltr', +'directory not found': 'directory not found', +'Disable': 'Disable', +'Disabled': 'Disabled', +'disabled in demo mode': 'disabled in demo mode', +'disabled in GAE mode': 'disabled in GAE mode', +'disabled in multi user mode': 'disabled in multi user mode', +'DISK': 'DISK', +'Disk Cache Keys': 'Disk Cache Keys', +'Disk Cleared': 'Disk Cleared', +'Display line numbers': 'Display line numbers', +'DO NOT use the "Pack compiled" feature.': 'DO NOT use the "Pack compiled" feature.', +'docs': 'docs', +'Docs': 'Docs', 'done!': '完成!', +'Downgrade': 'Downgrade', +'Download .w2p': 'Download .w2p', +'Download as .exe': 'Download as .exe', +'download layouts': 'download layouts', +'Download layouts from repository': 'Download layouts from repository', +'download plugins': 'download plugins', +'Download plugins from repository': 'Download plugins from repository', +'E-mail': '電子郵件', +'EDIT': '編輯', +'Edit': '編輯', +'edit all': 'edit all', +'Edit application': '編輯應用程式', 'edit controller': '編輯控件', +'edit controller:': 'edit controller:', +'Edit current record': '編輯當前紀錄', +'Edit Profile': '編輯設定檔', +'Edit This App': '編輯本應用程式', 'edit views:': '編輯視圖', 'edit_language': '編輯語言檔', +'Editing %s': 'Editing %s', +'Editing file': '編輯檔案', +'Editing file "%s"': '編輯檔案"%s"', +'Editing Language file': '編輯語言檔案', +'Editing Plural Forms File': 'Editing Plural Forms File', +'Editor': 'Editor', +'Email Address': 'Email Address', +'Enable': 'Enable', +'Enable Close-Tag': 'Enable Close-Tag', +'Enable Code Folding': 'Enable Code Folding', +'Enterprise Web Framework': '企業網站平台', +'Error': 'Error', +'Error logs for "%(app)s"': '"%(app)s"的錯誤紀錄', +'Error snapshot': 'Error snapshot', +'Error ticket': 'Error ticket', +'Errors': '錯誤紀錄', +'Exception %(extype)s: %(exvalue)s': 'Exception %(extype)s: %(exvalue)s', +'Exception %s': 'Exception %s', +'Exception instance attributes': 'Exception instance attributes', +'Exit Fullscreen': 'Exit Fullscreen', +'Expand Abbreviation (html files only)': 'Expand Abbreviation (html files only)', 'export as csv file': '以逗號分隔檔(csv)格式匯出', +'Exports:': 'Exports:', 'exposes': '外顯', +'exposes:': 'exposes:', 'extends': '擴展', +'failed to compile file because:': 'failed to compile file because:', 'failed to reload module because:': '因為下列原因無法重新載入程式模組:', +'File': 'File', 'file "%(filename)s" created': '檔案 "%(filename)s" 已創建', 'file "%(filename)s" deleted': '檔案 "%(filename)s" 已刪除', 'file "%(filename)s" uploaded': '檔案 "%(filename)s" 已上傳', 'file "%s" of %s restored': '檔案 %s 的 "%s" 已回存', 'file changed on disk': '在磁碟上檔案已改變', 'file does not exist': '檔案不存在', +'file not found': 'file not found', 'file saved on %(time)s': '檔案已於 %(time)s 儲存', 'file saved on %s': '檔案在 %s 已儲存', +'filename': 'filename', +'Filename': 'Filename', +'Files added': 'Files added', +'filter': 'filter', +'Find Next': 'Find Next', +'Find Previous': 'Find Previous', +'First name': '名', +'Form has errors': 'Form has errors', +'Frames': 'Frames', +'Functions with no doctests will result in [passed] tests.': '沒有 doctests 的函式會顯示 [passed].', +'GAE Email': 'GAE Email', +'GAE Output': 'GAE Output', +'GAE Password': 'GAE Password', +'Generate': 'Generate', +'Git Pull': 'Git Pull', +'Git Push': 'Git Push', +'Globals##debug': 'Globals##debug', +'go!': 'go!', +'Google App Engine Deployment Interface': 'Google App Engine Deployment Interface', +'Google Application Id': 'Google Application Id', +'Goto': 'Goto', +'graph model': 'graph model', +'Graph Model': 'Graph Model', +'Group ID': '群組編號', +'Hello World': '嗨! 世界', +'Help': '說明檔', +'here': 'here', +'Hide/Show Translated strings': 'Hide/Show Translated strings', +'Highlight current line': 'Highlight current line', +'Hits': 'Hits', +'Home': 'Home', +'honored only if the expression evaluates to true': 'honored only if the expression evaluates to true', 'htmledit': 'html編輯', +'If start the downgrade, be patient, it may take a while to rollback': 'If start the downgrade, be patient, it may take a while to rollback', +'If start the upgrade, be patient, it may take a while to download': 'If start the upgrade, be patient, it may take a while to download', +'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\n\t\tA green title indicates that all tests (if defined) passed. In this case test results are not shown.': 'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\n\t\tA green title indicates that all tests (if defined) passed. In this case test results are not shown.', +'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\nA green title indicates that all tests (if defined) passed. In this case test results are not shown.': 'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\nA green title indicates that all tests (if defined) passed. In this case test results are not shown.', +'if your application uses a database other than sqlite you will then have to configure its DAL in pythonanywhere.': 'if your application uses a database other than sqlite you will then have to configure its DAL in pythonanywhere.', +'import': 'import', +'Import/Export': '匯入/匯出', +'In development, use the default Rocket webserver that is currently supported by this debugger.': 'In development, use the default Rocket webserver that is currently supported by this debugger.', 'includes': '包含', +'Indent with tabs': 'Indent with tabs', +'Index': '索引', 'index': '索引', 'insert new': '插入新資料', 'insert new %s': '插入新資料 %s', +'inspect attributes': 'inspect attributes', +'Install': '安裝', +'Installation of %(plugin)s for %(app)s': 'Installation of %(plugin)s for %(app)s', +'Installed applications': '已安裝應用程式', +'Interaction at %s line %s': 'Interaction at %s line %s', +'Interactive console': 'Interactive console', 'internal error': '內部錯誤', +'internal error: %s': 'internal error: %s', +'Internal State': '內部狀態', +'Invalid action': '不合法的動作(action)', +'Invalid application name': 'Invalid application name', +'invalid circular reference': 'invalid circular reference', +'Invalid email': '不合法的電子郵件', +'Invalid git repository specified.': 'Invalid git repository specified.', 'invalid password': '密碼錯誤', +'invalid password.': 'invalid password.', +'Invalid Query': '不合法的查詢', 'invalid request': '不合法的網路要求(request)', +'Invalid request': 'Invalid request', +'invalid table names (auth_* tables already defined)': 'invalid table names (auth_* tables already defined)', 'invalid ticket': '不合法的問題單號', +'Key': 'Key', +'Keyboard shortcuts': 'Keyboard shortcuts', +'kill process': 'kill process', 'language file "%(filename)s" created/updated': '語言檔"%(filename)s"已創建或更新', +'Language files (static strings) updated': '語言檔已更新', 'languages': '語言檔', +'Languages': '各國語言', +'Last name': '姓', +'Last Revision': 'Last Revision', +'Last saved on:': '最後儲存時間:', +'Layout': '網頁配置', +'License for': '許可證', +'License:': 'License:', +'Line Nr': 'Line Nr', +'Line number': 'Line number', +'lists by exception': 'lists by exception', +'lists by ticket': 'lists by ticket', +'Loading...': 'Loading...', 'loading...': '載入中...', +'Local Apps': 'Local Apps', +'locals': 'locals', +'Locals##debug': 'Locals##debug', 'login': '登入', +'Login': '登入', +'Login successful': 'Login successful', +'Login to the Administrative Interface': '登入到管理員介面', +'Login/Register': 'Login/Register', +'Logout': '登出', +'Lost Password': '密碼遺忘', +'lost password': 'lost password', +'Main Menu': '主選單', +'Manage': 'Manage', +'Manage %(action)s': 'Manage %(action)s', +'Manage Access Control': 'Manage Access Control', +'Manage Admin Users/Students': 'Manage Admin Users/Students', +'Manage Cache': 'Manage Cache', +'Manage Students': 'Manage Students', +'Memberships': 'Memberships', +'Menu Model': '選單模組(menu)', 'merge': '合併', +'Models': '資料模組', 'models': '資料庫模組', +'Modified On': 'Modified On', +'Modules': '程式模組', 'modules': '程式模組', +'Multi User Mode': 'Multi User Mode', +'Name': '名字', 'new application "%s" created': '已創建新的應用程式 "%s"', +'new application "%s" imported': 'new application "%s" imported', +'New Application Wizard': 'New Application Wizard', +'New application wizard': 'New application wizard', 'new plugin installed': '已安裝新插件', +'New plugin installed: %s': 'New plugin installed: %s', +'New Record': '新紀錄', 'new record inserted': '已新增新紀錄', +'New simple application': 'New simple application', +'next': 'next', +'next %s rows': 'next %s rows', 'next 100 rows': '往後 100 筆', +'NO': '否', +'no changes': 'no changes', +'No databases in this application': '這應用程式不含資料庫', +'No Interaction yet': 'No Interaction yet', 'no match': '無法匹配', +'no package selected': 'no package selected', +'no permission to uninstall "%s"': 'no permission to uninstall "%s"', +'Node:': 'Node:', +'Not Authorized': 'Not Authorized', +'Not supported': 'Not supported', +'Note: If you receive an error with github status code of 128, ensure the system and account you are deploying from has a cooresponding ssh key configured in the openshift account.': 'Note: If you receive an error with github status code of 128, ensure the system and account you are deploying from has a cooresponding ssh key configured in the openshift account.', +"On production, you'll have to configure your webserver to use one process and multiple threads to use this debugger.": "On production, you'll have to configure your webserver to use one process and multiple threads to use this debugger.", +'Open new app in new window': 'Open new app in new window', +'OpenShift Deployment Interface': 'OpenShift Deployment Interface', +'OpenShift Output': 'OpenShift Output', +'or alternatively': 'or alternatively', +'Or Get from URL:': 'Or Get from URL:', 'or import from csv file': '或是從逗號分隔檔(CSV)匯入', 'or provide app url:': '或是提供應用程式的安裝網址:', +'Origin': '原文', +'Original/Translation': '原文/翻譯', +'Overview': 'Overview', +'Overwrite installed app': '覆蓋已安裝的應用程式', +'Pack all': '全部打包', +'Pack compiled': '打包已編譯資料', +'Pack custom': 'Pack custom', 'pack plugin': '打包插件', +'PAM authenticated user, cannot change password here': 'PAM 授權使用者, 無法在此變更密碼', +'Password': '密碼', 'password changed': '密碼已變更', +"Password fields don't match": '密碼欄不匹配', +'Past revisions': 'Past revisions', +'Path to appcfg.py': 'Path to appcfg.py', +'Path to local openshift repo root.': 'Path to local openshift repo root.', 'peek': '選取', +'Peeking at file': '選個文件', +'Permission': 'Permission', +'Permissions': 'Permissions', +'Please': 'Please', +'Please wait, giving pythonanywhere a moment...': 'Please wait, giving pythonanywhere a moment...', 'plugin': '插件', 'plugin "%(plugin)s" deleted': '已刪除插件"%(plugin)s"', +'Plugin "%s" in application': '在應用程式的插件 "%s"', +'plugin not specified': 'plugin not specified', +'Plugin page': 'Plugin page', +'plugins': 'plugins', +'Plugins': '插件', +'Plural Form #%s': 'Plural Form #%s', +'Plural-Forms:': 'Plural-Forms:', +'Powered by': '基於以下技術構建:', +'Preferences saved correctly': 'Preferences saved correctly', +'Preferences saved on session only': 'Preferences saved on session only', +'previous %s rows': 'previous %s rows', 'previous 100 rows': '往前 100 筆', +'Private files': 'Private files', +'private files': 'private files', +'Project Progress': 'Project Progress', +'Pull': 'Pull', +'Pull failed, certain files could not be checked out. Check logs for details.': 'Pull failed, certain files could not be checked out. Check logs for details.', +'Pull is not possible because you have unmerged files. Fix them up in the work tree, and then try again.': 'Pull is not possible because you have unmerged files. Fix them up in the work tree, and then try again.', +'Push': 'Push', +'Push failed, there are unmerged entries in the cache. Resolve merge issues manually and try again.': 'Push failed, there are unmerged entries in the cache. Resolve merge issues manually and try again.', +'pygraphviz library not found': 'pygraphviz library not found', +'PythonAnywhere Apps': 'PythonAnywhere Apps', +'PythonAnywhere Password': 'PythonAnywhere Password', +'Query:': '查詢:', +'RAM': 'RAM', +'RAM Cache Keys': 'RAM Cache Keys', +'Ram Cleared': 'Ram Cleared', +'Rapid Search': 'Rapid Search', +'Record': 'Record', 'record': '紀錄', 'record does not exist': '紀錄不存在', 'record id': '紀錄編號', +'Record ID': '紀錄編號', +'Record id': 'Record id', +'refresh': 'refresh', 'register': '註冊', +'Register': '註冊', +'Registration key': '註冊金鑰', +'Reload routes': 'Reload routes', +'Remember me (for 30 days)': '記住帳號(30 天)', +'Remove compiled': '編譯檔案已移除', +'Removed Breakpoint on %s at line %s': 'Removed Breakpoint on %s at line %s', +'Replace': 'Replace', +'Replace All': 'Replace All', +'Repository (%s)': 'Repository (%s)', +'request': 'request', +'requires distutils, but not installed': 'requires distutils, but not installed', +'requires python-git, but not installed': 'requires python-git, but not installed', +'Reset Password key': '重設密碼', 'resolve': '解決', +'Resolve Conflict file': '解決衝突檔案', +'response': 'response', +'restart': 'restart', 'restore': '回存', +'return': 'return', +'Revert': 'Revert', 'revert': '反向恢復', +'reverted to revision %s': 'reverted to revision %s', +'Revision %s': 'Revision %s', +'Revision:': 'Revision:', +'Role': '角色', +'Roles': 'Roles', +'Rows in table': '在資料表裏的資料', +'Rows in Table': 'Rows in Table', +'Rows selected': '筆資料被選擇', +'rules are not defined': 'rules are not defined', +'Run tests': 'Run tests', +'Run tests in this file': 'Run tests in this file', +"Run tests in this file (to run all files, you may also use the button labelled 'test')": "Run tests in this file (to run all files, you may also use the button labelled 'test')", +'Running on %s': 'Running on %s', +'Save': 'Save', 'save': '儲存', +'Save file:': 'Save file:', +'Save file: %s': 'Save file: %s', +'Save model as...': 'Save model as...', +'Save via Ajax': 'Save via Ajax', +'Saved file hash:': '檔案雜湊值已紀錄:', +'Screenshot %s': 'Screenshot %s', +'Search': 'Search', +'Select Files to Package': 'Select Files to Package', 'selected': '已選擇', +'session': 'session', 'session expired': '連線(session)已過時', +'Session saved correctly': 'Session saved correctly', +'Session saved on session only': 'Session saved on session only', +'Set Breakpoint on %s at line %s: %s': 'Set Breakpoint on %s at line %s: %s', 'shell': '命令列操作介面', +'Showing %s to %s of %s %s found': 'Showing %s to %s of %s %s found', +'Singular Form': 'Singular Form', +'Site': '網站', +'Size of cache:': 'Size of cache:', +'skip to generate': 'skip to generate', 'some files could not be removed': '部份檔案無法移除', +'Something went wrong please wait a few minutes before retrying': 'Something went wrong please wait a few minutes before retrying', +'Sorry, could not find mercurial installed': 'Sorry, could not find mercurial installed', +'source : db': 'source : db', +'source : filesystem': 'source : filesystem', +'Start a new app': 'Start a new app', +'Start searching': 'Start searching', +'Start wizard': 'Start wizard', 'state': '狀態', +'Static': 'Static', 'static': '靜態檔案', +'Static files': '靜態檔案', +'Statistics': 'Statistics', +'Step': 'Step', +'step': 'step', +'stop': 'stop', +'Stylesheet': '網頁風格檔', 'submit': '傳送', +'Submit': '傳送', +'successful': 'successful', +'Sure you want to delete this object?': '確定要刪除此物件?', +'switch to : db': 'switch to : db', +'switch to : filesystem': 'switch to : filesystem', +'Tab width (# characters)': 'Tab width (# characters)', 'table': '資料表', +'Table': 'Table', +'Table name': '資料表名稱', +'Temporary': 'Temporary', 'test': '測試', +'Testing application': '測試中的應用程式', +'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.': '"查詢"是一個像 "db.表1.欄位1==\'值\'" 的條件式. 以"db.表1.欄位1==db.表2.欄位2"方式則相當於執行 JOIN SQL.', +'The app exists, was created by wizard, continue to overwrite!': 'The app exists, was created by wizard, continue to overwrite!', +'The app exists, was NOT created by wizard, continue to overwrite!': 'The app exists, was NOT created by wizard, continue to overwrite!', 'the application logic, each URL path is mapped in one exposed function in the controller': '應用程式邏輯 - 每個網址路徑對應到一個控件的函式', +'The application logic, each URL path is mapped in one exposed function in the controller': 'The application logic, each URL path is mapped in one exposed function in the controller', 'the data representation, define database tables and sets': '資料展現層 - 用來定義資料表和集合', +'The data representation, define database tables and sets': 'The data representation, define database tables and sets', +'The presentations layer, views are also known as templates': 'The presentations layer, views are also known as templates', 'the presentations layer, views are also known as templates': '外觀展現層 - 視圖有時也被稱為樣板', +'Theme': 'Theme', +'There are no controllers': '沒有控件(controllers)', +'There are no models': '沒有資料庫模組(models)', +'There are no modules': '沒有程式模組(modules)', +'There are no plugins': 'There are no plugins', +'There are no private files': 'There are no private files', +'There are no static files': '沒有靜態檔案', +'There are no translators': 'There are no translators', +'There are no translators, only default language is supported': '沒有翻譯檔,只支援原始語言', +'There are no views': '沒有視圖', +'These files are not served, they are only available from within your app': 'These files are not served, they are only available from within your app', +'These files are served without processing, your images go here': 'These files are served without processing, your images go here', 'these files are served without processing, your images go here': '這些檔案保留未經處理,你的影像檔在此', +"This debugger may not work properly if you don't have a threaded webserver or you're using multiple daemon processes.": "This debugger may not work properly if you don't have a threaded webserver or you're using multiple daemon processes.", +'This is an experimental feature and it needs more testing. If you decide to downgrade you do it at your own risk': 'This is an experimental feature and it needs more testing. If you decide to downgrade you do it at your own risk', +'This is an experimental feature and it needs more testing. If you decide to upgrade you do it at your own risk': 'This is an experimental feature and it needs more testing. If you decide to upgrade you do it at your own risk', +'This is the %(filename)s template': '這是%(filename)s檔案的樣板(template)', +"This page can commit your changes to an openshift app repo and push them to your cloud instance. This assumes that you've already created the application instance using the web2py skeleton and have that repo somewhere on a filesystem that this web2py instance can access. This functionality requires GitPython installed and on the python path of the runtime that web2py is operating in.": "This page can commit your changes to an openshift app repo and push them to your cloud instance. This assumes that you've already created the application instance using the web2py skeleton and have that repo somewhere on a filesystem that this web2py instance can access. This functionality requires GitPython installed and on the python path of the runtime that web2py is operating in.", +'This page can upload your application to the Google App Engine computing cloud. Mind that you must first create indexes locally and this is done by installing the Google appserver and running the app locally with it once, or there will be errors when selecting records. Attention: deployment may take long time, depending on the network speed. Attention: it will overwrite your app.yaml. DO NOT SUBMIT TWICE.': 'This page can upload your application to the Google App Engine computing cloud. Mind that you must first create indexes locally and this is done by installing the Google appserver and running the app locally with it once, or there will be errors when selecting records. Attention: deployment may take long time, depending on the network speed. Attention: it will overwrite your app.yaml. DO NOT SUBMIT TWICE.', +'this page to see if a breakpoint was hit and debug interaction is required.': 'this page to see if a breakpoint was hit and debug interaction is required.', +'This will pull changes from the remote repo for application "%s"?': 'This will pull changes from the remote repo for application "%s"?', +'This will push changes to the remote repo for application "%s".': 'This will push changes to the remote repo for application "%s".', 'ticket': '問題單', +'Ticket': '問題單', +'Ticket ID': 'Ticket ID', +'Ticket Missing': 'Ticket Missing', +'Time in Cache (h:m:s)': 'Time in Cache (h:m:s)', +'Timestamp': '時間標記', +'TM': 'TM', 'to previous version.': '到前一個版本', +'To create a plugin, name a file/folder plugin_[name]': '檔案或目錄名稱以 plugin_開頭來創建插件', +'To emulate a breakpoint programatically, write:': 'To emulate a breakpoint programatically, write:', +'to use the debugger!': 'to use the debugger!', +'toggle breakpoint': 'toggle breakpoint', +'Toggle comment': 'Toggle comment', +'Toggle Fullscreen': 'Toggle Fullscreen', +'Traceback': 'Traceback', 'translation strings for the application': '翻譯此應用程式的字串', +'Translation strings for the application': 'Translation strings for the application', 'try': '嘗試', 'try something like': '嘗試如', +'Try the mobile interface': 'Try the mobile interface', +'try view': 'try view', +'Type PDB debugger command in here and hit Return (Enter) to execute it.': 'Type PDB debugger command in here and hit Return (Enter) to execute it.', +'Type some Python code in here and hit Return (Enter) to execute it.': 'Type some Python code in here and hit Return (Enter) to execute it.', +'Unable to check for upgrades': '無法做升級檢查', 'unable to create application "%s"': '無法創建應用程式 "%s"', 'unable to delete file "%(filename)s"': '無法刪除檔案 "%(filename)s"', 'unable to delete file plugin "%(plugin)s"': '無法刪查插件檔 "%(plugin)s"', +'Unable to determine the line number!': 'Unable to determine the line number!', +'Unable to download': '無法下載', +'Unable to download app': '無法下載應用程式', +'Unable to download app because:': '無法下載應用程式因為:', +'Unable to download because': '因為下列原因無法下載:', +'unable to download layout': 'unable to download layout', +'unable to download plugin: %s': 'unable to download plugin: %s', +'Unable to download the list of plugins': 'Unable to download the list of plugins', +'unable to install plugin "%s"': 'unable to install plugin "%s"', 'unable to parse csv file': '無法解析逗號分隔檔(csv)', 'unable to uninstall "%s"': '無法移除安裝 "%s"', 'unable to upgrade because "%s"': '無法升級因為 "%s"', 'uncheck all': '全不選', +'Uninstall': '解除安裝', +'Unsupported webserver working mode: %s': 'Unsupported webserver working mode: %s', 'update': '更新', 'update all languages': '將程式中待翻譯語句更新到所有的語言檔', +'Update:': '更新:', +'Upgrade': 'Upgrade', +'upgrade now to %s': 'upgrade now to %s', 'upgrade web2py now': 'upgrade web2py now', 'upgrade_web2py': '升級 web2py', +'upload': 'upload', +'Upload': 'Upload', +'Upload & install packed application': '上傳並安裝已打包的應用程式', +'Upload a package:': 'Upload a package:', +'Upload and install packed application': 'Upload and install packed application', 'upload application:': '上傳應用程式:', +'Upload existing application': '更新存在的應用程式', 'upload file:': '上傳檔案:', 'upload plugin file:': '上傳插件檔:', +'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': '使用下列方式來組合更複雜的條件式, (...)&(...) 代表同時存在的條件, (...)|(...) 代表擇一的條件, ~(...)則代表反向條件.', +'User': 'User', +'User %(id)s Logged-in': '使用者 %(id)s 已登入', +'User %(id)s Registered': '使用者 %(id)s 已註冊', +'User ID': '使用者編號', +'Username': 'Username', +'Users': 'Users', +'Using the shell may lock the database to other users of this app.': 'Using the shell may lock the database to other users of this app.', 'variables': 'variables', +'Verify Password': '驗證密碼', +'Version': '版本', +'Versioning': 'Versioning', 'versioning': '版本管理', +'View': '視圖', 'view': '視圖', +'Views': '視圖', 'views': '視圖', -'web2py Recent Tweets': 'web2py 最近的 Tweets', +'Warning!': 'Warning!', +'WARNING:': 'WARNING:', +'WARNING: The following views could not be compiled:': 'WARNING: The following views could not be compiled:', +'Web Framework': 'Web Framework', +'web2py Admin Password': 'web2py Admin Password', +'web2py apps to deploy': 'web2py apps to deploy', +'web2py Debugger': 'web2py Debugger', +'web2py downgrade': 'web2py downgrade', 'web2py is up to date': 'web2py 已經是最新版', +'web2py online debugger': 'web2py online debugger', +'web2py Recent Tweets': 'web2py 最近的 Tweets', +'web2py upgrade': 'web2py upgrade', 'web2py upgraded; please restart it': '已升級 web2py ; 請重新啟動', +'Welcome %s': '歡迎 %s', +'Welcome to web2py': '歡迎使用 web2py', +'Working...': 'Working...', +'WSGI reference name': 'WSGI reference name', +'YES': '是', +'Yes': 'Yes', +'You can also set and remove breakpoint in the edit window, using the Toggle Breakpoint button': 'You can also set and remove breakpoint in the edit window, using the Toggle Breakpoint button', +'You can inspect variables using the console below': 'You can inspect variables using the console below', +'You have one more login attempt before you are locked out': 'You have one more login attempt before you are locked out', +'You need to set up and reach a': 'You need to set up and reach a', +'You only need these if you have already registered': 'You only need these if you have already registered', +'Your application will be blocked until you click an action button (next, step, continue, etc.)': 'Your application will be blocked until you click an action button (next, step, continue, etc.)', } diff --git a/applications/admin/languages/zh.py b/applications/admin/languages/zh.py index d62b0804..7215a477 100755 --- a/applications/admin/languages/zh.py +++ b/applications/admin/languages/zh.py @@ -6,215 +6,243 @@ '"save"': '"保存"', '"submit"': '"提交"', '"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN': '"更新"是可配置项 如 "field1=\'newvalue\'",你无法在JOIN 中更新或删除', -'%Y-%m-%d': '%Y-%m-%d', -'%Y-%m-%d %H:%M:%S': '%Y-%m-%d %H:%M:%S', +'"User Exception" debug mode. ': '"User Exception" debug mode. ', +'%s': '%s', '%s %%{row} deleted': '%s 行已删', '%s %%{row} updated': '%s 行更新', +'%s selected': '%s selected', +'%s students registered': '%s students registered', +'%Y-%m-%d': '%Y-%m-%d', +'%Y-%m-%d %H:%M:%S': '%Y-%m-%d %H:%M:%S', '(requires internet access)': '(requires internet access)', +'(requires internet access, experimental)': '(requires internet access, experimental)', '(something like "it-it")': '(就酱 "it-it")', +'(version %s)': '(version %s)', +'?': '?', '@markmin\x01Searching: **%s** %%{file}': 'Searching: **%s** files', 'A new version of web2py is available': '新版本web2py已经可用', 'A new version of web2py is available: %s': '新版本web2py已经可用: %s', -'ATTENTION: Login requires a secure (HTTPS) connection or running on localhost.': '', -'ATTENTION: TESTING IS NOT THREAD SAFE SO DO NOT PERFORM MULTIPLE TESTS CONCURRENTLY.': '', -'ATTENTION: you cannot edit the running application!': '注意: 不能修改正在运行中的应用!', +'Abort': 'Abort', 'About': '关于', 'About application': '关于这个应用', +'Accept Terms': 'Accept Terms', +'Add breakpoint': 'Add breakpoint', +'additional code for your application': '给你的应用附加代码', +'Additional code for your application': 'Additional code for your application', +'Admin design page': 'Admin design page', +'admin disabled because no admin password': '管理员需要设定密码,否则无法管理', +'admin disabled because not supported on google app engine': '未支持GAE,无法管理', +'admin disabled because too many invalid login attempts': 'admin disabled because too many invalid login attempts', +'admin disabled because unable to access password file': '需要可以操作密码文件,否则无法进行管理', 'Admin is disabled because insecure channel': '管理因不安全通道而关闭', 'Admin is disabled because unsecure channel': '管理因不稳定通道而关闭', 'Admin language': 'Admin language', +'Admin versioning page': 'Admin versioning page', +'administrative interface': 'administrative interface', 'Administrator Password:': '管理员密码:', +'and rename it (required):': '重命名为 (必须):', +'and rename it:': ' 重命名为:', +'App does not exist or you are not authorized': 'App does not exist or you are not authorized', +'appadmin': '应用管理', +'appadmin is disabled because insecure channel': '应用管理因非法通道失效', +'Application': 'Application', +'application "%s" uninstalled': '应用"%s" 已被卸载', +'Application cannot be generated in demo mode': 'Application cannot be generated in demo mode', +'application compiled': '应用已编译完', +'Application exists already': 'Application exists already', +'application is compiled and cannot be designed': '应用已编译完无法设计', 'Application name:': 'Application name:', +'Application updated via git pull': 'Application updated via git pull', +'are not used': 'are not used', +'are not used yet': 'are not used yet', 'Are you sure you want to delete file "%s"?': '你真想删除文件"%s"?', 'Are you sure you want to delete plugin "%s"?': 'Are you sure you want to delete plugin "%s"?', 'Are you sure you want to delete this object?': 'Are you sure you want to delete this object?', 'Are you sure you want to uninstall application "%s"': '你真确定要卸载应用 "%s"', 'Are you sure you want to uninstall application "%s"?': '你真确定要卸载应用 "%s" ?', 'Are you sure you want to upgrade web2py now?': 'Are you sure you want to upgrade web2py now?', +'Are you sure?': 'Are you sure?', +'arguments': 'arguments', +'at char %s': 'at char %s', +'at line %s': 'at line %s', +'ATTENTION:': 'ATTENTION:', +'ATTENTION: Login requires a secure (HTTPS) connection or running on localhost.': '', +'ATTENTION: TESTING IS NOT THREAD SAFE SO DO NOT PERFORM MULTIPLE TESTS CONCURRENTLY.': '', +'ATTENTION: you cannot edit the running application!': '注意: 不能修改正在运行中的应用!', +'Autocomplete Python Code': 'Autocomplete Python Code', 'Available databases and tables': '可用数据库/表', +'Available Databases and Tables': 'Available Databases and Tables', +'back': 'back', +'Back to the plugins list': 'Back to the plugins list', +'Back to wizard': 'Back to wizard', +'Basics': 'Basics', +'Begin': 'Begin', +'breakpoint': 'breakpoint', +'Breakpoints': 'Breakpoints', +'breakpoints': 'breakpoints', +'Bulk Register': 'Bulk Register', +'Bulk Student Registration': 'Bulk Student Registration', +'Cache': 'Cache', +'cache': 'cache', +'Cache Cleared': 'Cache Cleared', +'Cache Keys': 'Cache Keys', +'cache, errors and sessions cleaned': '缓存、错误、sesiones已被清空', +'can be a git repo': 'can be a git repo', +'Cancel': 'Cancel', 'Cannot be empty': '不能不填', 'Cannot compile: there are errors in your app.        Debug it, correct errors and try again.': '无法编译: 应用中有错误,请修订后再试.', 'Cannot compile: there are errors in your app:': 'Cannot compile: there are errors in your app:', -'Change Password': '修改密码', +'cannot create file': '无法创建文件', +'cannot upload file "%(filename)s"': '无法上传文件 "%(filename)s"', +'Change Admin Password': 'Change Admin Password', 'Change admin password': 'change admin password', +'change editor settings': 'change editor settings', +'Change Password': '修改密码', +'Changelog': 'Changelog', +'check all': '检查所有', 'Check for upgrades': 'check for upgrades', 'Check to delete': '检验删除', 'Checking for upgrades...': '是否有升级版本检查ing...', 'Clean': '清除', +'Clear': 'Clear', +'Clear CACHE?': 'Clear CACHE?', +'Clear DISK': 'Clear DISK', +'Clear RAM': 'Clear RAM', +'click here for online examples': '猛击此处,查看在线实例', +'click here for the administrative interface': '猛击此处,进入管理界面', +'Click row to expand traceback': 'Click row to expand traceback', +'Click row to view a ticket': 'Click row to view a ticket', +'click to check for upgrades': '猛击查看是否有升级版本', 'Client IP': '客户端IP', +'code': 'code', +'Code listing': 'Code listing', +'collapse/expand all': 'collapse/expand all', +'Command': 'Command', +'Comment:': 'Comment:', +'Commit': 'Commit', +'Commit form': 'Commit form', +'Committed files': 'Committed files', 'Compile': '编译', +'Compile (all or nothing)': 'Compile (all or nothing)', +'Compile (skip failed views)': 'Compile (skip failed views)', +'compiled application removed': '已编译应用已移走', +'Condition': 'Condition', +'continue': 'continue', 'Controllers': '控制器s', +'controllers': '控制器', +'Count': 'Count', 'Create': 'create', +'create file with filename:': '创建文件用这名:', +'create new application:': '创建新应用:', 'Create new simple application': '创建一个新应用', +'Create/Upload': 'Create/Upload', +'created by': '创建自', +'Created by:': 'Created by:', +'Created On': 'Created On', +'Created on:': 'Created on:', +'crontab': '定期事务', 'Current request': '当前请求', 'Current response': '当前返回', 'Current session': '当前会话', -'DESIGN': '设计', -'Date and Time': '时间日期', -'Debug': 'Debug', -'Delete': '删除', -'Delete:': '删除:', -'Deploy': 'deploy', -'Deploy on Google App Engine': '部署到GAE', -'Deploy to OpenShift': 'Deploy to OpenShift', -'Description': '描述', -'Design for': '设计:', -'Disable': 'Disable', -'E-mail': '邮箱:', -'EDIT': '编辑', -'Edit': '修改', -'Edit Profile': '修订配置', -'Edit application': '修订应用', -'Edit current record': '修订当前记录', -'Editing Language file': '修订语言文件', -'Editing file': '修订文件', -'Editing file "%s"': '修订文件 %s', -'Enterprise Web Framework': '强悍的网络开发框架', -'Error logs for "%(app)s"': '"%(app)s" 的错误日志', -'Errors': '错误', -'Exception instance attributes': 'Exception instance attributes', -'First name': '姓', -'Functions with no doctests will result in [passed] tests.': '', -'Get from URL:': 'Get from URL:', -'Group ID': '组ID', -'Hello World': '道可道,非常道;名可名,非常名', -'Help': '帮助', -'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\nA green title indicates that all tests (if defined) passed. In this case test results are not shown.': 'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\nA green title indicates that all tests (if defined) passed. In this case test results are not shown.', -'Import/Export': '导入/导出', -'Install': 'install', -'Installed applications': '已安装的应用', -'Internal State': '内部状态', -'Invalid Query': '无效查询', -'Invalid action': '无效动作', -'Invalid email': '无效的email', -'Language files (static strings) updated': '语言文件(静态部分)已更新', -'Languages': '语言', -'Last name': '名', -'Last saved on:': '最后保存于:', -'License for': '许可证', -'Login': '登录', -'Login to the Administrative Interface': '登录到管理员界面', -'Logout': '注销', -'Lost Password': '忘记密码', -'Models': '模型s', -'Modules': '模块s', -'NO': '不', -'Name': '姓名', -'New Record': '新记录', -'New application wizard': 'New application wizard', -'New simple application': 'New simple application', -'No databases in this application': '这应用没有数据库', -'Origin': '起源', -'Original/Translation': '原始文件/翻译文件', -'Overwrite installed app': 'overwrite installed app', -'PAM authenticated user, cannot change password here': 'PAM authenticated user, cannot change password here', -'Pack all': '全部打包', -'Pack compiled': '包编译完', -'Password': '密码', -'Peeking at file': '选个文件', -'Plugin "%s" in application': 'Plugin "%s" in application', -'Plugins': 'Plugins', -'Powered by': '', -'Query:': '查询', -'Record ID': '记录ID', -'Register': '注册', -'Registration key': '注册密匙', -'Reload routes': 'Reload routes', -'Remove compiled': '已移除', -'Resolve Conflict file': '解决冲突文件', -'Role': '角色', -'Rows in table': '表行', -'Rows selected': '行选择', -'Running on %s': 'Running on %s', -'Saved file hash:': '已存文件Hash:', -'Site': '总站', -'Start wizard': 'start wizard', -'Static files': '静态文件', -'Sure you want to delete this object?': '真的要删除这个对象?', -'TM': '', -'Table name': '表名', -'Testing application': '应用测试', -'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.': '', -'There are no controllers': '冇控制器', -'There are no models': '冇模型s', -'There are no modules': '冇模块s', -'There are no static files': '冇静态文件', -'There are no translators, only default language is supported': '没有找到相应翻译,只能使用默认语言', -'There are no views': '冇视图', -'This is the %(filename)s template': '这是 %(filename)s 模板', -'Ticket': '传票', -'Timestamp': '时间戳', -'To create a plugin, name a file/folder plugin_[name]': 'To create a plugin, name a file/folder plugin_[name]', -'Unable to check for upgrades': '无法检查是否需要升级', -'Unable to download': '无法下载', -'Unable to download app': '无法下载应用', -'Unable to download app because:': 'Unable to download app because:', -'Unable to download because': 'Unable to download because', -'Uninstall': '卸载', -'Update:': '更新:', -'Upload & install packed application': 'Upload & install packed application', -'Upload a package:': 'Upload a package:', -'Upload and install packed application': 'Upload and install packed application', -'Upload existing application': '上传已有应用', -'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.', -'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...)  for NOT to build more complex queries.': '', -'Use an url:': 'Use an url:', -'User ID': '用户ID', -'Version': '版本', -'Views': '视图', -'Welcome to web2py': '欢迎使用web2py', -'YES': '是', -'additional code for your application': '给你的应用附加代码', -'admin disabled because no admin password': '管理员需要设定密码,否则无法管理', -'admin disabled because not supported on google app engine': '未支持GAE,无法管理', -'admin disabled because unable to access password file': '需要可以操作密码文件,否则无法进行管理', -'administrative interface': 'administrative interface', -'and rename it (required):': '重命名为 (必须):', -'and rename it:': ' 重命名为:', -'appadmin': '应用管理', -'appadmin is disabled because insecure channel': '应用管理因非法通道失效', -'application "%s" uninstalled': '应用"%s" 已被卸载', -'application compiled': '应用已编译完', -'application is compiled and cannot be designed': '应用已编译完无法设计', -'arguments': 'arguments', -'back': 'back', -'cache': 'cache', -'cache, errors and sessions cleaned': '缓存、错误、sesiones已被清空', -'cannot create file': '无法创建文件', -'cannot upload file "%(filename)s"': '无法上传文件 "%(filename)s"', -'check all': '检查所有', -'click here for online examples': '猛击此处,查看在线实例', -'click here for the administrative interface': '猛击此处,进入管理界面', -'click to check for upgrades': '猛击查看是否有升级版本', -'code': 'code', -'compiled application removed': '已编译应用已移走', -'controllers': '控制器', -'create file with filename:': '创建文件用这名:', -'create new application:': '创建新应用:', -'created by': '创建自', -'crontab': '定期事务', 'currently running': 'currently running', 'currently saved or': '保存当前的或', 'customize me!': '定制俺!', 'data uploaded': '数据已上传', +'Database': 'Database', 'database': '数据库', +'Database %s select': 'Database %s select', 'database %s select': '数据库 %s 选择', +'Database administration': 'Database administration', 'database administration': '数据库管理', +'Database Administration (appadmin)': 'Database Administration (appadmin)', +'Date and Time': '时间日期', 'db': '', +'Debug': 'Debug', 'defines tables': '已定义表', +'Delete': '删除', 'delete': '删除', 'delete all checked': '删除所有选择的', 'delete plugin': 'delete plugin', +'Delete this file (you will be asked to confirm deletion)': 'Delete this file (you will be asked to confirm deletion)', +'Delete:': '删除:', +'deleted after first hit': 'deleted after first hit', +'Demo': 'Demo', +'Deploy': 'deploy', +'Deploy on Google App Engine': '部署到GAE', +'Deploy to OpenShift': 'Deploy to OpenShift', +'Deploy to pythonanywhere': 'Deploy to pythonanywhere', +'Deploy to PythonAnywhere': 'Deploy to PythonAnywhere', +'Deployment form': 'Deployment form', +'Deployment Interface': 'Deployment Interface', +'Description': '描述', +'Description:': 'Description:', 'design': '设计', +'DESIGN': '设计', +'Design for': '设计:', +'Detailed traceback description': 'Detailed traceback description', +'details': 'details', 'direction: ltr': 'direction: ltr', +'directory not found': 'directory not found', +'Disable': 'Disable', +'Disabled': 'Disabled', +'disabled in demo mode': 'disabled in demo mode', +'disabled in GAE mode': 'disabled in GAE mode', +'disabled in multi user mode': 'disabled in multi user mode', +'DISK': 'DISK', +'Disk Cache Keys': 'Disk Cache Keys', +'Disk Cleared': 'Disk Cleared', +'Display line numbers': 'Display line numbers', +'DO NOT use the "Pack compiled" feature.': 'DO NOT use the "Pack compiled" feature.', +'docs': 'docs', +'Docs': 'Docs', 'done!': '搞定!', +'Downgrade': 'Downgrade', +'Download .w2p': 'Download .w2p', +'Download as .exe': 'Download as .exe', +'download layouts': 'download layouts', +'Download layouts from repository': 'Download layouts from repository', +'download plugins': 'download plugins', +'Download plugins from repository': 'Download plugins from repository', +'E-mail': '邮箱:', +'EDIT': '编辑', +'Edit': '修改', +'edit all': 'edit all', +'Edit application': '修订应用', 'edit controller': '修订控制器', +'edit controller:': 'edit controller:', +'Edit current record': '修订当前记录', +'Edit Profile': '修订配置', 'edit views:': 'edit views:', +'Editing %s': 'Editing %s', +'Editing file': '修订文件', +'Editing file "%s"': '修订文件 %s', +'Editing Language file': '修订语言文件', +'Editing Plural Forms File': 'Editing Plural Forms File', +'Editor': 'Editor', +'Email Address': 'Email Address', +'Enable': 'Enable', +'Enable Close-Tag': 'Enable Close-Tag', +'Enable Code Folding': 'Enable Code Folding', +'Enterprise Web Framework': '强悍的网络开发框架', +'Error': 'Error', +'Error logs for "%(app)s"': '"%(app)s" 的错误日志', +'Error snapshot': 'Error snapshot', +'Error ticket': 'Error ticket', +'Errors': '错误', +'Exception %(extype)s: %(exvalue)s': 'Exception %(extype)s: %(exvalue)s', +'Exception %s': 'Exception %s', +'Exception instance attributes': 'Exception instance attributes', +'Exit Fullscreen': 'Exit Fullscreen', +'Expand Abbreviation (html files only)': 'Expand Abbreviation (html files only)', 'export as csv file': '导出为CSV文件', +'Exports:': 'Exports:', 'exposes': '暴露', +'exposes:': 'exposes:', 'extends': '扩展', +'failed to compile file because:': 'failed to compile file because:', 'failed to reload module': '重新加载模块失败', 'failed to reload module because:': 'failed to reload module because:', +'File': 'File', 'file "%(filename)s" created': '文件 "%(filename)s" 已创建', 'file "%(filename)s" deleted': '文件 "%(filename)s" 已删除', 'file "%(filename)s" uploaded': '文件 "%(filename)s" 已上传', @@ -222,78 +250,417 @@ 'file "%s" of %s restored': '文件"%s" 有关 %s 已重存', 'file changed on disk': '硬盘上的文件已经修改', 'file does not exist': '文件并不存在', +'file not found': 'file not found', 'file saved on %(time)s': '文件保存于 %(time)s', 'file saved on %s': '文件保存在 %s', +'filename': 'filename', +'Filename': 'Filename', +'Files added': 'Files added', +'filter': 'filter', +'Find Next': 'Find Next', +'Find Previous': 'Find Previous', +'First name': '姓', +'Form has errors': 'Form has errors', +'Frames': 'Frames', +'Functions with no doctests will result in [passed] tests.': '', +'GAE Email': 'GAE Email', +'GAE Output': 'GAE Output', +'GAE Password': 'GAE Password', +'Generate': 'Generate', +'Get from URL:': 'Get from URL:', +'Git Pull': 'Git Pull', +'Git Push': 'Git Push', +'Globals##debug': 'Globals##debug', +'go!': 'go!', +'Google App Engine Deployment Interface': 'Google App Engine Deployment Interface', +'Google Application Id': 'Google Application Id', +'Goto': 'Goto', +'graph model': 'graph model', +'Graph Model': 'Graph Model', +'Group ID': '组ID', +'Hello World': '道可道,非常道;名可名,非常名', +'Help': '帮助', +'here': 'here', +'Hide/Show Translated strings': 'Hide/Show Translated strings', +'Highlight current line': 'Highlight current line', +'Hits': 'Hits', +'Home': 'Home', +'honored only if the expression evaluates to true': 'honored only if the expression evaluates to true', 'htmledit': 'html编辑', +'If start the downgrade, be patient, it may take a while to rollback': 'If start the downgrade, be patient, it may take a while to rollback', +'If start the upgrade, be patient, it may take a while to download': 'If start the upgrade, be patient, it may take a while to download', +'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\n\t\tA green title indicates that all tests (if defined) passed. In this case test results are not shown.': 'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\n\t\tA green title indicates that all tests (if defined) passed. In this case test results are not shown.', +'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\nA green title indicates that all tests (if defined) passed. In this case test results are not shown.': 'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\nA green title indicates that all tests (if defined) passed. In this case test results are not shown.', +'if your application uses a database other than sqlite you will then have to configure its DAL in pythonanywhere.': 'if your application uses a database other than sqlite you will then have to configure its DAL in pythonanywhere.', +'import': 'import', +'Import/Export': '导入/导出', +'In development, use the default Rocket webserver that is currently supported by this debugger.': 'In development, use the default Rocket webserver that is currently supported by this debugger.', 'includes': '包含', +'Indent with tabs': 'Indent with tabs', 'insert new': '新插入', 'insert new %s': '新插入 %s', +'inspect attributes': 'inspect attributes', +'Install': 'install', +'Installation of %(plugin)s for %(app)s': 'Installation of %(plugin)s for %(app)s', +'Installed applications': '已安装的应用', +'Interaction at %s line %s': 'Interaction at %s line %s', +'Interactive console': 'Interactive console', 'internal error': '内部错误', +'internal error: %s': 'internal error: %s', +'Internal State': '内部状态', +'Invalid action': '无效动作', +'Invalid application name': 'Invalid application name', +'invalid circular reference': 'invalid circular reference', +'Invalid email': '无效的email', +'Invalid git repository specified.': 'Invalid git repository specified.', 'invalid password': '无效密码', +'invalid password.': 'invalid password.', +'Invalid Query': '无效查询', 'invalid request': '无效请求', +'Invalid request': 'Invalid request', +'invalid table names (auth_* tables already defined)': 'invalid table names (auth_* tables already defined)', 'invalid ticket': '无效传票', +'Key': 'Key', +'Keyboard shortcuts': 'Keyboard shortcuts', +'kill process': 'kill process', 'language file "%(filename)s" created/updated': '语言文件 "%(filename)s"被创建/更新', +'Language files (static strings) updated': '语言文件(静态部分)已更新', 'languages': '语言', +'Languages': '语言', 'languages updated': '语言已被刷新', +'Last name': '名', +'Last Revision': 'Last Revision', +'Last saved on:': '最后保存于:', +'License for': '许可证', +'License:': 'License:', +'Line Nr': 'Line Nr', +'Line number': 'Line number', +'lists by exception': 'lists by exception', +'lists by ticket': 'lists by ticket', +'Loading...': 'Loading...', 'loading...': '载入中...', +'Local Apps': 'Local Apps', +'locals': 'locals', +'Locals##debug': 'Locals##debug', 'login': '登录', +'Login': '登录', +'Login successful': 'Login successful', +'Login to the Administrative Interface': '登录到管理员界面', +'Login/Register': 'Login/Register', +'Logout': '注销', +'Lost Password': '忘记密码', +'lost password': 'lost password', +'Main Menu': 'Main Menu', +'Manage': 'Manage', +'Manage %(action)s': 'Manage %(action)s', +'Manage Access Control': 'Manage Access Control', +'Manage Admin Users/Students': 'Manage Admin Users/Students', +'Manage Cache': 'Manage Cache', +'Manage Students': 'Manage Students', +'Memberships': 'Memberships', 'merge': '合并', +'Models': '模型s', 'models': '模型s', +'Modified On': 'Modified On', +'Modules': '模块s', 'modules': '模块s', +'Multi User Mode': 'Multi User Mode', +'Name': '姓名', 'new application "%s" created': '新应用 "%s"已被创建', +'new application "%s" imported': 'new application "%s" imported', +'New Application Wizard': 'New Application Wizard', +'New application wizard': 'New application wizard', 'new plugin installed': 'new plugin installed', +'New plugin installed: %s': 'New plugin installed: %s', +'New Record': '新记录', 'new record inserted': '新记录被插入', +'New simple application': 'New simple application', +'next': 'next', +'next %s rows': 'next %s rows', 'next 100 rows': '后100行', +'NO': '不', +'no changes': 'no changes', +'No databases in this application': '这应用没有数据库', +'No Interaction yet': 'No Interaction yet', 'no match': 'no match', +'no package selected': 'no package selected', +'no permission to uninstall "%s"': 'no permission to uninstall "%s"', +'Node:': 'Node:', +'Not Authorized': 'Not Authorized', +'Not supported': 'Not supported', +'Note: If you receive an error with github status code of 128, ensure the system and account you are deploying from has a cooresponding ssh key configured in the openshift account.': 'Note: If you receive an error with github status code of 128, ensure the system and account you are deploying from has a cooresponding ssh key configured in the openshift account.', +"On production, you'll have to configure your webserver to use one process and multiple threads to use this debugger.": "On production, you'll have to configure your webserver to use one process and multiple threads to use this debugger.", +'Open new app in new window': 'Open new app in new window', +'OpenShift Deployment Interface': 'OpenShift Deployment Interface', +'OpenShift Output': 'OpenShift Output', +'or alternatively': 'or alternatively', +'Or Get from URL:': 'Or Get from URL:', 'or import from csv file': '或者,从csv文件导入', 'or provide app url:': 'or provide app url:', 'or provide application url:': '或者,提供应用所在地址链接:', +'Origin': '起源', +'Original/Translation': '原始文件/翻译文件', +'Overview': 'Overview', +'Overwrite installed app': 'overwrite installed app', +'Pack all': '全部打包', +'Pack compiled': '包编译完', +'Pack custom': 'Pack custom', 'pack plugin': 'pack plugin', +'PAM authenticated user, cannot change password here': 'PAM authenticated user, cannot change password here', +'Password': '密码', 'password changed': 'password changed', +'Past revisions': 'Past revisions', +'Path to appcfg.py': 'Path to appcfg.py', +'Path to local openshift repo root.': 'Path to local openshift repo root.', +'Peeking at file': '选个文件', +'Permission': 'Permission', +'Permissions': 'Permissions', +'Please': 'Please', +'Please wait, giving pythonanywhere a moment...': 'Please wait, giving pythonanywhere a moment...', 'plugin "%(plugin)s" deleted': 'plugin "%(plugin)s" deleted', +'Plugin "%s" in application': 'Plugin "%s" in application', +'plugin not specified': 'plugin not specified', +'Plugin page': 'Plugin page', +'plugins': 'plugins', +'Plugins': 'Plugins', +'Plural Form #%s': 'Plural Form #%s', +'Plural-Forms:': 'Plural-Forms:', +'Powered by': '', +'Preferences saved correctly': 'Preferences saved correctly', +'Preferences saved on session only': 'Preferences saved on session only', +'previous %s rows': 'previous %s rows', 'previous 100 rows': '前100行', +'Private files': 'Private files', +'private files': 'private files', +'Project Progress': 'Project Progress', +'Pull': 'Pull', +'Pull failed, certain files could not be checked out. Check logs for details.': 'Pull failed, certain files could not be checked out. Check logs for details.', +'Pull is not possible because you have unmerged files. Fix them up in the work tree, and then try again.': 'Pull is not possible because you have unmerged files. Fix them up in the work tree, and then try again.', +'Push': 'Push', +'Push failed, there are unmerged entries in the cache. Resolve merge issues manually and try again.': 'Push failed, there are unmerged entries in the cache. Resolve merge issues manually and try again.', +'pygraphviz library not found': 'pygraphviz library not found', +'PythonAnywhere Apps': 'PythonAnywhere Apps', +'PythonAnywhere Password': 'PythonAnywhere Password', +'Query:': '查询', +'RAM': 'RAM', +'RAM Cache Keys': 'RAM Cache Keys', +'Ram Cleared': 'Ram Cleared', +'Rapid Search': 'Rapid Search', +'Record': 'Record', 'record': 'record', 'record does not exist': '记录并不存在', 'record id': '记录ID', +'Record ID': '记录ID', +'Record id': 'Record id', +'refresh': 'refresh', +'register': 'register', +'Register': '注册', +'Registration key': '注册密匙', +'Reload routes': 'Reload routes', +'Remove compiled': '已移除', +'Removed Breakpoint on %s at line %s': 'Removed Breakpoint on %s at line %s', +'Replace': 'Replace', +'Replace All': 'Replace All', +'Repository (%s)': 'Repository (%s)', +'request': 'request', +'requires distutils, but not installed': 'requires distutils, but not installed', +'requires python-git, but not installed': 'requires python-git, but not installed', +'Resolve Conflict file': '解决冲突文件', +'response': 'response', +'restart': 'restart', 'restore': '重存', +'return': 'return', +'Revert': 'Revert', 'revert': '恢复', +'reverted to revision %s': 'reverted to revision %s', +'Revision %s': 'Revision %s', +'Revision:': 'Revision:', +'Role': '角色', +'Roles': 'Roles', +'Rows in table': '表行', +'Rows in Table': 'Rows in Table', +'Rows selected': '行选择', +'rules are not defined': 'rules are not defined', +'Run tests': 'Run tests', +'Run tests in this file': 'Run tests in this file', +"Run tests in this file (to run all files, you may also use the button labelled 'test')": "Run tests in this file (to run all files, you may also use the button labelled 'test')", +'Running on %s': 'Running on %s', +'Save': 'Save', 'save': '保存', +'Save file:': 'Save file:', +'Save file: %s': 'Save file: %s', +'Save model as...': 'Save model as...', +'Save via Ajax': 'Save via Ajax', +'Saved file hash:': '已存文件Hash:', +'Screenshot %s': 'Screenshot %s', +'Search': 'Search', +'Select Files to Package': 'Select Files to Package', 'selected': '已选', +'session': 'session', 'session expired': '会话过期', +'Session saved correctly': 'Session saved correctly', +'Session saved on session only': 'Session saved on session only', +'Set Breakpoint on %s at line %s: %s': 'Set Breakpoint on %s at line %s: %s', 'shell': '', +'Showing %s to %s of %s %s found': 'Showing %s to %s of %s %s found', +'Singular Form': 'Singular Form', +'Site': '总站', +'Size of cache:': 'Size of cache:', +'skip to generate': 'skip to generate', 'some files could not be removed': '有些文件无法被移除', +'Something went wrong please wait a few minutes before retrying': 'Something went wrong please wait a few minutes before retrying', +'Sorry, could not find mercurial installed': 'Sorry, could not find mercurial installed', +'source : db': 'source : db', +'source : filesystem': 'source : filesystem', +'Start a new app': 'Start a new app', +'Start searching': 'Start searching', +'Start wizard': 'start wizard', 'state': '状态', +'Static': 'Static', 'static': '静态文件', +'Static files': '静态文件', +'Statistics': 'Statistics', +'Step': 'Step', +'step': 'step', +'stop': 'stop', 'submit': '提交', +'Submit': 'Submit', +'successful': 'successful', +'Sure you want to delete this object?': '真的要删除这个对象?', +'switch to : db': 'switch to : db', +'switch to : filesystem': 'switch to : filesystem', +'Tab width (# characters)': 'Tab width (# characters)', 'table': '表', +'Table': 'Table', +'Table name': '表名', +'Temporary': 'Temporary', 'test': '测试', +'Testing application': '应用测试', +'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.': '', +'The app exists, was created by wizard, continue to overwrite!': 'The app exists, was created by wizard, continue to overwrite!', +'The app exists, was NOT created by wizard, continue to overwrite!': 'The app exists, was NOT created by wizard, continue to overwrite!', 'the application logic, each URL path is mapped in one exposed function in the controller': '应用逻辑:每个URL由控制器暴露的函式完成映射', +'The application logic, each URL path is mapped in one exposed function in the controller': 'The application logic, each URL path is mapped in one exposed function in the controller', 'the data representation, define database tables and sets': '数据表达式,定义数据库/表', +'The data representation, define database tables and sets': 'The data representation, define database tables and sets', +'The presentations layer, views are also known as templates': 'The presentations layer, views are also known as templates', 'the presentations layer, views are also known as templates': '提交层/视图都在模板中可知', +'Theme': 'Theme', +'There are no controllers': '冇控制器', +'There are no models': '冇模型s', +'There are no modules': '冇模块s', +'There are no plugins': 'There are no plugins', +'There are no private files': 'There are no private files', +'There are no static files': '冇静态文件', +'There are no translators': 'There are no translators', +'There are no translators, only default language is supported': '没有找到相应翻译,只能使用默认语言', +'There are no views': '冇视图', +'These files are not served, they are only available from within your app': 'These files are not served, they are only available from within your app', +'These files are served without processing, your images go here': 'These files are served without processing, your images go here', 'these files are served without processing, your images go here': '', +"This debugger may not work properly if you don't have a threaded webserver or you're using multiple daemon processes.": "This debugger may not work properly if you don't have a threaded webserver or you're using multiple daemon processes.", +'This is an experimental feature and it needs more testing. If you decide to downgrade you do it at your own risk': 'This is an experimental feature and it needs more testing. If you decide to downgrade you do it at your own risk', +'This is an experimental feature and it needs more testing. If you decide to upgrade you do it at your own risk': 'This is an experimental feature and it needs more testing. If you decide to upgrade you do it at your own risk', +'This is the %(filename)s template': '这是 %(filename)s 模板', +"This page can commit your changes to an openshift app repo and push them to your cloud instance. This assumes that you've already created the application instance using the web2py skeleton and have that repo somewhere on a filesystem that this web2py instance can access. This functionality requires GitPython installed and on the python path of the runtime that web2py is operating in.": "This page can commit your changes to an openshift app repo and push them to your cloud instance. This assumes that you've already created the application instance using the web2py skeleton and have that repo somewhere on a filesystem that this web2py instance can access. This functionality requires GitPython installed and on the python path of the runtime that web2py is operating in.", +'This page can upload your application to the Google App Engine computing cloud. Mind that you must first create indexes locally and this is done by installing the Google appserver and running the app locally with it once, or there will be errors when selecting records. Attention: deployment may take long time, depending on the network speed. Attention: it will overwrite your app.yaml. DO NOT SUBMIT TWICE.': 'This page can upload your application to the Google App Engine computing cloud. Mind that you must first create indexes locally and this is done by installing the Google appserver and running the app locally with it once, or there will be errors when selecting records. Attention: deployment may take long time, depending on the network speed. Attention: it will overwrite your app.yaml. DO NOT SUBMIT TWICE.', +'this page to see if a breakpoint was hit and debug interaction is required.': 'this page to see if a breakpoint was hit and debug interaction is required.', +'This will pull changes from the remote repo for application "%s"?': 'This will pull changes from the remote repo for application "%s"?', +'This will push changes to the remote repo for application "%s".': 'This will push changes to the remote repo for application "%s".', +'Ticket': '传票', +'Ticket ID': 'Ticket ID', +'Ticket Missing': 'Ticket Missing', +'Time in Cache (h:m:s)': 'Time in Cache (h:m:s)', +'Timestamp': '时间戳', +'TM': '', 'to previous version.': 'to previous version.', +'To create a plugin, name a file/folder plugin_[name]': 'To create a plugin, name a file/folder plugin_[name]', +'To emulate a breakpoint programatically, write:': 'To emulate a breakpoint programatically, write:', +'to use the debugger!': 'to use the debugger!', 'to  previous version.': '退回前一版本', +'toggle breakpoint': 'toggle breakpoint', +'Toggle comment': 'Toggle comment', +'Toggle Fullscreen': 'Toggle Fullscreen', +'Traceback': 'Traceback', 'translation strings for the application': '应用的翻译字串', +'Translation strings for the application': 'Translation strings for the application', 'try': '尝试', 'try something like': '尝试', +'Try the mobile interface': 'Try the mobile interface', +'try view': 'try view', +'Type PDB debugger command in here and hit Return (Enter) to execute it.': 'Type PDB debugger command in here and hit Return (Enter) to execute it.', +'Type some Python code in here and hit Return (Enter) to execute it.': 'Type some Python code in here and hit Return (Enter) to execute it.', +'Unable to check for upgrades': '无法检查是否需要升级', 'unable to create application "%s"': '无法创建应用 "%s"', 'unable to delete file "%(filename)s"': '无法删除文件 "%(filename)s"', 'unable to delete file plugin "%(plugin)s"': 'unable to delete file plugin "%(plugin)s"', +'Unable to determine the line number!': 'Unable to determine the line number!', +'Unable to download': '无法下载', +'Unable to download app': '无法下载应用', +'Unable to download app because:': 'Unable to download app because:', +'Unable to download because': 'Unable to download because', +'unable to download layout': 'unable to download layout', +'unable to download plugin: %s': 'unable to download plugin: %s', +'Unable to download the list of plugins': 'Unable to download the list of plugins', +'unable to install plugin "%s"': 'unable to install plugin "%s"', 'unable to parse csv file': '无法生成 cvs', 'unable to uninstall "%s"': '无法卸载 "%s"', 'unable to upgrade because "%s"': 'unable to upgrade because "%s"', 'uncheck all': '反选全部', +'Uninstall': '卸载', +'Unsupported webserver working mode: %s': 'Unsupported webserver working mode: %s', 'update': '更新', 'update all languages': '更新所有语言', +'Update:': '更新:', +'Upgrade': 'Upgrade', +'upgrade now to %s': 'upgrade now to %s', 'upgrade web2py now': 'upgrade web2py now', +'upload': 'upload', +'Upload': 'Upload', +'Upload & install packed application': 'Upload & install packed application', +'Upload a package:': 'Upload a package:', +'Upload and install packed application': 'Upload and install packed application', 'upload application:': '提交已有的应用:', +'Upload existing application': '上传已有应用', 'upload file:': '提交文件:', 'upload plugin file:': 'upload plugin file:', +'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.', +'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...)  for NOT to build more complex queries.': '', +'Use an url:': 'Use an url:', +'User': 'User', +'User ID': '用户ID', +'Username': 'Username', +'Users': 'Users', +'Using the shell may lock the database to other users of this app.': 'Using the shell may lock the database to other users of this app.', 'variables': 'variables', +'Version': '版本', +'Versioning': 'Versioning', 'versioning': '版本', 'view': '视图', +'Views': '视图', 'views': '视图s', -'web2py Recent Tweets': 'twitter上的web2py进展实播', +'Warning!': 'Warning!', +'WARNING:': 'WARNING:', +'WARNING: The following views could not be compiled:': 'WARNING: The following views could not be compiled:', +'Web Framework': 'Web Framework', +'web2py Admin Password': 'web2py Admin Password', +'web2py apps to deploy': 'web2py apps to deploy', +'web2py Debugger': 'web2py Debugger', +'web2py downgrade': 'web2py downgrade', 'web2py is up to date': 'web2py现在已经是最新的版本了', +'web2py online debugger': 'web2py online debugger', +'web2py Recent Tweets': 'twitter上的web2py进展实播', +'web2py upgrade': 'web2py upgrade', 'web2py upgraded; please restart it': 'web2py upgraded; please restart it', +'Welcome to web2py': '欢迎使用web2py', +'Working...': 'Working...', +'WSGI reference name': 'WSGI reference name', +'YES': '是', +'Yes': 'Yes', +'You can also set and remove breakpoint in the edit window, using the Toggle Breakpoint button': 'You can also set and remove breakpoint in the edit window, using the Toggle Breakpoint button', +'You can inspect variables using the console below': 'You can inspect variables using the console below', +'You have one more login attempt before you are locked out': 'You have one more login attempt before you are locked out', +'You need to set up and reach a': 'You need to set up and reach a', +'You only need these if you have already registered': 'You only need these if you have already registered', +'Your application will be blocked until you click an action button (next, step, continue, etc.)': 'Your application will be blocked until you click an action button (next, step, continue, etc.)', } diff --git a/applications/welcome/languages/.DS_Store b/applications/welcome/languages/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..0c703e4471f572b9253907ba8dc1db9997cbcff9 GIT binary patch literal 6148 zcmeHKO-sZu5Pi`V7QF1yV}5}}e?eW>i--sP19nwJSlzO15pVtJzWGqLTCcLm1d=zI z%$p<+nlu2?yn8qSW&ozFf=P^#BJR}#ke(I z7+Y}Wit{~@U9mOx_tjpz+FN_rO`&5|p+G1Q3WNeXqX6%0Dbqv4XhVTeAQbpgK+cEE zDp)%9hI(|c(I)_LLbn#$@|F-zb}SuxLyoW{qY{mp{E3l_PJi~e(y=!*I+D)JJU;X1 z<0a|r^k)r6Dh;Cz1ww(L0{hmT$^C!9PiFLyKcqx26bJ?WnF49DxLwS-DZg8PY)|gm v%zDQvMdErfSZEJ^0@#srF@6M8kZ3}IKTzNUXyZ4r literal 0 HcmV?d00001 diff --git a/applications/welcome/languages/ca.py b/applications/welcome/languages/ca.py index 951894dc..ef6ec70f 100755 --- a/applications/welcome/languages/ca.py +++ b/applications/welcome/languages/ca.py @@ -35,8 +35,8 @@ 'Admin is disabled because insecure channel': 'Admin inhabilitat, el canal no és segur', 'Admin is disabled because unsecure channel': 'Admin inhabilitat, el canal no és segur', 'Administrative interface': 'Interfície administrativa', -'Administrative Interface': 'Interfície Administrativa', 'administrative interface': 'interfície administrativa', +'Administrative Interface': 'Interfície Administrativa', 'Administrator Password:': 'Contrasenya del Administrador:', 'Ajax Recipes': 'Receptes AJAX', 'An error occured, please %s the page': 'Hi ha hagut un error, per favor %s la pàgina', diff --git a/applications/welcome/languages/cs.py b/applications/welcome/languages/cs.py index 4a86a697..75add19f 100755 --- a/applications/welcome/languages/cs.py +++ b/applications/welcome/languages/cs.py @@ -31,8 +31,8 @@ 'Admin design page': 'Admin design page', 'Admin language': 'jazyk rozhraní', 'Administrative interface': 'pro administrátorské rozhraní klikněte sem', -'Administrative Interface': 'Administrátorské rozhraní', 'administrative interface': 'rozhraní pro správu', +'Administrative Interface': 'Administrátorské rozhraní', 'Administrator Password:': 'Administrátorské heslo:', 'Ajax Recipes': 'Recepty s ajaxem', 'An error occured, please %s the page': 'An error occured, please %s the page', diff --git a/applications/welcome/languages/default.py b/applications/welcome/languages/default.py deleted file mode 100755 index 5e6e8125..00000000 --- a/applications/welcome/languages/default.py +++ /dev/null @@ -1,122 +0,0 @@ -# coding: utf8 -{ -'!langcode!': 'en-us', -'!langname!': 'English (US)', -'%s %%(shop)': '%s %%(shop)', -'%s %%(shop[0])': '%s %%(shop[0])', -'%s %%{quark[0]}': '%s %%{quark[0]}', -'%s %%{shop[0]}': '%s %%{shop[0]}', -'%s %%{shop}': '%s %%{shop}', -'%Y-%m-%d': '%Y-%m-%d', -'%Y-%m-%d %H:%M:%S': '%Y-%m-%d %H:%M:%S', -'@markmin\x01**Hello World**': '**Hello World**', -'About': 'About', -'Access Control': 'Access Control', -'Administrative Interface': 'Administrative Interface', -'Ajax Recipes': 'Ajax Recipes', -'Are you sure you want to delete this object?': 'Are you sure you want to delete this object?', -'Buy this book': 'Buy this book', -'Cannot be empty': 'Cannot be empty', -'Check to delete': 'Check to delete', -'Client IP': 'Client IP', -'Community': 'Community', -'Components and Plugins': 'Components and Plugins', -'Controller': 'Controller', -'Copyright': 'Copyright', -'Created By': 'Created By', -'Created On': 'Created On', -'customize me!': 'customize me!', -'Database': 'Database', -'DB Model': 'DB Model', -'Demo': 'Demo', -'Deployment Recipes': 'Deployment Recipes', -'Description': 'Description', -'Documentation': 'Documentation', -"Don't know what to do?": "Don't know what to do?", -'Download': 'Download', -'E-mail': 'E-mail', -'Email and SMS': 'Email and SMS', -'enter an integer between %(min)g and %(max)g': 'enter an integer between %(min)g and %(max)g', -'enter date and time as %(format)s': 'enter date and time as %(format)s', -'Errors': 'Errors', -'FAQ': 'FAQ', -'First name': 'First name', -'Forms and Validators': 'Forms and Validators', -'Free Applications': 'Free Applications', -'Group %(group_id)s created': 'Group %(group_id)s created', -'Group ID': 'Group ID', -'Group uniquely assigned to user %(id)s': 'Group uniquely assigned to user %(id)s', -'Groups': 'Groups', -'Hello World': 'Hello World', -'Hello World ## comment': 'Hello World ', -'Hello World## comment': 'Hello World', -'Home': 'Home', -'How did you get here?': 'How did you get here?', -'Introduction': 'Introduction', -'Invalid email': 'Invalid email', -'Is Active': 'Is Active', -'Last name': 'Last name', -'Layout': 'Layout', -'Layout Plugins': 'Layout Plugins', -'Layouts': 'Layouts', -'Live Chat': 'Live Chat', -'Logged in': 'Logged in', -'Logged out': 'Logged out', -'Login': 'Login', -'Logout': 'Logout', -'Lost Password': 'Lost Password', -'Lost password?': 'Lost password?', -'Menu Model': 'Menu Model', -'Modified By': 'Modified By', -'Modified On': 'Modified On', -'My Sites': 'My Sites', -'Name': 'Name', -'Object or table name': 'Object or table name', -'Online examples': 'Online examples', -'Origin': 'Origin', -'Other Plugins': 'Other Plugins', -'Other Recipes': 'Other Recipes', -'Overview': 'Overview', -'Password': 'Password', -"Password fields don't match": "Password fields don't match", -'please input your password again': 'please input your password again', -'Plugins': 'Plugins', -'Powered by': 'Powered by', -'Preface': 'Preface', -'Profile': 'Profile', -'Python': 'Python', -'Quick Examples': 'Quick Examples', -'Recipes': 'Recipes', -'Record ID': 'Record ID', -'Register': 'Register', -'Registration identifier': 'Registration identifier', -'Registration key': 'Registration key', -'Registration successful': 'Registration successful', -'Remember me (for 30 days)': 'Remember me (for 30 days)', -'Reset Password key': 'Reset Password key', -'Role': 'Role', -'Semantic': 'Semantic', -'Services': 'Services', -'Stylesheet': 'Stylesheet', -'Support': 'Support', -'The Core': 'The Core', -'The output of the file is a dictionary that was rendered by the view %s': 'The output of the file is a dictionary that was rendered by the view %s', -'The Views': 'The Views', -'This App': 'This App', -'Timestamp': 'Timestamp', -'Twitter': 'Twitter', -'User %(id)s Logged-in': 'User %(id)s Logged-in', -'User %(id)s Logged-out': 'User %(id)s Logged-out', -'User %(id)s Registered': 'User %(id)s Registered', -'User ID': 'User ID', -'value already in database or empty': 'value already in database or empty', -'Verify Password': 'Verify Password', -'Videos': 'Videos', -'View': 'View', -'Welcome': 'Welcome', -'Welcome to web2py!': 'Welcome to web2py!', -'Which called the function %s located in the file %s': 'Which called the function %s located in the file %s', -'You are successfully running web2py': 'You are successfully running web2py', -'You can modify this application and adapt it to your needs': 'You can modify this application and adapt it to your needs', -'You visited the url %s': 'You visited the url %s', -} diff --git a/applications/welcome/languages/en.py b/applications/welcome/languages/en.py new file mode 100755 index 00000000..cb50edaa --- /dev/null +++ b/applications/welcome/languages/en.py @@ -0,0 +1,157 @@ +# -*- coding: utf-8 -*- +{ +'!langcode!': 'en-us', +'!langname!': 'English (US)', +'"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN': '"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN', +'%s %%{row} deleted': '%s %%{row} deleted', +'%s %%{row} updated': '%s %%{row} updated', +'%s selected': '%s selected', +'%Y-%m-%d': '%Y-%m-%d', +'%Y-%m-%d %H:%M:%S': '%Y-%m-%d %H:%M:%S', +'(**%.0d MB**)': '(**%.0d MB**)', +'**%(items)s** %%{item(items)}, **%(bytes)s** %%{byte(bytes)}': '**%(items)s** %%{item(items)}, **%(bytes)s** %%{byte(bytes)}', +'**%(items)s** items, **%(bytes)s** %%{byte(bytes)}': '**%(items)s** items, **%(bytes)s** %%{byte(bytes)}', +'**not available** (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)': '**not available** (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)', +'?': '?', +'``**not available**``:red (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)': '``**not available**``:red (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)', +'About': 'About', +'Access Control': 'Access Control', +'admin': 'admin', +'Ajax Recipes': 'Ajax Recipes', +'An error occured, please [[reload %s]] the page': 'An error occured, please [[reload %s]] the page', +'appadmin is disabled because insecure channel': 'appadmin is disabled because insecure channel', +'Are you sure you want to delete this object?': 'Are you sure you want to delete this object?', +'Available Databases and Tables': 'Available Databases and Tables', +"Buy web2py's book": "Buy web2py's book", +'cache': 'cache', +'Cache': 'Cache', +'Cache Cleared': 'Cache Cleared', +'Cache contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.': 'Cache contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.', +'Cache Keys': 'Cache Keys', +'Cannot be empty': 'Cannot be empty', +'Check to delete': 'Check to delete', +'Clear CACHE?': 'Clear CACHE?', +'Clear DISK': 'Clear DISK', +'Clear RAM': 'Clear RAM', +'Community': 'Community', +'Components and Plugins': 'Components and Plugins', +'Config.ini': 'Config.ini', +'Controller': 'Controller', +'Copyright': 'Copyright', +'Current request': 'Current request', +'Current response': 'Current response', +'Current session': 'Current session', +'data uploaded': 'data uploaded', +'Database': 'Database', +'Database %s select': 'Database %s select', +'Database Administration (appadmin)': 'Database Administration (appadmin)', +'db': 'db', +'DB Model': 'DB Model', +'Delete:': 'Delete:', +'Demo': 'Demo', +'Deployment Recipes': 'Deployment Recipes', +'design': 'design', +'Design': 'Design', +'DISK': 'DISK', +'Disk Cache Keys': 'Disk Cache Keys', +'Disk Cleared': 'Disk Cleared', +'DISK contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.': 'DISK contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.', +'Documentation': 'Documentation', +"Don't know what to do?": "Don't know what to do?", +'done!': 'done!', +'Download': 'Download', +'Edit current record': 'Edit current record', +'Email and SMS': 'Email and SMS', +'Errors': 'Errors', +'export as csv file': 'export as csv file', +'FAQ': 'FAQ', +'Forms and Validators': 'Forms and Validators', +'Free Applications': 'Free Applications', +'Graph Model': 'Graph Model', +'Groups': 'Groups', +'Hello World': 'Hello World', +'Helping web2py': 'Helping web2py', +'Hit Ratio: **%(ratio)s%%** (**%(hits)s** %%{hit(hits)} and **%(misses)s** %%{miss(misses)})': 'Hit Ratio: **%(ratio)s%%** (**%(hits)s** %%{hit(hits)} and **%(misses)s** %%{miss(misses)})', +'Home': 'Home', +'How did you get here?': 'How did you get here?', +'import': 'import', +'Import/Export': 'Import/Export', +'Internal State': 'Internal State', +'Introduction': 'Introduction', +'Invalid Query': 'Invalid Query', +'invalid request': 'invalid request', +'Key': 'Key', +'Layout': 'Layout', +'Live Chat': 'Live Chat', +'Log In': 'Log In', +'Lost Password': 'Lost Password', +'Manage %(action)s': 'Manage %(action)s', +'Manage Access Control': 'Manage Access Control', +'Manage Cache': 'Manage Cache', +'Memberships': 'Memberships', +'Menu Model': 'Menu Model', +'My Sites': 'My Sites', +'New Record': 'New Record', +'new record inserted': 'new record inserted', +'next %s rows': 'next %s rows', +'No databases in this application': 'No databases in this application', +'Number of entries: **%s**': 'Number of entries: **%s**', +'Online book': 'Online book', +'Online examples': 'Online examples', +'or import from csv file': 'or import from csv file', +'Other Recipes': 'Other Recipes', +'Overview': 'Overview', +'Permission': 'Permission', +'Permissions': 'Permissions', +'Plugins': 'Plugins', +'Powered by': 'Powered by', +'Preface': 'Preface', +'previous %s rows': 'previous %s rows', +'pygraphviz library not found': 'pygraphviz library not found', +'Python': 'Python', +'Query:': 'Query:', +'Quick Examples': 'Quick Examples', +'RAM': 'RAM', +'RAM Cache Keys': 'RAM Cache Keys', +'Ram Cleared': 'Ram Cleared', +'RAM contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.': 'RAM contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.', +'Recipes': 'Recipes', +'Record': 'Record', +'record does not exist': 'record does not exist', +'Record id': 'Record id', +'Role': 'Role', +'Roles': 'Roles', +'Rows in Table': 'Rows in Table', +'Rows selected': 'Rows selected', +'Save model as...': 'Save model as...', +'Services': 'Services', +'Sign Up': 'Sign Up', +'Size of cache:': 'Size of cache:', +'state': 'state', +'Statistics': 'Statistics', +'Stylesheet': 'Stylesheet', +'submit': 'submit', +'Support': 'Support', +'Table': 'Table', +'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.': 'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.', +'The Core': 'The Core', +'The output of the file is a dictionary that was rendered by the view %s': 'The output of the file is a dictionary that was rendered by the view %s', +'The Views': 'The Views', +'This App': 'This App', +'Time in Cache (h:m:s)': 'Time in Cache (h:m:s)', +'Traceback': 'Traceback', +'Twitter': 'Twitter', +'unable to parse csv file': 'unable to parse csv file', +'Update:': 'Update:', +'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.', +'User': 'User', +'Users': 'Users', +'Videos': 'Videos', +'View': 'View', +'Welcome to web2py!': 'Welcome to web2py!', +'Which called the function %s located in the file %s': 'Which called the function %s located in the file %s', +'Working...': 'Working...', +'You are successfully running web2py': 'You are successfully running web2py', +'You can modify this application and adapt it to your needs': 'You can modify this application and adapt it to your needs', +'You visited the url %s': 'You visited the url %s', +} diff --git a/applications/welcome/languages/plural-cs.py b/applications/welcome/languages/plural-cs.py index 2a795587..d418a664 100755 --- a/applications/welcome/languages/plural-cs.py +++ b/applications/welcome/languages/plural-cs.py @@ -1,21 +1,19 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -{ -# "singular form (0)": ["first plural form (1)", "second plural form (2)", ...], -'vteřina': ['vteřiny', 'vteřin'], -'vteřinou': ['vteřinami', 'vteřinami'], -'minuta': ['minuty', 'minut'], -'minutou': ['minutami', 'minutami'], -'hodina': ['hodiny','hodin'], -'hodinou': ['hodinami','hodinami'], -'den': ['dny','dnů'], -'dnem': ['dny','dny'], -'týden': ['týdny','týdnů'], -'týdnem': ['týdny','týdny'], -'měsíc': ['měsíce','měsíců'], -'měsícem': ['měsíci','měsíci'], -'rok': ['roky','let'], -'rokem': ['roky','lety'], -'záznam': ['záznamy', 'záznamů'], -'soubor': ['soubory', 'souborů'] -} +# -*- coding: utf-8 -*- +{ +'den': "['dny', 'dn\\xc5\\xaf']", +'dnem': "['dny', 'dny']", +'hodina': "['hodiny', 'hodin']", +'hodinou': "['hodinami', 'hodinami']", +'minuta': "['minuty', 'minut']", +'minutou': "['minutami', 'minutami']", +'měsíc': "['m\\xc4\\x9bs\\xc3\\xadce', 'm\\xc4\\x9bs\\xc3\\xadc\\xc5\\xaf']", +'měsícem': "['m\\xc4\\x9bs\\xc3\\xadci', 'm\\xc4\\x9bs\\xc3\\xadci']", +'rok': "['roky', 'let']", +'rokem': "['roky', 'lety']", +'soubor': "['soubory', 'soubor\\xc5\\xaf']", +'týden': "['t\\xc3\\xbddny', 't\\xc3\\xbddn\\xc5\\xaf']", +'týdnem': "['t\\xc3\\xbddny', 't\\xc3\\xbddny']", +'vteřina': "['vte\\xc5\\x99iny', 'vte\\xc5\\x99in']", +'vteřinou': "['vte\\xc5\\x99inami', 'vte\\xc5\\x99inami']", +'záznam': "['z\\xc3\\xa1znamy', 'z\\xc3\\xa1znam\\xc5\\xaf']", +} diff --git a/applications/welcome/languages/plural-en.py b/applications/welcome/languages/plural-en.py index 5103b462..fb41dc7e 100755 --- a/applications/welcome/languages/plural-en.py +++ b/applications/welcome/languages/plural-en.py @@ -1,16 +1,14 @@ -#!/usr/bin/env python # -*- coding: utf-8 -*- { -# "singular form (0)": ["first plural form (1)", "second plural form (2)", ...], -'account': ['accounts'], -'book': ['books'], -'is': ['are'], -'man': ['men'], -'miss': ['misses'], -'person': ['people'], -'quark': ['quarks'], -'shop': ['shops'], -'this': ['these'], -'was': ['were'], -'woman': ['women'], +'account': "['accounts']", +'book': "['books']", +'is': "['are']", +'man': "['men']", +'miss': "['misses']", +'person': "['people']", +'quark': "['quarks']", +'shop': "['shops']", +'this': "['these']", +'was': "['were']", +'woman': "['women']", } diff --git a/applications/welcome/languages/plural-es.py b/applications/welcome/languages/plural-es.py index 235f1a3a..72ac5f7b 100755 --- a/applications/welcome/languages/plural-es.py +++ b/applications/welcome/languages/plural-es.py @@ -1,9 +1,7 @@ -#!/usr/bin/env python # -*- coding: utf-8 -*- { -# "singular form (0)": ["first plural form (1)", "second plural form (2)", ...], -'fila': ['filas'], -'eliminada': ['eliminadas'], -'actualizada': ['actualizadas'], -'seleccionado': ['seleccionados'], +'actualizada': "['actualizadas']", +'eliminada': "['eliminadas']", +'fila': "['filas']", +'seleccionado': "['seleccionados']", } From 2ec0c0b5352dd4668b7a2b162562d47f9a9cedcd Mon Sep 17 00:00:00 2001 From: ilvalle Date: Fri, 9 Sep 2016 15:57:10 +0200 Subject: [PATCH 07/49] fix py3.5 xmlescape with bytes --- gluon/html.py | 6 +++--- gluon/tests/test_html.py | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/gluon/html.py b/gluon/html.py index da8e2d6e..ceef7bd2 100644 --- a/gluon/html.py +++ b/gluon/html.py @@ -20,7 +20,7 @@ import urllib import base64 from gluon import sanitizer, decoder import itertools -from gluon._compat import reduce, pickle, copyreg, HTMLParser, name2codepoint, iteritems, unichr, unicodeT, urllib_quote, to_bytes, to_native, to_unicode, basestring, urlencode, implements_bool +from gluon._compat import reduce, pickle, copyreg, HTMLParser, name2codepoint, iteritems, unichr, unicodeT, urllib_quote, to_bytes, to_native, to_unicode, basestring, urlencode, implements_bool, text_type from gluon.utils import local_html_escape import marshal @@ -122,7 +122,7 @@ def xmlescape(data, quote=True): if hasattr(data, 'xml') and callable(data.xml): return to_bytes(data.xml()) - if not(isinstance(data, basestring)): + if not(isinstance(data, (text_type, bytes))): # i.e., integers data=str(data) data = to_bytes(data, 'utf8', 'xmlcharrefreplace') @@ -1040,7 +1040,7 @@ class DIV(XmlComponent): hello >>> a.elements('a[u:v=$]')[0].xml() 'hello' - >>> a=FORM( INPUT(_type='text'), SELECT(range(1)), TEXTAREA() ) + >>> a=FORM( INPUT(_type='text'), SELECT(list(range(1))), TEXTAREA() ) >>> for c in a.elements('input, select, textarea'): c['_disabled'] = 'disabled' >>> a.xml() '
' diff --git a/gluon/tests/test_html.py b/gluon/tests/test_html.py index d7a75517..e091d1ce 100644 --- a/gluon/tests/test_html.py +++ b/gluon/tests/test_html.py @@ -253,6 +253,7 @@ class TestBareHelpers(unittest.TestCase): # test .get('attrib') self.assertEqual(DIV('

Test

', _class="class_test").get('_class'), 'class_test') + self.assertEqual(DIV(b'a').xml(), b'
a
') def test_CAT(self): # Empty CAT() From 1623328678ce84b11998f7e2053bec1e83e771bc Mon Sep 17 00:00:00 2001 From: ilvalle Date: Fri, 9 Sep 2016 21:13:27 +0200 Subject: [PATCH 08/49] fix missing to_unicode import, close #1442 --- gluon/sqlhtml.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gluon/sqlhtml.py b/gluon/sqlhtml.py index 9ddc34d6..03100e43 100644 --- a/gluon/sqlhtml.py +++ b/gluon/sqlhtml.py @@ -19,7 +19,7 @@ import urllib import re import os -from gluon._compat import StringIO, unichr, urllib_quote, iteritems, basestring, long, unicodeT, to_native +from gluon._compat import StringIO, unichr, urllib_quote, iteritems, basestring, long, unicodeT, to_native, to_unicode from gluon.http import HTTP, redirect from gluon.html import XmlComponent, truncate_string from gluon.html import XML, SPAN, TAG, A, DIV, CAT, UL, LI, TEXTAREA, BR, IMG From 9263f8c4c3be7dd3ac0d1e9948c23b52f10db0d0 Mon Sep 17 00:00:00 2001 From: Vinyl Darkscratch Date: Sat, 10 Sep 2016 22:06:14 -0700 Subject: [PATCH 09/49] Fixed test errors Cleaned the damage caused by a faulty script run that created a test error as described in https://travis-ci.org/web2py/web2py/builds/158680015 --- applications/welcome/languages/plural-cs.py | 32 ++++++++++----------- applications/welcome/languages/plural-en.py | 22 +++++++------- applications/welcome/languages/plural-es.py | 8 +++--- applications/welcome/languages/plural-ru.py | 26 ++++++++--------- applications/welcome/languages/plural-uk.py | 28 +++++++++--------- 5 files changed, 56 insertions(+), 60 deletions(-) diff --git a/applications/welcome/languages/plural-cs.py b/applications/welcome/languages/plural-cs.py index d418a664..b994d196 100755 --- a/applications/welcome/languages/plural-cs.py +++ b/applications/welcome/languages/plural-cs.py @@ -1,19 +1,19 @@ # -*- coding: utf-8 -*- { -'den': "['dny', 'dn\\xc5\\xaf']", -'dnem': "['dny', 'dny']", -'hodina': "['hodiny', 'hodin']", -'hodinou': "['hodinami', 'hodinami']", -'minuta': "['minuty', 'minut']", -'minutou': "['minutami', 'minutami']", -'měsíc': "['m\\xc4\\x9bs\\xc3\\xadce', 'm\\xc4\\x9bs\\xc3\\xadc\\xc5\\xaf']", -'měsícem': "['m\\xc4\\x9bs\\xc3\\xadci', 'm\\xc4\\x9bs\\xc3\\xadci']", -'rok': "['roky', 'let']", -'rokem': "['roky', 'lety']", -'soubor': "['soubory', 'soubor\\xc5\\xaf']", -'týden': "['t\\xc3\\xbddny', 't\\xc3\\xbddn\\xc5\\xaf']", -'týdnem': "['t\\xc3\\xbddny', 't\\xc3\\xbddny']", -'vteřina': "['vte\\xc5\\x99iny', 'vte\\xc5\\x99in']", -'vteřinou': "['vte\\xc5\\x99inami', 'vte\\xc5\\x99inami']", -'záznam': "['z\\xc3\\xa1znamy', 'z\\xc3\\xa1znam\\xc5\\xaf']", +'den': ['dny', 'dn\\xc5\\xaf'], +'dnem': ['dny', 'dny'], +'hodina': ['hodiny', 'hodin'], +'hodinou': ['hodinami', 'hodinami'], +'minuta': ['minuty', 'minut'], +'minutou': ['minutami', 'minutami'], +'měsíc': ['m\\xc4\\x9bs\\xc3\\xadce', 'm\\xc4\\x9bs\\xc3\\xadc\\xc5\\xaf'], +'měsícem': ['m\\xc4\\x9bs\\xc3\\xadci', 'm\\xc4\\x9bs\\xc3\\xadci'], +'rok': ['roky', 'let'], +'rokem': ['roky', 'lety'], +'soubor': ['soubory', 'soubor\\xc5\\xaf'], +'týden': ['t\\xc3\\xbddny', 't\\xc3\\xbddn\\xc5\\xaf'], +'týdnem': ['t\\xc3\\xbddny', 't\\xc3\\xbddny'], +'vteřina': ['vte\\xc5\\x99iny', 'vte\\xc5\\x99in'], +'vteřinou': ['vte\\xc5\\x99inami', 'vte\\xc5\\x99inami'], +'záznam': ['z\\xc3\\xa1znamy', 'z\\xc3\\xa1znam\\xc5\\xaf'], } diff --git a/applications/welcome/languages/plural-en.py b/applications/welcome/languages/plural-en.py index fb41dc7e..cbd345bf 100755 --- a/applications/welcome/languages/plural-en.py +++ b/applications/welcome/languages/plural-en.py @@ -1,14 +1,14 @@ # -*- coding: utf-8 -*- { -'account': "['accounts']", -'book': "['books']", -'is': "['are']", -'man': "['men']", -'miss': "['misses']", -'person': "['people']", -'quark': "['quarks']", -'shop': "['shops']", -'this': "['these']", -'was': "['were']", -'woman': "['women']", +'account': ['accounts'], +'book': ['books'], +'is': ['are'], +'man': ['men'], +'miss': ['misses'], +'person': ['people'], +'quark': ['quarks'], +'shop': ['shops'], +'this': ['these'], +'was': ['were'], +'woman': ['women'], } diff --git a/applications/welcome/languages/plural-es.py b/applications/welcome/languages/plural-es.py index 72ac5f7b..a8264d5c 100755 --- a/applications/welcome/languages/plural-es.py +++ b/applications/welcome/languages/plural-es.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- { -'actualizada': "['actualizadas']", -'eliminada': "['eliminadas']", -'fila': "['filas']", -'seleccionado': "['seleccionados']", +'actualizada': ['actualizadas'], +'eliminada': ['eliminadas'], +'fila': ['filas'], +'seleccionado': ['seleccionados'], } diff --git a/applications/welcome/languages/plural-ru.py b/applications/welcome/languages/plural-ru.py index d9e73a07..29699b8c 100755 --- a/applications/welcome/languages/plural-ru.py +++ b/applications/welcome/languages/plural-ru.py @@ -1,17 +1,15 @@ -#!/usr/bin/env python # -*- coding: utf-8 -*- { -# "singular form (0)": ["first plural form (1)", "second plural form (2)", ...], -'выбрана': ['выбраны','выбрано'], -'запись': ['записи','записей'], -'изменена': ['изменены','изменено'], -'строка': ['строки','строк'], -'удалена': ['удалены','удалено'], -'день': ['дня', 'дней'], -'месяц': ['месяца','месяцев'], -'неделю': ['недели','недель'], -'год': ['года','лет'], -'час': ['часа','часов'], -'минуту': ['минуты','минут'], -'секунду': ['секунды','секунд'], +'выбрана': ['\\xd0\\xb2\\xd1\\x8b\\xd0\\xb1\\xd1\\x80\\xd0\\xb0\\xd0\\xbd\\xd1\\x8b', '\\xd0\\xb2\\xd1\\x8b\\xd0\\xb1\\xd1\\x80\\xd0\\xb0\\xd0\\xbd\\xd0\\xbe'], +'год': ['\\xd0\\xb3\\xd0\\xbe\\xd0\\xb4\\xd0\\xb0', '\\xd0\\xbb\\xd0\\xb5\\xd1\\x82'], +'день': ['\\xd0\\xb4\\xd0\\xbd\\xd1\\x8f', '\\xd0\\xb4\\xd0\\xbd\\xd0\\xb5\\xd0\\xb9'], +'запись': ['\\xd0\\xb7\\xd0\\xb0\\xd0\\xbf\\xd0\\xb8\\xd1\\x81\\xd0\\xb8', '\\xd0\\xb7\\xd0\\xb0\\xd0\\xbf\\xd0\\xb8\\xd1\\x81\\xd0\\xb5\\xd0\\xb9'], +'изменена': ['\\xd0\\xb8\\xd0\\xb7\\xd0\\xbc\\xd0\\xb5\\xd0\\xbd\\xd0\\xb5\\xd0\\xbd\\xd1\\x8b', '\\xd0\\xb8\\xd0\\xb7\\xd0\\xbc\\xd0\\xb5\\xd0\\xbd\\xd0\\xb5\\xd0\\xbd\\xd0\\xbe'], +'месяц': ['\\xd0\\xbc\\xd0\\xb5\\xd1\\x81\\xd1\\x8f\\xd1\\x86\\xd0\\xb0', '\\xd0\\xbc\\xd0\\xb5\\xd1\\x81\\xd1\\x8f\\xd1\\x86\\xd0\\xb5\\xd0\\xb2'], +'минуту': ['\\xd0\\xbc\\xd0\\xb8\\xd0\\xbd\\xd1\\x83\\xd1\\x82\\xd1\\x8b', '\\xd0\\xbc\\xd0\\xb8\\xd0\\xbd\\xd1\\x83\\xd1\\x82'], +'неделю': ['\\xd0\\xbd\\xd0\\xb5\\xd0\\xb4\\xd0\\xb5\\xd0\\xbb\\xd0\\xb8', '\\xd0\\xbd\\xd0\\xb5\\xd0\\xb4\\xd0\\xb5\\xd0\\xbb\\xd1\\x8c'], +'секунду': ['\\xd1\\x81\\xd0\\xb5\\xd0\\xba\\xd1\\x83\\xd0\\xbd\\xd0\\xb4\\xd1\\x8b', '\\xd1\\x81\\xd0\\xb5\\xd0\\xba\\xd1\\x83\\xd0\\xbd\\xd0\\xb4'], +'строка': ['\\xd1\\x81\\xd1\\x82\\xd1\\x80\\xd0\\xbe\\xd0\\xba\\xd0\\xb8', '\\xd1\\x81\\xd1\\x82\\xd1\\x80\\xd0\\xbe\\xd0\\xba'], +'удалена': ['\\xd1\\x83\\xd0\\xb4\\xd0\\xb0\\xd0\\xbb\\xd0\\xb5\\xd0\\xbd\\xd1\\x8b', '\\xd1\\x83\\xd0\\xb4\\xd0\\xb0\\xd0\\xbb\\xd0\\xb5\\xd0\\xbd\\xd0\\xbe'], +'час': ['\\xd1\\x87\\xd0\\xb0\\xd1\\x81\\xd0\\xb0', '\\xd1\\x87\\xd0\\xb0\\xd1\\x81\\xd0\\xbe\\xd0\\xb2'], } diff --git a/applications/welcome/languages/plural-uk.py b/applications/welcome/languages/plural-uk.py index e75ef121..e6b91466 100755 --- a/applications/welcome/languages/plural-uk.py +++ b/applications/welcome/languages/plural-uk.py @@ -1,18 +1,16 @@ -#!/usr/bin/env python # -*- coding: utf-8 -*- { -# "singular form (0)": ["first plural form (1)", "second plural form (2)", ...], -'байт': ['байти','байтів'], -'годину': ['години','годин'], -'день': ['дні','днів'], -'елемент': ['елементи','елементів'], -'запис': ['записи','записів'], -'місяць': ['місяці','місяців'], -'поцілювання': ['поцілювання','поцілювань'], -'рядок': ['рядки','рядків'], -'рік': ['роки','років'], -'секунду': ['секунди','секунд'], -'схибнення': ['схибнення','схибнень'], -'тиждень': ['тижні','тижнів'], -'хвилину': ['хвилини','хвилин'], +'байт': ['\\xd0\\xb1\\xd0\\xb0\\xd0\\xb9\\xd1\\x82\\xd0\\xb8', '\\xd0\\xb1\\xd0\\xb0\\xd0\\xb9\\xd1\\x82\\xd1\\x96\\xd0\\xb2'], +'годину': ['\\xd0\\xb3\\xd0\\xbe\\xd0\\xb4\\xd0\\xb8\\xd0\\xbd\\xd0\\xb8', '\\xd0\\xb3\\xd0\\xbe\\xd0\\xb4\\xd0\\xb8\\xd0\\xbd'], +'день': ['\\xd0\\xb4\\xd0\\xbd\\xd1\\x96', '\\xd0\\xb4\\xd0\\xbd\\xd1\\x96\\xd0\\xb2'], +'елемент': ['\\xd0\\xb5\\xd0\\xbb\\xd0\\xb5\\xd0\\xbc\\xd0\\xb5\\xd0\\xbd\\xd1\\x82\\xd0\\xb8', '\\xd0\\xb5\\xd0\\xbb\\xd0\\xb5\\xd0\\xbc\\xd0\\xb5\\xd0\\xbd\\xd1\\x82\\xd1\\x96\\xd0\\xb2'], +'запис': ['\\xd0\\xb7\\xd0\\xb0\\xd0\\xbf\\xd0\\xb8\\xd1\\x81\\xd0\\xb8', '\\xd0\\xb7\\xd0\\xb0\\xd0\\xbf\\xd0\\xb8\\xd1\\x81\\xd1\\x96\\xd0\\xb2'], +'місяць': ['\\xd0\\xbc\\xd1\\x96\\xd1\\x81\\xd1\\x8f\\xd1\\x86\\xd1\\x96', '\\xd0\\xbc\\xd1\\x96\\xd1\\x81\\xd1\\x8f\\xd1\\x86\\xd1\\x96\\xd0\\xb2'], +'поцілювання': ['\\xd0\\xbf\\xd0\\xbe\\xd1\\x86\\xd1\\x96\\xd0\\xbb\\xd1\\x8e\\xd0\\xb2\\xd0\\xb0\\xd0\\xbd\\xd0\\xbd\\xd1\\x8f', '\\xd0\\xbf\\xd0\\xbe\\xd1\\x86\\xd1\\x96\\xd0\\xbb\\xd1\\x8e\\xd0\\xb2\\xd0\\xb0\\xd0\\xbd\\xd1\\x8c'], +'рядок': ['\\xd1\\x80\\xd1\\x8f\\xd0\\xb4\\xd0\\xba\\xd0\\xb8', '\\xd1\\x80\\xd1\\x8f\\xd0\\xb4\\xd0\\xba\\xd1\\x96\\xd0\\xb2'], +'рік': ['\\xd1\\x80\\xd0\\xbe\\xd0\\xba\\xd0\\xb8', '\\xd1\\x80\\xd0\\xbe\\xd0\\xba\\xd1\\x96\\xd0\\xb2'], +'секунду': ['\\xd1\\x81\\xd0\\xb5\\xd0\\xba\\xd1\\x83\\xd0\\xbd\\xd0\\xb4\\xd0\\xb8', '\\xd1\\x81\\xd0\\xb5\\xd0\\xba\\xd1\\x83\\xd0\\xbd\\xd0\\xb4'], +'схибнення': ['\\xd1\\x81\\xd1\\x85\\xd0\\xb8\\xd0\\xb1\\xd0\\xbd\\xd0\\xb5\\xd0\\xbd\\xd0\\xbd\\xd1\\x8f', '\\xd1\\x81\\xd1\\x85\\xd0\\xb8\\xd0\\xb1\\xd0\\xbd\\xd0\\xb5\\xd0\\xbd\\xd1\\x8c'], +'тиждень': ['\\xd1\\x82\\xd0\\xb8\\xd0\\xb6\\xd0\\xbd\\xd1\\x96', '\\xd1\\x82\\xd0\\xb8\\xd0\\xb6\\xd0\\xbd\\xd1\\x96\\xd0\\xb2'], +'хвилину': ['\\xd1\\x85\\xd0\\xb2\\xd0\\xb8\\xd0\\xbb\\xd0\\xb8\\xd0\\xbd\\xd0\\xb8', '\\xd1\\x85\\xd0\\xb2\\xd0\\xb8\\xd0\\xbb\\xd0\\xb8\\xd0\\xbd'], } From 808c85fdc395f48731739f6a79c852606865a16b Mon Sep 17 00:00:00 2001 From: Vinyl Darkscratch Date: Sat, 10 Sep 2016 22:12:48 -0700 Subject: [PATCH 10/49] Update welcome/es.py, Spanish complete! --- applications/welcome/languages/es.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/applications/welcome/languages/es.py b/applications/welcome/languages/es.py index b8c12cf1..490bf470 100755 --- a/applications/welcome/languages/es.py +++ b/applications/welcome/languages/es.py @@ -18,7 +18,7 @@ '?': '?', '@markmin\x01An error occured, please [[reload %s]] the page': 'Ha ocurrido un error, por favor [[recargar %s]] la página', '@markmin\x01Number of entries: **%s**': 'Número de entradas: **%s**', -'``**not available**``:red (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)': '``**not available**``:red (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)', +'``**not available**``:red (requires the Python [[guppy http://pypi.python.org/pypi/guppy/ popup]] library)': '``**no disponible**``:red (Necesita libreria de Python: [[guppy http://pypi.python.org/pypi/guppy/ popup]])', 'A new version of web2py is available': 'Hay una nueva versión de web2py disponible', 'A new version of web2py is available: %s': 'Hay una nueva versión de web2py disponible: %s', 'About': 'Acerca de', @@ -27,7 +27,7 @@ 'Access Control': 'Control de Acceso', 'Add': 'Añadir', 'additional code for your application': 'código adicional para su aplicación', -'admin': 'admin', +'admin': 'administrar', 'admin disabled because no admin password': 'admin deshabilitado por falta de contraseña', 'admin disabled because not supported on google app engine': 'admin deshabilitado, no es soportado en GAE', 'admin disabled because unable to access password file': 'admin deshabilitado, imposible acceder al archivo con la contraseña', @@ -170,7 +170,7 @@ 'exposes': 'expone', 'extends': 'extiende', 'failed to reload module': 'la recarga del módulo ha fallado', -'FAQ': 'FAQ', +'FAQ': 'Preguntas frecuentes', 'file "%(filename)s" created': 'archivo "%(filename)s" creado', 'file "%(filename)s" deleted': 'archivo "%(filename)s" eliminado', 'file "%(filename)s" uploaded': 'archivo "%(filename)s" subido', @@ -234,7 +234,7 @@ 'License for': 'Licencia para', 'Live Chat': 'Chat en vivo', 'loading...': 'cargando...', -'Log In': 'Log In', +'Log In': 'Iniciar sesion', 'Logged in': 'Sesión iniciada', 'Logged out': 'Sesión finalizada', 'Login': 'Inicio de sesión', From c0742190f05a26f5ca922da3d12cbe6e8e170583 Mon Sep 17 00:00:00 2001 From: abastardi Date: Mon, 12 Sep 2016 09:55:33 -0400 Subject: [PATCH 11/49] Avoid folder creation race condition --- gluon/admin.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/gluon/admin.py b/gluon/admin.py index 90b50c27..9615956f 100644 --- a/gluon/admin.py +++ b/gluon/admin.py @@ -435,13 +435,20 @@ def add_path_first(path): if not global_settings.web2py_runtime_gae: site.addsitedir(path) +def try_mkdir(path): + if not os.path.exists(path): + try: + os.mkdir(path) + except OSError as e: + if e.strerror == 'File exists': # In case of race condition. + pass + else: + raise e def create_missing_folders(): if not global_settings.web2py_runtime_gae: for path in ('applications', 'deposit', 'site-packages', 'logs'): - path = abspath(path, gluon=True) - if not os.path.exists(path): - os.mkdir(path) + try_mkdir(abspath(path, gluon=True)) """ OLD sys.path dance paths = (global_settings.gluon_parent, abspath( @@ -458,7 +465,5 @@ def create_missing_app_folders(request): for subfolder in ('models', 'views', 'controllers', 'databases', 'modules', 'cron', 'errors', 'sessions', 'languages', 'static', 'private', 'uploads'): - path = os.path.join(request.folder, subfolder) - if not os.path.exists(path): - os.mkdir(path) + try_mkdir(os.path.join(request.folder, subfolder)) global_settings.app_folders.add(request.folder) From 897e2ab95da7cd914cbec558d7adfa745590ca36 Mon Sep 17 00:00:00 2001 From: ilvalle Date: Fri, 16 Sep 2016 16:28:20 +0200 Subject: [PATCH 12/49] caching read_pyc for controllers and models --- gluon/compileapp.py | 5 +++-- gluon/restricted.py | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/gluon/compileapp.py b/gluon/compileapp.py index 0ee9c18c..70f924b1 100644 --- a/gluon/compileapp.py +++ b/gluon/compileapp.py @@ -581,7 +581,7 @@ def run_models_in(environment): if not regex.search(fname) and c != 'appadmin': continue elif compiled: - code = read_pyc(model) + code = getcfs(model, model, lambda: read_pyc(model)) elif is_gae: code = getcfs(model, model, lambda: compile2(read_file(model), model)) @@ -614,7 +614,8 @@ def run_controller_in(controller, function, environment): raise HTTP(404, rewrite.THREAD_LOCAL.routes.error_message % badf, web2py_error=badf) - restricted(read_pyc(filename), environment, layer=filename) + code = getcfs(filename, filename, lambda: read_pyc(filename)) + restricted(code, environment, layer=filename) elif function == '_TEST': # TESTING: adjust the path to include site packages from settings import global_settings diff --git a/gluon/restricted.py b/gluon/restricted.py index c67bcbf4..c0725a15 100644 --- a/gluon/restricted.py +++ b/gluon/restricted.py @@ -199,7 +199,7 @@ class RestrictedError(Exception): def compile2(code, layer): - return compile(code.rstrip(), layer, 'exec') + return compile(code, layer, 'exec') def restricted(code, environment=None, layer='Unknown'): From 352c93bc86347646d8190049fef9ba63f9c0dc0e Mon Sep 17 00:00:00 2001 From: ilvalle Date: Fri, 16 Sep 2016 19:33:07 +0200 Subject: [PATCH 13/49] added getcfs for run_view_in --- gluon/compileapp.py | 2 +- gluon/tests/test_appadmin.py | 13 +++++++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/gluon/compileapp.py b/gluon/compileapp.py index 70f924b1..42794bac 100644 --- a/gluon/compileapp.py +++ b/gluon/compileapp.py @@ -707,7 +707,7 @@ def run_view_in(environment): for f in files: compiled = pjoin(path, f) if os.path.exists(compiled): - code = read_pyc(compiled) + code = getcfs(compiled, compiled, lambda: read_pyc(compiled)) restricted(code, environment, layer=compiled) return if not os.path.exists(filename) and allow_generic: diff --git a/gluon/tests/test_appadmin.py b/gluon/tests/test_appadmin.py index 9d7e0493..77bb36d6 100644 --- a/gluon/tests/test_appadmin.py +++ b/gluon/tests/test_appadmin.py @@ -10,7 +10,7 @@ import sys import unittest -from gluon.compileapp import run_controller_in, run_view_in +from gluon.compileapp import run_controller_in, run_view_in, compile_application, remove_compiled_application from gluon.languages import translator from gluon.storage import Storage, List from gluon import fileutils @@ -76,7 +76,7 @@ class TestAppAdmin(unittest.TestCase): def run_view(self): return run_view_in(self.env) - def test_index(self): + def _test_index(self): result = self.run_function() self.assertTrue('db' in result['databases']) self.env.update(result) @@ -86,6 +86,15 @@ class TestAppAdmin(unittest.TestCase): print(e.message) self.fail('Could not make the view') + def test_index(self): + self._test_index() + + def test_index_compiled(self): + appname_path = os.path.join(os.getcwd(), 'applications', 'welcome') + compile_application(appname_path) + self._test_index() + remove_compiled_application(appname_path) + def test_select(self): request = self.env['request'] request.args = List(['db']) From 790593228f94f39acbff19cd47b1d7324c27c869 Mon Sep 17 00:00:00 2001 From: niphlod Date: Mon, 19 Sep 2016 20:41:41 +0200 Subject: [PATCH 14/49] fixes #1452 --- gluon/scheduler.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gluon/scheduler.py b/gluon/scheduler.py index 11dccd16..a68152b5 100644 --- a/gluon/scheduler.py +++ b/gluon/scheduler.py @@ -1499,6 +1499,8 @@ class Scheduler(MetaScheduler): kwargs.update(start_time=start_time, next_run_time=next_run_time) except: pass + if 'start_time' in kwargs and 'next_run_time' not in kwargs: + kwargs.update(next_run_time=kwargs['start_time']) rtn = self.db.scheduler_task.validate_and_insert(**kwargs) if not rtn.errors: rtn.uuid = tuuid From 25e8f4aef1f7e3bcd92ca17a7c21f0d97a1dfd7f Mon Sep 17 00:00:00 2001 From: niphlod Date: Mon, 19 Sep 2016 21:33:01 +0200 Subject: [PATCH 15/49] fixes #1449 codename "he who late imports by default makes everybody's life a misery for no speedup at all" --- gluon/contrib/login_methods/cas_auth.py | 21 +++++++++------------ gluon/globals.py | 2 +- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/gluon/contrib/login_methods/cas_auth.py b/gluon/contrib/login_methods/cas_auth.py index 61d99868..1a07c5f1 100644 --- a/gluon/contrib/login_methods/cas_auth.py +++ b/gluon/contrib/login_methods/cas_auth.py @@ -8,9 +8,11 @@ License: LGPL v3 Tinkered by Szabolcs Gyuris < szimszo n @ o regpreshaz dot eu> """ +import xml.dom.minidom as dom +import xml.parsers.expat as expat from gluon import current, redirect, URL - +from gluon._compat import urlopen, to_native class CasAuth(object): """ @@ -59,7 +61,7 @@ class CasAuth(object): # vars commented because of # https://code.google.com/p/web2py/issues/detail?id=1774 self.cas_my_url = URL(args=current.request.args, - #vars=current.request.vars, + #vars=current.request.vars, scheme=True) def login_url(self, next="/"): @@ -86,7 +88,6 @@ class CasAuth(object): exposed as CAS.login(request) returns a token on success, None on failed authentication """ - import urllib self.ticket = current.request.vars.ticket if not current.request.vars.ticket: redirect("%s?service=%s" % (self.cas_login_url, @@ -95,7 +96,7 @@ class CasAuth(object): url = "%s?service=%s&ticket=%s" % (self.cas_check_url, self.cas_my_url, self.ticket) - data = urllib.urlopen(url).read() + data = to_native(urlopen(url).read()) if data.startswith('yes') or data.startswith('no'): data = data.split('\n') if data[0] == 'yes': @@ -108,19 +109,16 @@ class CasAuth(object): a = b = c = data[1] return dict(user=a, email=b, username=c) return None - import xml.dom.minidom as dom - import xml.parsers.expat as expat try: dxml = dom.parseString(data) - envelop = dxml.getElementsByTagName( - "cas:authenticationSuccess") + envelop = dxml.getElementsByTagName("cas:authenticationSuccess") if len(envelop) > 0: res = dict() for x in envelop[0].childNodes: if x.nodeName.startswith('cas:') and len(x.childNodes): - key = x.nodeName[4:].encode('utf8') - value = x.childNodes[0].nodeValue.encode('utf8') - if not key in res: + key = to_native(x.nodeName[4:]) + value = to_native(x.childNodes[0].nodeValue) + if key not in res: res[key] = value else: if not isinstance(res[key], list): @@ -136,5 +134,4 @@ class CasAuth(object): exposed CAS.logout() redirects to the CAS logout page """ - import urllib redirect("%s?service=%s" % (self.cas_logout_url, self.cas_my_url)) diff --git a/gluon/globals.py b/gluon/globals.py index 41ac708e..ae4e0bc9 100644 --- a/gluon/globals.py +++ b/gluon/globals.py @@ -13,7 +13,7 @@ Contains the classes for the global used variables: - Session """ -from gluon._compat import pickle, StringIO, copyreg, Cookie, urlparse, PY2, iteritems, to_unicode, to_native, unicodeT +from gluon._compat import pickle, StringIO, copyreg, Cookie, urlparse, PY2, iteritems, to_unicode, to_native, unicodeT, long from gluon.storage import Storage, List from gluon.streamer import streamer, stream_file_or_304_or_206, DEFAULT_CHUNK_SIZE from gluon.contenttype import contenttype From 40d6a72b9063e13fb47731bd51b07ee23d2671ab Mon Sep 17 00:00:00 2001 From: niphlod Date: Wed, 21 Sep 2016 22:35:04 +0200 Subject: [PATCH 16/49] fixes #1455 --- gluon/tools.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/gluon/tools.py b/gluon/tools.py index e0838f9f..eb4a61f9 100644 --- a/gluon/tools.py +++ b/gluon/tools.py @@ -12,9 +12,11 @@ Auth, Mail, PluginManager and various utilities import base64 from functools import reduce -from gluon._compat import pickle, thread, urllib2, Cookie, StringIO, configparser, MIMEBase, MIMEMultipart, \ - MIMEText, Encoders, Charset, long, urllib_quote, iteritems, to_bytes, to_native, add_charset, \ - charset_QP, basestring, unicodeT, to_unicode +from gluon._compat import pickle, thread, urllib2, Cookie, StringIO +from gluon._compat import configparser, MIMEBase, MIMEMultipart, MIMEText +from gluon._compat import Encoders, Charset, long, urllib_quote, iteritems +from gluon._compat import to_bytes, to_native, add_charset +from gluon._compat import charset_QP, basestring, unicodeT, to_unicode import datetime import logging import sys @@ -40,8 +42,9 @@ from gluon.utils import web2py_uuid, compare from gluon.fileutils import read_file, check_credentials from gluon import * from gluon.contrib.autolinks import expand_one -from gluon.contrib.markmin.markmin2html import \ - replace_at_urls, replace_autolinks, replace_components +from gluon.contrib.markmin.markmin2html import replace_at_urls +from gluon.contrib.markmin.markmin2html import replace_autolinks +from gluon.contrib.markmin.markmin2html import replace_components from pydal.objects import Row, Set, Query import gluon.serializers as serializers @@ -1578,7 +1581,6 @@ class Auth(object): logged_out='Logged out', registration_successful='Registration successful', invalid_email='Invalid email', - unable_send_email='Unable to send email', invalid_login='Invalid login', invalid_user='Invalid user', invalid_password='Invalid password', @@ -3633,7 +3635,7 @@ class Auth(object): message=self.messages.retrieve_password % dict(password=password)): session.flash = self.messages.email_sent else: - session.flash = self.messages.unable_to_send_email + session.flash = self.messages.unable_send_email self.log_event(log, user) callback(onaccept, form) if not next: @@ -3930,7 +3932,7 @@ class Auth(object): if self.email_reset_password(user): session.flash = self.messages.email_sent else: - session.flash = self.messages.unable_to_send_email + session.flash = self.messages.unable_send_email self.log_event(log, user) callback(onaccept, form) if not next: From 37d2efaab85bcf651556ddc87903f6f5f7591fb9 Mon Sep 17 00:00:00 2001 From: niphlod Date: Wed, 21 Sep 2016 23:00:55 +0200 Subject: [PATCH 17/49] fixes #1413 --- handlers/wsgihandler.py | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/handlers/wsgihandler.py b/handlers/wsgihandler.py index 39b66d6c..e4f19c9c 100644 --- a/handlers/wsgihandler.py +++ b/handlers/wsgihandler.py @@ -7,22 +7,16 @@ Copyrighted by Massimo Di Pierro License: LGPLv3 (http://www.gnu.org/licenses/lgpl.html) -This is a WSGI handler for Apache -Requires apache+mod_wsgi. - -In httpd.conf put something like: - - LoadModule wsgi_module modules/mod_wsgi.so - WSGIScriptAlias / /path/to/wsgihandler.py - +This is a WSGI handler """ +import sys +import os + # change these parameters as required LOGGING = False SOFTCRON = False -import sys -import os path = os.path.dirname(os.path.abspath(__file__)) os.chdir(path) @@ -32,8 +26,6 @@ if not os.path.isdir('applications'): sys.path = [path] + [p for p in sys.path if not p == path] -sys.stdout = sys.stderr - import gluon.main if LOGGING: From 8ddccd41398e624b24abaa48173e812d301122a7 Mon Sep 17 00:00:00 2001 From: niphlod Date: Wed, 21 Sep 2016 23:13:45 +0200 Subject: [PATCH 18/49] removed leftover (be careful (BOTH contributors and mergers)) --- applications/welcome/languages/.DS_Store | Bin 6148 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 applications/welcome/languages/.DS_Store diff --git a/applications/welcome/languages/.DS_Store b/applications/welcome/languages/.DS_Store deleted file mode 100644 index 0c703e4471f572b9253907ba8dc1db9997cbcff9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHKO-sZu5Pi`V7QF1yV}5}}e?eW>i--sP19nwJSlzO15pVtJzWGqLTCcLm1d=zI z%$p<+nlu2?yn8qSW&ozFf=P^#BJR}#ke(I z7+Y}Wit{~@U9mOx_tjpz+FN_rO`&5|p+G1Q3WNeXqX6%0Dbqv4XhVTeAQbpgK+cEE zDp)%9hI(|c(I)_LLbn#$@|F-zb}SuxLyoW{qY{mp{E3l_PJi~e(y=!*I+D)JJU;X1 z<0a|r^k)r6Dh;Cz1ww(L0{hmT$^C!9PiFLyKcqx26bJ?WnF49DxLwS-DZg8PY)|gm v%zDQvMdErfSZEJ^0@#srF@6M8kZ3}IKTzNUXyZ4r From e5dcdb074f114e9709fbeea4981c4080d951e412 Mon Sep 17 00:00:00 2001 From: niphlod Date: Thu, 22 Sep 2016 00:01:22 +0200 Subject: [PATCH 19/49] fixes #1310 and improves upon ideas shared on #1450 --- gluon/compileapp.py | 31 +++++++++++++------------------ gluon/template.py | 27 ++++++++++++++------------- 2 files changed, 27 insertions(+), 31 deletions(-) diff --git a/gluon/compileapp.py b/gluon/compileapp.py index 42794bac..459c2848 100644 --- a/gluon/compileapp.py +++ b/gluon/compileapp.py @@ -594,7 +594,7 @@ def run_controller_in(controller, function, environment): """ Runs the controller.function() (for the app specified by the current folder). - It tries pre-compiled controller_function.pyc first before compiling it. + It tries pre-compiled controller.function.pyc first before compiling it. """ # if compiled should run compiled! @@ -606,20 +606,15 @@ def run_controller_in(controller, function, environment): filename = pjoin(path, 'controllers.%s.%s.pyc' % (controller, function)) if not os.path.exists(filename): - ### for backward compatibility - filename = pjoin(path, 'controllers_%s_%s.pyc' - % (controller, function)) - ### end for backward compatibility - if not os.path.exists(filename): - raise HTTP(404, - rewrite.THREAD_LOCAL.routes.error_message % badf, - web2py_error=badf) + raise HTTP(404, + rewrite.THREAD_LOCAL.routes.error_message % badf, + web2py_error=badf) code = getcfs(filename, filename, lambda: read_pyc(filename)) restricted(code, environment, layer=filename) elif function == '_TEST': # TESTING: adjust the path to include site packages - from settings import global_settings - from admin import abspath, add_path_first + from gluon.settings import global_settings + from gluon.admin import abspath, add_path_first paths = (global_settings.gluon_parent, abspath( 'site-packages', gluon=True), abspath('gluon', gluon=True), '') [add_path_first(path) for path in paths] @@ -642,7 +637,7 @@ def run_controller_in(controller, function, environment): raise HTTP(404, rewrite.THREAD_LOCAL.routes.error_message % badc, web2py_error=badc) - code = read_file(filename) + code = getcfs(filename, filename, lambda: read_file(filename)) exposed = find_exposed_functions(code) if not function in exposed: raise HTTP(404, @@ -669,7 +664,7 @@ def run_view_in(environment): Executes the view for the requested action. The view is the one specified in `response.view` or determined by the url or `view/generic.extension` - It tries the pre-compiled views_controller_function.pyc before compiling it. + It tries the pre-compiled views.controller.function.pyc before compiling it. """ request = current.request response = current.response @@ -691,18 +686,18 @@ def run_view_in(environment): else: filename = pjoin(folder, 'views', view) if os.path.exists(path): # compiled views - x = view.replace('/', '_') - files = ['views_%s.pyc' % x] + x = view.replace('/', '.') + files = ['views.%s.pyc' % x] is_compiled = os.path.exists(pjoin(path, files[0])) # Don't use a generic view if the non-compiled view exists. if is_compiled or (not is_compiled and not os.path.exists(filename)): if allow_generic: - files.append('views_generic.%s.pyc' % request.extension) + files.append('views.generic.%s.pyc' % request.extension) # for backward compatibility if request.extension == 'html': - files.append('views_%s.pyc' % x[:-5]) + files.append('views.%s.pyc' % x[:-5]) if allow_generic: - files.append('views_generic.pyc') + files.append('views.generic.pyc') # end backward compatibility code for f in files: compiled = pjoin(path, f) diff --git a/gluon/template.py b/gluon/template.py index 2afc29ab..e620df97 100644 --- a/gluon/template.py +++ b/gluon/template.py @@ -24,6 +24,9 @@ try: # have web2py from gluon.restricted import RestrictedError from gluon.globals import current + from gluon.cfs import getcfs + from gluon.fileutils import read_file + HAS_CFS = True except ImportError: # do not have web2py current = None @@ -426,7 +429,7 @@ class TemplateParser(object): # Allow Views to include other views dynamically context = self.context - if current and not "response" in context: + if current and "response" not in context: context["response"] = getattr(current, 'response', None) # Get the filename; filename looks like ``"template.html"``. @@ -779,12 +782,15 @@ def parse_template(filename, # First, if we have a str try to open the file if isinstance(filename, str): - try: - fp = open(os.path.join(path, filename), 'rb') - text = fp.read() - fp.close() - except IOError: - raise RestrictedError(filename, '', 'Unable to find the file') + fname = os.path.join(path, filename) + if HAS_CFS: + text = getcfs(fname, fname, lambda: read_file(fname)) + else: + try: + with open(fname, 'rb') as fp: + text = fp.read() + except IOError: + raise RestrictedError(filename, '', 'Unable to find the file') else: text = filename.read() text = to_native(text) @@ -890,7 +896,7 @@ def render(content="hello world", Response = DummyResponse # Add it to the context so we can use it. - if not 'NOESCAPE' in context: + if 'NOESCAPE' not in context: context['NOESCAPE'] = NOESCAPE if isinstance(content, unicodeT): @@ -936,8 +942,3 @@ def render(content="hello world", if old_response_body is not None: context['response'].body = old_response_body return text - - -if __name__ == '__main__': - import doctest - doctest.testmod() From 98d636314e3be3afef460a7507d71213555a214d Mon Sep 17 00:00:00 2001 From: niphlod Date: Thu, 22 Sep 2016 00:17:17 +0200 Subject: [PATCH 20/49] avoid downloading pip as 2.7 has ensurepip --- appveyor.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 80e86c5d..dde913d4 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -17,8 +17,7 @@ init: - set PATH=%PYTHON%;%PYTHON%\Scripts;%PATH% install: - - ps: Start-FileDownload https://bootstrap.pypa.io/get-pip.py - - python get-pip.py + - python -m ensurepip - pip install codecov - git submodule update --init --recursive - pip install pycrypto From e5355b5b12a7de1ee93bee6ab91fd2b79260706a Mon Sep 17 00:00:00 2001 From: niphlod Date: Thu, 22 Sep 2016 00:34:24 +0200 Subject: [PATCH 21/49] fixes #1407, encouraging a sane default --- applications/admin/views/web2py_ajax.html | 2 +- applications/examples/views/web2py_ajax.html | 2 +- applications/welcome/views/web2py_ajax.html | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/applications/admin/views/web2py_ajax.html b/applications/admin/views/web2py_ajax.html index a5de41ea..417859e9 100644 --- a/applications/admin/views/web2py_ajax.html +++ b/applications/admin/views/web2py_ajax.html @@ -4,7 +4,7 @@ var w2p_ajax_date_format = "{{=T('%Y-%m-%d')}}"; var w2p_ajax_datetime_format = "{{=T('%Y-%m-%d %H:%M:%S')}}"; var w2p_ajax_disable_with_message = "{{=T('Working...')}}"; - var ajax_error_500 = '{{=T.M('An error occured, please [[reload %s]] the page') % URL(args=request.args, vars=request.get_vars) }}' + var ajax_error_500 = "{{=T.M('An error occured, please [[reload %s]] the page') % URL(args=request.args, vars=request.get_vars) }}" //--> {{ response.files.insert(0,URL('static','js/jquery.js')) diff --git a/applications/examples/views/web2py_ajax.html b/applications/examples/views/web2py_ajax.html index bf554868..a0ba6f43 100644 --- a/applications/examples/views/web2py_ajax.html +++ b/applications/examples/views/web2py_ajax.html @@ -3,7 +3,7 @@ var w2p_ajax_confirm_message = "{{=T('Are you sure you want to delete this object?')}}"; var w2p_ajax_date_format = "{{=T('%Y-%m-%d')}}"; var w2p_ajax_datetime_format = "{{=T('%Y-%m-%d %H:%M:%S')}}"; - var ajax_error_500 = '{{=T.M('An error occured, please [[reload %s]] the page') % URL(args=request.args, vars=request.get_vars) }}' + var ajax_error_500 = "{{=T.M('An error occured, please [[reload %s]] the page') % URL(args=request.args, vars=request.get_vars) }}" //--> {{ response.files.insert(0,URL('static','js/jquery.js')) diff --git a/applications/welcome/views/web2py_ajax.html b/applications/welcome/views/web2py_ajax.html index b8e1a113..6fefd3a0 100644 --- a/applications/welcome/views/web2py_ajax.html +++ b/applications/welcome/views/web2py_ajax.html @@ -4,7 +4,7 @@ var w2p_ajax_disable_with_message = "{{=T('Working...')}}"; var w2p_ajax_date_format = "{{=T('%Y-%m-%d')}}"; var w2p_ajax_datetime_format = "{{=T('%Y-%m-%d %H:%M:%S')}}"; - var ajax_error_500 = '{{=T.M('An error occured, please [[reload %s]] the page') % URL(args=request.args, vars=request.get_vars) }}' + var ajax_error_500 = "{{=T.M('An error occured, please [[reload %s]] the page') % URL(args=request.args, vars=request.get_vars) }}" //--> {{ response.files.insert(0,URL('static','js/jquery.js')) From dd8b0760b5a012cb97965f2a1e07219e7d57e8c1 Mon Sep 17 00:00:00 2001 From: niphlod Date: Thu, 22 Sep 2016 01:34:34 +0200 Subject: [PATCH 22/49] fixes #1309 (and sessions2trash.py, too) --- applications/admin/cron/expire_sessions.py | 25 +++++++++++++-------- scripts/sessions2trash.py | 26 +++++++++------------- 2 files changed, 27 insertions(+), 24 deletions(-) diff --git a/applications/admin/cron/expire_sessions.py b/applications/admin/cron/expire_sessions.py index 10a428c3..34b16091 100644 --- a/applications/admin/cron/expire_sessions.py +++ b/applications/admin/cron/expire_sessions.py @@ -1,17 +1,20 @@ -EXPIRATION_MINUTES=60 -DIGITS=('0','1','2','3','4','5','6','7','8','9') -import os, time, stat, cPickle, logging -path = os.path.join(request.folder,'sessions') + +import os, time, stat, logging +from gluon._compat import pickle + +EXPIRATION_MINUTES = 60 + +path = os.path.join(request.folder, 'sessions') if not os.path.exists(path): os.mkdir(path) now = time.time() -for filename in os.listdir(path): - fullpath=os.path.join(path,filename) - if os.path.isfile(fullpath) and filename.startswith(DIGITS): +for path, dirs, files in os.walk(path, topdown=False): + for x in files: + fullpath = os.path.join(path, x) try: - filetime = os.stat(fullpath)[stat.ST_MTIME] # get it before our io + filetime = os.stat(fullpath)[stat.ST_MTIME] # get it before our io try: - session_data = cPickle.load(open(fullpath, 'rb+')) + session_data = pickle.load(open(fullpath, 'rb+')) expiration = session_data['auth']['expiration'] except: expiration = EXPIRATION_MINUTES * 60 @@ -19,3 +22,7 @@ for filename in os.listdir(path): os.unlink(fullpath) except: logging.exception('failure to check %s' % fullpath) + for d in dirs: + dd = os.path.join(path, d) + if not os.listdir(dd): + os.rmdir(dd) diff --git a/scripts/sessions2trash.py b/scripts/sessions2trash.py index 65758c87..f338b453 100755 --- a/scripts/sessions2trash.py +++ b/scripts/sessions2trash.py @@ -30,18 +30,14 @@ Typical usage: from __future__ import with_statement -import sys -import os -sys.path.append(os.path.join(*__file__.split(os.sep)[:-2] or ['.'])) - from gluon import current from gluon.storage import Storage +from gluon._compat import pickle from optparse import OptionParser -import cPickle import datetime -import os import stat import time +import os EXPIRATION_MINUTES = 60 SLEEP_MINUTES = 5 @@ -86,12 +82,12 @@ class SessionSet(object): status = 'trashed' if self.verbose > 1: - print 'key: %s' % str(item) - print 'expiration: %s seconds' % self.expiration - print 'last visit: %s' % str(last_visit) - print 'age: %s seconds' % age - print 'status: %s' % status - print '' + print('key: %s' % str(item)) + print('expiration: %s seconds' % self.expiration) + print('last visit: %s' % str(last_visit)) + print('age: %s seconds' % age) + print('status: %s' % status) + print('') elif self.verbose > 0: print('%s %s' % (str(item), status)) @@ -145,7 +141,7 @@ class SessionDb(object): def get(self): session = Storage() - session.update(cPickle.loads(self.row.session_data)) + session.update(pickle.loads(self.row.session_data)) return session def last_visit_default(self): @@ -155,7 +151,7 @@ class SessionDb(object): try: return datetime.datetime.strptime(self.row.modified_datetime, '%Y-%m-%d %H:%M:%S.%f') except: - print 'failed to retrieve last modified time (value: %s)' % self.row.modified_datetime + print('failed to retrieve last modified time (value: %s)' % self.row.modified_datetime) def __str__(self): return self.row.unique_key @@ -248,7 +244,7 @@ def main(): break else: if options.verbose: - print 'Sleeping %s seconds' % (options.sleep) + print('Sleeping %s seconds' % (options.sleep)) time.sleep(options.sleep) if __name__ == '__main__': From 4f0a2eb80ba82d3b66d3be9ea9611868a54cff9d Mon Sep 17 00:00:00 2001 From: niphlod Date: Thu, 22 Sep 2016 01:55:53 +0200 Subject: [PATCH 23/49] fixes #1190 --- gluon/sqlhtml.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/gluon/sqlhtml.py b/gluon/sqlhtml.py index 03100e43..8f8d0d68 100644 --- a/gluon/sqlhtml.py +++ b/gluon/sqlhtml.py @@ -875,7 +875,7 @@ def formstyle_bootstrap(form, fields): controls.add_class('span4') if isinstance(label, LABEL): - label['_class'] = add_class(label.get('_class'),'control-label') + label['_class'] = add_class(label.get('_class'), 'control-label') if _submit: # submit button has unwrapped label and controls, different class @@ -925,8 +925,11 @@ def formstyle_bootstrap3_stacked(form, fields): for e in controls.elements("input"): e.add_class('form-control') + elif isinstance(controls, CAT) and isinstance(controls[0], INPUT): + controls[0].add_class('form-control') + if isinstance(label, LABEL): - label['_class'] = add_class(label.get('_class'),'control-label') + label['_class'] = add_class(label.get('_class'), 'control-label') parent.append(DIV(label, _controls, _class='form-group', _id=id)) return parent @@ -975,8 +978,10 @@ def formstyle_bootstrap3_inline_factory(col_label_size=3): elif isinstance(controls, UL): for e in controls.elements("input"): e.add_class('form-control') + elif isinstance(controls, CAT) and isinstance(controls[0], INPUT): + controls[0].add_class('form-control') if isinstance(label, LABEL): - label['_class'] = add_class(label.get('_class'),'control-label %s' % label_col_class) + label['_class'] = add_class(label.get('_class'), 'control-label %s' % label_col_class) parent.append(DIV(label, _controls, _class='form-group', _id=id)) return parent From 55f929bab4a30146d9ed714f0067d6668dc280d5 Mon Sep 17 00:00:00 2001 From: niphlod Date: Fri, 23 Sep 2016 20:52:30 +0200 Subject: [PATCH 24/49] fix launching system_tests without coverage --- gluon/widget.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/gluon/widget.py b/gluon/widget.py index af3b7689..131bfc3f 100644 --- a/gluon/widget.py +++ b/gluon/widget.py @@ -55,8 +55,11 @@ def run_system_tests(options): """ import subprocess major_version = sys.version_info[0] - minor_version = sys.version_info[1] call_args = [sys.executable, '-m', 'unittest', '-v', 'gluon.tests'] + if major_version == 2: + sys.stderr.write("Python 2.7\n") + else: + sys.stderr.write("Experimental Python 3.x.\n") if options.with_coverage: has_coverage = False coverage_exec = 'coverage2' if major_version == 2 else 'coverage3' @@ -70,14 +73,12 @@ def run_system_tests(options): coverage_config_file) call_args = [coverage_exec, 'run', '--rcfile=%s' % coverage_config, '-m', 'unittest', '-v', 'gluon.tests'] - if major_version == 2: - sys.stderr.write("Python 2.7\n") - else: - sys.stderr.write("Experimental Python 3.x.\n") if has_coverage: ret = subprocess.call(call_args) else: ret = 256 + else: + ret = subprocess.call(call_args) sys.exit(ret and 1) From 54da251e46c68d3b4b491c511b7af1fc6c257d85 Mon Sep 17 00:00:00 2001 From: niphlod Date: Fri, 23 Sep 2016 21:17:43 +0200 Subject: [PATCH 25/49] here here --- gluon/packages/dal | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gluon/packages/dal b/gluon/packages/dal index 77e0d3f3..012dbe3e 160000 --- a/gluon/packages/dal +++ b/gluon/packages/dal @@ -1 +1 @@ -Subproject commit 77e0d3f386e326a2016a7e2139900ce72d7ddada +Subproject commit 012dbe3eed0404bc5d5516018f2bf9b3eb5b17ab From 9978e63621d8f14e5d93ae5feb767b200a77e797 Mon Sep 17 00:00:00 2001 From: niphlod Date: Fri, 23 Sep 2016 23:45:00 +0200 Subject: [PATCH 26/49] fixes #1069, untangles the js, modernizes the approach plus, avoids hitting the backend for each and every keypress... --- gluon/sqlhtml.py | 135 ++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 115 insertions(+), 20 deletions(-) diff --git a/gluon/sqlhtml.py b/gluon/sqlhtml.py index 8f8d0d68..e4291cae 100644 --- a/gluon/sqlhtml.py +++ b/gluon/sqlhtml.py @@ -657,7 +657,8 @@ class AutocompleteWidget(object): def __init__(self, request, field, id_field=None, db=None, orderby=None, limitby=(0, 10), distinct=False, keyword='_autocomplete_%(tablename)s_%(fieldname)s', - min_length=2, help_fields=None, help_string=None, at_beginning = True): + min_length=2, help_fields=None, help_string=None, + at_beginning=True, default_var='ac'): self.help_fields = help_fields or [] self.help_string = help_string @@ -680,7 +681,9 @@ class AutocompleteWidget(object): else: self.is_reference = False if hasattr(request, 'application'): - self.url = URL(args=request.args) + urlvars = request.vars + urlvars[default_var] = 1 + self.url = URL(args=request.args, vars=urlvars) self.callback() else: self.url = request @@ -688,35 +691,55 @@ class AutocompleteWidget(object): def callback(self): if self.keyword in self.request.vars: field = self.fields[0] + kword = self.request.vars[self.keyword] if isinstance(field, Field.Virtual): records = [] table_rows = self.db(self.db[field.tablename]).select(orderby=self.orderby) count = 0 for row in table_rows: if self.at_beginning: - if row[field.name].lower().startswith(self.request.vars[self.keyword]): + if row[field.name].lower().startswith(kword): count += 1 records.append(row) else: - if self.request.vars[self.keyword] in row[field.name].lower(): + if kword in row[field.name].lower(): count += 1 records.append(row) if count == 10: break - rows = Rows(self.db, records, table_rows.colnames, compact=table_rows.compact) + rows = Rows(self.db, records, table_rows.colnames, + compact=table_rows.compact) elif settings and settings.global_settings.web2py_runtime_gae: - rows = self.db(field.__ge__(self.request.vars[self.keyword]) & field.__lt__(self.request.vars[self.keyword] + u'\ufffd')).select(orderby=self.orderby, limitby=self.limitby, *(self.fields+self.help_fields)) + rows = self.db(field.__ge__(kword) & + field.__lt__(kword + u'\ufffd') + ).select(orderby=self.orderby, + limitby=self.limitby, + *(self.fields + self.help_fields)) elif self.at_beginning: - rows = self.db(field.like(self.request.vars[self.keyword] + '%', case_sensitive=False)).select(orderby=self.orderby, limitby=self.limitby, distinct=self.distinct, *(self.fields+self.help_fields)) + rows = self.db(field.like(kword + '%', case_sensitive=False) + ).select(orderby=self.orderby, + limitby=self.limitby, + distinct=self.distinct, + *(self.fields + self.help_fields)) else: - rows = self.db(field.contains(self.request.vars[self.keyword], case_sensitive=False)).select(orderby=self.orderby, limitby=self.limitby, distinct=self.distinct, *(self.fields+self.help_fields)) + rows = self.db(field.contains(kword, case_sensitive=False) + ).select(orderby=self.orderby, + limitby=self.limitby, + distinct=self.distinct, + *(self.fields + self.help_fields)) if rows: if self.is_reference: id_field = self.fields[1] if self.help_fields: - options = [OPTION( - self.help_string % dict([(h.name, s[h.name]) for h in self.fields[:1] + self.help_fields]), - _value=s[id_field.name], _selected=(k == 0)) for k, s in enumerate(rows)] + options = [ + OPTION( + self.help_string % dict( + [(h.name, s[h.name]) for h + in self.fields[:1] + self.help_fields]), + _value=s[id_field.name], + _selected=(k == 0)) + for k, s in enumerate(rows) + ] else: options = [OPTION( s[field.name], _value=s[id_field.name], @@ -763,28 +786,100 @@ class AutocompleteWidget(object): record = self.db( self.fields[1] == value).select(self.fields[0]).first() attr['value'] = record and record[self.fields[0].name] - attr['_onblur'] = "jQuery('#%(div_id)s').delay(1000).fadeOut('slow');" % \ + attr['_onblur'] = "jQuery('#%(div_id)s').delay(500).fadeOut('slow');" % \ dict(div_id=div_id, u='F' + self.keyword) - attr['_onkeyup'] = "jQuery('#%(key3)s').val('');var e=event.which?event.which:event.keyCode; function %(u)s(){jQuery('#%(id)s').val(jQuery('#%(key)s :selected').text());jQuery('#%(key3)s').val(jQuery('#%(key)s').val())}; if(e==39) %(u)s(); else if(e==40) {if(jQuery('#%(key)s option:selected').next().length)jQuery('#%(key)s option:selected').attr('selected',null).next().attr('selected','selected'); %(u)s();} else if(e==38) {if(jQuery('#%(key)s option:selected').prev().length)jQuery('#%(key)s option:selected').attr('selected',null).prev().attr('selected','selected'); %(u)s();} else if(jQuery('#%(id)s').val().length>=%(min_length)s) jQuery.get('%(url)s?%(key)s='+encodeURIComponent(jQuery('#%(id)s').val()),function(data){if(data=='')jQuery('#%(key3)s').val('');else{jQuery('#%(id)s').next('.error').hide();jQuery('#%(div_id)s').html(data).show().focus();jQuery('#%(div_id)s select').css('width',jQuery('#%(id)s').css('width'));jQuery('#%(key3)s').val(jQuery('#%(key)s').val());jQuery('#%(key)s').change(%(u)s);jQuery('#%(key)s').click(%(u)s);};}); else jQuery('#%(div_id)s').fadeOut('slow');" % \ + js = """ + (function($) { + function doit(e_) { + $('#%(key3)s').val(''); + var e=e_.which?e_.which:e_.keyCode; + function %(u)s(){ + $('#%(id)s').val($('#%(key)s :selected').text()); + $('#%(key3)s').val($('#%(key)s').val()) + }; + if(e==39) %(u)s(); + else if(e==40) { + if($('#%(key)s option:selected').next().length) + $('#%(key)s option:selected').attr('selected',null).next().attr('selected','selected'); + %(u)s(); + } + else if(e==38) { + if($('#%(key)s option:selected').prev().length) + $('#%(key)s option:selected').attr('selected',null).prev().attr('selected','selected'); + %(u)s(); + } + else if($('#%(id)s').val().length>=%(min_length)s) + $.get('%(url)s&%(key)s='+encodeURIComponent($('#%(id)s').val()), + function(data){ + if(data=='')$('#%(key3)s').val(''); + else{ + $('#%(id)s').next('.error').hide(); + $('#%(div_id)s').html(data).show().focus(); + $('#%(div_id)s select').css('width',$('#%(id)s').css('width')); + $('#%(key3)s').val($('#%(key)s').val()); + $('#%(key)s').change(%(u)s).click(%(u)s); + }; + }); + else $('#%(div_id)s').fadeOut('slow'); + } + var tmr = null; + $("#%(id)s").on('keyup focus',function(e) { + if (tmr) clearTimeout(tmr); + if($('#%(id)s').val().length>=%(min_length)s) { + tmr = setTimeout(function() { tmr = null; doit(e); }, 300); + } + }); + })(jQuery)""".replace('\n', '').replace(' ' * 4, '') % \ dict(url=self.url, min_length=self.min_length, key=self.keyword, id=attr['_id'], key2=key2, key3=key3, name=name, div_id=div_id, u='F' + self.keyword) - if self.min_length == 0: - attr['_onfocus'] = attr['_onkeyup'] return CAT(INPUT(**attr), INPUT(_type='hidden', _id=key3, _value=value, _name=name, requires=field.requires), + SCRIPT(js), DIV(_id=div_id, _style='position:absolute;')) else: attr['_name'] = field.name - attr['_onblur'] = "jQuery('#%(div_id)s').delay(1000).fadeOut('slow');" % \ + attr['_onblur'] = "jQuery('#%(div_id)s').delay(500).fadeOut('slow');" % \ dict(div_id=div_id, u='F' + self.keyword) - attr['_onkeyup'] = "var e=event.which?event.which:event.keyCode; function %(u)s(){jQuery('#%(id)s').val(jQuery('#%(key)s').val())}; if(e==39) %(u)s(); else if(e==40) {if(jQuery('#%(key)s option:selected').next().length)jQuery('#%(key)s option:selected').attr('selected',null).next().attr('selected','selected'); %(u)s();} else if(e==38) {if(jQuery('#%(key)s option:selected').prev().length)jQuery('#%(key)s option:selected').attr('selected',null).prev().attr('selected','selected'); %(u)s();} else if(jQuery('#%(id)s').val().length>=%(min_length)s) jQuery.get('%(url)s?%(key)s='+encodeURIComponent(jQuery('#%(id)s').val()),function(data){jQuery('#%(id)s').next('.error').hide();jQuery('#%(div_id)s').html(data).show().focus();jQuery('#%(div_id)s select').css('width',jQuery('#%(id)s').css('width'));jQuery('#%(key)s').change(%(u)s);jQuery('#%(key)s').click(%(u)s);}); else jQuery('#%(div_id)s').fadeOut('slow');" % \ + js = """ + (function($) { + function doit(e_) { + var e=e_.which?e_.which:e_.keyCode; + function %(u)s(){ + $('#%(id)s').val($('#%(key)s').val()) + }; + if(e==39) %(u)s(); + else if(e==40) { + if($('#%(key)s option:selected').next().length) + $('#%(key)s option:selected').attr('selected',null).next().attr('selected','selected'); + %(u)s(); + } else if(e==38) { + if($('#%(key)s option:selected').prev().length) + $('#%(key)s option:selected').attr('selected',null).prev().attr('selected','selected'); + %(u)s(); + } else if($('#%(id)s').val().length>=%(min_length)s) + $.get('%(url)s&%(key)s='+encodeURIComponent($('#%(id)s').val()), + function(data){ + $('#%(id)s').next('.error').hide(); + $('#%(div_id)s').html(data).show().focus(); + $('#%(div_id)s select').css('width',$('#%(id)s').css('width')); + $('#%(key)s').change(%(u)s).click(%(u)s); + } + ); + else $('#%(div_id)s').fadeOut('slow'); + } + var tmr = null; + $("#%(id)s").on('keyup focus',function(e) { + if (tmr) clearTimeout(tmr); + if($('#%(id)s').val().length>=%(min_length)s) { + tmr = setTimeout(function() { tmr = null; doit(e); }, 300); + } + }); + })(jQuery)""".replace('\n', '').replace(' ' * 4, '') % \ dict(url=self.url, min_length=self.min_length, key=self.keyword, id=attr['_id'], div_id=div_id, u='F' + self.keyword) - if self.min_length == 0: - attr['_onfocus'] = attr['_onkeyup'] - return CAT(INPUT(**attr), + return CAT(INPUT(**attr), SCRIPT(js), DIV(_id=div_id, _style='position:absolute;')) From 576aaf668d8ddc573cb210616f37d61a3d76d7a3 Mon Sep 17 00:00:00 2001 From: ilvalle Date: Sat, 24 Sep 2016 09:02:25 +0200 Subject: [PATCH 27/49] cache (and compile) parse_template in run_view_in, fix #1474 --- applications/welcome/controllers/appadmin.py | 2 +- gluon/compileapp.py | 68 ++++++-------------- gluon/restricted.py | 8 +-- gluon/template.py | 16 ++--- gluon/tests/test_appadmin.py | 7 ++ 5 files changed, 33 insertions(+), 68 deletions(-) diff --git a/applications/welcome/controllers/appadmin.py b/applications/welcome/controllers/appadmin.py index 0b8b227f..4d4e965f 100644 --- a/applications/welcome/controllers/appadmin.py +++ b/applications/welcome/controllers/appadmin.py @@ -409,7 +409,7 @@ def ccache(): import copy import time import math - from gluon import portalocker + from pydal.contrib import portalocker ram = { 'entries': 0, diff --git a/gluon/compileapp.py b/gluon/compileapp.py index 459c2848..b3d9cf61 100644 --- a/gluon/compileapp.py +++ b/gluon/compileapp.py @@ -430,13 +430,10 @@ def build_environment(request, response, session, store_current=True): current.T = t current.cache = c - global __builtins__ if is_jython: # jython hack + global __builtins__ __builtins__ = mybuiltin() - elif is_pypy: # apply the same hack to pypy too - __builtins__ = mybuiltin() - elif PY2: - __builtins__['__import__'] = builtin.__import__ # WHY? + environment['request'] = request environment['response'] = response environment['session'] = session @@ -487,7 +484,7 @@ def compile_views(folder, skip_failed_views=False): else: raise Exception("%s in %s" % (e, fname)) else: - filename = ('views/%s.py' % fname).replace('/', '_').replace('\\', '_') + filename = 'views.%s.py' % fname.replace(os.path.sep, '.') filename = pjoin(folder, 'compiled', filename) write_file(filename, data) save_pyc(filename) @@ -503,7 +500,7 @@ def compile_models(folder): path = pjoin(folder, 'models') for fname in listdir(path, '.+\.py$'): data = read_file(pjoin(path, fname)) - modelfile = 'models.'+fname.replace(os.path.sep,'.') + modelfile = 'models.'+fname.replace(os.path.sep, '.') filename = pjoin(folder, 'compiled', modelfile) mktree(filename) write_file(filename, data) @@ -582,11 +579,10 @@ def run_models_in(environment): continue elif compiled: code = getcfs(model, model, lambda: read_pyc(model)) - elif is_gae: + else: code = getcfs(model, model, lambda: compile2(read_file(model), model)) - else: - code = getcfs(model, model, None) + restricted(code, environment, layer=model) @@ -610,7 +606,6 @@ def run_controller_in(controller, function, environment): rewrite.THREAD_LOCAL.routes.error_message % badf, web2py_error=badf) code = getcfs(filename, filename, lambda: read_pyc(filename)) - restricted(code, environment, layer=filename) elif function == '_TEST': # TESTING: adjust the path to include site packages from gluon.settings import global_settings @@ -629,7 +624,6 @@ def run_controller_in(controller, function, environment): environment['__symbols__'] = environment.keys() code = read_file(filename) code += TEST_CODE - restricted(code, environment, layer=filename) else: filename = pjoin(folder, 'controllers/%s.py' % controller) @@ -644,10 +638,10 @@ def run_controller_in(controller, function, environment): rewrite.THREAD_LOCAL.routes.error_message % badf, web2py_error=badf) code = "%s\nresponse._vars=response._caller(%s)\n" % (code, function) - if is_gae: - layer = filename + ':' + function - code = getcfs(layer, filename, lambda: compile2(code, layer)) - restricted(code, environment, filename) + layer = filename + ':' + function + code = getcfs(layer, filename, lambda: compile2(code, layer)) + + restricted(code, environment, layer=filename) response = current.response vars = response._vars if response.postprocessing: @@ -682,7 +676,7 @@ def run_view_in(environment): if not isinstance(view, str): ccode = parse_template(view, pjoin(folder, 'views'), context=environment) - restricted(ccode, environment, 'file stream') + layer = 'file stream' else: filename = pjoin(folder, 'views', view) if os.path.exists(path): # compiled views @@ -713,16 +707,13 @@ def run_view_in(environment): rewrite.THREAD_LOCAL.routes.error_message % badv, web2py_error=badv) layer = filename - if is_gae: - ccode = getcfs(layer, filename, - lambda: compile2(parse_template(view, - pjoin(folder, 'views'), - context=environment), layer)) - else: - ccode = parse_template(view, - pjoin(folder, 'views'), - context=environment) - restricted(ccode, environment, layer) + # Cache the compiled template + ccode = getcfs(layer, filename, + lambda: compile2(parse_template(view, + pjoin(folder, 'views'), + context=environment), + layer)) + restricted(ccode, environment, layer=layer) def remove_compiled_application(folder): @@ -748,26 +739,3 @@ def compile_application(folder, skip_failed_views=False): compile_controllers(folder) failed_views = compile_views(folder, skip_failed_views) return failed_views - - -def test(): - """ - Example:: - - >>> import traceback, types - >>> environment={'x':1} - >>> open('a.py', 'w').write('print 1/x') - >>> save_pyc('a.py') - >>> os.unlink('a.py') - >>> if type(read_pyc('a.pyc'))==types.CodeType: print 'code' - code - >>> exec read_pyc('a.pyc') in environment - 1 - """ - - return - - -if __name__ == '__main__': - import doctest - doctest.testmod() diff --git a/gluon/restricted.py b/gluon/restricted.py index c0725a15..84c46b36 100644 --- a/gluon/restricted.py +++ b/gluon/restricted.py @@ -202,7 +202,7 @@ def compile2(code, layer): return compile(code, layer, 'exec') -def restricted(code, environment=None, layer='Unknown'): +def restricted(ccode, environment=None, layer='Unknown'): """ Runs code in environment and returns the output. If an exception occurs in code it raises a RestrictedError containing the traceback. Layer is @@ -213,10 +213,6 @@ def restricted(code, environment=None, layer='Unknown'): environment['__file__'] = layer environment['__name__'] = '__restricted__' try: - if isinstance(code, types.CodeType): - ccode = code - else: - ccode = compile2(code, layer) exec(ccode, environment) except HTTP: raise @@ -231,7 +227,7 @@ def restricted(code, environment=None, layer='Unknown'): sys.excepthook(etype, evalue, tb) del tb output = "%s %s" % (etype, evalue) - raise RestrictedError(layer, code, output, environment) + raise RestrictedError(layer, ccode, output, environment) def snapshot(info=None, context=5, code=None, environment=None): diff --git a/gluon/template.py b/gluon/template.py index e620df97..41da7f2d 100644 --- a/gluon/template.py +++ b/gluon/template.py @@ -24,9 +24,6 @@ try: # have web2py from gluon.restricted import RestrictedError from gluon.globals import current - from gluon.cfs import getcfs - from gluon.fileutils import read_file - HAS_CFS = True except ImportError: # do not have web2py current = None @@ -783,14 +780,11 @@ def parse_template(filename, # First, if we have a str try to open the file if isinstance(filename, str): fname = os.path.join(path, filename) - if HAS_CFS: - text = getcfs(fname, fname, lambda: read_file(fname)) - else: - try: - with open(fname, 'rb') as fp: - text = fp.read() - except IOError: - raise RestrictedError(filename, '', 'Unable to find the file') + try: + with open(fname, 'rb') as fp: + text = fp.read() + except IOError: + raise RestrictedError(filename, '', 'Unable to find the file') else: text = filename.read() text = to_native(text) diff --git a/gluon/tests/test_appadmin.py b/gluon/tests/test_appadmin.py index 77bb36d6..c5e7402e 100644 --- a/gluon/tests/test_appadmin.py +++ b/gluon/tests/test_appadmin.py @@ -16,6 +16,7 @@ from gluon.storage import Storage, List from gluon import fileutils from gluon.dal import DAL, Field, Table from gluon.http import HTTP +from gluon.fileutils import open_file DEFAULT_URI = os.getenv('DB', 'sqlite:memory') @@ -76,12 +77,18 @@ class TestAppAdmin(unittest.TestCase): def run_view(self): return run_view_in(self.env) + def run_view_file_stream(self): + view_path = os.path.join(self.env['request'].folder, 'views', 'appadmin.html') + self.env['response'].view = open_file(view_path, 'r') + return run_view_in(self.env) + def _test_index(self): result = self.run_function() self.assertTrue('db' in result['databases']) self.env.update(result) try: self.run_view() + self.run_view_file_stream() except Exception as e: print(e.message) self.fail('Could not make the view') From b4acfd0724845633f667a55e593a15576379554d Mon Sep 17 00:00:00 2001 From: ilvalle Date: Sun, 25 Sep 2016 10:11:47 +0200 Subject: [PATCH 28/49] removed unnecessary env clone for _view_environment --- gluon/compileapp.py | 1 - 1 file changed, 1 deletion(-) diff --git a/gluon/compileapp.py b/gluon/compileapp.py index b3d9cf61..23e66628 100644 --- a/gluon/compileapp.py +++ b/gluon/compileapp.py @@ -441,7 +441,6 @@ def build_environment(request, response, session, store_current=True): lambda name, reload=False, app=request.application:\ local_import_aux(name, reload, app) BaseAdapter.set_folder(pjoin(request.folder, 'databases')) - response._view_environment = copy.copy(environment) custom_import_install() return environment From 4468355d013055be44913d1b2da57cadb360fe7f Mon Sep 17 00:00:00 2001 From: ilvalle Date: Sun, 25 Sep 2016 10:43:42 +0200 Subject: [PATCH 29/49] fix py3 xmlrpc imports, close #1473 --- applications/admin/controllers/pythonanywhere.py | 4 +--- gluon/_compat.py | 2 ++ gluon/contrib/simplejsonrpc.py | 11 ++++++++--- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/applications/admin/controllers/pythonanywhere.py b/applications/admin/controllers/pythonanywhere.py index 33dfda6f..e61b06ab 100644 --- a/applications/admin/controllers/pythonanywhere.py +++ b/applications/admin/controllers/pythonanywhere.py @@ -4,10 +4,8 @@ import os import re import gzip import tarfile -from gluon._compat import StringIO -from xmlrpclib import ProtocolError from gluon.contrib.simplejsonrpc import ServerProxy - +from gluon._compat import StringIO, ProtocolError def deploy(): response.title = T('Deploy to pythonanywhere') diff --git a/gluon/_compat.py b/gluon/_compat.py index f7b53dde..a87a5c94 100644 --- a/gluon/_compat.py +++ b/gluon/_compat.py @@ -31,6 +31,7 @@ if PY2: from types import ClassType import cgi import cookielib + from xmlrpclib import ProtocolError BytesIO = StringIO reduce = reduce hashlib_md5 = hashlib.md5 @@ -94,6 +95,7 @@ else: from urllib.request import FancyURLopener, urlopen from urllib.parse import quote as urllib_quote, unquote as urllib_unquote, urlencode from http import cookiejar as cookielib + from xmlrpc.client import ProtocolError import html # warning, this is the python3 module and not the web2py html module hashlib_md5 = lambda s: hashlib.md5(bytes(s, 'utf8')) iterkeys = lambda d: iter(d.keys()) diff --git a/gluon/contrib/simplejsonrpc.py b/gluon/contrib/simplejsonrpc.py index 2a4547f7..f60dc4c7 100644 --- a/gluon/contrib/simplejsonrpc.py +++ b/gluon/contrib/simplejsonrpc.py @@ -17,12 +17,17 @@ __copyright__ = "Copyright (C) 2011 Mariano Reingart" __license__ = "LGPL 3.0" __version__ = "0.05" +import sys +PY2 = sys.version_info[0] == 2 import urllib -from xmlrpclib import Transport, SafeTransport -from cStringIO import StringIO +if PY2: + from xmlrpclib import Transport, SafeTransport + from cStringIO import StringIO +else: + from xmlrpc.client import Transport, SafeTransport + from io import StringIO import random -import sys import json From e9473f570f9427ae168f3603bf7576779cc6bcff Mon Sep 17 00:00:00 2001 From: sasa Date: Sun, 25 Sep 2016 20:03:23 +0200 Subject: [PATCH 30/49] Translation for serbian --- applications/admin/languages/sr-cr.py | 438 ++++++++++++------------ applications/admin/languages/sr-lt.py | 467 +++++++++++++------------- 2 files changed, 453 insertions(+), 452 deletions(-) diff --git a/applications/admin/languages/sr-cr.py b/applications/admin/languages/sr-cr.py index 56a9a384..882819b4 100755 --- a/applications/admin/languages/sr-cr.py +++ b/applications/admin/languages/sr-cr.py @@ -5,64 +5,64 @@ '"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN': '"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN', '"User Exception" debug mode. ': '"User Exception" debug mode. ', '%s': '%s', -'%s %%{row} deleted': '%s %%{row} deleted', -'%s %%{row} updated': '%s %%{row} updated', +'%s %%{row} deleted': '%s %%{row} је избрисан', +'%s %%{row} updated': '%s %%{row} је ажуриран', '%s selected': '%s selected', '%s students registered': '%s students registered', '%Y-%m-%d': '%d-%m-%Y', '%Y-%m-%d %H:%M:%S': '%d-%m-%Y %H:%M:%S', '(requires internet access)': '(захтијева приступ интернету)', -'(requires internet access, experimental)': '(requires internet access, experimental)', -'(something like "it-it")': '(нешто као "it-it")', +'(requires internet access, experimental)': '(захтијева приступ интернету, експериментално)', +'(something like "it-it")': '(на примјер "it-it")', '(version %s)': '(version %s)', '?': '?', '@markmin\x01(file **gluon/contrib/plural_rules/%s.py** is not found)': '(датотека **gluon/contrib/plural_rules/%s.py** није пронађена)', -'Abort': 'Abort', +'Abort': 'Одустани', 'About': 'Информације', 'About application': 'О апликацији', -'Accept Terms': 'Accept Terms', +'Accept Terms': 'Прихватање услова коришћења', 'Add breakpoint': 'Add breakpoint', 'Additional code for your application': 'Додатни код за апликацију', 'Admin design page': 'Admin design page', -'admin disabled because no admin password': 'admin disabled because no admin password', -'admin disabled because not supported on google app engine': 'admin disabled because not supported on google app engine', -'admin disabled because too many invalid login attempts': 'admin disabled because too many invalid login attempts', +'admin disabled because no admin password': 'администрација онемогућена јер нема лозинке', +'admin disabled because not supported on google app engine': 'администрација онемогућена на google app engine', +'admin disabled because too many invalid login attempts': 'администрација онемогућена због већег броја неуспјелих покушаја', 'admin disabled because unable to access password file': 'администрација онемогућена јер не могу приступити датотеци са лозинком', -'Admin is disabled because insecure channel': 'Admin is disabled because insecure channel', +'Admin is disabled because insecure channel': 'Администрација онемогућена због несигурне везе', 'Admin language': 'Језик администратора', 'Admin versioning page': 'Admin versioning page', -'administrative interface': 'административни интерфејс', +'administrative interface': 'административно окружење', 'Administrator Password:': 'Лозинка администратора:', 'and rename it:': 'и преименуј у:', -'App does not exist or you are not authorized': 'App does not exist or you are not authorized', +'App does not exist or you are not authorized': 'Апликација не постоји или немате права приступа', 'appadmin': 'appadmin', -'appadmin is disabled because insecure channel': 'appadmin is disabled because insecure channel', -'Application': 'Application', -'application "%s" uninstalled': 'application "%s" uninstalled', +'appadmin is disabled because insecure channel': 'администрација онемогућена због несигурне везе', +'Application': 'Апликација', +'application "%s" uninstalled': 'апликација "%s" је деинсталирана', 'Application cannot be generated in demo mode': 'Application cannot be generated in demo mode', -'application compiled': 'application compiled', -'Application exists already': 'Application exists already', -'application is compiled and cannot be designed': 'application is compiled and cannot be designed', +'application compiled': 'апликација је компајлирана', +'Application exists already': 'Апликација већ постоји', +'application is compiled and cannot be designed': 'апликација је компајлирана и не може се даље уређивати', 'Application name:': 'Назив апликације:', -'Application updated via git pull': 'Application updated via git pull', +'Application updated via git pull': 'Апликација ажурирана преко git pull', 'are not used': 'није кориштено', 'are not used yet': 'није још кориштено', -'Are you sure you want to delete file "%s"?': 'Are you sure you want to delete file "%s"?', -'Are you sure you want to delete plugin "%s"?': 'Are you sure you want to delete plugin "%s"?', +'Are you sure you want to delete file "%s"?': 'Да ли сте сигурни да желите избрисати датотеку "%s"?', +'Are you sure you want to delete plugin "%s"?': 'Да ли сте сигурни да желите избрисати помоћни модул "%s"?', 'Are you sure you want to delete this object?': 'Да ли сте сигурни да желите обрисати?', -'Are you sure you want to uninstall application "%s"?': 'Are you sure you want to uninstall application "%s"?', -'Are you sure?': 'Are you sure?', +'Are you sure you want to uninstall application "%s"?': 'Да ли сте сигурни да желите деинсталирати апликацију "%s"?', +'Are you sure?': 'Да ли сте сигурни?', 'arguments': 'arguments', 'at char %s': 'код слова %s', 'at line %s': 'на линији %s', -'ATTENTION:': 'ATTENTION:', +'ATTENTION:': 'ПАЖЊА:', 'ATTENTION: Login requires a secure (HTTPS) connection or running on localhost.': 'ATTENTION: Login requires a secure (HTTPS) connection or running on localhost.', 'ATTENTION: TESTING IS NOT THREAD SAFE SO DO NOT PERFORM MULTIPLE TESTS CONCURRENTLY.': 'ATTENTION: TESTING IS NOT THREAD SAFE SO DO NOT PERFORM MULTIPLE TESTS CONCURRENTLY.', -'ATTENTION: you cannot edit the running application!': 'ATTENTION: you cannot edit the running application!', +'ATTENTION: you cannot edit the running application!': 'ПАЖЊА: не можете уређивати покренуту апликацију!', 'Autocomplete Python Code': 'Autocomplete Python Code', -'Available Databases and Tables': 'Available Databases and Tables', +'Available Databases and Tables': 'Доступне базе података и табеле', 'back': 'назад', -'Back to the plugins list': 'Back to the plugins list', +'Back to the plugins list': 'Назад на листу помоћних модула', 'Back to wizard': 'Back to wizard', 'Basics': 'Основе', 'Begin': 'Почетак', @@ -71,19 +71,19 @@ 'breakpoints': 'breakpoints', 'Bulk Register': 'Bulk Register', 'Bulk Student Registration': 'Bulk Student Registration', -'Cache': 'Cache', -'cache': 'cache', +'Cache': 'Кеш', +'cache': 'кеш', 'Cache Cleared': 'Cache Cleared', 'Cache Keys': 'Cache Keys', 'cache, errors and sessions cleaned': 'кеш, грешке и сесије су обрисани', -'can be a git repo': 'може бити git repo', -'Cancel': 'Cancel', -'Cannot be empty': 'Cannot be empty', -'Cannot compile: there are errors in your app:': 'Cannot compile: there are errors in your app:', -'cannot create file': 'cannot create file', +'can be a git repo': 'може бити git репозиторијум', +'Cancel': 'Откажи', +'Cannot be empty': 'Не може бити празно', +'Cannot compile: there are errors in your app:': 'Не могу компајлирати: грешка у апликацији:', +'cannot create file': 'не могу креирати датотеку', 'cannot upload file "%(filename)s"': 'не мофу отпремити датотеку "%(filename)s"', -'Change Admin Password': 'Change Admin Password', -'Change admin password': 'Промијени лзинку администратора', +'Change Admin Password': 'Промијени лозинку администратора', +'Change admin password': 'Промијени лозинку администратора', 'change editor settings': 'change editor settings', 'Changelog': 'Changelog', 'check all': 'check all', @@ -91,66 +91,66 @@ 'Check to delete': 'Check to delete', 'Checking for upgrades...': 'Провјеравам могућност надоградње...', 'Clean': 'Прочисти', -'Clear': 'Clear', -'Clear CACHE?': 'Clear CACHE?', -'Clear DISK': 'Clear DISK', -'Clear RAM': 'Clear RAM', +'Clear': 'Обриши', +'Clear CACHE?': 'Обриши CACHE?', +'Clear DISK': 'Обриши DISK', +'Clear RAM': 'Обриши RAM', 'Click row to expand traceback': 'Click row to expand traceback', 'Click row to view a ticket': 'Click row to view a ticket', 'code': 'код', -'Code listing': 'Code listing', +'Code listing': 'Приказ кода', 'collapse/expand all': 'сакрити/приказати све', -'Command': 'Command', -'Comment:': 'Comment:', +'Command': 'Наредба', +'Comment:': 'Коментар:', 'Commit': 'Commit', 'Commit form': 'Commit form', 'Committed files': 'Committed files', 'Compile': 'Компајлирај', -'Compile (all or nothing)': 'Compile (all or nothing)', -'Compile (skip failed views)': 'Compile (skip failed views)', -'compiled application removed': 'compiled application removed', -'Condition': 'Condition', -'continue': 'continue', +'Compile (all or nothing)': 'Компајлирај (све или ништа)', +'Compile (skip failed views)': 'Компајлирај (игнориши грешке)', +'compiled application removed': 'компајлирана апликација је уклоњена', +'Condition': 'Стање', +'continue': 'настави', 'Controllers': 'Контролери', 'controllers': 'контролери', -'Count': 'Count', +'Count': 'Редни број', 'Create': 'Креирај', 'create file with filename:': 'Креирај датотеку под називом:', 'Create rules': 'Креирај правила', -'Create/Upload': 'Create/Upload', +'Create/Upload': 'Креирај/Преузми', 'created by': 'израдио', 'Created by:': 'Created by:', 'Created On': 'Created On', 'Created on:': 'Created on:', 'crontab': 'crontab', -'Current request': 'Current request', -'Current response': 'Current response', -'Current session': 'Current session', +'Current request': 'Тренутни захтјев', +'Current response': 'Тренутни одговор', +'Current session': 'Тренутна сесија', 'currently running': 'тренутно покренут', 'currently saved or': 'тренутно сачувано или', 'data uploaded': 'data uploaded', -'Database': 'Database', +'Database': 'База података', 'Database %s select': 'Database %s select', -'Database administration': 'Database administration', +'Database administration': 'Администрација базе података', 'database administration': 'администрација базе података', -'Database Administration (appadmin)': 'Database Administration (appadmin)', -'Date and Time': 'Date and Time', +'Database Administration (appadmin)': 'Администрација базе података (appadmin)', +'Date and Time': 'Датум и вријеме', 'db': 'db', -'Debug': 'Debug', +'Debug': 'Отклони грешку', 'defines tables': 'дефинише табеле', 'Delete': 'Обриши', 'delete': 'обриши', -'delete all checked': 'delete all checked', -'delete plugin': 'delete plugin', -'Delete this file (you will be asked to confirm deletion)': 'Обриши ову даатотеку (бићете упитани за потврду брисања)', -'Delete:': 'Delete:', +'delete all checked': 'избриши све означено', +'delete plugin': 'избриши помоћни модул', +'Delete this file (you will be asked to confirm deletion)': 'Обриши ову датотеку (бићете упитани за потврду брисања)', +'Delete:': 'Избриши:', 'deleted after first hit': 'deleted after first hit', 'Demo': 'Demo', 'Deploy': 'Постави', 'Deploy on Google App Engine': 'Постави на Google App Engine', 'Deploy to OpenShift': 'Постави на OpenShift', -'Deploy to pythonanywhere': 'Deploy to pythonanywhere', -'Deploy to PythonAnywhere': 'Deploy to PythonAnywhere', +'Deploy to pythonanywhere': 'Постави на pythonanywhere', +'Deploy to PythonAnywhere': 'Постави на PythonAnywhere', 'Deployment form': 'Deployment form', 'Deployment Interface': 'Deployment Interface', 'Description:': 'Description:', @@ -160,10 +160,10 @@ 'direction: ltr': 'direction: ltr', 'directory not found': 'directory not found', 'Disable': 'Искључи', -'Disabled': 'Disabled', -'disabled in demo mode': 'disabled in demo mode', -'disabled in GAE mode': 'disabled in GAE mode', -'disabled in multi user mode': 'disabled in multi user mode', +'Disabled': 'Искључено', +'disabled in demo mode': 'онемогућено у демо моду', +'disabled in GAE mode': 'онемогућено у GAE моду', +'disabled in multi user mode': 'онемогућено у вишекорисничком моду', 'DISK': 'DISK', 'Disk Cache Keys': 'Disk Cache Keys', 'Disk Cleared': 'Disk Cleared', @@ -173,20 +173,20 @@ 'Docs': 'Docs', 'done!': 'done!', 'Downgrade': 'Downgrade', -'Download .w2p': 'Download .w2p', -'Download as .exe': 'Download as .exe', +'Download .w2p': 'Преузми као .w2p', +'Download as .exe': 'Преузми као .exe', 'download layouts': 'преузми layouts', 'Download layouts from repository': 'Download layouts from repository', -'download plugins': 'преузми plugins', -'Download plugins from repository': 'Download plugins from repository', -'Edit': 'Уређивање', +'download plugins': 'преузми помоћне модуле', +'Download plugins from repository': 'Преузми помоћне модуле из репозиторијум', +'Edit': 'Уреди', 'edit all': 'уреди све', 'Edit application': 'Уреди апликацију', 'edit controller': 'уреди контролер', 'edit controller:': 'edit controller:', 'Edit current record': 'Edit current record', -'edit views:': 'уреди views:', -'Editing %s': 'Editing %s', +'edit views:': 'уреди приказ:', +'Editing %s': 'Уређивање %s', 'Editing file "%s"': 'Уређивање датотеке "%s"', 'Editing Language file': 'Уређивање језичке датотеке', 'Editing Plural Forms File': 'Editing Plural Forms File', @@ -206,21 +206,21 @@ 'Exit Fullscreen': 'Exit Fullscreen', 'Expand Abbreviation': 'Expand Abbreviation', 'Expand Abbreviation (html files only)': 'Expand Abbreviation (html files only)', -'export as csv file': 'export as csv file', -'Exports:': 'Exports:', -'exposes': 'exposes', -'exposes:': 'exposes:', +'export as csv file': 'извези као csv датотеку', +'Exports:': 'Извози:', +'exposes': 'приказује', +'exposes:': 'приказује:', 'extends': 'проширује', 'failed to compile file because:': 'нисам могао да компајлирам због:', 'failed to reload module because:': 'failed to reload module because:', 'File': 'Датотека', -'file "%(filename)s" created': 'file "%(filename)s" created', -'file "%(filename)s" deleted': 'file "%(filename)s" deleted', -'file "%(filename)s" uploaded': 'file "%(filename)s" uploaded', -'file "%s" of %s restored': 'file "%s" of %s restored', +'file "%(filename)s" created': 'датотека "%(filename)s" је креирана', +'file "%(filename)s" deleted': 'датотека "%(filename)s" је избрисана', +'file "%(filename)s" uploaded': 'датотека "%(filename)s" је отпремљена', +'file "%s" of %s restored': 'датотека "%s" од %s е враћено у претходно стање', 'file changed on disk': 'file changed on disk', 'file does not exist': 'датотека не постоји', -'file not found': 'file not found', +'file not found': 'датотека није пронађена', 'file saved on %(time)s': 'file saved on %(time)s', 'file saved on %s': 'датотека сачувана на %s', 'filename': 'filename', @@ -242,7 +242,7 @@ 'Globals##debug': 'Globals##debug', 'Go to Matching Pair': 'Go to Matching Pair', 'go!': 'крени!', -'Google App Engine Deployment Interface': 'Google App Engine Deployment Interface', +'Google App Engine Deployment Interface': 'Google App Engine Dинсталационо окружење', 'Google Application Id': 'Google Application Id', 'Goto': 'Goto', 'graph model': 'graph model', @@ -260,7 +260,7 @@ 'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\nA green title indicates that all tests (if defined) passed. In this case test results are not shown.': 'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\nA green title indicates that all tests (if defined) passed. In this case test results are not shown.', 'if your application uses a database other than sqlite you will then have to configure its DAL in pythonanywhere.': 'if your application uses a database other than sqlite you will then have to configure its DAL in pythonanywhere.', 'import': 'import', -'Import/Export': 'Import/Export', +'Import/Export': 'инсталационо окружење', 'In development, use the default Rocket webserver that is currently supported by this debugger.': 'In development, use the default Rocket webserver that is currently supported by this debugger.', 'includes': 'укључује', 'Indent with tabs': 'Indent with tabs', @@ -270,49 +270,49 @@ 'Installed applications': 'Инсталиране апликације', 'Interaction at %s line %s': 'Interaction at %s line %s', 'Interactive console': 'Interactive console', -'internal error': 'internal error', -'internal error: %s': 'internal error: %s', +'internal error': 'унутрашња грешка', +'internal error: %s': 'унутрашња грешка: %s', 'Internal State': 'Internal State', 'Invalid action': 'Invalid action', 'Invalid application name': 'Invalid application name', 'invalid circular reference': 'invalid circular reference', 'Invalid git repository specified.': 'Invalid git repository specified.', -'invalid password': 'invalid password', -'invalid password.': 'погрешна лозинка.', -'Invalid Query': 'Invalid Query', +'invalid password': 'Неважећа лозинка', +'invalid password.': 'неважећа лозинка.', +'Invalid Query': 'Погрешан упит', 'invalid request': 'invalid request', 'Invalid request': 'Invalid request', 'invalid table names (auth_* tables already defined)': 'invalid table names (auth_* tables already defined)', -'invalid ticket': 'invalid ticket', +'invalid ticket': 'погрешан тикет', 'Key': 'Key', 'Key bindings': 'Пречице', 'Key bindings for ZenCoding Plugin': 'Пречице за ZenCoding Plugin', -'Keyboard shortcuts': 'Keyboard shortcuts', +'Keyboard shortcuts': 'Пречице на тастатури', 'kill process': 'kill process', -'language file "%(filename)s" created/updated': 'language file "%(filename)s" created/updated', +'language file "%(filename)s" created/updated': 'језичка датотека "%(filename)s" је креирана/ажурирана', 'Language files (static strings) updated': 'Језичке датотеке су ажуриране', 'languages': 'језици', 'Languages': 'Језици', 'Last Revision': 'Last Revision', 'Last saved on:': 'Посљедња измјена:', 'License for': 'Лиценца за', -'License:': 'License:', +'License:': 'Лиценца:', 'Line Nr': 'Line Nr', -'Line number': 'Line number', -'lists by exception': 'lists by exception', -'lists by ticket': 'lists by ticket', -'Loading...': 'Loading...', +'Line number': 'Линија број', +'lists by exception': 'прикажи грешке', +'lists by ticket': 'прикажи тикете', +'Loading...': 'Преузимам...', 'loading...': 'преузимам...', -'Local Apps': 'Local Apps', +'Local Apps': 'Локалне апликације', 'locals': 'locals', 'Locals##debug': 'Locals##debug', 'Login': 'Пријава', 'Login successful': 'Login successful', -'Login to the Administrative Interface': 'Пријава за административни интерфејс', -'Login/Register': 'Login/Register', -'Logout': 'Излаз', -'lost password': 'lost password', -'Main Menu': 'Main Menu', +'Login to the Administrative Interface': 'Пријава за административно окружење', +'Login/Register': 'Пријава/Регистрација', +'Logout': 'Одјава', +'lost password': 'изгубљена лозинка', +'Main Menu': 'Главни мени', 'Manage': 'Manage', 'Manage %(action)s': 'Manage %(action)s', 'Manage Access Control': 'Manage Access Control', @@ -321,68 +321,68 @@ 'Manage Students': 'Manage Students', 'Match Pair': 'Match Pair', 'Memberships': 'Memberships', -'merge': 'merge', +'merge': 'споји', 'Merge Lines': 'Споји линије', -'Models': 'Models', -'models': 'models', +'Models': 'Модели', +'models': 'Модели', 'Modified On': 'Modified On', -'Modules': 'Modules', -'modules': 'modules', -'Multi User Mode': 'Multi User Mode', -'new application "%s" created': 'new application "%s" created', -'new application "%s" imported': 'new application "%s" imported', +'Modules': 'Модули', +'modules': 'модули', +'Multi User Mode': 'Вишекориснички режим рада', +'new application "%s" created': 'нова апликација "%s" је креирана', +'new application "%s" imported': 'нова апликација "%s" је увежена', 'New Application Wizard': 'Чаробњак за нове апликације', 'New application wizard': 'Чаробњак за нове апликације', -'new plugin installed': 'new plugin installed', -'New plugin installed: %s': 'New plugin installed: %s', -'New Record': 'New Record', -'new record inserted': 'new record inserted', +'new plugin installed': 'нови помоћни модул је инсталиран', +'New plugin installed: %s': 'Инсталиран нови помоћни модул: %s', +'New Record': 'Нови запис', +'new record inserted': 'унешен нови запис', 'New simple application': 'Нова једноставна апликација', -'next': 'next', +'next': 'следећи', 'next %s rows': 'next %s rows', 'Next Edit Point': 'Next Edit Point', -'NO': 'NO', -'no changes': 'no changes', -'No databases in this application': 'No databases in this application', -'No Interaction yet': 'No Interaction yet', -'no match': 'no match', -'no package selected': 'no package selected', -'no permission to uninstall "%s"': 'no permission to uninstall "%s"', +'NO': 'НЕ', +'no changes': 'нема промјена', +'No databases in this application': 'Нема базе података у апликацији', +'No Interaction yet': 'Нема још интеракције', +'no match': 'нема подударања', +'no package selected': 'пакет није одабран', +'no permission to uninstall "%s"': 'немате овлаштење да деинсталирате "%s"', 'No ticket_storage.txt found under /private folder': 'No ticket_storage.txt found under /private folder', 'Node:': 'Node:', -'Not Authorized': 'Not Authorized', -'Not supported': 'Not supported', +'Not Authorized': 'Немате овлашћење', +'Not supported': 'Није подржано', 'Note: If you receive an error with github status code of 128, ensure the system and account you are deploying from has a cooresponding ssh key configured in the openshift account.': 'Note: If you receive an error with github status code of 128, ensure the system and account you are deploying from has a cooresponding ssh key configured in the openshift account.', "On production, you'll have to configure your webserver to use one process and multiple threads to use this debugger.": "On production, you'll have to configure your webserver to use one process and multiple threads to use this debugger.", 'online designer': 'онлајн дизајнер', -'Open new app in new window': 'Open new app in new window', -'OpenShift Deployment Interface': 'OpenShift Deployment Interface', +'Open new app in new window': 'Отвори нову апликацију у новом прозору', +'OpenShift Deployment Interface': 'OpenShift инсталационо окружење', 'OpenShift Output': 'OpenShift Output', -'or alternatively': 'or alternatively', +'or alternatively': 'или алтернативно', 'Or Get from URL:': 'Or Get from URL:', -'or import from csv file': 'or import from csv file', +'or import from csv file': 'или увези помоћу csv датотеке', 'Original/Translation': 'Оргинал/Превод', -'Overview': 'Overview', -'Overwrite installed app': 'Пребриши постојећу апликацију', +'Overview': 'Преглед', +'Overwrite installed app': 'Замјени већ постојећу апликацију', 'Pack all': 'Запакуј све', -'Pack compiled': 'Pack compiled', -'Pack custom': 'Pack custom', -'pack plugin': 'pack plugin', -'password changed': 'password changed', -'Past revisions': 'Past revisions', +'Pack compiled': 'Запакуј компајлирано', +'Pack custom': 'Прилагођено паковање', +'pack plugin': 'запакуј помоћни модул', +'password changed': 'лозинка је промијењена', +'Past revisions': 'Претходне корекције', 'Path to appcfg.py': 'Path to appcfg.py', 'Path to local openshift repo root.': 'Path to local openshift repo root.', -'Peeking at file': 'Peeking at file', -'Permission': 'Permission', -'Permissions': 'Permissions', -'Please': 'Please', +'Peeking at file': 'Преглед датотеке', +'Permission': 'Дозвола', +'Permissions': 'Дозволе', +'Please': 'Молим', 'Please wait, giving pythonanywhere a moment...': 'Please wait, giving pythonanywhere a moment...', -'plugin "%(plugin)s" deleted': 'plugin "%(plugin)s" deleted', -'Plugin "%s" in application': 'Plugin "%s" in application', +'plugin "%(plugin)s" deleted': 'помоћни модул "%(plugin)s" је избрисан', +'Plugin "%s" in application': 'Помоћни модул "%s" у апликацији', 'plugin not specified': 'plugin not specified', -'Plugin page': 'Plugin page', -'plugins': 'plugins', -'Plugins': 'Plugins', +'Plugin page': 'Страница помоћних модула', +'plugins': 'помоћни модули', +'Plugins': 'Помоћни модули', 'Plural Form #%s': 'Plural Form #%s', 'Plural-Forms:': 'Plural-Forms:', 'Powered by': 'Омогућио', @@ -390,8 +390,8 @@ 'Preferences saved on session only': 'Preferences saved on session only', 'previous %s rows': 'previous %s rows', 'Previous Edit Point': 'Previous Edit Point', -'Private files': 'Private files', -'private files': 'private files', +'Private files': 'Приватне датотеке', +'private files': 'приватне датотеке', 'Project Progress': 'Напредак пројекта', 'Pull': 'Pull', 'Pull failed, certain files could not be checked out. Check logs for details.': 'Pull failed, certain files could not be checked out. Check logs for details.', @@ -401,7 +401,7 @@ 'pygraphviz library not found': 'pygraphviz library not found', 'PythonAnywhere Apps': 'PythonAnywhere Apps', 'PythonAnywhere Password': 'PythonAnywhere Password', -'Query:': 'Query:', +'Query:': 'Упит:', 'RAM': 'RAM', 'RAM Cache Keys': 'RAM Cache Keys', 'Ram Cleared': 'Ram Cleared', @@ -412,11 +412,11 @@ 'refresh': 'refresh', 'register': 'register', 'Reload routes': 'Обнови преусмјерења', -'Remove compiled': 'Remove compiled', +'Remove compiled': 'Уклони компајлирано', 'Removed Breakpoint on %s at line %s': 'Removed Breakpoint on %s at line %s', 'Replace': 'Замијени', 'Replace All': 'Замијени све', -'Repository (%s)': 'Repository (%s)', +'Repository (%s)': 'Репозиторијум (%s)', 'request': 'request', 'requires distutils, but not installed': 'requires distutils, but not installed', 'requires python-git, but not installed': 'requires python-git, but not installed', @@ -430,28 +430,28 @@ 'reverted to revision %s': 'reverted to revision %s', 'Revision %s': 'Revision %s', 'Revision:': 'Revision:', -'Role': 'Role', -'Roles': 'Roles', -'Rows in Table': 'Rows in Table', +'Role': 'Улога', +'Roles': 'Улоге', +'Rows in Table': 'Записи у табели', 'Rows selected': 'Rows selected', 'rules are not defined': 'правила нису дефинисана', 'rules:': 'правила:', -'Run tests': 'Run tests', -'Run tests in this file': 'Run tests in this file', +'Run tests': 'Покрени тестове', +'Run tests in this file': 'Покрени тестове у датотеци', "Run tests in this file (to run all files, you may also use the button labelled 'test')": "Run tests in this file (to run all files, you may also use the button labelled 'test')", 'Running on %s': 'Покренути на %s', 'Save': 'Сачувај', -'Save file:': 'Save file:', -'Save file: %s': 'Save file: %s', -'Save model as...': 'Save model as...', -'Save via Ajax': 'сачувај via Ajax', +'Save file:': 'Сачувај датотеку:', +'Save file: %s': 'Сачувај датотеку: %s', +'Save model as...': 'Сачувај модел као...', +'Save via Ajax': 'Сачувај преко Ajax', 'Saved file hash:': 'Сачувано као хаш:', -'Screenshot %s': 'Screenshot %s', -'Search': 'Search', -'Select Files to Package': 'Select Files to Package', +'Screenshot %s': 'Снимак екрана %s', +'Search': 'Претрага', +'Select Files to Package': 'Одабери датотеке за паковање', 'session': 'сесија', -'session expired': 'сесија истекла', -'Session saved correctly': 'Session saved correctly', +'session expired': 'сесија је истекла', +'Session saved correctly': 'Сесија је уредно сачувана', 'Session saved on session only': 'Session saved on session only', 'Set Breakpoint on %s at line %s: %s': 'Set Breakpoint on %s at line %s: %s', 'shell': 'shell', @@ -459,10 +459,10 @@ 'Singular Form': 'Singular Form', 'Site': 'Сајт', 'Size of cache:': 'Size of cache:', -'skip to generate': 'skip to generate', -'some files could not be removed': 'some files could not be removed', +'skip to generate': 'прескочи генерисање', +'some files could not be removed': 'неке датотеке не могу бити уклоњене', 'Something went wrong please wait a few minutes before retrying': 'Something went wrong please wait a few minutes before retrying', -'Sorry, could not find mercurial installed': 'Sorry, could not find mercurial installed', +'Sorry, could not find mercurial installed': 'Жалим, mercurial није инсталиран', 'source : db': 'source : db', 'source : filesystem': 'source : filesystem', 'Start a new app': 'Покрени нову апликацију', @@ -474,15 +474,15 @@ 'Static files': 'Static files', 'Statistics': 'Statistics', 'Step': 'Корак', -'step': 'step', +'step': 'kорак', 'stop': 'stop', -'submit': 'submit', +'submit': 'прихвати', 'Submit': 'Прихвати', 'successful': 'успјешан', -'switch to : db': 'switch to : db', -'switch to : filesystem': 'switch to : filesystem', +'switch to : db': 'пређи на : db', +'switch to : filesystem': 'пређи на : filesystem', 'Tab width (# characters)': 'Tab width (# characters)', -'Table': 'Table', +'Table': 'Табела', 'Temporary': 'Temporary', 'test': 'тест', 'Testing application': 'Тестирање апликације', @@ -492,16 +492,16 @@ 'The application logic, each URL path is mapped in one exposed function in the controller': 'The application logic, each URL path is mapped in one exposed function in the controller', 'The data representation, define database tables and sets': 'The data representation, define database tables and sets', 'The presentations layer, views are also known as templates': 'The presentations layer, views are also known as templates', -'Theme': 'Theme', -'There are no controllers': 'There are no controllers', -'There are no models': 'There are no models', -'There are no modules': 'There are no modules', -'There are no plugins': 'There are no plugins', -'There are no private files': 'There are no private files', -'There are no static files': 'There are no static files', -'There are no translators': 'There are no translators', +'Theme': 'Табела', +'There are no controllers': 'Нема контолера', +'There are no models': 'Нема модела', +'There are no modules': 'Нема модула', +'There are no plugins': 'Нема помоћних модула', +'There are no private files': 'Нема приватних датотека', +'There are no static files': 'Нема статичних датотека', +'There are no translators': 'Нема преводиоца', 'There are no translators, only default language is supported': 'There are no translators, only default language is supported', -'There are no views': 'There are no views', +'There are no views': 'Нема преводиоца', 'These files are not served, they are only available from within your app': 'These files are not served, they are only available from within your app', 'These files are served without processing, your images go here': 'These files are served without processing, your images go here', "This debugger may not work properly if you don't have a threaded webserver or you're using multiple daemon processes.": "This debugger may not work properly if you don't have a threaded webserver or you're using multiple daemon processes.", @@ -512,9 +512,9 @@ 'this page to see if a breakpoint was hit and debug interaction is required.': 'this page to see if a breakpoint was hit and debug interaction is required.', 'This will pull changes from the remote repo for application "%s"?': 'This will pull changes from the remote repo for application "%s"?', 'This will push changes to the remote repo for application "%s".': 'This will push changes to the remote repo for application "%s".', -'Ticket': 'Ticket', -'Ticket ID': 'Ticket ID', -'Ticket Missing': 'Ticket nedostaje', +'Ticket': 'Тикет', +'Ticket ID': 'Тикет ID', +'Ticket Missing': 'Недостаје тикет', 'Time in Cache (h:m:s)': 'Time in Cache (h:m:s)', 'to previous version.': 'на претходну верзију.', 'To create a plugin, name a file/folder plugin_[name]': 'To create a plugin, name a file/folder plugin_[name]', @@ -525,67 +525,67 @@ 'Toggle Fullscreen': 'Toggle Fullscreen', 'Traceback': 'Traceback', 'Translation strings for the application': 'Ријечи у апликацији које треба превести', -'try something like': 'try something like', -'Try the mobile interface': 'Пробај мобилни интерфејс', -'try view': 'try view', +'try something like': 'на примјер', +'Try the mobile interface': 'Пробај мобилнo окружење', +'try view': 'пробај приказ', 'Type PDB debugger command in here and hit Return (Enter) to execute it.': 'Type PDB debugger command in here and hit Return (Enter) to execute it.', 'Type some Python code in here and hit Return (Enter) to execute it.': 'Type some Python code in here and hit Return (Enter) to execute it.', -'Unable to check for upgrades': 'Unable to check for upgrades', +'Unable to check for upgrades': 'Не могу да провјерим могућност надоградње', 'unable to create application "%s"': 'unable to create application "%s"', -'unable to delete file "%(filename)s"': 'unable to delete file "%(filename)s"', -'unable to delete file plugin "%(plugin)s"': 'unable to delete file plugin "%(plugin)s"', -'Unable to determine the line number!': 'Unable to determine the line number!', -'Unable to download app because:': 'Unable to download app because:', +'unable to delete file "%(filename)s"': 'не могу избрисати датотеку "%(filename)s"', +'unable to delete file plugin "%(plugin)s"': 'не могу избрисати помоћни модул "%(plugin)s"', +'Unable to determine the line number!': 'Не могу да утврдим број реда!', +'Unable to download app because:': 'Не могу да преузмем апликацију због:', 'unable to download layout': 'unable to download layout', 'unable to download plugin: %s': 'unable to download plugin: %s', -'Unable to download the list of plugins': 'Unable to download the list of plugins', -'unable to install plugin "%s"': 'unable to install plugin "%s"', -'unable to parse csv file': 'unable to parse csv file', -'unable to uninstall "%s"': 'unable to uninstall "%s"', -'unable to upgrade because "%s"': 'unable to upgrade because "%s"', +'Unable to download the list of plugins': 'Не могу да преузмем списак помоћних модула', +'unable to install plugin "%s"': 'не могу да инсталирам помоћни модул "%s"', +'unable to parse csv file': 'не могу да расчланим csv датотеку', +'unable to uninstall "%s"': 'не могу да деинсталирам "%s"', +'unable to upgrade because "%s"': 'не могу да ажуримам због "%s"', 'uncheck all': 'uncheck all', 'Uninstall': 'Деинсталирај', 'Unsupported webserver working mode: %s': 'Unsupported webserver working mode: %s', 'update': 'ажурирај', 'update all languages': 'ажурирај све језике', -'Update:': 'Update:', -'Upgrade': 'Upgrade', -'upgrade now to %s': 'upgrade now to %s', +'Update:': 'Ажурирај:', +'Upgrade': 'Надоградња', +'upgrade now to %s': 'ажуриран на %s', 'upload': 'Отпреми', -'Upload': 'Upload', +'Upload': 'Преузми', 'Upload a package:': 'Преузми пакет:', 'Upload and install packed application': 'Преузми и инсталирај запаковану апликацију', 'upload file:': 'преузми датотеку:', -'upload plugin file:': 'преузми плагин датотеку:', +'upload plugin file:': 'преузми датотеку помоћног модула:', 'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.', -'User': 'User', -'Username': 'Username', -'Users': 'Users', +'User': 'Корисник', +'Username': 'Корисничко име', +'Users': 'Корисници', 'Using the shell may lock the database to other users of this app.': 'Using the shell may lock the database to other users of this app.', 'variables': 'variables', 'Version': 'Верзија', 'Version %s.%s.%s (%s) %s': 'Верзија %s.%s.%s (%s) %s', -'Versioning': 'Versioning', -'Views': 'Views', -'views': 'views', -'Warning!': 'Warning!', -'WARNING:': 'WARNING:', +'Versioning': 'Креирање верзија', +'Views': 'Прикази', +'views': 'прикази', +'Warning!': 'Упозорење!', +'WARNING:': 'УПОЗОРЕЊЕ:', 'WARNING: The following views could not be compiled:': 'WARNING: The following views could not be compiled:', 'Web Framework': 'Web Framework', -'web2py Admin Password': 'web2py Admin Password', -'web2py apps to deploy': 'web2py apps to deploy', +'web2py Admin Password': 'web2py администраторска лозинка', +'web2py apps to deploy': 'web2py апликација за инсталацију', 'web2py Debugger': 'web2py Debugger', 'web2py downgrade': 'web2py downgrade', 'web2py is up to date': 'web2py је ажуран', 'web2py online debugger': 'web2py online debugger', 'web2py Recent Tweets': 'web2py Recent Tweets', -'web2py upgrade': 'web2py upgrade', -'web2py upgraded; please restart it': 'web2py upgraded; please restart it', -'Working...': 'Working...', +'web2py upgrade': 'web2py надоградња', +'web2py upgraded; please restart it': 'web2py је ажуриран; молим да рестартујете', +'Working...': 'Извршавам...', 'Wrap with Abbreviation': 'Wrap with Abbreviation', 'WSGI reference name': 'WSGI reference name', -'YES': 'YES', -'Yes': 'Yes', +'YES': 'ДА', +'Yes': 'Да', 'You can also set and remove breakpoint in the edit window, using the Toggle Breakpoint button': 'You can also set and remove breakpoint in the edit window, using the Toggle Breakpoint button', 'You can inspect variables using the console below': 'You can inspect variables using the console below', 'You have one more login attempt before you are locked out': 'You have one more login attempt before you are locked out', diff --git a/applications/admin/languages/sr-lt.py b/applications/admin/languages/sr-lt.py index 659cb84e..4f6ad085 100755 --- a/applications/admin/languages/sr-lt.py +++ b/applications/admin/languages/sr-lt.py @@ -5,64 +5,65 @@ '"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN': '"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN', '"User Exception" debug mode. ': '"User Exception" debug mode. ', '%s': '%s', -'%s %%{row} deleted': '%s %%{row} deleted', -'%s %%{row} updated': '%s %%{row} updated', +'%s %%{row} deleted': '%s %%{row} je izbrisan', +'%s %%{row} updated': '%s %%{row} je ažuriran', '%s selected': '%s selected', '%s students registered': '%s students registered', '%Y-%m-%d': '%d-%m-%Y', '%Y-%m-%d %H:%M:%S': '%d-%m-%Y %H:%M:%S', '(requires internet access)': '(zahtijeva pristup internetu)', -'(requires internet access, experimental)': '(requires internet access, experimental)', -'(something like "it-it")': '(nešto kao "it-it")', +'(requires internet access, experimental)': '(zahtijeva pristup internetu, eksperimentalno)', +'(something like "it-it")': '(na primjer "it-it")', '(version %s)': '(version %s)', '?': '?', '@markmin\x01(file **gluon/contrib/plural_rules/%s.py** is not found)': '(datoteka **gluon/contrib/plural_rules/%s.py** nije pronađena)', -'Abort': 'Abort', +'@markmin\x01An error occured, please [[reload %s]] the page': 'An error occured, please [[reload %s]] the page', +'Abort': 'Odustani', 'About': 'Informacije', 'About application': 'O aplikaciji', -'Accept Terms': 'Accept Terms', +'Accept Terms': 'Prihvatanje uslova korišćenja', 'Add breakpoint': 'Add breakpoint', 'Additional code for your application': 'Dodatni kod za aplikaciju', 'Admin design page': 'Admin design page', -'admin disabled because no admin password': 'admin disabled because no admin password', -'admin disabled because not supported on google app engine': 'admin disabled because not supported on google app engine', -'admin disabled because too many invalid login attempts': 'admin disabled because too many invalid login attempts', +'admin disabled because no admin password': 'administracija onemogućena jer nema lozinke', +'admin disabled because not supported on google app engine': 'administracija onemogućena na google app engine', +'admin disabled because too many invalid login attempts': 'administracija onemogućena jer zbog većeg broja neuspjelih pokušaja', 'admin disabled because unable to access password file': 'administracija onemogućena jer ne mogu pristupiti datoteci sa lozinkom', -'Admin is disabled because insecure channel': 'Admin is disabled because insecure channel', +'Admin is disabled because insecure channel': 'Administracija onemogućena zbog nesigurne veze', 'Admin language': 'Jezik administratora', 'Admin versioning page': 'Admin versioning page', -'administrative interface': 'administrativni interfejs', +'administrative interface': 'administrativno okruženje', 'Administrator Password:': 'Lozinka administratora:', 'and rename it:': 'i preimenuj u:', -'App does not exist or you are not authorized': 'App does not exist or you are not authorized', +'App does not exist or you are not authorized': 'Aplikacija ne postoji ili nemate prava pristupa', 'appadmin': 'appadmin', -'appadmin is disabled because insecure channel': 'appadmin is disabled because insecure channel', -'Application': 'Application', -'application "%s" uninstalled': 'application "%s" uninstalled', +'appadmin is disabled because insecure channel': 'administracija onemogućena zbog nesigurne veze', +'Application': 'Aplikacija', +'application "%s" uninstalled': 'aplikacija "%s" je deinstalirana', 'Application cannot be generated in demo mode': 'Application cannot be generated in demo mode', -'application compiled': 'application compiled', -'Application exists already': 'Application exists already', -'application is compiled and cannot be designed': 'application is compiled and cannot be designed', +'application compiled': 'aplikacija je kompajlirana', +'Application exists already': 'Aplikacija već postoji', +'application is compiled and cannot be designed': 'aplikacija je kompajlirana i ne može se dalje uređivati', 'Application name:': 'Naziv aplikacije:', -'Application updated via git pull': 'Application updated via git pull', +'Application updated via git pull': 'Aplikacija ažurirana preko git pull', 'are not used': 'nije korišteno', 'are not used yet': 'nije još korišteno', -'Are you sure you want to delete file "%s"?': 'Are you sure you want to delete file "%s"?', -'Are you sure you want to delete plugin "%s"?': 'Are you sure you want to delete plugin "%s"?', +'Are you sure you want to delete file "%s"?': 'Da li ste sigurni da želite izbrisati datoteku "%s"?', +'Are you sure you want to delete plugin "%s"?': 'Da li ste sigurni da želite izbrisati pomoćni modul "%s"?', 'Are you sure you want to delete this object?': 'Da li ste sigurni da želite obrisati?', -'Are you sure you want to uninstall application "%s"?': 'Are you sure you want to uninstall application "%s"?', -'Are you sure?': 'Are you sure?', +'Are you sure you want to uninstall application "%s"?': 'Da li ste sigurni da želite deinstalirati aplikaciju "%s"?', +'Are you sure?': 'Da li ste sigurni?', 'arguments': 'arguments', 'at char %s': 'kod slova %s', 'at line %s': 'na liniji %s', -'ATTENTION:': 'ATTENTION:', +'ATTENTION:': 'PAŽNJA:', 'ATTENTION: Login requires a secure (HTTPS) connection or running on localhost.': 'ATTENTION: Login requires a secure (HTTPS) connection or running on localhost.', 'ATTENTION: TESTING IS NOT THREAD SAFE SO DO NOT PERFORM MULTIPLE TESTS CONCURRENTLY.': 'ATTENTION: TESTING IS NOT THREAD SAFE SO DO NOT PERFORM MULTIPLE TESTS CONCURRENTLY.', -'ATTENTION: you cannot edit the running application!': 'ATTENTION: you cannot edit the running application!', +'ATTENTION: you cannot edit the running application!': 'ATTENTION: ne možete uređivati pokrenutu aplikaciju!', 'Autocomplete Python Code': 'Autocomplete Python Code', -'Available Databases and Tables': 'Available Databases and Tables', +'Available Databases and Tables': 'Dostupne baze podataka i tabele', 'back': 'nazad', -'Back to the plugins list': 'Back to the plugins list', +'Back to the plugins list': 'Nazad na listu pomoćnih modula', 'Back to wizard': 'Back to wizard', 'Basics': 'Osnove', 'Begin': 'Početak', @@ -71,19 +72,19 @@ 'breakpoints': 'breakpoints', 'Bulk Register': 'Bulk Register', 'Bulk Student Registration': 'Bulk Student Registration', -'Cache': 'Cache', -'cache': 'cache', +'Cache': 'Keš', +'cache': 'keš', 'Cache Cleared': 'Cache Cleared', 'Cache Keys': 'Cache Keys', 'cache, errors and sessions cleaned': 'keš, greške i sesije su obrisani', -'can be a git repo': 'može biti git repo', -'Cancel': 'Cancel', -'Cannot be empty': 'Cannot be empty', -'Cannot compile: there are errors in your app:': 'Cannot compile: there are errors in your app:', -'cannot create file': 'cannot create file', +'can be a git repo': 'može biti git repozitorijum', +'Cancel': 'Otkaži', +'Cannot be empty': 'Ne može biti prazno', +'Cannot compile: there are errors in your app:': 'Ne mogu kompajlirati: greška u aplikaciji:', +'cannot create file': 'ne mogu kreirati datoteku', 'cannot upload file "%(filename)s"': 'ne mogu otpremiti datoteku "%(filename)s"', -'Change Admin Password': 'Change Admin Password', 'Change admin password': 'Promijeni lozinku administratora', +'Change Admin Password': 'Promijeni lozinku administratora', 'change editor settings': 'change editor settings', 'Changelog': 'Changelog', 'check all': 'check all', @@ -91,66 +92,66 @@ 'Check to delete': 'Check to delete', 'Checking for upgrades...': 'Provjeravam mogućnost nadogradnje...', 'Clean': 'Pročisti', -'Clear': 'Clear', -'Clear CACHE?': 'Clear CACHE?', -'Clear DISK': 'Clear DISK', -'Clear RAM': 'Clear RAM', +'Clear': 'Obriši', +'Clear CACHE?': 'Obriši CACHE?', +'Clear DISK': 'Obriši DISK', +'Clear RAM': 'Obriši RAM', 'Click row to expand traceback': 'Click row to expand traceback', 'Click row to view a ticket': 'Click row to view a ticket', 'code': 'kod', -'Code listing': 'Code listing', +'Code listing': 'Prikaz koda', 'collapse/expand all': 'sakriti/prikazati sve', -'Command': 'Command', -'Comment:': 'Comment:', +'Command': 'Naredba', +'Comment:': 'Komentar:', 'Commit': 'Commit', 'Commit form': 'Commit form', 'Committed files': 'Committed files', 'Compile': 'Kompajliraj', -'Compile (all or nothing)': 'Compile (all or nothing)', -'Compile (skip failed views)': 'Compile (skip failed views)', -'compiled application removed': 'compiled application removed', -'Condition': 'Condition', -'continue': 'continue', +'Compile (all or nothing)': 'Kompajliraj (sve ili ništa)', +'Compile (skip failed views)': 'Kompajliraj (ignoriši greške)', +'compiled application removed': 'kompajlirana aplikacija je uklonjena', +'Condition': 'Stanje', +'continue': 'nastavi', 'Controllers': 'Kontroleri', 'controllers': 'kontroleri', -'Count': 'Count', +'Count': 'Redni broj', 'Create': 'Kreiraj', 'create file with filename:': 'Kreiraj datoteku pod nazivom:', 'Create rules': 'Kreiraj pravila', -'Create/Upload': 'Create/Upload', +'Create/Upload': 'Kreiraj/Preuzmi', 'created by': 'izradio', 'Created by:': 'Created by:', 'Created On': 'Created On', 'Created on:': 'Created on:', 'crontab': 'crontab', -'Current request': 'Current request', -'Current response': 'Current response', -'Current session': 'Current session', +'Current request': 'Trenutni zahtjev', +'Current response': 'Trenutni odgovor', +'Current session': 'Trenutna sesija', 'currently running': 'trenutno pokrenut', 'currently saved or': 'trenutno sačuvano ili', 'data uploaded': 'data uploaded', -'Database': 'Database', +'Database': 'Baza podataka', 'Database %s select': 'Database %s select', -'Database administration': 'Database administration', 'database administration': 'administracija baze podataka', -'Database Administration (appadmin)': 'Database Administration (appadmin)', -'Date and Time': 'Date and Time', +'Database administration': 'Administracija baze podataka', +'Database Administration (appadmin)': 'Administracija baze podataka (appadmin)', +'Date and Time': 'Datum i vrijeme', 'db': 'db', -'Debug': 'Debug', +'Debug': 'Otkloni grešku', 'defines tables': 'definiše tabele', -'Delete': 'Obriši', -'delete': 'obriši', -'delete all checked': 'delete all checked', -'delete plugin': 'delete plugin', -'Delete this file (you will be asked to confirm deletion)': 'Obriši ovu datoteku (bićete upitani za potvrdu brisanja)', -'Delete:': 'Delete:', +'delete': 'Izbriši', +'Delete': 'Izbriši', +'delete all checked': 'izbriši sve označeno', +'delete plugin': 'izbriši pomoćni modul', +'Delete this file (you will be asked to confirm deletion)': 'Izbriši ovu datoteku (bićete upitani za potvrdu brisanja)', +'Delete:': 'Izbriši:', 'deleted after first hit': 'deleted after first hit', 'Demo': 'Demo', 'Deploy': 'Postavi', 'Deploy on Google App Engine': 'Postavi na Google App Engine', 'Deploy to OpenShift': 'Postavi na OpenShift', -'Deploy to pythonanywhere': 'Deploy to pythonanywhere', -'Deploy to PythonAnywhere': 'Deploy to PythonAnywhere', +'Deploy to pythonanywhere': 'Postavi na pythonanywhere', +'Deploy to PythonAnywhere': 'Postavi na PythonAnywhere', 'Deployment form': 'Deployment form', 'Deployment Interface': 'Deployment Interface', 'Description:': 'Description:', @@ -160,33 +161,33 @@ 'direction: ltr': 'direction: ltr', 'directory not found': 'directory not found', 'Disable': 'Isključi', -'Disabled': 'Disabled', -'disabled in demo mode': 'disabled in demo mode', -'disabled in GAE mode': 'disabled in GAE mode', -'disabled in multi user mode': 'disabled in multi user mode', +'Disabled': 'Isključeno', +'disabled in demo mode': 'onemogućeno u demo modu', +'disabled in GAE mode': 'onemogućeno u GAE modu', +'disabled in multi user mode': 'onemogućeno u višekorisničkom modu', 'DISK': 'DISK', 'Disk Cache Keys': 'Disk Cache Keys', 'Disk Cleared': 'Disk Cleared', 'Display line numbers': 'Display line numbers', 'DO NOT use the "Pack compiled" feature.': 'DO NOT use the "Pack compiled" feature.', -'docs': 'dokumentacija', 'Docs': 'Docs', +'docs': 'dokumentacija', 'done!': 'done!', 'Downgrade': 'Downgrade', -'Download .w2p': 'Download .w2p', -'Download as .exe': 'Download as .exe', +'Download .w2p': 'Preuzmi kao .w2p', +'Download as .exe': 'Preuzmi kao .exe', 'download layouts': 'preuzmi layouts', 'Download layouts from repository': 'Download layouts from repository', -'download plugins': 'preuzmi plugins', -'Download plugins from repository': 'Download plugins from repository', -'Edit': 'Uređivanje', +'download plugins': 'preuzmi pomoćne module', +'Download plugins from repository': 'Preuzmi pomoćne module iz repozitorijum', +'Edit': 'Uredi', 'edit all': 'uredi sve', 'Edit application': 'Uredi aplikaciju', 'edit controller': 'uredi controller', 'edit controller:': 'edit controller:', 'Edit current record': 'Edit current record', -'edit views:': 'uredi views:', -'Editing %s': 'Editing %s', +'edit views:': 'uredi prikaz:', +'Editing %s': 'Uređivanje %s', 'Editing file "%s"': 'Uređivanje datoteke "%s"', 'Editing Language file': 'Uređivanje jezičke datoteke', 'Editing Plural Forms File': 'Editing Plural Forms File', @@ -206,21 +207,21 @@ 'Exit Fullscreen': 'Exit Fullscreen', 'Expand Abbreviation': 'Expand Abbreviation', 'Expand Abbreviation (html files only)': 'Expand Abbreviation (html files only)', -'export as csv file': 'export as csv file', -'Exports:': 'Exports:', -'exposes': 'exposes', -'exposes:': 'exposes:', +'export as csv file': 'izvezi kao csv datoteku', +'Exports:': 'Izvozi:', +'exposes': 'prikazuje', +'exposes:': 'prikazuje:', 'extends': 'proširuje', 'failed to compile file because:': 'nisam mogao da kompajliram zbog:', 'failed to reload module because:': 'failed to reload module because:', 'File': 'Datoteka', -'file "%(filename)s" created': 'file "%(filename)s" created', -'file "%(filename)s" deleted': 'file "%(filename)s" deleted', -'file "%(filename)s" uploaded': 'file "%(filename)s" uploaded', -'file "%s" of %s restored': 'file "%s" of %s restored', +'file "%(filename)s" created': 'datoteka "%(filename)s" je kreirana', +'file "%(filename)s" deleted': 'datoteka "%(filename)s" je izbrisana', +'file "%(filename)s" uploaded': 'datoteka "%(filename)s" je otpremljena', +'file "%s" of %s restored': 'datoteka "%s" od %s je vraćeno u prethodno stanje', 'file changed on disk': 'file changed on disk', 'file does not exist': 'datoteka ne postoji', -'file not found': 'file not found', +'file not found': 'datoteka nije pronađena', 'file saved on %(time)s': 'file saved on %(time)s', 'file saved on %s': 'datoteka sačuvana na %s', 'filename': 'filename', @@ -242,11 +243,11 @@ 'Globals##debug': 'Globals##debug', 'Go to Matching Pair': 'Go to Matching Pair', 'go!': 'kreni!', -'Google App Engine Deployment Interface': 'Google App Engine Deployment Interface', +'Google App Engine Deployment Interface': 'Google App Engine instalaciono okruženje', 'Google Application Id': 'Google Application Id', 'Goto': 'Goto', -'graph model': 'graph model', 'Graph Model': 'Graph Model', +'graph model': 'graph model', 'Help': 'Pomoć', 'here': 'here', 'Hide/Show Translated strings': 'Sakriti/Prikazati prevedene riječi', @@ -260,7 +261,7 @@ 'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\nA green title indicates that all tests (if defined) passed. In this case test results are not shown.': 'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\nA green title indicates that all tests (if defined) passed. In this case test results are not shown.', 'if your application uses a database other than sqlite you will then have to configure its DAL in pythonanywhere.': 'if your application uses a database other than sqlite you will then have to configure its DAL in pythonanywhere.', 'import': 'import', -'Import/Export': 'Import/Export', +'Import/Export': 'Uvoz/Izvoz', 'In development, use the default Rocket webserver that is currently supported by this debugger.': 'In development, use the default Rocket webserver that is currently supported by this debugger.', 'includes': 'uključuje', 'Indent with tabs': 'Indent with tabs', @@ -270,49 +271,49 @@ 'Installed applications': 'Instalirane aplikacije', 'Interaction at %s line %s': 'Interaction at %s line %s', 'Interactive console': 'Interactive console', -'internal error': 'internal error', -'internal error: %s': 'internal error: %s', +'internal error': 'unutrašnja greška', +'internal error: %s': 'unutrašnja greška: %s', 'Internal State': 'Internal State', 'Invalid action': 'Invalid action', 'Invalid application name': 'Invalid application name', 'invalid circular reference': 'invalid circular reference', 'Invalid git repository specified.': 'Invalid git repository specified.', -'invalid password': 'invalid password', -'invalid password.': 'pogrešna lozinka.', -'Invalid Query': 'Invalid Query', +'invalid password': 'Nevažeća lozinka', +'invalid password.': 'nevažeća lozinka.', +'Invalid Query': 'Pogrešan upit', 'invalid request': 'invalid request', 'Invalid request': 'Invalid request', 'invalid table names (auth_* tables already defined)': 'invalid table names (auth_* tables already defined)', -'invalid ticket': 'invalid ticket', +'invalid ticket': 'pogrešan tiket', 'Key': 'Key', 'Key bindings': 'Prečice', -'Key bindings for ZenCoding Plugin': 'Prečice za for ZenCoding Plugin', -'Keyboard shortcuts': 'Keyboard shortcuts', +'Key bindings for ZenCoding Plugin': 'Prečice za ZenCoding Plugin', +'Keyboard shortcuts': 'Prečice na tastaturi', 'kill process': 'kill process', -'language file "%(filename)s" created/updated': 'language file "%(filename)s" created/updated', +'language file "%(filename)s" created/updated': 'jezička datoteka "%(filename)s" je kreirana/ažurirana', 'Language files (static strings) updated': 'Jezičke datoteke su ažurirane', -'languages': 'jezici', 'Languages': 'Jezici', +'languages': 'jezici', 'Last Revision': 'Last Revision', 'Last saved on:': 'Posljednja izmjena:', 'License for': 'Licenca za', -'License:': 'License:', -'Line Nr': 'Line Nr', -'Line number': 'Line number', -'lists by exception': 'lists by exception', -'lists by ticket': 'lists by ticket', -'Loading...': 'Loading...', +'License:': 'Licenca:', +'Line Nr': 'Linija broj', +'Line number': 'Linija broj', +'lists by exception': 'prikaži greške', +'lists by ticket': 'prikaži tikete', +'Loading...': 'Preuzimam...', 'loading...': 'preuzimam...', -'Local Apps': 'Local Apps', +'Local Apps': 'Lokalne aplikacije', 'locals': 'locals', 'Locals##debug': 'Locals##debug', 'Login': 'Prijava', 'Login successful': 'Login successful', -'Login to the Administrative Interface': 'Prijava za administrativni interfejs', -'Login/Register': 'Login/Register', -'Logout': 'Izlaz', -'lost password': 'lost password', -'Main Menu': 'Main Menu', +'Login to the Administrative Interface': 'Prijava za administrativno okruženje', +'Login/Register': 'Prijava/Registracija', +'Logout': 'Odjava', +'lost password': 'izgubljena lozinka', +'Main Menu': 'Glavni meni', 'Manage': 'Manage', 'Manage %(action)s': 'Manage %(action)s', 'Manage Access Control': 'Manage Access Control', @@ -321,68 +322,68 @@ 'Manage Students': 'Manage Students', 'Match Pair': 'Match Pair', 'Memberships': 'Memberships', -'merge': 'merge', +'merge': 'spoji', 'Merge Lines': 'Spoji linije', -'Models': 'Models', -'models': 'models', +'Models': 'Modeli', +'models': 'modeli', 'Modified On': 'Modified On', -'Modules': 'Modules', -'modules': 'modules', -'Multi User Mode': 'Multi User Mode', -'new application "%s" created': 'new application "%s" created', -'new application "%s" imported': 'new application "%s" imported', -'New Application Wizard': 'Čarobnjak za nove aplikacije', +'modules': 'moduli', +'Modules': 'Moduli', +'Multi User Mode': 'Višekorisnički režim rada', +'new application "%s" created': 'nova aplikacija "%s" je kreirana', +'new application "%s" imported': 'nova aplikacija "%s" je uvežena', 'New application wizard': 'Čarobnjak za nove aplikacije', -'new plugin installed': 'new plugin installed', -'New plugin installed: %s': 'New plugin installed: %s', -'New Record': 'New Record', -'new record inserted': 'new record inserted', +'New Application Wizard': 'Čarobnjak za nove aplikacije', +'new plugin installed': 'novi pomoćni modul je instaliran', +'New plugin installed: %s': 'Instaliran novi pomoćni modul: %s', +'New Record': 'Novi zapis', +'new record inserted': 'unešen novi zapis', 'New simple application': 'Nova jednostavna aplikacija', -'next': 'next', +'next': 'sledeći', 'next %s rows': 'next %s rows', 'Next Edit Point': 'Next Edit Point', -'NO': 'NO', -'no changes': 'no changes', -'No databases in this application': 'No databases in this application', -'No Interaction yet': 'No Interaction yet', -'no match': 'no match', -'no package selected': 'no package selected', -'no permission to uninstall "%s"': 'no permission to uninstall "%s"', +'NO': 'NE', +'no changes': 'nema promjena', +'No databases in this application': 'Nema baze podataka u aplikaciji', +'No Interaction yet': 'Nema još interakcije', +'no match': 'nema podudaranja', +'no package selected': 'paket nije odabran', +'no permission to uninstall "%s"': 'nemate ovlaštenje da deinstalirate "%s"', 'No ticket_storage.txt found under /private folder': 'No ticket_storage.txt found under /private folder', 'Node:': 'Node:', -'Not Authorized': 'Not Authorized', -'Not supported': 'Not supported', +'Not Authorized': 'Nemate ovlašćenje', +'Not supported': 'Nije podržano', 'Note: If you receive an error with github status code of 128, ensure the system and account you are deploying from has a cooresponding ssh key configured in the openshift account.': 'Note: If you receive an error with github status code of 128, ensure the system and account you are deploying from has a cooresponding ssh key configured in the openshift account.', "On production, you'll have to configure your webserver to use one process and multiple threads to use this debugger.": "On production, you'll have to configure your webserver to use one process and multiple threads to use this debugger.", 'online designer': 'onlajn dizajner', -'Open new app in new window': 'Open new app in new window', -'OpenShift Deployment Interface': 'OpenShift Deployment Interface', +'Open new app in new window': 'Otvori novu aplikaciju u novom prozoru', +'OpenShift Deployment Interface': 'OpenShift instalaciono okruženje', 'OpenShift Output': 'OpenShift Output', -'or alternatively': 'or alternatively', +'or alternatively': 'ili alternativno', 'Or Get from URL:': 'Or Get from URL:', -'or import from csv file': 'or import from csv file', +'or import from csv file': 'ili uvezi pomoću csv datoteke', 'Original/Translation': 'Original/Prevod', -'Overview': 'Overview', -'Overwrite installed app': 'Prebriši postojeću aplikaciju', +'Overview': 'Pregled', +'Overwrite installed app': 'Zamjeni već postojeću aplikaciju', 'Pack all': 'Zapakuj sve', -'Pack compiled': 'Pack compiled', -'Pack custom': 'Pack custom', -'pack plugin': 'pack plugin', -'password changed': 'password changed', -'Past revisions': 'Past revisions', +'Pack compiled': 'Zapakuj kompajlirano', +'Pack custom': 'Prilagođeno pakovanje', +'pack plugin': 'zapakuj pomoćni modul', +'password changed': 'lozinka je promijenjena', +'Past revisions': 'Prethodne korekcije', 'Path to appcfg.py': 'Path to appcfg.py', 'Path to local openshift repo root.': 'Path to local openshift repo root.', -'Peeking at file': 'Peeking at file', -'Permission': 'Permission', -'Permissions': 'Permissions', -'Please': 'Please', +'Peeking at file': 'Pregled datoteke', +'Permission': 'Dozvola', +'Permissions': 'Dozvole', +'Please': 'Molim', 'Please wait, giving pythonanywhere a moment...': 'Please wait, giving pythonanywhere a moment...', -'plugin "%(plugin)s" deleted': 'plugin "%(plugin)s" deleted', -'Plugin "%s" in application': 'Plugin "%s" in application', +'plugin "%(plugin)s" deleted': 'Pomoćni modul "%(plugin)s" je izbrisan', +'Plugin "%s" in application': 'Pomoćni modul "%s" u aplikaciji', 'plugin not specified': 'plugin not specified', -'Plugin page': 'Plugin page', -'plugins': 'plugins', -'Plugins': 'Plugins', +'Plugin page': 'Stranica pomoćnih modula', +'Plugins': 'Pomoćni moduli', +'plugins': 'pomoćni moduli', 'Plural Form #%s': 'Plural Form #%s', 'Plural-Forms:': 'Plural-Forms:', 'Powered by': 'Omogućio', @@ -390,18 +391,18 @@ 'Preferences saved on session only': 'Preferences saved on session only', 'previous %s rows': 'previous %s rows', 'Previous Edit Point': 'Previous Edit Point', -'Private files': 'Private files', -'private files': 'private files', +'private files': 'privatne datoteke', +'Private files': 'Privatne datoteke', 'Project Progress': 'Napredak projekta', 'Pull': 'Pull', 'Pull failed, certain files could not be checked out. Check logs for details.': 'Pull failed, certain files could not be checked out. Check logs for details.', 'Pull is not possible because you have unmerged files. Fix them up in the work tree, and then try again.': 'Pull is not possible because you have unmerged files. Fix them up in the work tree, and then try again.', 'Push': 'Push', 'Push failed, there are unmerged entries in the cache. Resolve merge issues manually and try again.': 'Push failed, there are unmerged entries in the cache. Resolve merge issues manually and try again.', -'pygraphviz library not found': 'pygraphviz library not found', +'pygraphviz library not found': 'pygraphviz biblioteka nije pronađena', 'PythonAnywhere Apps': 'PythonAnywhere Apps', 'PythonAnywhere Password': 'PythonAnywhere Password', -'Query:': 'Query:', +'Query:': 'Upit:', 'RAM': 'RAM', 'RAM Cache Keys': 'RAM Cache Keys', 'Ram Cleared': 'Ram Cleared', @@ -416,7 +417,7 @@ 'Removed Breakpoint on %s at line %s': 'Removed Breakpoint on %s at line %s', 'Replace': 'Zamijeni', 'Replace All': 'Zamijeni sve', -'Repository (%s)': 'Repository (%s)', +'Repository (%s)': 'Repozitorijum (%s)', 'request': 'request', 'requires distutils, but not installed': 'requires distutils, but not installed', 'requires python-git, but not installed': 'requires python-git, but not installed', @@ -430,78 +431,78 @@ 'reverted to revision %s': 'reverted to revision %s', 'Revision %s': 'Revision %s', 'Revision:': 'Revision:', -'Role': 'Role', -'Roles': 'Roles', -'Rows in Table': 'Rows in Table', +'Role': 'Uloga', +'Roles': 'Uloge', +'Rows in Table': 'Zapisi u tabeli', 'Rows selected': 'Rows selected', 'rules are not defined': 'pravila nisu definisana', 'rules:': 'pravila:', -'Run tests': 'Run tests', -'Run tests in this file': 'Run tests in this file', +'Run tests': 'Pokreni testove', +'Run tests in this file': 'Pokreni testove u datoteci', "Run tests in this file (to run all files, you may also use the button labelled 'test')": "Run tests in this file (to run all files, you may also use the button labelled 'test')", 'Running on %s': 'Pokrenuto na %s', 'Save': 'Sačuvaj', -'Save file:': 'Save file:', -'Save file: %s': 'Save file: %s', -'Save model as...': 'Save model as...', -'Save via Ajax': 'Sačuvaj via Ajax', +'Save file:': 'Sačuvaj datoteku:', +'Save file: %s': 'Sačuvaj datoteku: %s', +'Save model as...': 'Sačuvaj model kao...', +'Save via Ajax': 'Sačuvaj preko Ajax', 'Saved file hash:': 'Sačuvano kao haš:', -'Screenshot %s': 'Screenshot %s', -'Search': 'Search', -'Select Files to Package': 'Select Files to Package', +'Screenshot %s': 'Snimak ekrana %s', +'Search': 'Pretraga', +'Select Files to Package': 'Odaberi datoteke za pakovanje', 'session': 'sesija', -'session expired': 'sesija istekla', -'Session saved correctly': 'Session saved correctly', +'session expired': 'sesija je istekla', +'Session saved correctly': 'Sesija je uredno sačuvana', 'Session saved on session only': 'Session saved on session only', 'Set Breakpoint on %s at line %s: %s': 'Set Breakpoint on %s at line %s: %s', 'shell': 'shell', -'Showing %s to %s of %s %s found': 'Showing %s to %s of %s %s found', +'Showing %s to %s of %s %s found': 'Prikazujem %s do %s od %s %s pronađenih', 'Singular Form': 'Singular Form', -'Site': 'Sajt', +'Site': 'Početna', 'Size of cache:': 'Size of cache:', -'skip to generate': 'skip to generate', -'some files could not be removed': 'some files could not be removed', +'skip to generate': 'preskoči generisanje', +'some files could not be removed': 'neke datoteke ne mogu biti uklonjene', 'Something went wrong please wait a few minutes before retrying': 'Something went wrong please wait a few minutes before retrying', -'Sorry, could not find mercurial installed': 'Sorry, could not find mercurial installed', +'Sorry, could not find mercurial installed': 'Žalim, mercurial nije instaliran', 'source : db': 'source : db', 'source : filesystem': 'source : filesystem', 'Start a new app': 'Pokreni novu aplikaciju', 'Start searching': 'Pokreni pretragu', 'Start wizard': 'Pokreni čarobnjaka', 'state': 'state', -'Static': 'Static', 'static': 'static', +'Static': 'Static', 'Static files': 'Static files', 'Statistics': 'Statistics', 'Step': 'Korak', -'step': 'step', +'step': 'korak', 'stop': 'stop', -'submit': 'submit', 'Submit': 'Prihvati', +'submit': 'prihvati', 'successful': 'uspješan', -'switch to : db': 'switch to : db', -'switch to : filesystem': 'switch to : filesystem', +'switch to : db': 'pređi na : db', +'switch to : filesystem': 'pređi na : filesystem', 'Tab width (# characters)': 'Tab width (# characters)', -'Table': 'Table', +'Table': 'Tabela', 'Temporary': 'Temporary', 'test': 'test', -'Testing application': 'Testing application', +'Testing application': 'Testiranje aplikacije', 'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.': 'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.', 'The app exists, was created by wizard, continue to overwrite!': 'The app exists, was created by wizard, continue to overwrite!', 'The app exists, was NOT created by wizard, continue to overwrite!': 'The app exists, was NOT created by wizard, continue to overwrite!', 'The application logic, each URL path is mapped in one exposed function in the controller': 'The application logic, each URL path is mapped in one exposed function in the controller', 'The data representation, define database tables and sets': 'The data representation, define database tables and sets', 'The presentations layer, views are also known as templates': 'The presentations layer, views are also known as templates', -'Theme': 'Theme', -'There are no controllers': 'There are no controllers', -'There are no models': 'There are no models', -'There are no modules': 'There are no modules', -'There are no plugins': 'There are no plugins', -'There are no private files': 'There are no private files', -'There are no static files': 'There are no static files', -'There are no translators': 'There are no translators', +'Theme': 'Teme', +'There are no controllers': 'Nema kontolera', +'There are no models': 'Nema modela', +'There are no modules': 'Nema modula', +'There are no plugins': 'Nema pomoćnih modula', +'There are no private files': 'Nema privatnih datoteka', +'There are no static files': 'Nema statičnih datoteka', +'There are no translators': 'Nema prevodioca', 'There are no translators, only default language is supported': 'There are no translators, only default language is supported', -'There are no views': 'There are no views', +'There are no views': 'Nema stranica prikaza', 'These files are not served, they are only available from within your app': 'These files are not served, they are only available from within your app', 'These files are served without processing, your images go here': 'These files are served without processing, your images go here', "This debugger may not work properly if you don't have a threaded webserver or you're using multiple daemon processes.": "This debugger may not work properly if you don't have a threaded webserver or you're using multiple daemon processes.", @@ -512,9 +513,9 @@ 'this page to see if a breakpoint was hit and debug interaction is required.': 'this page to see if a breakpoint was hit and debug interaction is required.', 'This will pull changes from the remote repo for application "%s"?': 'This will pull changes from the remote repo for application "%s"?', 'This will push changes to the remote repo for application "%s".': 'This will push changes to the remote repo for application "%s".', -'Ticket': 'Ticket', -'Ticket ID': 'Ticket ID', -'Ticket Missing': 'Ticket nedostaje', +'Ticket': 'Tiket', +'Ticket ID': 'Tiket ID', +'Ticket Missing': 'Nedostaje tiket', 'Time in Cache (h:m:s)': 'Time in Cache (h:m:s)', 'to previous version.': 'na prethodnu verziju.', 'To create a plugin, name a file/folder plugin_[name]': 'To create a plugin, name a file/folder plugin_[name]', @@ -525,67 +526,67 @@ 'Toggle Fullscreen': 'Toggle Fullscreen', 'Traceback': 'Traceback', 'Translation strings for the application': 'Riječi u aplikaciji koje treba prevesti', -'try something like': 'try something like', -'Try the mobile interface': 'Probaj mobilni interfejs', -'try view': 'try view', +'try something like': 'na primjer', +'Try the mobile interface': 'Probaj mobilno okruženje', +'try view': 'probaj prikaz', 'Type PDB debugger command in here and hit Return (Enter) to execute it.': 'Type PDB debugger command in here and hit Return (Enter) to execute it.', 'Type some Python code in here and hit Return (Enter) to execute it.': 'Type some Python code in here and hit Return (Enter) to execute it.', -'Unable to check for upgrades': 'Unable to check for upgrades', +'Unable to check for upgrades': 'Ne mogu da provjerim mogućnost nadogradnje', 'unable to create application "%s"': 'unable to create application "%s"', -'unable to delete file "%(filename)s"': 'unable to delete file "%(filename)s"', -'unable to delete file plugin "%(plugin)s"': 'unable to delete file plugin "%(plugin)s"', -'Unable to determine the line number!': 'Unable to determine the line number!', -'Unable to download app because:': 'Unable to download app because:', +'unable to delete file "%(filename)s"': 'ne mogu izbrisati datoteku "%(filename)s"', +'unable to delete file plugin "%(plugin)s"': 'ne mogu izbrisati pomoćni modul "%(plugin)s"', +'Unable to determine the line number!': 'Ne mogu da utvrdim broj reda!', +'Unable to download app because:': 'Ne mogu da preuzmem aplikaciju zbog:', 'unable to download layout': 'unable to download layout', 'unable to download plugin: %s': 'unable to download plugin: %s', -'Unable to download the list of plugins': 'Unable to download the list of plugins', -'unable to install plugin "%s"': 'unable to install plugin "%s"', -'unable to parse csv file': 'unable to parse csv file', -'unable to uninstall "%s"': 'unable to uninstall "%s"', -'unable to upgrade because "%s"': 'unable to upgrade because "%s"', +'Unable to download the list of plugins': 'Ne mogu da preuzmem spisak pomoćnih modula', +'unable to install plugin "%s"': 'ne mogu da instaliram pomoćni modul "%s"', +'unable to parse csv file': 'ne mogu da rasčlanim csv datoteku', +'unable to uninstall "%s"': 'ne mogu da deinstaliram "%s"', +'unable to upgrade because "%s"': 'ne mogu da ažurimam zbog "%s"', 'uncheck all': 'uncheck all', 'Uninstall': 'Deinstaliraj', 'Unsupported webserver working mode: %s': 'Unsupported webserver working mode: %s', 'update': 'ažuriraj', 'update all languages': 'ažuriraj sve jezike', -'Update:': 'Update:', -'Upgrade': 'Upgrade', -'upgrade now to %s': 'upgrade now to %s', +'Update:': 'Ažuriraj:', +'Upgrade': 'Nadogradnja', +'upgrade now to %s': 'ažuriran na %s', 'upload': 'Otpremi', -'Upload': 'Upload', +'Upload': 'Preuzmi', 'Upload a package:': 'Preuzmi paket:', 'Upload and install packed application': 'Preuzmi i instaliraj zapakovanu aplikaciju', 'upload file:': 'preuzmi datoteku:', -'upload plugin file:': 'preuzmi plugin datoteku:', +'upload plugin file:': 'preuzmi datoteku pomoćnog modula:', 'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.', -'User': 'User', -'Username': 'Username', -'Users': 'Users', +'User': 'Korisnik', +'Username': 'Korisničko ime', +'Users': 'Korisnici', 'Using the shell may lock the database to other users of this app.': 'Using the shell may lock the database to other users of this app.', -'variables': 'variables', +'variables': 'promenljive', 'Version': 'Verzija', 'Version %s.%s.%s (%s) %s': 'Verzija %s.%s.%s (%s) %s', -'Versioning': 'Versioning', -'Views': 'Views', -'views': 'views', -'Warning!': 'Warning!', -'WARNING:': 'WARNING:', -'WARNING: The following views could not be compiled:': 'WARNING: The following views could not be compiled:', +'Versioning': 'Kreiranje verzija', +'views': 'prikazi', +'Views': 'Prikazi', +'Warning!':A 'Upozorenje!', +'WARNING:': 'UPOZORENJE:', +'WARNING: The following views could not be compiled:': 'WARNING: Sledeći prikazi ne mogu biti kompajlirani:', 'Web Framework': 'Web Framework', -'web2py Admin Password': 'web2py Admin Password', -'web2py apps to deploy': 'web2py apps to deploy', +'web2py Admin Password': 'web2py administratorska lozinka', +'web2py apps to deploy': 'web2py aplikacija za instalaciju', 'web2py Debugger': 'web2py Debugger', 'web2py downgrade': 'web2py downgrade', 'web2py is up to date': 'web2py je ažuran', 'web2py online debugger': 'web2py online debugger', 'web2py Recent Tweets': 'web2py Recent Tweets', -'web2py upgrade': 'web2py upgrade', -'web2py upgraded; please restart it': 'web2py upgraded; please restart it', -'Working...': 'Working...', +'web2py upgrade': 'web2py nadogradnja', +'web2py upgraded; please restart it': 'web2py je ažuriran; molim da restartujete', +'Working...': 'Izvršavam...', 'Wrap with Abbreviation': 'Wrap with Abbreviation', -'WSGI reference name': 'WSGI reference name', -'YES': 'YES', -'Yes': 'Yes', +'WSGI reference name': 'WSGI referentni naziv', +'YES': 'DA', +'Yes': 'Da', 'You can also set and remove breakpoint in the edit window, using the Toggle Breakpoint button': 'You can also set and remove breakpoint in the edit window, using the Toggle Breakpoint button', 'You can inspect variables using the console below': 'You can inspect variables using the console below', 'You have one more login attempt before you are locked out': 'You have one more login attempt before you are locked out', From cee7c87859c298629e69cc19be273dd4c4d2f806 Mon Sep 17 00:00:00 2001 From: mdipierro Date: Tue, 27 Sep 2016 16:41:17 -0500 Subject: [PATCH 31/49] fixed error in serbian tranlation file --- applications/admin/languages/sr-lt.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/admin/languages/sr-lt.py b/applications/admin/languages/sr-lt.py index 4f6ad085..a807b8cc 100755 --- a/applications/admin/languages/sr-lt.py +++ b/applications/admin/languages/sr-lt.py @@ -569,7 +569,7 @@ 'Versioning': 'Kreiranje verzija', 'views': 'prikazi', 'Views': 'Prikazi', -'Warning!':A 'Upozorenje!', +'Warning!': 'Upozorenje!', 'WARNING:': 'UPOZORENJE:', 'WARNING: The following views could not be compiled:': 'WARNING: Sledeći prikazi ne mogu biti kompajlirani:', 'Web Framework': 'Web Framework', From 40263576898994056c04b105854fa8afd02cee28 Mon Sep 17 00:00:00 2001 From: mdipierro Date: Tue, 27 Sep 2016 16:49:20 -0500 Subject: [PATCH 32/49] fixed undefined var in web2py.js --- applications/admin/static/js/web2py.js | 4 ++-- applications/examples/static/js/web2py.js | 6 +++--- applications/welcome/static/js/web2py.js | 10 +++++----- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/applications/admin/static/js/web2py.js b/applications/admin/static/js/web2py.js index f3d14b29..7853e8cb 100644 --- a/applications/admin/static/js/web2py.js +++ b/applications/admin/static/js/web2py.js @@ -617,8 +617,8 @@ } if (confirm_message) { if (confirm_message == 'default') { - confirm_message = w2p_ajax_confirm_message || - 'Are you sure you want to delete this object?'; + confirm_message = !web2py.isUndefined(w2p_ajax_confirm_message) ? + w2p_ajax_confirm_message : 'Are you sure you want to delete this object?'; } if (!web2py.confirm(confirm_message)) { web2py.stopEverything(e); diff --git a/applications/examples/static/js/web2py.js b/applications/examples/static/js/web2py.js index 15ff515c..7853e8cb 100644 --- a/applications/examples/static/js/web2py.js +++ b/applications/examples/static/js/web2py.js @@ -562,7 +562,7 @@ var flash = $('.w2p_flash'); web2py.hide_flash(); flash.html(message).addClass(status); - if (flash.html()) flash.slideDown(); + if (flash.html()) flash.append(' × ').slideDown(); }, hide_flash: function () { $('.w2p_flash').fadeOut(0).html(''); @@ -617,8 +617,8 @@ } if (confirm_message) { if (confirm_message == 'default') { - confirm_message = w2p_ajax_confirm_message || - 'Are you sure you want to delete this object?'; + confirm_message = !web2py.isUndefined(w2p_ajax_confirm_message) ? + w2p_ajax_confirm_message : 'Are you sure you want to delete this object?'; } if (!web2py.confirm(confirm_message)) { web2py.stopEverything(e); diff --git a/applications/welcome/static/js/web2py.js b/applications/welcome/static/js/web2py.js index 2bedd1c5..7853e8cb 100644 --- a/applications/welcome/static/js/web2py.js +++ b/applications/welcome/static/js/web2py.js @@ -201,7 +201,7 @@ showsTime: true, timeFormat: '24' }); - $(this).prop('autocomplete', 'off'); + $(this).attr('autocomplete', 'off'); $(this).data('w2p_datetime', 1); $(this).trigger('click'); } @@ -218,7 +218,7 @@ showsTime: false }); $(this).data('w2p_date', 1); - $(this).prop('autocomplete', 'off'); + $(this).attr('autocomplete', 'off'); $(this).trigger('click'); } }); @@ -227,7 +227,7 @@ if (web2py.isUndefined(active)) { $(this).timeEntry({ spinnerImage: '' - }).prop('autocomplete', 'off'); + }).attr('autocomplete', 'off'); $(this).data('w2p_time', 1); } }); @@ -617,8 +617,8 @@ } if (confirm_message) { if (confirm_message == 'default') { - confirm_message = w2p_ajax_confirm_message || - 'Are you sure you want to delete this object?'; + confirm_message = !web2py.isUndefined(w2p_ajax_confirm_message) ? + w2p_ajax_confirm_message : 'Are you sure you want to delete this object?'; } if (!web2py.confirm(confirm_message)) { web2py.stopEverything(e); From 78cc6d69a29921d7dfd6fa207e8220f47eabeed8 Mon Sep 17 00:00:00 2001 From: mdipierro Date: Tue, 27 Sep 2016 17:09:05 -0500 Subject: [PATCH 33/49] fixed web2py_ajax.html and escaping (not backward compatible fix) --- applications/admin/views/web2py_ajax.html | 10 +++++----- applications/examples/views/web2py_ajax.html | 9 +++++---- applications/welcome/views/web2py_ajax.html | 10 +++++----- 3 files changed, 15 insertions(+), 14 deletions(-) diff --git a/applications/admin/views/web2py_ajax.html b/applications/admin/views/web2py_ajax.html index 417859e9..357d8050 100644 --- a/applications/admin/views/web2py_ajax.html +++ b/applications/admin/views/web2py_ajax.html @@ -1,10 +1,10 @@ {{ response.files.insert(0,URL('static','js/jquery.js')) diff --git a/applications/examples/views/web2py_ajax.html b/applications/examples/views/web2py_ajax.html index a0ba6f43..357d8050 100644 --- a/applications/examples/views/web2py_ajax.html +++ b/applications/examples/views/web2py_ajax.html @@ -1,9 +1,10 @@ {{ response.files.insert(0,URL('static','js/jquery.js')) diff --git a/applications/welcome/views/web2py_ajax.html b/applications/welcome/views/web2py_ajax.html index 6fefd3a0..357d8050 100644 --- a/applications/welcome/views/web2py_ajax.html +++ b/applications/welcome/views/web2py_ajax.html @@ -1,10 +1,10 @@ {{ response.files.insert(0,URL('static','js/jquery.js')) From 3ab30295ed037e8bcad086b5897a955cb487a4d6 Mon Sep 17 00:00:00 2001 From: Giovanni Barillari Date: Wed, 28 Sep 2016 13:10:42 +0200 Subject: [PATCH 34/49] Updated pyDAL to 16.9 --- gluon/packages/dal | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gluon/packages/dal b/gluon/packages/dal index 012dbe3e..12bc6d97 160000 --- a/gluon/packages/dal +++ b/gluon/packages/dal @@ -1 +1 @@ -Subproject commit 012dbe3eed0404bc5d5516018f2bf9b3eb5b17ab +Subproject commit 12bc6d97402acce462c1193f57bbba4afde7c3c3 From a31cf09dd3d2dc682f58ee77529bd41ba644106e Mon Sep 17 00:00:00 2001 From: ilvalle Date: Wed, 28 Sep 2016 20:51:44 +0200 Subject: [PATCH 35/49] minor compileapp refactor --- gluon/compileapp.py | 53 +++++++++++++++++++++++---------------------- gluon/globals.py | 6 ++--- gluon/main.py | 4 ++-- 3 files changed, 31 insertions(+), 32 deletions(-) diff --git a/gluon/compileapp.py b/gluon/compileapp.py index 23e66628..32c02177 100644 --- a/gluon/compileapp.py +++ b/gluon/compileapp.py @@ -230,8 +230,8 @@ def LOAD(c=None, f='index', args=None, vars=None, if isinstance(page, dict): other_response._vars = page other_response._view_environment.update(page) - run_view_in(other_response._view_environment) - page = other_response.body.getvalue() + page = run_view_in(other_response._view_environment) + current.request, current.response = original_request, original_response js = None if ajax_trap: @@ -309,8 +309,8 @@ class LoadFactory(object): if isinstance(page, dict): other_response._vars = page other_response._view_environment.update(page) - run_view_in(other_response._view_environment) - page = other_response.body.getvalue() + page = run_view_in(other_response._view_environment) + current.request, current.response = original_request, original_response js = None if ajax_trap: @@ -577,13 +577,11 @@ def run_models_in(environment): if not regex.search(fname) and c != 'appadmin': continue elif compiled: - code = getcfs(model, model, lambda: read_pyc(model)) + f = lambda: read_pyc(model) else: - code = getcfs(model, model, - lambda: compile2(read_file(model), model)) - - restricted(code, environment, layer=model) - + f = lambda: compile2(read_file(model), model) + ccode = getcfs(model, model, f) + restricted(ccode, environment, layer=model) def run_controller_in(controller, function, environment): """ @@ -594,17 +592,17 @@ def run_controller_in(controller, function, environment): # if compiled should run compiled! folder = current.request.folder - path = pjoin(folder, 'compiled') + cpath = pjoin(folder, 'compiled') badc = 'invalid controller (%s/%s)' % (controller, function) badf = 'invalid function (%s/%s)' % (controller, function) - if os.path.exists(path): - filename = pjoin(path, 'controllers.%s.%s.pyc' + if os.path.exists(cpath): + filename = pjoin(cpath, 'controllers.%s.%s.pyc' % (controller, function)) if not os.path.exists(filename): raise HTTP(404, rewrite.THREAD_LOCAL.routes.error_message % badf, web2py_error=badf) - code = getcfs(filename, filename, lambda: read_pyc(filename)) + ccode = getcfs(filename, filename, lambda: read_pyc(filename)) elif function == '_TEST': # TESTING: adjust the path to include site packages from gluon.settings import global_settings @@ -623,6 +621,7 @@ def run_controller_in(controller, function, environment): environment['__symbols__'] = environment.keys() code = read_file(filename) code += TEST_CODE + ccode = compile2(code, filename) else: filename = pjoin(folder, 'controllers/%s.py' % controller) @@ -636,11 +635,11 @@ def run_controller_in(controller, function, environment): raise HTTP(404, rewrite.THREAD_LOCAL.routes.error_message % badf, web2py_error=badf) - code = "%s\nresponse._vars=response._caller(%s)\n" % (code, function) - layer = filename + ':' + function - code = getcfs(layer, filename, lambda: compile2(code, layer)) + code = "%s\nresponse._vars=response._caller(%s)" % (code, function) + layer = "%s:%s" % (filename, function) + ccode = getcfs(layer, filename, lambda: compile2(code, layer)) - restricted(code, environment, layer=filename) + restricted(ccode, environment, layer=filename) response = current.response vars = response._vars if response.postprocessing: @@ -663,9 +662,10 @@ def run_view_in(environment): response = current.response view = environment['response'].view folder = request.folder - path = pjoin(folder, 'compiled') + cpath = pjoin(folder, 'compiled') badv = 'invalid view (%s)' % view patterns = response.get('generic_patterns') + layer = None if patterns: regex = re_compile('|'.join(map(fnmatch.translate, patterns))) short_action = '%(controller)s/%(function)s.%(extension)s' % request @@ -678,10 +678,10 @@ def run_view_in(environment): layer = 'file stream' else: filename = pjoin(folder, 'views', view) - if os.path.exists(path): # compiled views + if os.path.exists(cpath): # compiled views x = view.replace('/', '.') files = ['views.%s.pyc' % x] - is_compiled = os.path.exists(pjoin(path, files[0])) + is_compiled = os.path.exists(pjoin(cpath, files[0])) # Don't use a generic view if the non-compiled view exists. if is_compiled or (not is_compiled and not os.path.exists(filename)): if allow_generic: @@ -693,11 +693,11 @@ def run_view_in(environment): files.append('views.generic.pyc') # end backward compatibility code for f in files: - compiled = pjoin(path, f) + compiled = pjoin(cpath, f) if os.path.exists(compiled): - code = getcfs(compiled, compiled, lambda: read_pyc(compiled)) - restricted(code, environment, layer=compiled) - return + ccode = getcfs(compiled, compiled, lambda: read_pyc(compiled)) + layer = compiled + break if not os.path.exists(filename) and allow_generic: view = 'generic.' + request.extension filename = pjoin(folder, 'views', view) @@ -713,7 +713,8 @@ def run_view_in(environment): context=environment), layer)) restricted(ccode, environment, layer=layer) - + # parse_template saves everything in response body + return environment['response'].body.getvalue() def remove_compiled_application(folder): """ diff --git a/gluon/globals.py b/gluon/globals.py index ae4e0bc9..29fb3f0d 100644 --- a/gluon/globals.py +++ b/gluon/globals.py @@ -439,13 +439,11 @@ class Response(Storage): from gluon._compat import StringIO (obody, oview) = (self.body, self.view) (self.body, self.view) = (StringIO(), view) - run_view_in(self._view_environment) - page = self.body.getvalue() + page = run_view_in(self._view_environment) self.body.close() (self.body, self.view) = (obody, oview) else: - run_view_in(self._view_environment) - page = self.body.getvalue() + page = run_view_in(self._view_environment) return page def include_meta(self): diff --git a/gluon/main.py b/gluon/main.py index 971c48a7..a830d7a8 100644 --- a/gluon/main.py +++ b/gluon/main.py @@ -180,8 +180,8 @@ def serve_controller(request, response, session): if isinstance(page, dict): response._vars = page response._view_environment.update(page) - run_view_in(response._view_environment) - page = response.body.getvalue() + page = run_view_in(response._view_environment) + # logic to garbage collect after exec, not always, once every 100 requests global requests requests = ('requests' in globals()) and (requests + 1) % 100 or 0 From 3a6df38d62fc975c1041c46643fc3f492c1b5501 Mon Sep 17 00:00:00 2001 From: niphlod Date: Thu, 29 Sep 2016 00:03:45 +0200 Subject: [PATCH 36/49] fixes #1407 passing a properly escaped string --- applications/admin/views/web2py_ajax.html | 12 +++++++----- applications/examples/views/web2py_ajax.html | 11 ++++++----- applications/welcome/views/web2py_ajax.html | 12 +++++++----- gluon/tests/test_appadmin.py | 1 + 4 files changed, 21 insertions(+), 15 deletions(-) diff --git a/applications/admin/views/web2py_ajax.html b/applications/admin/views/web2py_ajax.html index 357d8050..28ec0e02 100644 --- a/applications/admin/views/web2py_ajax.html +++ b/applications/admin/views/web2py_ajax.html @@ -1,10 +1,12 @@ {{ response.files.insert(0,URL('static','js/jquery.js')) diff --git a/applications/examples/views/web2py_ajax.html b/applications/examples/views/web2py_ajax.html index 357d8050..0f064de4 100644 --- a/applications/examples/views/web2py_ajax.html +++ b/applications/examples/views/web2py_ajax.html @@ -1,10 +1,11 @@ {{ response.files.insert(0,URL('static','js/jquery.js')) diff --git a/applications/welcome/views/web2py_ajax.html b/applications/welcome/views/web2py_ajax.html index 357d8050..28ec0e02 100644 --- a/applications/welcome/views/web2py_ajax.html +++ b/applications/welcome/views/web2py_ajax.html @@ -1,10 +1,12 @@ {{ response.files.insert(0,URL('static','js/jquery.js')) diff --git a/gluon/tests/test_appadmin.py b/gluon/tests/test_appadmin.py index c5e7402e..4b502c12 100644 --- a/gluon/tests/test_appadmin.py +++ b/gluon/tests/test_appadmin.py @@ -31,6 +31,7 @@ class TestAppAdmin(unittest.TestCase): def setUp(self): from gluon.globals import Request, Response, Session, current from gluon.html import A, DIV, FORM, MENU, TABLE, TR, INPUT, URL, XML + from gluon.html import ASSIGNJS from gluon.validators import IS_NOT_EMPTY from gluon.compileapp import LOAD from gluon.http import HTTP, redirect From a1154a6f423347b580381043cd794945de081def Mon Sep 17 00:00:00 2001 From: mdipierro Date: Fri, 30 Sep 2016 09:59:08 -0500 Subject: [PATCH 37/49] reverted 28db54d0e884fd454082ef05a3757cef32240d53 changes to compileapp.py --- gluon/compileapp.py | 69 +++++++++++++++++++++++++++++++++------------ 1 file changed, 51 insertions(+), 18 deletions(-) diff --git a/gluon/compileapp.py b/gluon/compileapp.py index 23e66628..459c2848 100644 --- a/gluon/compileapp.py +++ b/gluon/compileapp.py @@ -430,10 +430,13 @@ def build_environment(request, response, session, store_current=True): current.T = t current.cache = c + global __builtins__ if is_jython: # jython hack - global __builtins__ __builtins__ = mybuiltin() - + elif is_pypy: # apply the same hack to pypy too + __builtins__ = mybuiltin() + elif PY2: + __builtins__['__import__'] = builtin.__import__ # WHY? environment['request'] = request environment['response'] = response environment['session'] = session @@ -441,6 +444,7 @@ def build_environment(request, response, session, store_current=True): lambda name, reload=False, app=request.application:\ local_import_aux(name, reload, app) BaseAdapter.set_folder(pjoin(request.folder, 'databases')) + response._view_environment = copy.copy(environment) custom_import_install() return environment @@ -483,7 +487,7 @@ def compile_views(folder, skip_failed_views=False): else: raise Exception("%s in %s" % (e, fname)) else: - filename = 'views.%s.py' % fname.replace(os.path.sep, '.') + filename = ('views/%s.py' % fname).replace('/', '_').replace('\\', '_') filename = pjoin(folder, 'compiled', filename) write_file(filename, data) save_pyc(filename) @@ -499,7 +503,7 @@ def compile_models(folder): path = pjoin(folder, 'models') for fname in listdir(path, '.+\.py$'): data = read_file(pjoin(path, fname)) - modelfile = 'models.'+fname.replace(os.path.sep, '.') + modelfile = 'models.'+fname.replace(os.path.sep,'.') filename = pjoin(folder, 'compiled', modelfile) mktree(filename) write_file(filename, data) @@ -578,10 +582,11 @@ def run_models_in(environment): continue elif compiled: code = getcfs(model, model, lambda: read_pyc(model)) - else: + elif is_gae: code = getcfs(model, model, lambda: compile2(read_file(model), model)) - + else: + code = getcfs(model, model, None) restricted(code, environment, layer=model) @@ -605,6 +610,7 @@ def run_controller_in(controller, function, environment): rewrite.THREAD_LOCAL.routes.error_message % badf, web2py_error=badf) code = getcfs(filename, filename, lambda: read_pyc(filename)) + restricted(code, environment, layer=filename) elif function == '_TEST': # TESTING: adjust the path to include site packages from gluon.settings import global_settings @@ -623,6 +629,7 @@ def run_controller_in(controller, function, environment): environment['__symbols__'] = environment.keys() code = read_file(filename) code += TEST_CODE + restricted(code, environment, layer=filename) else: filename = pjoin(folder, 'controllers/%s.py' % controller) @@ -637,10 +644,10 @@ def run_controller_in(controller, function, environment): rewrite.THREAD_LOCAL.routes.error_message % badf, web2py_error=badf) code = "%s\nresponse._vars=response._caller(%s)\n" % (code, function) - layer = filename + ':' + function - code = getcfs(layer, filename, lambda: compile2(code, layer)) - - restricted(code, environment, layer=filename) + if is_gae: + layer = filename + ':' + function + code = getcfs(layer, filename, lambda: compile2(code, layer)) + restricted(code, environment, filename) response = current.response vars = response._vars if response.postprocessing: @@ -675,7 +682,7 @@ def run_view_in(environment): if not isinstance(view, str): ccode = parse_template(view, pjoin(folder, 'views'), context=environment) - layer = 'file stream' + restricted(ccode, environment, 'file stream') else: filename = pjoin(folder, 'views', view) if os.path.exists(path): # compiled views @@ -706,13 +713,16 @@ def run_view_in(environment): rewrite.THREAD_LOCAL.routes.error_message % badv, web2py_error=badv) layer = filename - # Cache the compiled template - ccode = getcfs(layer, filename, - lambda: compile2(parse_template(view, - pjoin(folder, 'views'), - context=environment), - layer)) - restricted(ccode, environment, layer=layer) + if is_gae: + ccode = getcfs(layer, filename, + lambda: compile2(parse_template(view, + pjoin(folder, 'views'), + context=environment), layer)) + else: + ccode = parse_template(view, + pjoin(folder, 'views'), + context=environment) + restricted(ccode, environment, layer) def remove_compiled_application(folder): @@ -738,3 +748,26 @@ def compile_application(folder, skip_failed_views=False): compile_controllers(folder) failed_views = compile_views(folder, skip_failed_views) return failed_views + + +def test(): + """ + Example:: + + >>> import traceback, types + >>> environment={'x':1} + >>> open('a.py', 'w').write('print 1/x') + >>> save_pyc('a.py') + >>> os.unlink('a.py') + >>> if type(read_pyc('a.pyc'))==types.CodeType: print 'code' + code + >>> exec read_pyc('a.pyc') in environment + 1 + """ + + return + + +if __name__ == '__main__': + import doctest + doctest.testmod() From d03337a737727de885db2ac4734352045f3b5378 Mon Sep 17 00:00:00 2001 From: mdipierro Date: Fri, 30 Sep 2016 11:24:55 -0500 Subject: [PATCH 38/49] compile views with . separator anot _ seperator --- applications/examples/static/css/stupid.css | 6 +++--- fabfile.py | 20 ++++++++++++++++++++ gluon/compileapp.py | 3 ++- 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/applications/examples/static/css/stupid.css b/applications/examples/static/css/stupid.css index 80bf9b09..3e68bedd 100644 --- a/applications/examples/static/css/stupid.css +++ b/applications/examples/static/css/stupid.css @@ -54,8 +54,8 @@ header, main, footer {display:block; with:100%} /* IE fix */ .right {right:0; text-align:right} .middle div {vertical-align:middle} .bottom div {vertical-align:bottom} -.xscroll {overflow-x:scroll} -.yscroll {overflow-y:scroll} +.xscroll {overflow-x:scroll !important} +.yscroll {overflow-y:scroll !important} .nowrap {white-space:nowrap; overflow-x:hidden} .fill {width:100%} .lifted {box-shadow:5px 5px 10px #666} @@ -75,7 +75,7 @@ input:invalid, input.error, textarea:invalid, textarea.error {background: #ffdfd /*** grid ***/ .container {margin-right:-20px} .container>.quarter, .container>.half, .container>.third, .container>.twothirds, .container>.threequarters {display:inline-block; padding: 0 20px 0 0; vertical-align:top} -.container>.fill{display: inline-block} +.container>.fill{display: inline-block; padding-right: 20px; margin-right:-10px} .container img, .container video {max-width:100%} .max900 {margin-left:auto; margin-right:auto} diff --git a/fabfile.py b/fabfile.py index 2e7db9e8..00a52c02 100644 --- a/fabfile.py +++ b/fabfile.py @@ -136,6 +136,26 @@ def deploy(appname=None, all=False): if backup: print 'TO RESTORE: fab restore:%s' % backup + +def deploynobackup(appname=None): + """fab -H username@host deploy:appname,all""" + appname = appname or os.path.split(os.getcwd())[-1] + appfolder = applications+'/'+appname + zipfile = os.path.join(appfolder, '_update.zip') + if os.path.exists(zipfile): + os.unlink(zipfile) + + local('zip -r _update.zip */*.py */*/*.py views/*.html views/*/*.html static/*') + + put('_update.zip','/tmp/_update.zip') + try: + with cd(appfolder): + sudo('unzip -o /tmp/_update.zip') + sudo('chown -R www-data:www-data *') + sudo('echo "%s" > DATE_DEPLOYMENT' % now) + + finally: + sudo('rm /tmp/_update.zip') def restore(backup): """fab -H username@host restore:backupfilename""" diff --git a/gluon/compileapp.py b/gluon/compileapp.py index 459c2848..7ba67e8e 100644 --- a/gluon/compileapp.py +++ b/gluon/compileapp.py @@ -487,7 +487,8 @@ def compile_views(folder, skip_failed_views=False): else: raise Exception("%s in %s" % (e, fname)) else: - filename = ('views/%s.py' % fname).replace('/', '_').replace('\\', '_') + filename = 'views.%s.py' % fname.replace(os.path.sep, '.') + # filename = ('views/%s.py' % fname).replace('/', '_').replace('\\', '_') filename = pjoin(folder, 'compiled', filename) write_file(filename, data) save_pyc(filename) From b19c3419ec9313ce9cac62849e7d6f247ec40f65 Mon Sep 17 00:00:00 2001 From: mdipierro Date: Fri, 30 Sep 2016 13:54:37 -0500 Subject: [PATCH 39/49] do not cache normal views because of dependencies --- gluon/compileapp.py | 67 +++++++++++---------------------------------- 1 file changed, 16 insertions(+), 51 deletions(-) diff --git a/gluon/compileapp.py b/gluon/compileapp.py index 7ba67e8e..7ca15433 100644 --- a/gluon/compileapp.py +++ b/gluon/compileapp.py @@ -430,13 +430,10 @@ def build_environment(request, response, session, store_current=True): current.T = t current.cache = c - global __builtins__ if is_jython: # jython hack + global __builtins__ __builtins__ = mybuiltin() - elif is_pypy: # apply the same hack to pypy too - __builtins__ = mybuiltin() - elif PY2: - __builtins__['__import__'] = builtin.__import__ # WHY? + environment['request'] = request environment['response'] = response environment['session'] = session @@ -444,7 +441,6 @@ def build_environment(request, response, session, store_current=True): lambda name, reload=False, app=request.application:\ local_import_aux(name, reload, app) BaseAdapter.set_folder(pjoin(request.folder, 'databases')) - response._view_environment = copy.copy(environment) custom_import_install() return environment @@ -488,7 +484,6 @@ def compile_views(folder, skip_failed_views=False): raise Exception("%s in %s" % (e, fname)) else: filename = 'views.%s.py' % fname.replace(os.path.sep, '.') - # filename = ('views/%s.py' % fname).replace('/', '_').replace('\\', '_') filename = pjoin(folder, 'compiled', filename) write_file(filename, data) save_pyc(filename) @@ -504,7 +499,7 @@ def compile_models(folder): path = pjoin(folder, 'models') for fname in listdir(path, '.+\.py$'): data = read_file(pjoin(path, fname)) - modelfile = 'models.'+fname.replace(os.path.sep,'.') + modelfile = 'models.'+fname.replace(os.path.sep, '.') filename = pjoin(folder, 'compiled', modelfile) mktree(filename) write_file(filename, data) @@ -583,11 +578,10 @@ def run_models_in(environment): continue elif compiled: code = getcfs(model, model, lambda: read_pyc(model)) - elif is_gae: + else: code = getcfs(model, model, lambda: compile2(read_file(model), model)) - else: - code = getcfs(model, model, None) + restricted(code, environment, layer=model) @@ -611,7 +605,6 @@ def run_controller_in(controller, function, environment): rewrite.THREAD_LOCAL.routes.error_message % badf, web2py_error=badf) code = getcfs(filename, filename, lambda: read_pyc(filename)) - restricted(code, environment, layer=filename) elif function == '_TEST': # TESTING: adjust the path to include site packages from gluon.settings import global_settings @@ -630,7 +623,6 @@ def run_controller_in(controller, function, environment): environment['__symbols__'] = environment.keys() code = read_file(filename) code += TEST_CODE - restricted(code, environment, layer=filename) else: filename = pjoin(folder, 'controllers/%s.py' % controller) @@ -645,10 +637,10 @@ def run_controller_in(controller, function, environment): rewrite.THREAD_LOCAL.routes.error_message % badf, web2py_error=badf) code = "%s\nresponse._vars=response._caller(%s)\n" % (code, function) - if is_gae: - layer = filename + ':' + function - code = getcfs(layer, filename, lambda: compile2(code, layer)) - restricted(code, environment, filename) + layer = filename + ':' + function + code = getcfs(layer, filename, lambda: compile2(code, layer)) + + restricted(code, environment, layer=filename) response = current.response vars = response._vars if response.postprocessing: @@ -683,7 +675,7 @@ def run_view_in(environment): if not isinstance(view, str): ccode = parse_template(view, pjoin(folder, 'views'), context=environment) - restricted(ccode, environment, 'file stream') + layer = 'file stream' else: filename = pjoin(folder, 'views', view) if os.path.exists(path): # compiled views @@ -714,16 +706,12 @@ def run_view_in(environment): rewrite.THREAD_LOCAL.routes.error_message % badv, web2py_error=badv) layer = filename - if is_gae: - ccode = getcfs(layer, filename, - lambda: compile2(parse_template(view, - pjoin(folder, 'views'), - context=environment), layer)) - else: - ccode = parse_template(view, - pjoin(folder, 'views'), - context=environment) - restricted(ccode, environment, layer) + # Compile the template + ccode = parse_template(view, + pjoin(folder, 'views'), + context=environment) + + restricted(ccode, environment, layer=layer) def remove_compiled_application(folder): @@ -749,26 +737,3 @@ def compile_application(folder, skip_failed_views=False): compile_controllers(folder) failed_views = compile_views(folder, skip_failed_views) return failed_views - - -def test(): - """ - Example:: - - >>> import traceback, types - >>> environment={'x':1} - >>> open('a.py', 'w').write('print 1/x') - >>> save_pyc('a.py') - >>> os.unlink('a.py') - >>> if type(read_pyc('a.pyc'))==types.CodeType: print 'code' - code - >>> exec read_pyc('a.pyc') in environment - 1 - """ - - return - - -if __name__ == '__main__': - import doctest - doctest.testmod() From a867a65ebe0ad2e45d4ad2ea60e00eb0ed24ae71 Mon Sep 17 00:00:00 2001 From: mdipierro Date: Fri, 30 Sep 2016 13:55:48 -0500 Subject: [PATCH 40/49] syncing pydal 16.09 --- gluon/packages/dal | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gluon/packages/dal b/gluon/packages/dal index 012dbe3e..12bc6d97 160000 --- a/gluon/packages/dal +++ b/gluon/packages/dal @@ -1 +1 @@ -Subproject commit 012dbe3eed0404bc5d5516018f2bf9b3eb5b17ab +Subproject commit 12bc6d97402acce462c1193f57bbba4afde7c3c3 From 590a505c540737117e0cf2ff8649936c12c82a8c Mon Sep 17 00:00:00 2001 From: mdipierro Date: Fri, 30 Sep 2016 16:02:40 -0500 Subject: [PATCH 41/49] upgraded PyMysql to 0.7.9, thanks niphlod --- gluon/contrib/pymysql/__init__.py | 75 +- gluon/contrib/pymysql/_compat.py | 21 + gluon/contrib/pymysql/_socketio.py | 134 + gluon/contrib/pymysql/charset.py | 50 +- gluon/contrib/pymysql/connections.py | 1724 +- gluon/contrib/pymysql/constants/CLIENT.py | 19 +- gluon/contrib/pymysql/constants/COMMAND.py | 10 + gluon/contrib/pymysql/constants/CR.py | 68 + gluon/contrib/pymysql/constants/FIELD_TYPE.py | 1 + .../pymysql/constants/SERVER_STATUS.py | 1 - gluon/contrib/pymysql/converters.py | 419 +- gluon/contrib/pymysql/cursors.py | 499 +- gluon/contrib/pymysql/err.py | 78 +- gluon/contrib/pymysql/optionfile.py | 20 + gluon/contrib/pymysql/tests/__init__.py | 23 +- gluon/contrib/pymysql/tests/base.py | 86 +- .../pymysql/tests/data/load_local_data.txt | 22749 ++++++++++++++++ .../tests/data/load_local_warn_data.txt | 50 + .../contrib/pymysql/tests/test_DictCursor.py | 149 +- gluon/contrib/pymysql/tests/test_SSCursor.py | 40 +- gluon/contrib/pymysql/tests/test_basic.py | 258 +- .../contrib/pymysql/tests/test_connection.py | 576 + .../contrib/pymysql/tests/test_converters.py | 67 + gluon/contrib/pymysql/tests/test_cursor.py | 104 + gluon/contrib/pymysql/tests/test_err.py | 21 + gluon/contrib/pymysql/tests/test_issues.py | 361 +- .../contrib/pymysql/tests/test_load_local.py | 93 + gluon/contrib/pymysql/tests/test_nextset.py | 68 + .../contrib/pymysql/tests/test_optionfile.py | 32 + .../pymysql/tests/thirdparty/__init__.py | 8 + .../tests/thirdparty/test_MySQLdb/__init__.py | 7 + .../thirdparty/test_MySQLdb/capabilities.py | 298 + .../tests/thirdparty/test_MySQLdb/dbapi20.py | 856 + .../test_MySQLdb/test_MySQLdb_capabilities.py | 109 + .../test_MySQLdb/test_MySQLdb_dbapi20.py | 210 + .../test_MySQLdb/test_MySQLdb_nonstandard.py | 101 + gluon/contrib/pymysql/times.py | 4 + gluon/contrib/pymysql/util.py | 3 + 38 files changed, 28064 insertions(+), 1328 deletions(-) create mode 100755 gluon/contrib/pymysql/_compat.py create mode 100755 gluon/contrib/pymysql/_socketio.py create mode 100755 gluon/contrib/pymysql/constants/CR.py create mode 100755 gluon/contrib/pymysql/optionfile.py create mode 100755 gluon/contrib/pymysql/tests/data/load_local_data.txt create mode 100755 gluon/contrib/pymysql/tests/data/load_local_warn_data.txt create mode 100755 gluon/contrib/pymysql/tests/test_connection.py create mode 100755 gluon/contrib/pymysql/tests/test_converters.py create mode 100755 gluon/contrib/pymysql/tests/test_cursor.py create mode 100755 gluon/contrib/pymysql/tests/test_err.py create mode 100755 gluon/contrib/pymysql/tests/test_load_local.py create mode 100755 gluon/contrib/pymysql/tests/test_nextset.py create mode 100755 gluon/contrib/pymysql/tests/test_optionfile.py create mode 100755 gluon/contrib/pymysql/tests/thirdparty/__init__.py create mode 100755 gluon/contrib/pymysql/tests/thirdparty/test_MySQLdb/__init__.py create mode 100755 gluon/contrib/pymysql/tests/thirdparty/test_MySQLdb/capabilities.py create mode 100755 gluon/contrib/pymysql/tests/thirdparty/test_MySQLdb/dbapi20.py create mode 100755 gluon/contrib/pymysql/tests/thirdparty/test_MySQLdb/test_MySQLdb_capabilities.py create mode 100755 gluon/contrib/pymysql/tests/thirdparty/test_MySQLdb/test_MySQLdb_dbapi20.py create mode 100755 gluon/contrib/pymysql/tests/thirdparty/test_MySQLdb/test_MySQLdb_nonstandard.py diff --git a/gluon/contrib/pymysql/__init__.py b/gluon/contrib/pymysql/__init__.py index c1e6d037..bf34c558 100644 --- a/gluon/contrib/pymysql/__init__.py +++ b/gluon/contrib/pymysql/__init__.py @@ -1,7 +1,7 @@ -''' -PyMySQL: A pure-Python drop-in replacement for MySQLdb. +""" +PyMySQL: A pure-Python MySQL client library. -Copyright (c) 2010 PyMySQL contributors +Copyright (c) 2010-2016 PyMySQL contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -20,40 +20,32 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -''' - -VERSION = (0, 5, None) - -from constants import FIELD_TYPE -from converters import escape_dict, escape_sequence, escape_string -from err import Warning, Error, InterfaceError, DataError, \ - DatabaseError, OperationalError, IntegrityError, InternalError, \ - NotSupportedError, ProgrammingError, MySQLError -from times import Date, Time, Timestamp, \ - DateFromTicks, TimeFromTicks, TimestampFromTicks - +""" import sys -try: - frozenset -except NameError: - from sets import ImmutableSet as frozenset - try: - from sets import BaseSet as set - except ImportError: - from sets import Set as set +from ._compat import PY2 +from .constants import FIELD_TYPE +from .converters import escape_dict, escape_sequence, escape_string +from .err import ( + Warning, Error, InterfaceError, DataError, + DatabaseError, OperationalError, IntegrityError, InternalError, + NotSupportedError, ProgrammingError, MySQLError) +from .times import ( + Date, Time, Timestamp, + DateFromTicks, TimeFromTicks, TimestampFromTicks) + +VERSION = (0, 7, 9, None) threadsafety = 1 apilevel = "2.0" -paramstyle = "format" +paramstyle = "pyformat" + class DBAPISet(frozenset): - def __ne__(self, other): if isinstance(other, set): - return super(DBAPISet, self).__ne__(self, other) + return frozenset.__ne__(self, other) else: return other not in self @@ -80,40 +72,52 @@ TIMESTAMP = DBAPISet([FIELD_TYPE.TIMESTAMP, FIELD_TYPE.DATETIME]) DATETIME = TIMESTAMP ROWID = DBAPISet() + def Binary(x): """Return x as a binary type.""" - return str(x) + if PY2: + return bytearray(x) + else: + return bytes(x) + def Connect(*args, **kwargs): """ Connect to the database; see connections.Connection.__init__() for more information. """ - from connections import Connection + from .connections import Connection return Connection(*args, **kwargs) +from pymysql import connections as _orig_conn +if _orig_conn.Connection.__init__.__doc__ is not None: + Connect.__doc__ = _orig_conn.Connection.__init__.__doc__ +del _orig_conn + + def get_client_info(): # for MySQLdb compatibility - return '%s.%s.%s' % VERSION + return '.'.join(map(str, VERSION)) connect = Connection = Connect # we include a doctored version_info here for MySQLdb compatibility -version_info = (1,2,2,"final",0) +version_info = (1,2,6,"final",0) NULL = "NULL" __version__ = get_client_info() def thread_safe(): - return True # match MySQLdb.thread_safe() + return True # match MySQLdb.thread_safe() def install_as_MySQLdb(): """ After this function is called, any application that imports MySQLdb or - _mysql will unwittingly actually use + _mysql will unwittingly actually use """ sys.modules["MySQLdb"] = sys.modules["_mysql"] = sys.modules["pymysql"] + __all__ = [ 'BINARY', 'Binary', 'Connect', 'Connection', 'DATE', 'Date', 'Time', 'Timestamp', 'DateFromTicks', 'TimeFromTicks', 'TimestampFromTicks', @@ -126,6 +130,5 @@ __all__ = [ 'paramstyle', 'threadsafety', 'version_info', "install_as_MySQLdb", - - "NULL","__version__", - ] + "NULL", "__version__", +] diff --git a/gluon/contrib/pymysql/_compat.py b/gluon/contrib/pymysql/_compat.py new file mode 100755 index 00000000..252789ec --- /dev/null +++ b/gluon/contrib/pymysql/_compat.py @@ -0,0 +1,21 @@ +import sys + +PY2 = sys.version_info[0] == 2 +PYPY = hasattr(sys, 'pypy_translation_info') +JYTHON = sys.platform.startswith('java') +IRONPYTHON = sys.platform == 'cli' +CPYTHON = not PYPY and not JYTHON and not IRONPYTHON + +if PY2: + import __builtin__ + range_type = xrange + text_type = unicode + long_type = long + str_type = basestring + unichr = __builtin__.unichr +else: + range_type = range + text_type = str + long_type = int + str_type = str + unichr = chr diff --git a/gluon/contrib/pymysql/_socketio.py b/gluon/contrib/pymysql/_socketio.py new file mode 100755 index 00000000..6a11d42e --- /dev/null +++ b/gluon/contrib/pymysql/_socketio.py @@ -0,0 +1,134 @@ +""" +SocketIO imported from socket module in Python 3. + +Copyright (c) 2001-2013 Python Software Foundation; All Rights Reserved. +""" + +from socket import * +import io +import errno + +__all__ = ['SocketIO'] + +EINTR = errno.EINTR +_blocking_errnos = (errno.EAGAIN, errno.EWOULDBLOCK) + +class SocketIO(io.RawIOBase): + + """Raw I/O implementation for stream sockets. + + This class supports the makefile() method on sockets. It provides + the raw I/O interface on top of a socket object. + """ + + # One might wonder why not let FileIO do the job instead. There are two + # main reasons why FileIO is not adapted: + # - it wouldn't work under Windows (where you can't used read() and + # write() on a socket handle) + # - it wouldn't work with socket timeouts (FileIO would ignore the + # timeout and consider the socket non-blocking) + + # XXX More docs + + def __init__(self, sock, mode): + if mode not in ("r", "w", "rw", "rb", "wb", "rwb"): + raise ValueError("invalid mode: %r" % mode) + io.RawIOBase.__init__(self) + self._sock = sock + if "b" not in mode: + mode += "b" + self._mode = mode + self._reading = "r" in mode + self._writing = "w" in mode + self._timeout_occurred = False + + def readinto(self, b): + """Read up to len(b) bytes into the writable buffer *b* and return + the number of bytes read. If the socket is non-blocking and no bytes + are available, None is returned. + + If *b* is non-empty, a 0 return value indicates that the connection + was shutdown at the other end. + """ + self._checkClosed() + self._checkReadable() + if self._timeout_occurred: + raise IOError("cannot read from timed out object") + while True: + try: + return self._sock.recv_into(b) + except timeout: + self._timeout_occurred = True + raise + except error as e: + n = e.args[0] + if n == EINTR: + continue + if n in _blocking_errnos: + return None + raise + + def write(self, b): + """Write the given bytes or bytearray object *b* to the socket + and return the number of bytes written. This can be less than + len(b) if not all data could be written. If the socket is + non-blocking and no bytes could be written None is returned. + """ + self._checkClosed() + self._checkWritable() + try: + return self._sock.send(b) + except error as e: + # XXX what about EINTR? + if e.args[0] in _blocking_errnos: + return None + raise + + def readable(self): + """True if the SocketIO is open for reading. + """ + if self.closed: + raise ValueError("I/O operation on closed socket.") + return self._reading + + def writable(self): + """True if the SocketIO is open for writing. + """ + if self.closed: + raise ValueError("I/O operation on closed socket.") + return self._writing + + def seekable(self): + """True if the SocketIO is open for seeking. + """ + if self.closed: + raise ValueError("I/O operation on closed socket.") + return super().seekable() + + def fileno(self): + """Return the file descriptor of the underlying socket. + """ + self._checkClosed() + return self._sock.fileno() + + @property + def name(self): + if not self.closed: + return self.fileno() + else: + return -1 + + @property + def mode(self): + return self._mode + + def close(self): + """Close the SocketIO object. This doesn't close the underlying + socket, except if all references to it have disappeared. + """ + if self.closed: + return + io.RawIOBase.close(self) + self._sock._decref_socketios() + self._sock = None + diff --git a/gluon/contrib/pymysql/charset.py b/gluon/contrib/pymysql/charset.py index 507fd07d..968376cf 100644 --- a/gluon/contrib/pymysql/charset.py +++ b/gluon/contrib/pymysql/charset.py @@ -5,11 +5,28 @@ MBLENGTH = { 91:2 } -class Charset: + +class Charset(object): def __init__(self, id, name, collation, is_default): self.id, self.name, self.collation = id, name, collation self.is_default = is_default == 'Yes' + def __repr__(self): + return "Charset(id=%s, name=%r, collation=%r)" % ( + self.id, self.name, self.collation) + + @property + def encoding(self): + name = self.name + if name == 'utf8mb4': + return 'utf8' + return name + + @property + def is_binary(self): + return self.id == 63 + + class Charsets: def __init__(self): self._by_id = {} @@ -21,6 +38,7 @@ class Charsets: return self._by_id[id] def by_name(self, name): + name = name.lower() for c in self._by_id.values(): if c.name == name and c.is_default: return c @@ -92,13 +110,11 @@ _charsets.add(Charset(52, 'cp1251', 'cp1251_general_cs', '')) _charsets.add(Charset(53, 'macroman', 'macroman_bin', '')) _charsets.add(Charset(54, 'utf16', 'utf16_general_ci', 'Yes')) _charsets.add(Charset(55, 'utf16', 'utf16_bin', '')) -_charsets.add(Charset(56, 'utf16le', 'utf16le_general_ci', 'Yes')) _charsets.add(Charset(57, 'cp1256', 'cp1256_general_ci', 'Yes')) _charsets.add(Charset(58, 'cp1257', 'cp1257_bin', '')) _charsets.add(Charset(59, 'cp1257', 'cp1257_general_ci', 'Yes')) _charsets.add(Charset(60, 'utf32', 'utf32_general_ci', 'Yes')) _charsets.add(Charset(61, 'utf32', 'utf32_bin', '')) -_charsets.add(Charset(62, 'utf16le', 'utf16le_bin', '')) _charsets.add(Charset(63, 'binary', 'binary', 'Yes')) _charsets.add(Charset(64, 'armscii8', 'armscii8_bin', '')) _charsets.add(Charset(65, 'ascii', 'ascii_bin', '')) @@ -155,10 +171,6 @@ _charsets.add(Charset(117, 'utf16', 'utf16_persian_ci', '')) _charsets.add(Charset(118, 'utf16', 'utf16_esperanto_ci', '')) _charsets.add(Charset(119, 'utf16', 'utf16_hungarian_ci', '')) _charsets.add(Charset(120, 'utf16', 'utf16_sinhala_ci', '')) -_charsets.add(Charset(121, 'utf16', 'utf16_german2_ci', '')) -_charsets.add(Charset(122, 'utf16', 'utf16_croatian_ci', '')) -_charsets.add(Charset(123, 'utf16', 'utf16_unicode_520_ci', '')) -_charsets.add(Charset(124, 'utf16', 'utf16_vietnamese_ci', '')) _charsets.add(Charset(128, 'ucs2', 'ucs2_unicode_ci', '')) _charsets.add(Charset(129, 'ucs2', 'ucs2_icelandic_ci', '')) _charsets.add(Charset(130, 'ucs2', 'ucs2_latvian_ci', '')) @@ -179,10 +191,6 @@ _charsets.add(Charset(144, 'ucs2', 'ucs2_persian_ci', '')) _charsets.add(Charset(145, 'ucs2', 'ucs2_esperanto_ci', '')) _charsets.add(Charset(146, 'ucs2', 'ucs2_hungarian_ci', '')) _charsets.add(Charset(147, 'ucs2', 'ucs2_sinhala_ci', '')) -_charsets.add(Charset(148, 'ucs2', 'ucs2_german2_ci', '')) -_charsets.add(Charset(149, 'ucs2', 'ucs2_croatian_ci', '')) -_charsets.add(Charset(150, 'ucs2', 'ucs2_unicode_520_ci', '')) -_charsets.add(Charset(151, 'ucs2', 'ucs2_vietnamese_ci', '')) _charsets.add(Charset(159, 'ucs2', 'ucs2_general_mysql500_ci', '')) _charsets.add(Charset(160, 'utf32', 'utf32_unicode_ci', '')) _charsets.add(Charset(161, 'utf32', 'utf32_icelandic_ci', '')) @@ -204,10 +212,6 @@ _charsets.add(Charset(176, 'utf32', 'utf32_persian_ci', '')) _charsets.add(Charset(177, 'utf32', 'utf32_esperanto_ci', '')) _charsets.add(Charset(178, 'utf32', 'utf32_hungarian_ci', '')) _charsets.add(Charset(179, 'utf32', 'utf32_sinhala_ci', '')) -_charsets.add(Charset(180, 'utf32', 'utf32_german2_ci', '')) -_charsets.add(Charset(181, 'utf32', 'utf32_croatian_ci', '')) -_charsets.add(Charset(182, 'utf32', 'utf32_unicode_520_ci', '')) -_charsets.add(Charset(183, 'utf32', 'utf32_vietnamese_ci', '')) _charsets.add(Charset(192, 'utf8', 'utf8_unicode_ci', '')) _charsets.add(Charset(193, 'utf8', 'utf8_icelandic_ci', '')) _charsets.add(Charset(194, 'utf8', 'utf8_latvian_ci', '')) @@ -228,10 +232,6 @@ _charsets.add(Charset(208, 'utf8', 'utf8_persian_ci', '')) _charsets.add(Charset(209, 'utf8', 'utf8_esperanto_ci', '')) _charsets.add(Charset(210, 'utf8', 'utf8_hungarian_ci', '')) _charsets.add(Charset(211, 'utf8', 'utf8_sinhala_ci', '')) -_charsets.add(Charset(212, 'utf8', 'utf8_german2_ci', '')) -_charsets.add(Charset(213, 'utf8', 'utf8_croatian_ci', '')) -_charsets.add(Charset(214, 'utf8', 'utf8_unicode_520_ci', '')) -_charsets.add(Charset(215, 'utf8', 'utf8_vietnamese_ci', '')) _charsets.add(Charset(223, 'utf8', 'utf8_general_mysql500_ci', '')) _charsets.add(Charset(224, 'utf8mb4', 'utf8mb4_unicode_ci', '')) _charsets.add(Charset(225, 'utf8mb4', 'utf8mb4_icelandic_ci', '')) @@ -258,9 +258,13 @@ _charsets.add(Charset(245, 'utf8mb4', 'utf8mb4_croatian_ci', '')) _charsets.add(Charset(246, 'utf8mb4', 'utf8mb4_unicode_520_ci', '')) _charsets.add(Charset(247, 'utf8mb4', 'utf8mb4_vietnamese_ci', '')) -def charset_by_name(name): - return _charsets.by_name(name) -def charset_by_id(id): - return _charsets.by_id(id) +charset_by_name = _charsets.by_name +charset_by_id = _charsets.by_id + +def charset_to_encoding(name): + """Convert MySQL's charset name to Python's codec name""" + if name == 'utf8mb4': + return 'utf8' + return name diff --git a/gluon/contrib/pymysql/connections.py b/gluon/contrib/pymysql/connections.py index e4f91330..d5e39a1c 100644 --- a/gluon/contrib/pymysql/connections.py +++ b/gluon/contrib/pymysql/connections.py @@ -1,91 +1,141 @@ # Python implementation of the MySQL client-server protocol -# http://forge.mysql.com/wiki/MySQL_Internals_ClientServer_Protocol - -try: - import hashlib - sha_new = lambda *args, **kwargs: hashlib.new("sha1", *args, **kwargs) -except ImportError: - import sha - sha_new = sha.new +# http://dev.mysql.com/doc/internals/en/client-server-protocol.html +# Error codes: +# http://dev.mysql.com/doc/refman/5.5/en/error-messages-client.html +from __future__ import print_function +from ._compat import PY2, range_type, text_type, str_type, JYTHON, IRONPYTHON +import errno +from functools import partial +import hashlib +import io +import os import socket +import struct +import sys +import traceback +import warnings + +from .charset import MBLENGTH, charset_by_name, charset_by_id +from .constants import CLIENT, COMMAND, FIELD_TYPE, SERVER_STATUS +from .converters import escape_item, escape_string, through, conversions as _conv +from .cursors import Cursor +from .optionfile import Parser +from .util import byte2int, int2byte +from . import err + try: import ssl SSL_ENABLED = True except ImportError: + ssl = None SSL_ENABLED = False -import struct -import sys -import os -import ConfigParser - -try: - import cStringIO as StringIO -except ImportError: - import StringIO - try: import getpass DEFAULT_USER = getpass.getuser() -except ImportError: + del getpass +except (ImportError, KeyError): + # KeyError occurs when there's no entry in OS database for a current user. DEFAULT_USER = None -from charset import MBLENGTH, charset_by_name, charset_by_id -from cursors import Cursor -from constants import FIELD_TYPE, FLAG -from constants import SERVER_STATUS -from constants.CLIENT import * -from constants.COMMAND import * -from util import join_bytes, byte2int, int2byte -from converters import escape_item, encoders, decoders -from err import raise_mysql_exception, Warning, Error, \ - InterfaceError, DataError, DatabaseError, OperationalError, \ - IntegrityError, InternalError, NotSupportedError, ProgrammingError DEBUG = False +_py_version = sys.version_info[:2] + + +# socket.makefile() in Python 2 is not usable because very inefficient and +# bad behavior about timeout. +# XXX: ._socketio doesn't work under IronPython. +if _py_version == (2, 7) and not IRONPYTHON: + # read method of file-like returned by sock.makefile() is very slow. + # So we copy io-based one from Python 3. + from ._socketio import SocketIO + + def _makefile(sock, mode): + return io.BufferedReader(SocketIO(sock, mode)) +elif _py_version == (2, 6): + # Python 2.6 doesn't have fast io module. + # So we make original one. + class SockFile(object): + def __init__(self, sock): + self._sock = sock + + def read(self, n): + read = self._sock.recv(n) + if len(read) == n: + return read + while True: + data = self._sock.recv(n-len(read)) + if not data: + return read + read += data + if len(read) == n: + return read + + def _makefile(sock, mode): + assert mode == 'rb' + return SockFile(sock) +else: + # socket.makefile in Python 3 is nice. + def _makefile(sock, mode): + return sock.makefile(mode) + + +TEXT_TYPES = set([ + FIELD_TYPE.BIT, + FIELD_TYPE.BLOB, + FIELD_TYPE.LONG_BLOB, + FIELD_TYPE.MEDIUM_BLOB, + FIELD_TYPE.STRING, + FIELD_TYPE.TINY_BLOB, + FIELD_TYPE.VAR_STRING, + FIELD_TYPE.VARCHAR, + FIELD_TYPE.GEOMETRY]) + +sha_new = partial(hashlib.new, 'sha1') + NULL_COLUMN = 251 UNSIGNED_CHAR_COLUMN = 251 UNSIGNED_SHORT_COLUMN = 252 UNSIGNED_INT24_COLUMN = 253 UNSIGNED_INT64_COLUMN = 254 -UNSIGNED_CHAR_LENGTH = 1 -UNSIGNED_SHORT_LENGTH = 2 -UNSIGNED_INT24_LENGTH = 3 -UNSIGNED_INT64_LENGTH = 8 DEFAULT_CHARSET = 'latin1' +MAX_PACKET_LEN = 2**24-1 -def dump_packet(data): - + +def dump_packet(data): # pragma: no cover def is_ascii(data): - if byte2int(data) >= 65 and byte2int(data) <= 122: #data.isalnum(): + if 65 <= byte2int(data) <= 122: + if isinstance(data, int): + return chr(data) return data return '.' - + try: - print "packet length %d" % len(data) - print "method call[1]: %s" % sys._getframe(1).f_code.co_name - print "method call[2]: %s" % sys._getframe(2).f_code.co_name - print "method call[3]: %s" % sys._getframe(3).f_code.co_name - print "method call[4]: %s" % sys._getframe(4).f_code.co_name - print "method call[5]: %s" % sys._getframe(5).f_code.co_name - print "-" * 88 - except ValueError: pass - dump_data = [data[i:i+16] for i in xrange(len(data)) if i%16 == 0] + print("packet length:", len(data)) + for i in range(1, 6): + f = sys._getframe(i) + print("call[%d]: %s (line %d)" % (i, f.f_code.co_name, f.f_lineno)) + print("-" * 66) + except ValueError: + pass + dump_data = [data[i:i+16] for i in range_type(0, min(len(data), 256), 16)] for d in dump_data: - print ' '.join(map(lambda x:"%02X" % byte2int(x), d)) + \ - ' ' * (16 - len(d)) + ' ' * 2 + \ - ' '.join(map(lambda x:"%s" % is_ascii(x), d)) - print "-" * 88 - print "" + print(' '.join(map(lambda x: "{:02X}".format(byte2int(x)), d)) + + ' ' * (16 - len(d)) + ' ' * 2 + + ''.join(map(lambda x: "{}".format(is_ascii(x)), d))) + print("-" * 66) + print() + def _scramble(password, message): - if password == None or len(password) == 0: - return int2byte(0) - if DEBUG: print 'password=' + password + if not password: + return b'' + if DEBUG: print('password=' + str(password)) stage1 = sha_new(password).digest() stage2 = sha_new(stage1).digest() s = sha_new() @@ -94,11 +144,12 @@ def _scramble(password, message): result = s.digest() return _my_crypt(result, stage1) + def _my_crypt(message1, message2): length = len(message1) - result = struct.pack('B', length) - for i in xrange(length): - x = (struct.unpack('B', message1[i:i+1])[0] ^ \ + result = b'' + for i in range_type(length): + x = (struct.unpack('B', message1[i:i+1])[0] ^ struct.unpack('B', message2[i:i+1])[0]) result += struct.pack('B', x) return result @@ -106,17 +157,19 @@ def _my_crypt(message1, message2): # old_passwords support ported from libmysql/password.c SCRAMBLE_LENGTH_323 = 8 + class RandStruct_323(object): def __init__(self, seed1, seed2): - self.max_value = 0x3FFFFFFFL + self.max_value = 0x3FFFFFFF self.seed1 = seed1 % self.max_value self.seed2 = seed2 % self.max_value def my_rnd(self): - self.seed1 = (self.seed1 * 3L + self.seed2) % self.max_value - self.seed2 = (self.seed1 + self.seed2 + 33L) % self.max_value + self.seed1 = (self.seed1 * 3 + self.seed2) % self.max_value + self.seed2 = (self.seed1 + self.seed2 + 33) % self.max_value return float(self.seed1) / float(self.max_value) + def _scramble_323(password, message): hash_pass = _hash_password_323(password) hash_message = _hash_password_323(message[:SCRAMBLE_LENGTH_323]) @@ -125,286 +178,273 @@ def _scramble_323(password, message): rand_st = RandStruct_323(hash_pass_n[0] ^ hash_message_n[0], hash_pass_n[1] ^ hash_message_n[1]) - outbuf = StringIO.StringIO() - for _ in xrange(min(SCRAMBLE_LENGTH_323, len(message))): + outbuf = io.BytesIO() + for _ in range_type(min(SCRAMBLE_LENGTH_323, len(message))): outbuf.write(int2byte(int(rand_st.my_rnd() * 31) + 64)) extra = int2byte(int(rand_st.my_rnd() * 31)) out = outbuf.getvalue() - outbuf = StringIO.StringIO() + outbuf = io.BytesIO() for c in out: outbuf.write(int2byte(byte2int(c) ^ byte2int(extra))) return outbuf.getvalue() + def _hash_password_323(password): - nr = 1345345333L - add = 7L - nr2 = 0x12345671L + nr = 1345345333 + add = 7 + nr2 = 0x12345671 - for c in [byte2int(x) for x in password if x not in (' ', '\t')]: - nr^= (((nr & 63)+add)*c)+ (nr << 8) & 0xFFFFFFFF - nr2= (nr2 + ((nr2 << 8) ^ nr)) & 0xFFFFFFFF - add= (add + c) & 0xFFFFFFFF + # x in py3 is numbers, p27 is chars + for c in [byte2int(x) for x in password if x not in (' ', '\t', 32, 9)]: + nr ^= (((nr & 63) + add) * c) + (nr << 8) & 0xFFFFFFFF + nr2 = (nr2 + ((nr2 << 8) ^ nr)) & 0xFFFFFFFF + add = (add + c) & 0xFFFFFFFF - r1 = nr & ((1L << 31) - 1L) # kill sign bits - r2 = nr2 & ((1L << 31) - 1L) - - # pack + r1 = nr & ((1 << 31) - 1) # kill sign bits + r2 = nr2 & ((1 << 31) - 1) return struct.pack(">LL", r1, r2) + def pack_int24(n): - return struct.pack('BBB', n&0xFF, (n>>8)&0xFF, (n>>16)&0xFF) + return struct.pack(' len(self.__data): - raise Exception('Invalid advance amount (%s) for cursor. ' - 'Position=%s' % (length, new_position)) - self.__position = new_position + def __init__(self, data, encoding): + self._position = 0 + self._data = data - def rewind(self, position=0): - """Set the position of the data buffer cursor to 'position'.""" - if position < 0 or position > len(self.__data): - raise Exception("Invalid position to rewind cursor to: %s." % position) - self.__position = position + def get_all_data(self): + return self._data - def peek(self, size): - """Look at the first 'size' bytes in packet without moving cursor.""" - result = self.__data[self.__position:(self.__position+size)] - if len(result) != size: - error = ('Result length not requested length:\n' - 'Expected=%s. Actual=%s. Position: %s. Data Length: %s' - % (size, len(result), self.__position, len(self.__data))) - if DEBUG: - print error - self.dump() - raise AssertionError(error) - return result + def read(self, size): + """Read the first 'size' bytes in packet and advance cursor past them.""" + result = self._data[self._position:(self._position+size)] + if len(result) != size: + error = ('Result length not requested length:\n' + 'Expected=%s. Actual=%s. Position: %s. Data Length: %s' + % (size, len(result), self._position, len(self._data))) + if DEBUG: + print(error) + self.dump() + raise AssertionError(error) + self._position += size + return result - def get_bytes(self, position, length=1): - """Get 'length' bytes starting at 'position'. + def read_all(self): + """Read all remaining data in the packet. - Position is start of payload (first four packet header bytes are not - included) starting at index '0'. + (Subsequent read() will return errors.) + """ + result = self._data[self._position:] + self._position = None # ensure no subsequent read() + return result - No error checking is done. If requesting outside end of buffer - an empty string (or string shorter than 'length') may be returned! - """ - return self.__data[position:(position+length)] + def advance(self, length): + """Advance the cursor in data buffer 'length' bytes.""" + new_position = self._position + length + if new_position < 0 or new_position > len(self._data): + raise Exception('Invalid advance amount (%s) for cursor. ' + 'Position=%s' % (length, new_position)) + self._position = new_position - def read_length_coded_binary(self): - """Read a 'Length Coded Binary' number from the data buffer. + def rewind(self, position=0): + """Set the position of the data buffer cursor to 'position'.""" + if position < 0 or position > len(self._data): + raise Exception("Invalid position to rewind cursor to: %s." % position) + self._position = position - Length coded numbers can be anywhere from 1 to 9 bytes depending - on the value of the first byte. - """ - c = byte2int(self.read(1)) - if c == NULL_COLUMN: - return None - if c < UNSIGNED_CHAR_COLUMN: - return c - elif c == UNSIGNED_SHORT_COLUMN: - return unpack_uint16(self.read(UNSIGNED_SHORT_LENGTH)) - elif c == UNSIGNED_INT24_COLUMN: - return unpack_int24(self.read(UNSIGNED_INT24_LENGTH)) - elif c == UNSIGNED_INT64_COLUMN: - # TODO: what was 'longlong'? confirm it wasn't used? - return unpack_int64(self.read(UNSIGNED_INT64_LENGTH)) + def get_bytes(self, position, length=1): + """Get 'length' bytes starting at 'position'. - def read_length_coded_string(self): - """Read a 'Length Coded String' from the data buffer. + Position is start of payload (first four packet header bytes are not + included) starting at index '0'. - A 'Length Coded String' consists first of a length coded - (unsigned, positive) integer represented in 1-9 bytes followed by - that many bytes of binary data. (For example "cat" would be "3cat".) - """ - length = self.read_length_coded_binary() - if length is None: - return None - return self.read(length) + No error checking is done. If requesting outside end of buffer + an empty string (or string shorter than 'length') may be returned! + """ + return self._data[position:(position+length)] - def is_ok_packet(self): - return byte2int(self.get_bytes(0)) == 0 + if PY2: + def read_uint8(self): + result = ord(self._data[self._position]) + self._position += 1 + return result + else: + def read_uint8(self): + result = self._data[self._position] + self._position += 1 + return result - def is_eof_packet(self): - return byte2int(self.get_bytes(0)) == 254 # 'fe' + def read_uint16(self): + result = struct.unpack_from('= 1 and field_count <= 250 + def read_uint24(self): + low, high = struct.unpack_from('= 7 + + def is_eof_packet(self): + # http://dev.mysql.com/doc/internals/en/generic-response-packets.html#packet-EOF_Packet + # Caution: \xFE may be LengthEncodedInteger. + # If \xFE is LengthEncodedInteger header, 8bytes followed. + return self._data[0:1] == b'\xfe' and len(self._data) < 9 + + def is_auth_switch_request(self): + # http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::AuthSwitchRequest + return self._data[0:1] == b'\xfe' + + def is_resultset_packet(self): + field_count = ord(self._data[0:1]) + return 1 <= field_count <= 250 + + def is_load_local_packet(self): + return self._data[0:1] == b'\xfb' + + def is_error_packet(self): + return self._data[0:1] == b'\xff' + + def check_error(self): + if self.is_error_packet(): + self.rewind() + self.advance(1) # field_count == error (we already know that) + errno = self.read_uint16() + if DEBUG: print("errno =", errno) + err.raise_mysql_exception(self._data) + + def dump(self): + dump_packet(self._data) class FieldDescriptorPacket(MysqlPacket): - """A MysqlPacket that represents a specific column's metadata in the result. + """A MysqlPacket that represents a specific column's metadata in the result. - Parsing is automatically done and the results are exported via public - attributes on the class such as: db, table_name, name, length, type_code. - """ - - def __init__(self, *args): - MysqlPacket.__init__(self, *args) - self.__parse_field_descriptor() - - def __parse_field_descriptor(self): - """Parse the 'Field Descriptor' (Metadata) packet. - - This is compatible with MySQL 4.1+ (not compatible with MySQL 4.0). + Parsing is automatically done and the results are exported via public + attributes on the class such as: db, table_name, name, length, type_code. """ - self.catalog = self.read_length_coded_string() - self.db = self.read_length_coded_string() - self.table_name = self.read_length_coded_string() - self.org_table = self.read_length_coded_string() - self.name = self.read_length_coded_string().decode(self.connection.charset) - self.org_name = self.read_length_coded_string() - self.advance(1) # non-null filler - self.charsetnr = struct.unpack(' 2: use_unicode = True - if compress or named_pipe: - raise NotImplementedError, "compress and named_pipe arguments are not supported" + if db is not None and database is None: + database = db + if passwd is not None and not password: + password = passwd - if ssl and (ssl.has_key('capath') or ssl.has_key('cipher')): - raise NotImplementedError, 'ssl options capath and cipher are not supported' + if compress or named_pipe: + raise NotImplementedError("compress and named_pipe arguments are not supported") + + if local_infile: + client_flag |= CLIENT.LOCAL_FILES self.ssl = False if ssl: if not SSL_ENABLED: - raise NotImplementedError, "ssl module not found" + raise NotImplementedError("ssl module not found") self.ssl = True - client_flag |= SSL - for k in ('key', 'cert', 'ca'): - v = None - if ssl.has_key(k): - v = ssl[k] - setattr(self, k, v) + client_flag |= CLIENT.SSL + self.ctx = self._create_ssl_ctx(ssl) if read_default_group and not read_default_file: if sys.platform.startswith("win"): @@ -530,29 +615,37 @@ class Connection(object): if not read_default_group: read_default_group = "client" - cfg = ConfigParser.RawConfigParser() + cfg = Parser() cfg.read(os.path.expanduser(read_default_file)) - def _config(key, default): + def _config(key, arg): + if arg: + return arg try: - return cfg.get(read_default_group,key) - except: - return default + return cfg.get(read_default_group, key) + except Exception: + return arg - user = _config("user",user) - passwd = _config("password",passwd) + user = _config("user", user) + password = _config("password", password) host = _config("host", host) - db = _config("db",db) - unix_socket = _config("socket",unix_socket) + database = _config("database", database) + unix_socket = _config("socket", unix_socket) port = int(_config("port", port)) charset = _config("default-character-set", charset) - self.host = host - self.port = port + self.host = host or "localhost" + self.port = port or 3306 self.user = user or DEFAULT_USER - self.password = passwd - self.db = db + self.password = password or "" + self.db = database self.unix_socket = unix_socket + if read_timeout is not None and read_timeout <= 0: + raise ValueError("read_timeout should be >= 0") + self._read_timeout = read_timeout + if write_timeout is not None and write_timeout <= 0: + raise ValueError("write_timeout should be >= 0") + self._write_timeout = write_timeout if charset: self.charset = charset self.use_unicode = True @@ -563,102 +656,167 @@ class Connection(object): if use_unicode is not None: self.use_unicode = use_unicode - client_flag |= CAPABILITIES - client_flag |= MULTI_STATEMENTS + self.encoding = charset_by_name(self.charset).encoding + + client_flag |= CLIENT.CAPABILITIES if self.db: - client_flag |= CONNECT_WITH_DB + client_flag |= CLIENT.CONNECT_WITH_DB self.client_flag = client_flag self.cursorclass = cursorclass self.connect_timeout = connect_timeout - self._connect() - self._result = None self._affected_rows = 0 self.host_info = "Not connected" - self.messages = [] - self.set_charset(charset) - self.encoders = encoders - self.decoders = conv + #: specified autocommit mode. None means use server default. + self.autocommit_mode = autocommit - self.autocommit(False) - - if sql_mode is not None: - c = self.cursor() - c.execute("SET sql_mode=%s", (sql_mode,)) - - self.commit() - - if init_command is not None: - c = self.cursor() - c.execute(init_command) - - self.commit() + if conv is None: + conv = _conv + # Need for MySQLdb compatibility. + self.encoders = dict([(k, v) for (k, v) in conv.items() if type(k) is not int]) + self.decoders = dict([(k, v) for (k, v) in conv.items() if type(k) is int]) + self.sql_mode = sql_mode + self.init_command = init_command + self.max_allowed_packet = max_allowed_packet + self._auth_plugin_map = auth_plugin_map + if defer_connect: + self._sock = None + else: + self.connect() + def _create_ssl_ctx(self, sslp): + if isinstance(sslp, ssl.SSLContext): + return sslp + ca = sslp.get('ca') + capath = sslp.get('capath') + hasnoca = ca is None and capath is None + ctx = ssl.create_default_context(cafile=ca, capath=capath) + ctx.check_hostname = not hasnoca and sslp.get('check_hostname', True) + ctx.verify_mode = ssl.CERT_NONE if hasnoca else ssl.CERT_REQUIRED + if 'cert' in sslp: + ctx.load_cert_chain(sslp['cert'], keyfile=sslp.get('key')) + if 'cipher' in sslp: + ctx.set_ciphers(sslp['cipher']) + ctx.options |= ssl.OP_NO_SSLv2 + ctx.options |= ssl.OP_NO_SSLv3 + return ctx def close(self): - ''' Send the quit message and close the socket ''' - if self.socket is None: - raise Error("Already closed") - send_data = struct.pack('= 5: + self.client_flag |= CLIENT.MULTI_RESULTS if self.user is None: - raise ValueError, "Did not specify a username" + raise ValueError("Did not specify a username") charset_id = charset_by_name(self.charset).id - self.user = self.user.encode(self.charset) + if isinstance(self.user, text_type): + self.user = self.user.encode(self.encoding) - data_init = struct.pack('=5.0) + data += authresp + b'\0' - if self.db: - self.db = self.db.encode(self.charset) - data += self.db + int2byte(0) + if self.db and self.server_capabilities & CLIENT.CONNECT_WITH_DB: + if isinstance(self.db, text_type): + self.db = self.db.encode(self.encoding) + data += self.db + b'\0' - data = pack_int24(len(data)) + int2byte(next_packet) + data - next_packet += 2 + if self.server_capabilities & CLIENT.PLUGIN_AUTH: + name = self._auth_plugin_name + if isinstance(name, text_type): + name = name.encode('ascii') + data += name + b'\0' - if DEBUG: dump_packet(data) + self.write_packet(data) + auth_packet = self._read_packet() - self.wfile.write(data) - self.wfile.flush() + # if authentication method isn't accepted the first byte + # will have the octet 254 + if auth_packet.is_auth_switch_request(): + # https://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::AuthSwitchRequest + auth_packet.read_uint8() # 0xfe packet identifier + plugin_name = auth_packet.read_string() + if self.server_capabilities & CLIENT.PLUGIN_AUTH and plugin_name is not None: + auth_packet = self._process_auth(plugin_name, auth_packet) + else: + # send legacy handshake + data = _scramble_323(self.password.encode('latin1'), self.salt) + b'\0' + self.write_packet(data) + auth_packet = self._read_packet() - auth_packet = MysqlPacket(self) - auth_packet.check_error() - if DEBUG: auth_packet.dump() + def _process_auth(self, plugin_name, auth_packet): + plugin_class = self._auth_plugin_map.get(plugin_name) + if not plugin_class: + plugin_class = self._auth_plugin_map.get(plugin_name.decode('ascii')) + if plugin_class: + try: + handler = plugin_class(self) + return handler.authenticate(auth_packet) + except AttributeError: + if plugin_name != b'dialog': + raise err.OperationalError(2059, "Authentication plugin '%s'" \ + " not loaded: - %r missing authenticate method" % (plugin_name, plugin_class)) + except TypeError: + raise err.OperationalError(2059, "Authentication plugin '%s'" \ + " not loaded: - %r cannot be constructed with connection object" % (plugin_name, plugin_class)) + else: + handler = None + if plugin_name == b"mysql_native_password": + # https://dev.mysql.com/doc/internals/en/secure-password-authentication.html#packet-Authentication::Native41 + data = _scramble(self.password.encode('latin1'), auth_packet.read_all()) + b'\0' + elif plugin_name == b"mysql_old_password": + # https://dev.mysql.com/doc/internals/en/old-password-authentication.html + data = _scramble_323(self.password.encode('latin1'), auth_packet.read_all()) + b'\0' + elif plugin_name == b"mysql_clear_password": + # https://dev.mysql.com/doc/internals/en/clear-text-authentication.html + data = self.password.encode('latin1') + b'\0' + elif plugin_name == b"dialog": + pkt = auth_packet + while True: + flag = pkt.read_uint8() + echo = (flag & 0x06) == 0x02 + last = (flag & 0x01) == 0x01 + prompt = pkt.read_all() - # if old_passwords is enabled the packet will be 1 byte long and - # have the octet 254 - - if auth_packet.is_eof_packet(): - # send legacy handshake - #raise NotImplementedError, "old_passwords are not supported. Check to see if mysqld was started with --old-passwords, if old-passwords=1 in a my.cnf file, or if there are some short hashes in your mysql.user table." - # TODO: is this the correct charset? - data = _scramble_323(self.password.encode(self.charset), self.salt.encode(self.charset)) + int2byte(0) - data = pack_int24(len(data)) + int2byte(next_packet) + data - - self.wfile.write(data) - self.wfile.flush() - auth_packet = MysqlPacket(self) - auth_packet.check_error() - if DEBUG: auth_packet.dump() + if prompt == b"Password: ": + self.write_packet(self.password.encode('latin1') + b'\0') + elif handler: + resp = 'no response - TypeError within plugin.prompt method' + try: + resp = handler.prompt(echo, prompt) + self.write_packet(resp + b'\0') + except AttributeError: + raise err.OperationalError(2059, "Authentication plugin '%s'" \ + " not loaded: - %r missing prompt method" % (plugin_name, handler)) + except TypeError: + raise err.OperationalError(2061, "Authentication plugin '%s'" \ + " %r didn't respond with string. Returned '%r' to prompt %r" % (plugin_name, handler, resp, prompt)) + else: + raise err.OperationalError(2059, "Authentication plugin '%s' (%r) not configured" % (plugin_name, handler)) + pkt = self._read_packet() + pkt.check_error() + if pkt.is_ok_packet() or last: + break + return pkt + else: + raise err.OperationalError(2059, "Authentication plugin '%s' not configured" % plugin_name) + self.write_packet(data) + pkt = self._read_packet() + pkt.check_error() + return pkt # _mysql support def thread_id(self): @@ -877,64 +1204,87 @@ class Connection(object): def _get_server_information(self): i = 0 - packet = MysqlPacket(self) + packet = self._read_packet() data = packet.get_all_data() if DEBUG: dump_packet(data) - #packet_len = byte2int(data[i:i+1]) - #i += 4 self.protocol_version = byte2int(data[i:i+1]) - i += 1 - server_end = data.find(int2byte(0), i) - # TODO: is this the correct charset? should it be default_charset? - self.server_version = data[i:server_end].decode(self.charset) + server_end = data.find(b'\0', i) + self.server_version = data[i:server_end].decode('latin1') i = server_end + 1 - self.server_thread_id = struct.unpack('= i + 1: - i += 1 + self.server_capabilities = struct.unpack('= i + 6: + lang, stat, cap_h, salt_len = struct.unpack('= i+12-1: - rest_salt = data[i:i+12] - self.salt += rest_salt + self.server_capabilities |= cap_h << 16 + if DEBUG: print("salt_len:", salt_len) + salt_len = max(12, salt_len - 9) + + # reserved + i += 10 + + if len(data) >= i + salt_len: + # salt_len includes auth_plugin_data_part_1 and filler + self.salt += data[i:i+salt_len] + i += salt_len + + i+=1 + # AUTH PLUGIN NAME may appear here. + if self.server_capabilities & CLIENT.PLUGIN_AUTH and len(data) >= i: + # Due to Bug#59453 the auth-plugin-name is missing the terminating + # NUL-char in versions prior to 5.5.10 and 5.6.2. + # ref: https://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::Handshake + # didn't use version checks as mariadb is corrected and reports + # earlier than those two. + server_end = data.find(b'\0', i) + if server_end < 0: # pragma: no cover - very specific upstream bug + # not found \0 and last field so take it all + self._auth_plugin_name = data[i:].decode('latin1') + else: + self._auth_plugin_name = data[i:server_end].decode('latin1') def get_server_info(self): return self.server_version - Warning = Warning - Error = Error - InterfaceError = InterfaceError - DatabaseError = DatabaseError - DataError = DataError - OperationalError = OperationalError - IntegrityError = IntegrityError - InternalError = InternalError - ProgrammingError = ProgrammingError - NotSupportedError = NotSupportedError + Warning = err.Warning + Error = err.Error + InterfaceError = err.InterfaceError + DatabaseError = err.DatabaseError + DataError = err.DataError + OperationalError = err.OperationalError + IntegrityError = err.IntegrityError + InternalError = err.InternalError + ProgrammingError = err.ProgrammingError + NotSupportedError = err.NotSupportedError + -# TODO: move OK and EOF packet parsing/logic into a proper subclass -# of MysqlPacket like has been done with FieldDescriptorPacket. class MySQLResult(object): def __init__(self, connection): - from weakref import proxy - self.connection = proxy(connection) + """ + :type connection: Connection + """ + self.connection = connection self.affected_rows = None self.insert_id = None - self.server_status = 0 + self.server_status = None self.warning_count = 0 self.message = None self.field_count = 0 @@ -948,122 +1298,202 @@ class MySQLResult(object): self._finish_unbuffered_query() def read(self): - self.first_packet = self.connection.read_packet() + try: + first_packet = self.connection._read_packet() - # TODO: use classes for different packet types? - if self.first_packet.is_ok_packet(): - self._read_ok_packet() - else: - self._read_result_packet() + if first_packet.is_ok_packet(): + self._read_ok_packet(first_packet) + elif first_packet.is_load_local_packet(): + self._read_load_local_packet(first_packet) + else: + self._read_result_packet(first_packet) + finally: + self.connection = None def init_unbuffered_query(self): self.unbuffered_active = True - self.first_packet = self.connection.read_packet() + first_packet = self.connection._read_packet() - if self.first_packet.is_ok_packet(): - self._read_ok_packet() + if first_packet.is_ok_packet(): + self._read_ok_packet(first_packet) self.unbuffered_active = False + self.connection = None + elif first_packet.is_load_local_packet(): + self._read_load_local_packet(first_packet) + self.unbuffered_active = False + self.connection = None else: - self.field_count = byte2int(self.first_packet.read(1)) + self.field_count = first_packet.read_length_encoded_integer() self._get_descriptions() - + # Apparently, MySQLdb picks this number because it's the maximum # value of a 64bit unsigned integer. Since we're emulating MySQLdb, # we set it to this instead of None, which would be preferred. self.affected_rows = 18446744073709551615 - def _read_ok_packet(self): - ok_packet = OKPacketWrapper(self.first_packet) + def _read_ok_packet(self, first_packet): + ok_packet = OKPacketWrapper(first_packet) self.affected_rows = ok_packet.affected_rows self.insert_id = ok_packet.insert_id self.server_status = ok_packet.server_status self.warning_count = ok_packet.warning_count self.message = ok_packet.message + self.has_next = ok_packet.has_next + + def _read_load_local_packet(self, first_packet): + load_packet = LoadLocalPacketWrapper(first_packet) + sender = LoadLocalFile(load_packet.filename, self.connection) + try: + sender.send_data() + except: + self.connection._read_packet() # skip ok packet + raise + + ok_packet = self.connection._read_packet() + if not ok_packet.is_ok_packet(): # pragma: no cover - upstream induced protocol error + raise err.OperationalError(2014, "Commands Out of Sync") + self._read_ok_packet(ok_packet) def _check_packet_is_eof(self, packet): - if packet.is_eof_packet(): - eof_packet = EOFPacketWrapper(packet) - self.warning_count = eof_packet.warning_count - self.has_next = eof_packet.has_next - return True - return False + if not packet.is_eof_packet(): + return False + #TODO: Support CLIENT.DEPRECATE_EOF + # 1) Add DEPRECATE_EOF to CAPABILITIES + # 2) Mask CAPABILITIES with server_capabilities + # 3) if server_capabilities & CLIENT.DEPRECATE_EOF: use OKPacketWrapper instead of EOFPacketWrapper + wp = EOFPacketWrapper(packet) + self.warning_count = wp.warning_count + self.has_next = wp.has_next + return True - def _read_result_packet(self): - self.field_count = byte2int(self.first_packet.read(1)) + def _read_result_packet(self, first_packet): + self.field_count = first_packet.read_length_encoded_integer() self._get_descriptions() self._read_rowdata_packet() def _read_rowdata_packet_unbuffered(self): # Check if in an active query - if self.unbuffered_active == False: return - + if not self.unbuffered_active: + return + # EOF - packet = self.connection.read_packet() + packet = self.connection._read_packet() if self._check_packet_is_eof(packet): self.unbuffered_active = False + self.connection = None self.rows = None return - row = [] - for field in self.fields: - data = packet.read_length_coded_string() - converted = None - if field.type_code in self.connection.decoders: - converter = self.connection.decoders[field.type_code] - if DEBUG: print "DEBUG: field=%s, converter=%s" % (field, converter) - if data != None: - converted = converter(self.connection, field, data) - row.append(converted) - + row = self._read_row_from_packet(packet) self.affected_rows = 1 - self.rows = tuple((row)) - if DEBUG: self.rows + self.rows = (row,) # rows should tuple of row for MySQL-python compatibility. + return row def _finish_unbuffered_query(self): # After much reading on the MySQL protocol, it appears that there is, # in fact, no way to stop MySQL from sending all the data after # executing a query, so we just spin, and wait for an EOF packet. while self.unbuffered_active: - packet = self.connection.read_packet() + packet = self.connection._read_packet() if self._check_packet_is_eof(packet): self.unbuffered_active = False + self.connection = None # release reference to kill cyclic reference. - # TODO: implement this as an iteratable so that it is more - # memory efficient and lower-latency to client... def _read_rowdata_packet(self): - """Read a rowdata packet for each data row in the result set.""" - rows = [] - while True: - packet = self.connection.read_packet() - if self._check_packet_is_eof(packet): - break + """Read a rowdata packet for each data row in the result set.""" + rows = [] + while True: + packet = self.connection._read_packet() + if self._check_packet_is_eof(packet): + self.connection = None # release reference to kill cyclic reference. + break + rows.append(self._read_row_from_packet(packet)) + self.affected_rows = len(rows) + self.rows = tuple(rows) + + def _read_row_from_packet(self, packet): row = [] - for field in self.fields: - data = packet.read_length_coded_string() - converted = None - if field.type_code in self.connection.decoders: - converter = self.connection.decoders[field.type_code] - if DEBUG: print "DEBUG: field=%s, converter=%s" % (field, converter) - if data != None: - converted = converter(self.connection, field, data) - row.append(converted) - - rows.append(tuple(row)) - - self.affected_rows = len(rows) - self.rows = tuple(rows) - if DEBUG: self.rows + for encoding, converter in self.converters: + try: + data = packet.read_length_coded_string() + except IndexError: + # No more columns in this row + # See https://github.com/PyMySQL/PyMySQL/pull/434 + break + if data is not None: + if encoding is not None: + data = data.decode(encoding) + if DEBUG: print("DEBUG: DATA = ", data) + if converter is not None: + data = converter(data) + row.append(data) + return tuple(row) def _get_descriptions(self): """Read a column descriptor packet for each column in the result.""" self.fields = [] + self.converters = [] + use_unicode = self.connection.use_unicode + conn_encoding = self.connection.encoding description = [] - for i in xrange(self.field_count): - field = self.connection.read_packet(FieldDescriptorPacket) + + for i in range_type(self.field_count): + field = self.connection._read_packet(FieldDescriptorPacket) self.fields.append(field) description.append(field.description()) + field_type = field.type_code + if use_unicode: + if field_type == FIELD_TYPE.JSON: + # When SELECT from JSON column: charset = binary + # When SELECT CAST(... AS JSON): charset = connection encoding + # This behavior is different from TEXT / BLOB. + # We should decode result by connection encoding regardless charsetnr. + # See https://github.com/PyMySQL/PyMySQL/issues/488 + encoding = conn_encoding # SELECT CAST(... AS JSON) + elif field_type in TEXT_TYPES: + if field.charsetnr == 63: # binary + # TEXTs with charset=binary means BINARY types. + encoding = None + else: + encoding = conn_encoding + else: + # Integers, Dates and Times, and other basic data is encoded in ascii + encoding = 'ascii' + else: + encoding = None + converter = self.connection.decoders.get(field_type) + if converter is through: + converter = None + if DEBUG: print("DEBUG: field={}, converter={}".format(field, converter)) + self.converters.append((encoding, converter)) - eof_packet = self.connection.read_packet() + eof_packet = self.connection._read_packet() assert eof_packet.is_eof_packet(), 'Protocol error, expecting EOF' self.description = tuple(description) + + +class LoadLocalFile(object): + def __init__(self, filename, connection): + self.filename = filename + self.connection = connection + + def send_data(self): + """Send data packets from the local file to the server""" + if not self.connection._sock: + raise err.InterfaceError("(0, '')") + conn = self.connection + + try: + with open(self.filename, 'rb') as open_file: + packet_size = min(conn.max_allowed_packet, 16*1024) # 16KB is efficient enough + while True: + chunk = open_file.read(packet_size) + if not chunk: + break + conn.write_packet(chunk) + except IOError: + raise err.OperationalError(1017, "Can't find file '{0}'".format(self.filename)) + finally: + # send the empty packet to signify we are done sending data + conn.write_packet(b'') diff --git a/gluon/contrib/pymysql/constants/CLIENT.py b/gluon/contrib/pymysql/constants/CLIENT.py index 9d11ea10..6625b6a7 100644 --- a/gluon/contrib/pymysql/constants/CLIENT.py +++ b/gluon/contrib/pymysql/constants/CLIENT.py @@ -1,4 +1,4 @@ - +# https://dev.mysql.com/doc/internals/en/capability-flags.html#packet-Protocol::CapabilityFlags LONG_PASSWORD = 1 FOUND_ROWS = 1 << 1 LONG_FLAG = 1 << 2 @@ -12,9 +12,20 @@ PROTOCOL_41 = 1 << 9 INTERACTIVE = 1 << 10 SSL = 1 << 11 IGNORE_SIGPIPE = 1 << 12 -TRANSACTIONS = 1 << 13 +TRANSACTIONS = 1 << 13 SECURE_CONNECTION = 1 << 15 MULTI_STATEMENTS = 1 << 16 MULTI_RESULTS = 1 << 17 -CAPABILITIES = LONG_PASSWORD|LONG_FLAG|TRANSACTIONS| \ - PROTOCOL_41|SECURE_CONNECTION +PS_MULTI_RESULTS = 1 << 18 +PLUGIN_AUTH = 1 << 19 +PLUGIN_AUTH_LENENC_CLIENT_DATA = 1 << 21 +CAPABILITIES = ( + LONG_PASSWORD | LONG_FLAG | PROTOCOL_41 | TRANSACTIONS + | SECURE_CONNECTION | MULTI_STATEMENTS | MULTI_RESULTS + | PLUGIN_AUTH | PLUGIN_AUTH_LENENC_CLIENT_DATA) + +# Not done yet +CONNECT_ATTRS = 1 << 20 +HANDLE_EXPIRED_PASSWORDS = 1 << 22 +SESSION_TRACK = 1 << 23 +DEPRECATE_EOF = 1 << 24 diff --git a/gluon/contrib/pymysql/constants/COMMAND.py b/gluon/contrib/pymysql/constants/COMMAND.py index 4a757da2..1da27553 100644 --- a/gluon/contrib/pymysql/constants/COMMAND.py +++ b/gluon/contrib/pymysql/constants/COMMAND.py @@ -21,3 +21,13 @@ COM_BINLOG_DUMP = 0x12 COM_TABLE_DUMP = 0x13 COM_CONNECT_OUT = 0x14 COM_REGISTER_SLAVE = 0x15 +COM_STMT_PREPARE = 0x16 +COM_STMT_EXECUTE = 0x17 +COM_STMT_SEND_LONG_DATA = 0x18 +COM_STMT_CLOSE = 0x19 +COM_STMT_RESET = 0x1a +COM_SET_OPTION = 0x1b +COM_STMT_FETCH = 0x1c +COM_DAEMON = 0x1d +COM_BINLOG_DUMP_GTID = 0x1e +COM_END = 0x1f diff --git a/gluon/contrib/pymysql/constants/CR.py b/gluon/contrib/pymysql/constants/CR.py new file mode 100755 index 00000000..48ca956e --- /dev/null +++ b/gluon/contrib/pymysql/constants/CR.py @@ -0,0 +1,68 @@ +# flake8: noqa +# errmsg.h +CR_ERROR_FIRST = 2000 +CR_UNKNOWN_ERROR = 2000 +CR_SOCKET_CREATE_ERROR = 2001 +CR_CONNECTION_ERROR = 2002 +CR_CONN_HOST_ERROR = 2003 +CR_IPSOCK_ERROR = 2004 +CR_UNKNOWN_HOST = 2005 +CR_SERVER_GONE_ERROR = 2006 +CR_VERSION_ERROR = 2007 +CR_OUT_OF_MEMORY = 2008 +CR_WRONG_HOST_INFO = 2009 +CR_LOCALHOST_CONNECTION = 2010 +CR_TCP_CONNECTION = 2011 +CR_SERVER_HANDSHAKE_ERR = 2012 +CR_SERVER_LOST = 2013 +CR_COMMANDS_OUT_OF_SYNC = 2014 +CR_NAMEDPIPE_CONNECTION = 2015 +CR_NAMEDPIPEWAIT_ERROR = 2016 +CR_NAMEDPIPEOPEN_ERROR = 2017 +CR_NAMEDPIPESETSTATE_ERROR = 2018 +CR_CANT_READ_CHARSET = 2019 +CR_NET_PACKET_TOO_LARGE = 2020 +CR_EMBEDDED_CONNECTION = 2021 +CR_PROBE_SLAVE_STATUS = 2022 +CR_PROBE_SLAVE_HOSTS = 2023 +CR_PROBE_SLAVE_CONNECT = 2024 +CR_PROBE_MASTER_CONNECT = 2025 +CR_SSL_CONNECTION_ERROR = 2026 +CR_MALFORMED_PACKET = 2027 +CR_WRONG_LICENSE = 2028 + +CR_NULL_POINTER = 2029 +CR_NO_PREPARE_STMT = 2030 +CR_PARAMS_NOT_BOUND = 2031 +CR_DATA_TRUNCATED = 2032 +CR_NO_PARAMETERS_EXISTS = 2033 +CR_INVALID_PARAMETER_NO = 2034 +CR_INVALID_BUFFER_USE = 2035 +CR_UNSUPPORTED_PARAM_TYPE = 2036 + +CR_SHARED_MEMORY_CONNECTION = 2037 +CR_SHARED_MEMORY_CONNECT_REQUEST_ERROR = 2038 +CR_SHARED_MEMORY_CONNECT_ANSWER_ERROR = 2039 +CR_SHARED_MEMORY_CONNECT_FILE_MAP_ERROR = 2040 +CR_SHARED_MEMORY_CONNECT_MAP_ERROR = 2041 +CR_SHARED_MEMORY_FILE_MAP_ERROR = 2042 +CR_SHARED_MEMORY_MAP_ERROR = 2043 +CR_SHARED_MEMORY_EVENT_ERROR = 2044 +CR_SHARED_MEMORY_CONNECT_ABANDONED_ERROR = 2045 +CR_SHARED_MEMORY_CONNECT_SET_ERROR = 2046 +CR_CONN_UNKNOW_PROTOCOL = 2047 +CR_INVALID_CONN_HANDLE = 2048 +CR_SECURE_AUTH = 2049 +CR_FETCH_CANCELED = 2050 +CR_NO_DATA = 2051 +CR_NO_STMT_METADATA = 2052 +CR_NO_RESULT_SET = 2053 +CR_NOT_IMPLEMENTED = 2054 +CR_SERVER_LOST_EXTENDED = 2055 +CR_STMT_CLOSED = 2056 +CR_NEW_STMT_METADATA = 2057 +CR_ALREADY_CONNECTED = 2058 +CR_AUTH_PLUGIN_CANNOT_LOAD = 2059 +CR_DUPLICATE_CONNECTION_ATTR = 2060 +CR_AUTH_PLUGIN_ERR = 2061 +CR_ERROR_LAST = 2061 diff --git a/gluon/contrib/pymysql/constants/FIELD_TYPE.py b/gluon/contrib/pymysql/constants/FIELD_TYPE.py index 3df7ff48..51bd5143 100644 --- a/gluon/contrib/pymysql/constants/FIELD_TYPE.py +++ b/gluon/contrib/pymysql/constants/FIELD_TYPE.py @@ -17,6 +17,7 @@ YEAR = 13 NEWDATE = 14 VARCHAR = 15 BIT = 16 +JSON = 245 NEWDECIMAL = 246 ENUM = 247 SET = 248 diff --git a/gluon/contrib/pymysql/constants/SERVER_STATUS.py b/gluon/contrib/pymysql/constants/SERVER_STATUS.py index 010f542d..6f5d5663 100644 --- a/gluon/contrib/pymysql/constants/SERVER_STATUS.py +++ b/gluon/contrib/pymysql/constants/SERVER_STATUS.py @@ -9,4 +9,3 @@ SERVER_STATUS_LAST_ROW_SENT = 128 SERVER_STATUS_DB_DROPPED = 256 SERVER_STATUS_NO_BACKSLASH_ESCAPES = 512 SERVER_STATUS_METADATA_CHANGED = 1024 - diff --git a/gluon/contrib/pymysql/converters.py b/gluon/contrib/pymysql/converters.py index 56e93f9d..4c00bc45 100644 --- a/gluon/contrib/pymysql/converters.py +++ b/gluon/contrib/pymysql/converters.py @@ -1,106 +1,162 @@ -import re +from ._compat import PY2, text_type, long_type, JYTHON, IRONPYTHON, unichr + import datetime +from decimal import Decimal +import re import time -import sys -from constants import FIELD_TYPE, FLAG -from charset import charset_by_id +from .constants import FIELD_TYPE, FLAG +from .charset import charset_by_id, charset_to_encoding -PYTHON3 = sys.version_info[0] > 2 -try: - set -except NameError: - try: - from sets import BaseSet as set - except ImportError: - from sets import Set as set +def escape_item(val, charset, mapping=None): + if mapping is None: + mapping = encoders + encoder = mapping.get(type(val)) -ESCAPE_REGEX = re.compile(r"[\0\n\r\032\'\"\\]") -ESCAPE_MAP = {'\0': '\\0', '\n': '\\n', '\r': '\\r', '\032': '\\Z', - '\'': '\\\'', '"': '\\"', '\\': '\\\\'} + # Fallback to default when no encoder found + if not encoder: + try: + encoder = mapping[text_type] + except KeyError: + raise TypeError("no default type converter defined") -def escape_item(val, charset): - if type(val) in [tuple, list, set]: - return escape_sequence(val, charset) - if type(val) is dict: - return escape_dict(val, charset) - if PYTHON3 and hasattr(val, "decode") and not isinstance(val, unicode): - # deal with py3k bytes - val = val.decode(charset) - encoder = encoders[type(val)] - val = encoder(val) - if type(val) in [str, int]: - return val - val = val.encode(charset) + if encoder in (escape_dict, escape_sequence): + val = encoder(val, charset, mapping) + else: + val = encoder(val, mapping) return val -def escape_dict(val, charset): +def escape_dict(val, charset, mapping=None): n = {} for k, v in val.items(): - quoted = escape_item(v, charset) + quoted = escape_item(v, charset, mapping) n[k] = quoted return n -def escape_sequence(val, charset): +def escape_sequence(val, charset, mapping=None): n = [] for item in val: - quoted = escape_item(item, charset) + quoted = escape_item(item, charset, mapping) n.append(quoted) return "(" + ",".join(n) + ")" -def escape_set(val, charset): - val = map(lambda x: escape_item(x, charset), val) - return ','.join(val) +def escape_set(val, charset, mapping=None): + return ','.join([escape_item(x, charset, mapping) for x in val]) -def escape_bool(value): +def escape_bool(value, mapping=None): return str(int(value)) -def escape_object(value): +def escape_object(value, mapping=None): return str(value) -def escape_int(value): - return value +def escape_int(value, mapping=None): + return str(value) -escape_long = escape_object - -def escape_float(value): +def escape_float(value, mapping=None): return ('%.15g' % value) -def escape_string(value): - return ("'%s'" % ESCAPE_REGEX.sub( - lambda match: ESCAPE_MAP.get(match.group(0)), value)) +_escape_table = [unichr(x) for x in range(128)] +_escape_table[0] = u'\\0' +_escape_table[ord('\\')] = u'\\\\' +_escape_table[ord('\n')] = u'\\n' +_escape_table[ord('\r')] = u'\\r' +_escape_table[ord('\032')] = u'\\Z' +_escape_table[ord('"')] = u'\\"' +_escape_table[ord("'")] = u"\\'" -def escape_unicode(value): - return escape_string(value) +def _escape_unicode(value, mapping=None): + """escapes *value* without adding quote. -def escape_None(value): + Value should be unicode + """ + return value.translate(_escape_table) + +if PY2: + def escape_string(value, mapping=None): + """escape_string escapes *value* but not surround it with quotes. + + Value should be bytes or unicode. + """ + if isinstance(value, unicode): + return _escape_unicode(value) + assert isinstance(value, (bytes, bytearray)) + value = value.replace('\\', '\\\\') + value = value.replace('\0', '\\0') + value = value.replace('\n', '\\n') + value = value.replace('\r', '\\r') + value = value.replace('\032', '\\Z') + value = value.replace("'", "\\'") + value = value.replace('"', '\\"') + return value + + def escape_bytes(value, mapping=None): + assert isinstance(value, (bytes, bytearray)) + return b"_binary'%s'" % escape_string(value) +else: + escape_string = _escape_unicode + + # On Python ~3.5, str.decode('ascii', 'surrogateescape') is slow. + # (fixed in Python 3.6, http://bugs.python.org/issue24870) + # Workaround is str.decode('latin1') then translate 0x80-0xff into 0udc80-0udcff. + # We can escape special chars and surrogateescape at once. + _escape_bytes_table = _escape_table + [chr(i) for i in range(0xdc80, 0xdd00)] + + def escape_bytes(value, mapping=None): + return "_binary'%s'" % value.decode('latin1').translate(_escape_bytes_table) + + +def escape_unicode(value, mapping=None): + return u"'%s'" % _escape_unicode(value) + +def escape_str(value, mapping=None): + return "'%s'" % escape_string(str(value), mapping) + +def escape_None(value, mapping=None): return 'NULL' -def escape_timedelta(obj): +def escape_timedelta(obj, mapping=None): seconds = int(obj.seconds) % 60 minutes = int(obj.seconds // 60) % 60 hours = int(obj.seconds // 3600) % 24 + int(obj.days) * 24 - return escape_string('%02d:%02d:%02d' % (hours, minutes, seconds)) + if obj.microseconds: + fmt = "'{0:02d}:{1:02d}:{2:02d}.{3:06d}'" + else: + fmt = "'{0:02d}:{1:02d}:{2:02d}'" + return fmt.format(hours, minutes, seconds, obj.microseconds) -def escape_time(obj): - s = "%02d:%02d:%02d" % (int(obj.hour), int(obj.minute), - int(obj.second)) +def escape_time(obj, mapping=None): if obj.microsecond: - s += ".%f" % obj.microsecond + fmt = "'{0.hour:02}:{0.minute:02}:{0.second:02}.{0.microsecond:06}'" + else: + fmt = "'{0.hour:02}:{0.minute:02}:{0.second:02}'" + return fmt.format(obj) - return escape_string(s) +def escape_datetime(obj, mapping=None): + if obj.microsecond: + fmt = "'{0.year:04}-{0.month:02}-{0.day:02} {0.hour:02}:{0.minute:02}:{0.second:02}.{0.microsecond:06}'" + else: + fmt = "'{0.year:04}-{0.month:02}-{0.day:02} {0.hour:02}:{0.minute:02}:{0.second:02}'" + return fmt.format(obj) -def escape_datetime(obj): - return escape_string(obj.strftime("%Y-%m-%d %H:%M:%S")) +def escape_date(obj, mapping=None): + fmt = "'{0.year:04}-{0.month:02}-{0.day:02}'" + return fmt.format(obj) -def escape_date(obj): - return escape_string(obj.strftime("%Y-%m-%d")) - -def escape_struct_time(obj): +def escape_struct_time(obj, mapping=None): return escape_datetime(datetime.datetime(*obj[:6])) -def convert_datetime(connection, field, obj): +def _convert_second_fraction(s): + if not s: + return 0 + # Pad zeros to ensure the fraction length in microseconds + s = s.ljust(6, '0') + return int(s[:6]) + +DATETIME_RE = re.compile(r"(\d{1,4})-(\d{1,2})-(\d{1,2})[T ](\d{1,2}):(\d{1,2}):(\d{1,2})(?:.(\d{1,6}))?") + + +def convert_datetime(obj): """Returns a DATETIME or TIMESTAMP column value as a datetime object: >>> datetime_or_None('2007-02-25 23:06:20') @@ -116,22 +172,24 @@ def convert_datetime(connection, field, obj): True """ - if not isinstance(obj, unicode): - obj = obj.decode(connection.charset) - if ' ' in obj: - sep = ' ' - elif 'T' in obj: - sep = 'T' - else: - return convert_date(connection, field, obj) + if not PY2 and isinstance(obj, (bytes, bytearray)): + obj = obj.decode('ascii') + + m = DATETIME_RE.match(obj) + if not m: + return convert_date(obj) try: - ymd, hms = obj.split(sep, 1) - return datetime.datetime(*[ int(x) for x in ymd.split('-')+hms.split(':') ]) + groups = list(m.groups()) + groups[-1] = _convert_second_fraction(groups[-1]) + return datetime.datetime(*[ int(x) for x in groups ]) except ValueError: - return convert_date(connection, field, obj) + return convert_date(obj) -def convert_timedelta(connection, field, obj): +TIMEDELTA_RE = re.compile(r"(-)?(\d{1,3}):(\d{1,2}):(\d{1,2})(?:.(\d{1,6}))?") + + +def convert_timedelta(obj): """Returns a TIME column as a timedelta object: >>> timedelta_or_None('25:06:17') @@ -148,25 +206,33 @@ def convert_timedelta(connection, field, obj): can accept values as (+|-)DD HH:MM:SS. The latter format will not be parsed correctly by this function. """ + if not PY2 and isinstance(obj, (bytes, bytearray)): + obj = obj.decode('ascii') + + m = TIMEDELTA_RE.match(obj) + if not m: + return None + try: - microseconds = 0 - if not isinstance(obj, unicode): - obj = obj.decode(connection.charset) - if "." in obj: - (obj, tail) = obj.split('.') - microseconds = int(tail) - hours, minutes, seconds = obj.split(':') + groups = list(m.groups()) + groups[-1] = _convert_second_fraction(groups[-1]) + negate = -1 if groups[0] else 1 + hours, minutes, seconds, microseconds = groups[1:] + tdelta = datetime.timedelta( hours = int(hours), minutes = int(minutes), seconds = int(seconds), - microseconds = microseconds - ) + microseconds = int(microseconds) + ) * negate return tdelta except ValueError: return None -def convert_time(connection, field, obj): +TIME_RE = re.compile(r"(\d{1,2}):(\d{1,2}):(\d{1,2})(?:.(\d{1,6}))?") + + +def convert_time(obj): """Returns a TIME column as a time object: >>> time_or_None('15:06:17') @@ -188,18 +254,24 @@ def convert_time(connection, field, obj): to be treated as time-of-day and not a time offset, then you can use set this function as the converter for FIELD_TYPE.TIME. """ + if not PY2 and isinstance(obj, (bytes, bytearray)): + obj = obj.decode('ascii') + + m = TIME_RE.match(obj) + if not m: + return None + try: - microseconds = 0 - if "." in obj: - (obj, tail) = obj.split('.') - microseconds = int(tail) - hours, minutes, seconds = obj.split(':') + groups = list(m.groups()) + groups[-1] = _convert_second_fraction(groups[-1]) + hours, minutes, seconds, microseconds = groups return datetime.time(hour=int(hours), minute=int(minutes), - second=int(seconds), microsecond=microseconds) + second=int(seconds), microsecond=int(microseconds)) except ValueError: return None -def convert_date(connection, field, obj): + +def convert_date(obj): """Returns a DATE column as a date object: >>> date_or_None('2007-02-26') @@ -213,14 +285,15 @@ def convert_date(connection, field, obj): True """ + if not PY2 and isinstance(obj, (bytes, bytearray)): + obj = obj.decode('ascii') try: - if not isinstance(obj, unicode): - obj = obj.decode(connection.charset) return datetime.date(*[ int(x) for x in obj.split('-', 2) ]) except ValueError: return None -def convert_mysql_timestamp(connection, field, timestamp): + +def convert_mysql_timestamp(timestamp): """Convert a MySQL TIMESTAMP to a Timestamp object. MySQL >= 4.1 returns TIMESTAMP in the same format as DATETIME: @@ -241,11 +314,10 @@ def convert_mysql_timestamp(connection, field, timestamp): True """ - if not isinstance(timestamp, unicode): - timestamp = timestamp.decode(connection.charset) - + if not PY2 and isinstance(timestamp, (bytes, bytearray)): + timestamp = timestamp.decode('ascii') if timestamp[4] == '-': - return convert_datetime(connection, field, timestamp) + return convert_datetime(timestamp) timestamp += "0"*(14-len(timestamp)) # padding year, month, day, hour, minute, second = \ int(timestamp[:4]), int(timestamp[4:6]), int(timestamp[6:8]), \ @@ -256,101 +328,92 @@ def convert_mysql_timestamp(connection, field, timestamp): return None def convert_set(s): + if isinstance(s, (bytes, bytearray)): + return set(s.split(b",")) return set(s.split(",")) -def convert_bit(connection, field, b): - #b = "\x00" * (8 - len(b)) + b # pad w/ zeroes - #return struct.unpack(">Q", b)[0] - # - # the snippet above is right, but MySQLdb doesn't process bits, - # so we shouldn't either - return b + +def through(x): + return x + + +#def convert_bit(b): +# b = "\x00" * (8 - len(b)) + b # pad w/ zeroes +# return struct.unpack(">Q", b)[0] +# +# the snippet above is right, but MySQLdb doesn't process bits, +# so we shouldn't either +convert_bit = through + def convert_characters(connection, field, data): field_charset = charset_by_id(field.charsetnr).name + encoding = charset_to_encoding(field_charset) if field.flags & FLAG.SET: - return convert_set(data.decode(field_charset)) + return convert_set(data.decode(encoding)) if field.flags & FLAG.BINARY: return data if connection.use_unicode: - data = data.decode(field_charset) + data = data.decode(encoding) elif connection.charset != field_charset: - data = data.decode(field_charset) - data = data.encode(connection.charset) + data = data.decode(encoding) + data = data.encode(connection.encoding) return data -def convert_int(connection, field, data): - return int(data) - -def convert_long(connection, field, data): - return long(data) - -def convert_float(connection, field, data): - return float(data) - encoders = { - bool: escape_bool, - int: escape_int, - long: escape_long, - float: escape_float, - str: escape_string, - unicode: escape_unicode, - tuple: escape_sequence, - list:escape_sequence, - set:escape_sequence, - dict:escape_dict, - type(None):escape_None, - datetime.date: escape_date, - datetime.datetime : escape_datetime, - datetime.timedelta : escape_timedelta, - datetime.time : escape_time, - time.struct_time : escape_struct_time, - } + bool: escape_bool, + int: escape_int, + long_type: escape_int, + float: escape_float, + str: escape_str, + text_type: escape_unicode, + tuple: escape_sequence, + list: escape_sequence, + set: escape_sequence, + frozenset: escape_sequence, + dict: escape_dict, + bytearray: escape_bytes, + type(None): escape_None, + datetime.date: escape_date, + datetime.datetime: escape_datetime, + datetime.timedelta: escape_timedelta, + datetime.time: escape_time, + time.struct_time: escape_struct_time, + Decimal: escape_object, +} + +if not PY2 or JYTHON or IRONPYTHON: + encoders[bytes] = escape_bytes decoders = { - FIELD_TYPE.BIT: convert_bit, - FIELD_TYPE.TINY: convert_int, - FIELD_TYPE.SHORT: convert_int, - FIELD_TYPE.LONG: convert_long, - FIELD_TYPE.FLOAT: convert_float, - FIELD_TYPE.DOUBLE: convert_float, - FIELD_TYPE.DECIMAL: convert_float, - FIELD_TYPE.NEWDECIMAL: convert_float, - FIELD_TYPE.LONGLONG: convert_long, - FIELD_TYPE.INT24: convert_int, - FIELD_TYPE.YEAR: convert_int, - FIELD_TYPE.TIMESTAMP: convert_mysql_timestamp, - FIELD_TYPE.DATETIME: convert_datetime, - FIELD_TYPE.TIME: convert_timedelta, - FIELD_TYPE.DATE: convert_date, - FIELD_TYPE.SET: convert_set, - FIELD_TYPE.BLOB: convert_characters, - FIELD_TYPE.TINY_BLOB: convert_characters, - FIELD_TYPE.MEDIUM_BLOB: convert_characters, - FIELD_TYPE.LONG_BLOB: convert_characters, - FIELD_TYPE.STRING: convert_characters, - FIELD_TYPE.VAR_STRING: convert_characters, - FIELD_TYPE.VARCHAR: convert_characters, - #FIELD_TYPE.BLOB: str, - #FIELD_TYPE.STRING: str, - #FIELD_TYPE.VAR_STRING: str, - #FIELD_TYPE.VARCHAR: str - } -conversions = decoders # for MySQLdb compatibility + FIELD_TYPE.BIT: convert_bit, + FIELD_TYPE.TINY: int, + FIELD_TYPE.SHORT: int, + FIELD_TYPE.LONG: int, + FIELD_TYPE.FLOAT: float, + FIELD_TYPE.DOUBLE: float, + FIELD_TYPE.LONGLONG: int, + FIELD_TYPE.INT24: int, + FIELD_TYPE.YEAR: int, + FIELD_TYPE.TIMESTAMP: convert_mysql_timestamp, + FIELD_TYPE.DATETIME: convert_datetime, + FIELD_TYPE.TIME: convert_timedelta, + FIELD_TYPE.DATE: convert_date, + FIELD_TYPE.SET: convert_set, + FIELD_TYPE.BLOB: through, + FIELD_TYPE.TINY_BLOB: through, + FIELD_TYPE.MEDIUM_BLOB: through, + FIELD_TYPE.LONG_BLOB: through, + FIELD_TYPE.STRING: through, + FIELD_TYPE.VAR_STRING: through, + FIELD_TYPE.VARCHAR: through, + FIELD_TYPE.DECIMAL: Decimal, + FIELD_TYPE.NEWDECIMAL: Decimal, +} -try: - # python version > 2.3 - from decimal import Decimal - def convert_decimal(connection, field, data): - data = data.decode(connection.charset) - return Decimal(data) - decoders[FIELD_TYPE.DECIMAL] = convert_decimal - decoders[FIELD_TYPE.NEWDECIMAL] = convert_decimal - def escape_decimal(obj): - return unicode(obj) - encoders[Decimal] = escape_decimal - -except ImportError: - pass +# for MySQLdb compatibility +conversions = encoders.copy() +conversions.update(decoders) +Thing2Literal = escape_str diff --git a/gluon/contrib/pymysql/cursors.py b/gluon/contrib/pymysql/cursors.py index f9775f56..c3e16ba1 100644 --- a/gluon/contrib/pymysql/cursors.py +++ b/gluon/contrib/pymysql/cursors.py @@ -1,67 +1,82 @@ # -*- coding: utf-8 -*- -import struct +from __future__ import print_function, absolute_import +from functools import partial import re +import warnings -try: - import cStringIO as StringIO -except ImportError: - import StringIO +from ._compat import range_type, text_type, PY2 +from . import err -from err import Warning, Error, InterfaceError, DataError, \ - DatabaseError, OperationalError, IntegrityError, InternalError, \ - NotSupportedError, ProgrammingError -insert_values = re.compile(r'\svalues\s*(\(.+\))', re.IGNORECASE) +#: Regular expression for :meth:`Cursor.executemany`. +#: executemany only suports simple bulk insert. +#: You can use it to load large dataset. +RE_INSERT_VALUES = re.compile( + r"\s*((?:INSERT|REPLACE)\s.+\sVALUES?\s+)" + + r"(\(\s*(?:%s|%\(.+\)s)\s*(?:,\s*(?:%s|%\(.+\)s)\s*)*\))" + + r"(\s*(?:ON DUPLICATE.*)?)\Z", + re.IGNORECASE | re.DOTALL) + class Cursor(object): - ''' + """ This is the object you use to interact with the database. - ''' + """ + + #: Max stetement size which :meth:`executemany` generates. + #: + #: Max size of allowed statement is max_allowed_packet - packet_header_size. + #: Default value of max_allowed_packet is 1048576. + max_stmt_length = 1024000 + + _defer_warnings = False + def __init__(self, connection): - ''' + """ Do not create an instance of a Cursor yourself. Call connections.Connection.cursor(). - ''' - from weakref import proxy - self.connection = proxy(connection) + """ + self.connection = connection self.description = None self.rownumber = 0 self.rowcount = -1 self.arraysize = 1 self._executed = None - self.messages = [] - self.errorhandler = connection.errorhandler - self._has_next = None - self._rows = () - - def __del__(self): - ''' - When this gets GC'd close it. - ''' - self.close() + self._result = None + self._rows = None + self._warnings_handled = False def close(self): - ''' + """ Closing a cursor just exhausts all remaining data. - ''' - if not self.connection: + """ + conn = self.connection + if conn is None: return try: while self.nextset(): pass - except: - pass + finally: + self.connection = None - self.connection = None + def __enter__(self): + return self + + def __exit__(self, *exc_info): + del exc_info + self.close() def _get_db(self): if not self.connection: - self.errorhandler(self, ProgrammingError, "cursor closed") + raise err.ProgrammingError("Cursor closed") return self.connection def _check_executed(self): if not self._executed: - self.errorhandler(self, ProgrammingError, "execute() first") + raise err.ProgrammingError("execute() first") + + def _conv_row(self, row): + return row def setinputsizes(self, *args): """Does nothing, required by DB API.""" @@ -69,69 +84,152 @@ class Cursor(object): def setoutputsizes(self, *args): """Does nothing, required by DB API.""" - def nextset(self): - ''' Get the next query set ''' - if self._executed: - self.fetchall() - del self.messages[:] - - if not self._has_next: + def _nextset(self, unbuffered=False): + """Get the next query set""" + conn = self._get_db() + current_result = self._result + # for unbuffered queries warnings are only available once whole result has been read + if unbuffered: + self._show_warnings() + if current_result is None or current_result is not conn._result: return None - connection = self._get_db() - connection.next_result() + if not current_result.has_next: + return None + conn.next_result(unbuffered=unbuffered) self._do_get_result() return True - def execute(self, query, args=None): - ''' Execute a query ''' - from sys import exc_info + def nextset(self): + return self._nextset(False) + def _ensure_bytes(self, x, encoding=None): + if isinstance(x, text_type): + x = x.encode(encoding) + elif isinstance(x, (tuple, list)): + x = type(x)(self._ensure_bytes(v, encoding=encoding) for v in x) + return x + + def _escape_args(self, args, conn): + ensure_bytes = partial(self._ensure_bytes, encoding=conn.encoding) + + if isinstance(args, (tuple, list)): + if PY2: + args = tuple(map(ensure_bytes, args)) + return tuple(conn.literal(arg) for arg in args) + elif isinstance(args, dict): + if PY2: + args = dict((ensure_bytes(key), ensure_bytes(val)) for + (key, val) in args.items()) + return dict((key, conn.literal(val)) for (key, val) in args.items()) + else: + # If it's not a dictionary let's try escaping it anyways. + # Worst case it will throw a Value error + if PY2: + args = ensure_bytes(args) + return conn.escape(args) + + def mogrify(self, query, args=None): + """ + Returns the exact string that is sent to the database by calling the + execute() method. + + This method follows the extension to the DB API 2.0 followed by Psycopg. + """ conn = self._get_db() - charset = conn.charset - del self.messages[:] - - # TODO: make sure that conn.escape is correct - - if isinstance(query, unicode): - query = query.encode(charset) + if PY2: # Use bytes on Python 2 always + query = self._ensure_bytes(query, encoding=conn.encoding) if args is not None: - if isinstance(args, tuple) or isinstance(args, list): - escaped_args = tuple(conn.escape(arg) for arg in args) - elif isinstance(args, dict): - escaped_args = dict((key, conn.escape(val)) for (key, val) in args.items()) - else: - #If it's not a dictionary let's try escaping it anyways. - #Worst case it will throw a Value error - escaped_args = conn.escape(args) + query = query % self._escape_args(args, conn) - query = query % escaped_args + return query - result = 0 - try: - result = self._query(query) - except: - exc, value, tb = exc_info() - del tb - self.messages.append((exc,value)) - self.errorhandler(self, exc, value) + def execute(self, query, args=None): + """Execute a query + :param str query: Query to execute. + + :param args: parameters used with query. (optional) + :type args: tuple, list or dict + + :return: Number of affected rows + :rtype: int + + If args is a list or tuple, %s can be used as a placeholder in the query. + If args is a dict, %(name)s can be used as a placeholder in the query. + """ + while self.nextset(): + pass + + query = self.mogrify(query, args) + + result = self._query(query) self._executed = query return result def executemany(self, query, args): - ''' Run several data against one query ''' - del self.messages[:] - #conn = self._get_db() + # type: (str, list) -> int + """Run several data against one query + + :param query: query to execute on server + :param args: Sequence of sequences or mappings. It is used as parameter. + :return: Number of rows affected, if any. + + This method improves performance on multiple-row INSERT and + REPLACE. Otherwise it is equivalent to looping over args with + execute(). + """ if not args: return - #charset = conn.charset - #if isinstance(query, unicode): - # query = query.encode(charset) - self.rowcount = sum([ self.execute(query, arg) for arg in args ]) + m = RE_INSERT_VALUES.match(query) + if m: + q_prefix = m.group(1) % () + q_values = m.group(2).rstrip() + q_postfix = m.group(3) or '' + assert q_values[0] == '(' and q_values[-1] == ')' + return self._do_execute_many(q_prefix, q_values, q_postfix, args, + self.max_stmt_length, + self._get_db().encoding) + + self.rowcount = sum(self.execute(query, arg) for arg in args) return self.rowcount + def _do_execute_many(self, prefix, values, postfix, args, max_stmt_length, encoding): + conn = self._get_db() + escape = self._escape_args + if isinstance(prefix, text_type): + prefix = prefix.encode(encoding) + if PY2 and isinstance(values, text_type): + values = values.encode(encoding) + if isinstance(postfix, text_type): + postfix = postfix.encode(encoding) + sql = bytearray(prefix) + args = iter(args) + v = values % escape(next(args), conn) + if isinstance(v, text_type): + if PY2: + v = v.encode(encoding) + else: + v = v.encode(encoding, 'surrogateescape') + sql += v + rows = 0 + for arg in args: + v = values % escape(arg, conn) + if isinstance(v, text_type): + if PY2: + v = v.encode(encoding) + else: + v = v.encode(encoding, 'surrogateescape') + if len(sql) + len(v) + len(postfix) + 1 > max_stmt_length: + rows += self.execute(sql + postfix) + sql = bytearray(prefix) + else: + sql += b',' + sql += v + rows += self.execute(sql + postfix) + self.rowcount = rows + return rows def callproc(self, procname, args=()): """Execute stored procedure procname with args @@ -164,23 +262,18 @@ class Cursor(object): conn = self._get_db() for index, arg in enumerate(args): q = "SET @_%s_%d=%s" % (procname, index, conn.escape(arg)) - if isinstance(q, unicode): - q = q.encode(conn.charset) self._query(q) self.nextset() q = "CALL %s(%s)" % (procname, ','.join(['@_%s_%d' % (procname, i) - for i in range(len(args))])) - if isinstance(q, unicode): - q = q.encode(conn.charset) + for i in range_type(len(args))])) self._query(q) self._executed = q - return args def fetchone(self): - ''' Fetch the next row ''' + """Fetch the next row""" self._check_executed() if self._rows is None or self.rownumber >= len(self._rows): return None @@ -189,20 +282,20 @@ class Cursor(object): return result def fetchmany(self, size=None): - ''' Fetch several rows ''' + """Fetch several rows""" self._check_executed() + if self._rows is None: + return () end = self.rownumber + (size or self.arraysize) result = self._rows[self.rownumber:end] - if self._rows is None: - return None self.rownumber = min(end, len(self._rows)) return result def fetchall(self): - ''' Fetch all the rows ''' + """Fetch all the rows""" self._check_executed() if self._rows is None: - return None + return () if self.rownumber: result = self._rows[self.rownumber:] else: @@ -217,11 +310,10 @@ class Cursor(object): elif mode == 'absolute': r = value else: - self.errorhandler(self, ProgrammingError, - "unknown scroll mode %s" % mode) + raise err.ProgrammingError("unknown scroll mode %s" % mode) - if r < 0 or r >= len(self._rows): - self.errorhandler(self, IndexError, "out of range") + if not (0 <= r < len(self._rows)): + raise IndexError("out of range") self.rownumber = r def _query(self, q): @@ -233,92 +325,112 @@ class Cursor(object): def _do_get_result(self): conn = self._get_db() - self.rowcount = conn._result.affected_rows self.rownumber = 0 - self.description = conn._result.description - self.lastrowid = conn._result.insert_id - self._rows = conn._result.rows - self._has_next = conn._result.has_next + self._result = result = conn._result + + self.rowcount = result.affected_rows + self.description = result.description + self.lastrowid = result.insert_id + self._rows = result.rows + self._warnings_handled = False + + if not self._defer_warnings: + self._show_warnings() + + def _show_warnings(self): + if self._warnings_handled: + return + self._warnings_handled = True + if self._result and (self._result.has_next or not self._result.warning_count): + return + ws = self._get_db().show_warnings() + if ws is None: + return + for w in ws: + msg = w[-1] + if PY2: + if isinstance(msg, unicode): + msg = msg.encode('utf-8', 'replace') + warnings.warn(err.Warning(*w[1:3]), stacklevel=4) def __iter__(self): return iter(self.fetchone, None) - Warning = Warning - Error = Error - InterfaceError = InterfaceError - DatabaseError = DatabaseError - DataError = DataError - OperationalError = OperationalError - IntegrityError = IntegrityError - InternalError = InternalError - ProgrammingError = ProgrammingError - NotSupportedError = NotSupportedError + Warning = err.Warning + Error = err.Error + InterfaceError = err.InterfaceError + DatabaseError = err.DatabaseError + DataError = err.DataError + OperationalError = err.OperationalError + IntegrityError = err.IntegrityError + InternalError = err.InternalError + ProgrammingError = err.ProgrammingError + NotSupportedError = err.NotSupportedError -class DictCursor(Cursor): + +class DictCursorMixin(object): + # You can override this to use OrderedDict or other dict-like types. + dict_type = dict + + def _do_get_result(self): + super(DictCursorMixin, self)._do_get_result() + fields = [] + if self.description: + for f in self._result.fields: + name = f.name + if name in fields: + name = f.table_name + '.' + name + fields.append(name) + self._fields = fields + + if fields and self._rows: + self._rows = [self._conv_row(r) for r in self._rows] + + def _conv_row(self, row): + if row is None: + return None + return self.dict_type(zip(self._fields, row)) + + +class DictCursor(DictCursorMixin, Cursor): """A cursor which returns results as a dictionary""" - def execute(self, query, args=None): - result = super(DictCursor, self).execute(query, args) - if self.description: - self._fields = [ field[0] for field in self.description ] - return result - - def fetchone(self): - ''' Fetch the next row ''' - self._check_executed() - if self._rows is None or self.rownumber >= len(self._rows): - return None - result = dict(zip(self._fields, self._rows[self.rownumber])) - self.rownumber += 1 - return result - - def fetchmany(self, size=None): - ''' Fetch several rows ''' - self._check_executed() - if self._rows is None: - return None - end = self.rownumber + (size or self.arraysize) - result = [ dict(zip(self._fields, r)) for r in self._rows[self.rownumber:end] ] - self.rownumber = min(end, len(self._rows)) - return tuple(result) - - def fetchall(self): - ''' Fetch all the rows ''' - self._check_executed() - if self._rows is None: - return None - if self.rownumber: - result = [ dict(zip(self._fields, r)) for r in self._rows[self.rownumber:] ] - else: - result = [ dict(zip(self._fields, r)) for r in self._rows ] - self.rownumber = len(self._rows) - return tuple(result) class SSCursor(Cursor): """ Unbuffered Cursor, mainly useful for queries that return a lot of data, or for connections to remote servers over a slow network. - + Instead of copying every row of data into a buffer, this will fetch rows as needed. The upside of this, is the client uses much less memory, and rows are returned much faster when traveling over a slow network, or if the result set is very big. - + There are limitations, though. The MySQL protocol doesn't support returning the total number of rows, so the only way to tell how many rows there are is to iterate over every row returned. Also, it currently isn't possible to scroll backwards, as only the current row is held in memory. """ - + + _defer_warnings = True + + def _conv_row(self, row): + return row + def close(self): - conn = self._get_db() - conn._result._finish_unbuffered_query() - + conn = self.connection + if conn is None: + return + + if self._result is not None and self._result is conn._result: + self._result._finish_unbuffered_query() + try: - if self._has_next: - while self.nextset(): pass - except: pass + while self.nextset(): + pass + finally: + self.connection = None def _query(self, q): conn = self._get_db() @@ -326,38 +438,31 @@ class SSCursor(Cursor): conn.query(q, unbuffered=True) self._do_get_result() return self.rowcount - + + def nextset(self): + return self._nextset(unbuffered=True) + def read_next(self): - """ Read next row """ - - conn = self._get_db() - conn._result._read_rowdata_packet_unbuffered() - return conn._result.rows - + """Read next row""" + return self._conv_row(self._result._read_rowdata_packet_unbuffered()) + def fetchone(self): - """ Fetch next row """ - + """Fetch next row""" self._check_executed() row = self.read_next() if row is None: + self._show_warnings() return None self.rownumber += 1 return row - + def fetchall(self): """ Fetch all, as per MySQLdb. Pretty useless for large queries, as it is buffered. See fetchall_unbuffered(), if you want an unbuffered generator version of this method. """ - - rows = [] - while True: - row = self.fetchone() - if row is None: - break - rows.append(row) - return tuple(rows) + return list(self.fetchall_unbuffered()) def fetchall_unbuffered(self): """ @@ -365,46 +470,50 @@ class SSCursor(Cursor): however, it doesn't make sense to return everything in a list, as that would use ridiculous memory for large result sets. """ - - row = self.fetchone() - while row is not None: - yield row - row = self.fetchone() - + return iter(self.fetchone, None) + + def __iter__(self): + return self.fetchall_unbuffered() + def fetchmany(self, size=None): - """ Fetch many """ - + """Fetch many""" self._check_executed() if size is None: size = self.arraysize - + rows = [] - for i in range(0, size): + for i in range_type(size): row = self.read_next() if row is None: + self._show_warnings() break rows.append(row) self.rownumber += 1 - return tuple(rows) - + return rows + def scroll(self, value, mode='relative'): self._check_executed() - if not mode == 'relative' and not mode == 'absolute': - self.errorhandler(self, ProgrammingError, - "unknown scroll mode %s" % mode) - + if mode == 'relative': if value < 0: - self.errorhandler(self, NotSupportedError, - "Backwards scrolling not supported by this cursor") - - for i in range(0, value): self.read_next() + raise err.NotSupportedError( + "Backwards scrolling not supported by this cursor") + + for _ in range_type(value): + self.read_next() self.rownumber += value - else: + elif mode == 'absolute': if value < self.rownumber: - self.errorhandler(self, NotSupportedError, + raise err.NotSupportedError( "Backwards scrolling not supported by this cursor") - + end = value - self.rownumber - for i in range(0, end): self.read_next() + for _ in range_type(end): + self.read_next() self.rownumber = value + else: + raise err.ProgrammingError("unknown scroll mode %s" % mode) + + +class SSDictCursor(DictCursorMixin, SSCursor): + """An unbuffered cursor, which returns results as a dictionary""" diff --git a/gluon/contrib/pymysql/err.py b/gluon/contrib/pymysql/err.py index b4322c63..24862632 100644 --- a/gluon/contrib/pymysql/err.py +++ b/gluon/contrib/pymysql/err.py @@ -1,57 +1,39 @@ import struct +from .constants import ER -try: - StandardError, Warning -except ImportError: - try: - from exceptions import StandardError, Warning - except ImportError: - import sys - e = sys.modules['exceptions'] - StandardError = e.StandardError - Warning = e.Warning - -from constants import ER -import sys -class MySQLError(StandardError): - +class MySQLError(Exception): """Exception related to operation with MySQL.""" class Warning(Warning, MySQLError): - """Exception raised for important warnings like data truncations while inserting, etc.""" -class Error(MySQLError): +class Error(MySQLError): """Exception that is the base class of all other error exceptions (not Warning).""" class InterfaceError(Error): - """Exception raised for errors that are related to the database interface rather than the database itself.""" class DatabaseError(Error): - """Exception raised for errors that are related to the database.""" class DataError(DatabaseError): - """Exception raised for errors that are due to problems with the processed data like division by zero, numeric value out of range, etc.""" class OperationalError(DatabaseError): - """Exception raised for errors that are related to the database's operation and not necessarily under the control of the programmer, e.g. an unexpected disconnect occurs, the data source name is not @@ -60,28 +42,24 @@ class OperationalError(DatabaseError): class IntegrityError(DatabaseError): - """Exception raised when the relational integrity of the database is affected, e.g. a foreign key check fails, duplicate key, etc.""" class InternalError(DatabaseError): - """Exception raised when the database encounters an internal error, e.g. the cursor is not valid anymore, the transaction is out of sync, etc.""" class ProgrammingError(DatabaseError): - """Exception raised for programming errors, e.g. table not found or already exists, syntax error in the SQL statement, wrong number of parameters specified, etc.""" class NotSupportedError(DatabaseError): - """Exception raised in case a method or database API was used which is not supported by the database, e.g. requesting a .rollback() on a connection that does not support transaction or @@ -90,10 +68,12 @@ class NotSupportedError(DatabaseError): error_map = {} + def _map_error(exc, *errors): for error in errors: error_map[error] = exc + _map_error(ProgrammingError, ER.DB_CREATE_EXISTS, ER.SYNTAX_ERROR, ER.PARSE_ERROR, ER.NO_SUCH_TABLE, ER.WRONG_DB_NAME, ER.WRONG_TABLE_NAME, ER.FIELD_SPECIFIED_TWICE, @@ -104,44 +84,24 @@ _map_error(DataError, ER.WARN_DATA_TRUNCATED, ER.WARN_NULL_TO_NOTNULL, ER.DATA_TOO_LONG, ER.DATETIME_FUNCTION_OVERFLOW) _map_error(IntegrityError, ER.DUP_ENTRY, ER.NO_REFERENCED_ROW, ER.NO_REFERENCED_ROW_2, ER.ROW_IS_REFERENCED, ER.ROW_IS_REFERENCED_2, - ER.CANNOT_ADD_FOREIGN) + ER.CANNOT_ADD_FOREIGN, ER.BAD_NULL_ERROR) _map_error(NotSupportedError, ER.WARNING_NOT_COMPLETE_ROLLBACK, ER.NOT_SUPPORTED_YET, ER.FEATURE_DISABLED, ER.UNKNOWN_STORAGE_ENGINE) -_map_error(OperationalError, ER.DBACCESS_DENIED_ERROR, ER.ACCESS_DENIED_ERROR, - ER.TABLEACCESS_DENIED_ERROR, ER.COLUMNACCESS_DENIED_ERROR) +_map_error(OperationalError, ER.DBACCESS_DENIED_ERROR, ER.ACCESS_DENIED_ERROR, + ER.CON_COUNT_ERROR, ER.TABLEACCESS_DENIED_ERROR, + ER.COLUMNACCESS_DENIED_ERROR) + del _map_error, ER - -def _get_error_info(data): - errno = struct.unpack('= 2 and value[0] == value[-1] == quote: + return value[1:-1] + return value + + def get(self, section, option): + value = configparser.RawConfigParser.get(self, section, option) + return self.__remove_quotes(value) diff --git a/gluon/contrib/pymysql/tests/__init__.py b/gluon/contrib/pymysql/tests/__init__.py index 8ad5f8aa..a9f5a4bf 100644 --- a/gluon/contrib/pymysql/tests/__init__.py +++ b/gluon/contrib/pymysql/tests/__init__.py @@ -1,13 +1,18 @@ -from pymysql.tests.test_issues import * -from pymysql.tests.test_example import * -from pymysql.tests.test_basic import * +# Sorted by alphabetical order from pymysql.tests.test_DictCursor import * +from pymysql.tests.test_SSCursor import * +from pymysql.tests.test_basic import * +from pymysql.tests.test_connection import * +from pymysql.tests.test_converters import * +from pymysql.tests.test_cursor import * +from pymysql.tests.test_err import * +from pymysql.tests.test_issues import * +from pymysql.tests.test_load_local import * +from pymysql.tests.test_nextset import * +from pymysql.tests.test_optionfile import * -import sys -if sys.version_info[0] == 2: - # MySQLdb tests were designed for Python 3 - from pymysql.tests.thirdparty import * +from pymysql.tests.thirdparty import * if __name__ == "__main__": - import unittest - unittest.main() + import unittest2 + unittest2.main() diff --git a/gluon/contrib/pymysql/tests/base.py b/gluon/contrib/pymysql/tests/base.py index ce11b6b2..740157b1 100644 --- a/gluon/contrib/pymysql/tests/base.py +++ b/gluon/contrib/pymysql/tests/base.py @@ -1,20 +1,86 @@ -import pymysql -import unittest +import gc +import json +import os +import re +import warnings -class PyMySQLTestCase(unittest.TestCase): - # Edit this to suit your test environment. - databases = [ - {"host":"localhost","user":"root", - "passwd":"","db":"test_pymysql", "use_unicode": True}, - {"host":"localhost","user":"root","passwd":"","db":"test_pymysql2"}] +import unittest2 + +import pymysql +from .._compat import CPYTHON + + +class PyMySQLTestCase(unittest2.TestCase): + # You can specify your test environment creating a file named + # "databases.json" or editing the `databases` variable below. + fname = os.path.join(os.path.dirname(__file__), "databases.json") + if os.path.exists(fname): + with open(fname) as f: + databases = json.load(f) + else: + databases = [ + {"host":"localhost","user":"root", + "passwd":"","db":"test_pymysql", "use_unicode": True, 'local_infile': True}, + {"host":"localhost","user":"root","passwd":"","db":"test_pymysql2"}] + + def mysql_server_is(self, conn, version_tuple): + """Return True if the given connection is on the version given or + greater. + + e.g.:: + + if self.mysql_server_is(conn, (5, 6, 4)): + # do something for MySQL 5.6.4 and above + """ + server_version = conn.get_server_info() + server_version_tuple = tuple( + (int(dig) if dig is not None else 0) + for dig in + re.match(r'(\d+)\.(\d+)\.(\d+)', server_version).group(1, 2, 3) + ) + return server_version_tuple >= version_tuple def setUp(self): self.connections = [] - for params in self.databases: self.connections.append(pymysql.connect(**params)) + self.addCleanup(self._teardown_connections) - def tearDown(self): + def _teardown_connections(self): for connection in self.connections: connection.close() + def safe_create_table(self, connection, tablename, ddl, cleanup=True): + """create a table. + + Ensures any existing version of that table is first dropped. + + Also adds a cleanup rule to drop the table after the test + completes. + """ + cursor = connection.cursor() + + with warnings.catch_warnings(): + warnings.simplefilter("ignore") + cursor.execute("drop table if exists `%s`" % (tablename,)) + cursor.execute(ddl) + cursor.close() + if cleanup: + self.addCleanup(self.drop_table, connection, tablename) + + def drop_table(self, connection, tablename): + cursor = connection.cursor() + with warnings.catch_warnings(): + warnings.simplefilter("ignore") + cursor.execute("drop table if exists `%s`" % (tablename,)) + cursor.close() + + def safe_gc_collect(self): + """Ensure cycles are collected via gc. + + Runs additional times on non-CPython platforms. + + """ + gc.collect() + if not CPYTHON: + gc.collect() diff --git a/gluon/contrib/pymysql/tests/data/load_local_data.txt b/gluon/contrib/pymysql/tests/data/load_local_data.txt new file mode 100755 index 00000000..f9f99c8f --- /dev/null +++ b/gluon/contrib/pymysql/tests/data/load_local_data.txt @@ -0,0 +1,22749 @@ +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +71,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +71,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +71,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +71,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +71,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +71,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +71,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +71,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, diff --git a/gluon/contrib/pymysql/tests/data/load_local_warn_data.txt b/gluon/contrib/pymysql/tests/data/load_local_warn_data.txt new file mode 100755 index 00000000..2bda5a96 --- /dev/null +++ b/gluon/contrib/pymysql/tests/data/load_local_warn_data.txt @@ -0,0 +1,50 @@ +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, +5,6, +7,8, +1,2, +3,4, diff --git a/gluon/contrib/pymysql/tests/test_DictCursor.py b/gluon/contrib/pymysql/tests/test_DictCursor.py index 0166214a..9a0d638b 100755 --- a/gluon/contrib/pymysql/tests/test_DictCursor.py +++ b/gluon/contrib/pymysql/tests/test_DictCursor.py @@ -2,54 +2,117 @@ from pymysql.tests import base import pymysql.cursors import datetime +import warnings + class TestDictCursor(base.PyMySQLTestCase): + bob = {'name': 'bob', 'age': 21, 'DOB': datetime.datetime(1990, 2, 6, 23, 4, 56)} + jim = {'name': 'jim', 'age': 56, 'DOB': datetime.datetime(1955, 5, 9, 13, 12, 45)} + fred = {'name': 'fred', 'age': 100, 'DOB': datetime.datetime(1911, 9, 12, 1, 1, 1)} + + cursor_type = pymysql.cursors.DictCursor + + def setUp(self): + super(TestDictCursor, self).setUp() + self.conn = conn = self.connections[0] + c = conn.cursor(self.cursor_type) + + # create a table ane some data to query + with warnings.catch_warnings(): + warnings.filterwarnings("ignore") + c.execute("drop table if exists dictcursor") + # include in filterwarnings since for unbuffered dict cursor warning for lack of table + # will only be propagated at start of next execute() call + c.execute("""CREATE TABLE dictcursor (name char(20), age int , DOB datetime)""") + data = [("bob", 21, "1990-02-06 23:04:56"), + ("jim", 56, "1955-05-09 13:12:45"), + ("fred", 100, "1911-09-12 01:01:01")] + c.executemany("insert into dictcursor values (%s,%s,%s)", data) + + def tearDown(self): + c = self.conn.cursor() + c.execute("drop table dictcursor") + super(TestDictCursor, self).tearDown() + + def _ensure_cursor_expired(self, cursor): + pass def test_DictCursor(self): - #all assert test compare to the structure as would come out from MySQLdb - conn = self.connections[0] - c = conn.cursor(pymysql.cursors.DictCursor) - # create a table ane some data to query - c.execute("""CREATE TABLE dictcursor (name char(20), age int , DOB datetime)""") - data = (("bob",21,"1990-02-06 23:04:56"), - ("jim",56,"1955-05-09 13:12:45"), - ("fred",100,"1911-09-12 01:01:01")) - bob = {'name':'bob','age':21,'DOB':datetime.datetime(1990, 02, 6, 23, 04, 56)} - jim = {'name':'jim','age':56,'DOB':datetime.datetime(1955, 05, 9, 13, 12, 45)} - fred = {'name':'fred','age':100,'DOB':datetime.datetime(1911, 9, 12, 1, 1, 1)} - try: - c.executemany("insert into dictcursor values (%s,%s,%s)", data) - # try an update which should return no rows - c.execute("update dictcursor set age=20 where name='bob'") - bob['age'] = 20 - # pull back the single row dict for bob and check - c.execute("SELECT * from dictcursor where name='bob'") - r = c.fetchone() - self.assertEqual(bob,r,"fetchone via DictCursor failed") - # same again, but via fetchall => tuple) - c.execute("SELECT * from dictcursor where name='bob'") - r = c.fetchall() - self.assertEqual((bob,),r,"fetch a 1 row result via fetchall failed via DictCursor") - # same test again but iterate over the - c.execute("SELECT * from dictcursor where name='bob'") - for r in c: - self.assertEqual(bob, r,"fetch a 1 row result via iteration failed via DictCursor") - # get all 3 row via fetchall - c.execute("SELECT * from dictcursor") - r = c.fetchall() - self.assertEqual((bob,jim,fred), r, "fetchall failed via DictCursor") - #same test again but do a list comprehension - c.execute("SELECT * from dictcursor") - r = [x for x in c] - self.assertEqual([bob,jim,fred], r, "list comprehension failed via DictCursor") - # get all 2 row via fetchmany - c.execute("SELECT * from dictcursor") - r = c.fetchmany(2) - self.assertEqual((bob,jim), r, "fetchmany failed via DictCursor") - finally: - c.execute("drop table dictcursor") + bob, jim, fred = self.bob.copy(), self.jim.copy(), self.fred.copy() + #all assert test compare to the structure as would come out from MySQLdb + conn = self.conn + c = conn.cursor(self.cursor_type) -__all__ = ["TestDictCursor"] + # try an update which should return no rows + c.execute("update dictcursor set age=20 where name='bob'") + bob['age'] = 20 + # pull back the single row dict for bob and check + c.execute("SELECT * from dictcursor where name='bob'") + r = c.fetchone() + self.assertEqual(bob, r, "fetchone via DictCursor failed") + self._ensure_cursor_expired(c) + + # same again, but via fetchall => tuple) + c.execute("SELECT * from dictcursor where name='bob'") + r = c.fetchall() + self.assertEqual([bob], r, "fetch a 1 row result via fetchall failed via DictCursor") + # same test again but iterate over the + c.execute("SELECT * from dictcursor where name='bob'") + for r in c: + self.assertEqual(bob, r, "fetch a 1 row result via iteration failed via DictCursor") + # get all 3 row via fetchall + c.execute("SELECT * from dictcursor") + r = c.fetchall() + self.assertEqual([bob,jim,fred], r, "fetchall failed via DictCursor") + #same test again but do a list comprehension + c.execute("SELECT * from dictcursor") + r = list(c) + self.assertEqual([bob,jim,fred], r, "DictCursor should be iterable") + # get all 2 row via fetchmany + c.execute("SELECT * from dictcursor") + r = c.fetchmany(2) + self.assertEqual([bob, jim], r, "fetchmany failed via DictCursor") + self._ensure_cursor_expired(c) + + def test_custom_dict(self): + class MyDict(dict): pass + + class MyDictCursor(self.cursor_type): + dict_type = MyDict + + keys = ['name', 'age', 'DOB'] + bob = MyDict([(k, self.bob[k]) for k in keys]) + jim = MyDict([(k, self.jim[k]) for k in keys]) + fred = MyDict([(k, self.fred[k]) for k in keys]) + + cur = self.conn.cursor(MyDictCursor) + cur.execute("SELECT * FROM dictcursor WHERE name='bob'") + r = cur.fetchone() + self.assertEqual(bob, r, "fetchone() returns MyDictCursor") + self._ensure_cursor_expired(cur) + + cur.execute("SELECT * FROM dictcursor") + r = cur.fetchall() + self.assertEqual([bob, jim, fred], r, + "fetchall failed via MyDictCursor") + + cur.execute("SELECT * FROM dictcursor") + r = list(cur) + self.assertEqual([bob, jim, fred], r, + "list failed via MyDictCursor") + + cur.execute("SELECT * FROM dictcursor") + r = cur.fetchmany(2) + self.assertEqual([bob, jim], r, + "list failed via MyDictCursor") + self._ensure_cursor_expired(cur) + + +class TestSSDictCursor(TestDictCursor): + cursor_type = pymysql.cursors.SSDictCursor + + def _ensure_cursor_expired(self, cursor): + list(cursor.fetchall_unbuffered()) if __name__ == "__main__": import unittest diff --git a/gluon/contrib/pymysql/tests/test_SSCursor.py b/gluon/contrib/pymysql/tests/test_SSCursor.py index a0e3caf3..e6d6cf53 100755 --- a/gluon/contrib/pymysql/tests/test_SSCursor.py +++ b/gluon/contrib/pymysql/tests/test_SSCursor.py @@ -3,7 +3,7 @@ import sys try: from pymysql.tests import base import pymysql.cursors -except: +except Exception: # For local testing from top-level directory, without installing sys.path.append('../pymysql') from pymysql.tests import base @@ -12,7 +12,7 @@ except: class TestSSCursor(base.PyMySQLTestCase): def test_SSCursor(self): affected_rows = 18446744073709551615 - + conn = self.connections[0] data = [ ('America', '', 'America/Jamaica'), @@ -25,22 +25,23 @@ class TestSSCursor(base.PyMySQLTestCase): ('America', '', 'America/Costa_Rica'), ('America', '', 'America/Denver'), ('America', '', 'America/Detroit'),] - + try: cursor = conn.cursor(pymysql.cursors.SSCursor) - + # Create table cursor.execute(('CREATE TABLE tz_data (' 'region VARCHAR(64),' 'zone VARCHAR(64),' 'name VARCHAR(64))')) - + + conn.begin() # Test INSERT for i in data: cursor.execute('INSERT INTO tz_data VALUES (%s, %s, %s)', i) self.assertEqual(conn.affected_rows(), 1, 'affected_rows does not match') conn.commit() - + # Test fetchone() iter = 0 cursor.execute('SELECT * FROM tz_data') @@ -49,46 +50,55 @@ class TestSSCursor(base.PyMySQLTestCase): if row is None: break iter += 1 - + # Test cursor.rowcount self.assertEqual(cursor.rowcount, affected_rows, 'cursor.rowcount != %s' % (str(affected_rows))) - + # Test cursor.rownumber self.assertEqual(cursor.rownumber, iter, 'cursor.rowcount != %s' % (str(iter))) - + # Test row came out the same as it went in self.assertEqual((row in data), True, 'Row not found in source data') - + # Test fetchall cursor.execute('SELECT * FROM tz_data') self.assertEqual(len(cursor.fetchall()), len(data), 'fetchall failed. Number of rows does not match') - + # Test fetchmany cursor.execute('SELECT * FROM tz_data') self.assertEqual(len(cursor.fetchmany(2)), 2, 'fetchmany failed. Number of rows does not match') - + # So MySQLdb won't throw "Commands out of sync" while True: res = cursor.fetchone() if res is None: break - + # Test update, affected_rows() cursor.execute('UPDATE tz_data SET zone = %s', ['Foo']) conn.commit() self.assertEqual(cursor.rowcount, len(data), 'Update failed. affected_rows != %s' % (str(len(data)))) - + # Test executemany cursor.executemany('INSERT INTO tz_data VALUES (%s, %s, %s)', data) self.assertEqual(cursor.rowcount, len(data), 'executemany failed. cursor.rowcount != %s' % (str(len(data)))) - + + # Test multiple datasets + cursor.execute('SELECT 1; SELECT 2; SELECT 3') + self.assertListEqual(list(cursor), [(1, )]) + self.assertTrue(cursor.nextset()) + self.assertListEqual(list(cursor), [(2, )]) + self.assertTrue(cursor.nextset()) + self.assertListEqual(list(cursor), [(3, )]) + self.assertFalse(cursor.nextset()) + finally: cursor.execute('DROP TABLE tz_data') cursor.close() diff --git a/gluon/contrib/pymysql/tests/test_basic.py b/gluon/contrib/pymysql/tests/test_basic.py index fb7a30f8..ed9c4f61 100644 --- a/gluon/contrib/pymysql/tests/test_basic.py +++ b/gluon/contrib/pymysql/tests/test_basic.py @@ -1,8 +1,19 @@ -from pymysql.tests import base -from pymysql import util - -import time +# coding: utf-8 import datetime +import json +import time +import warnings + +from unittest2 import SkipTest + +from pymysql import util +import pymysql.cursors +from pymysql.tests import base +from pymysql.err import ProgrammingError + + +__all__ = ["TestConversion", "TestCursor", "TestBulkInserts"] + class TestConversion(base.PyMySQLTestCase): def test_datatypes(self): @@ -12,16 +23,13 @@ class TestConversion(base.PyMySQLTestCase): c.execute("create table test_datatypes (b bit, i int, l bigint, f real, s varchar(32), u varchar(32), bb blob, d date, dt datetime, ts timestamp, td time, t time, st datetime)") try: # insert values - v = (True, -3, 123456789012, 5.7, "hello'\" world", u"Espa\xc3\xb1ol", "binary\x00data".encode(conn.charset), datetime.date(1988,2,2), datetime.datetime.now(), datetime.timedelta(5,6), datetime.time(16,32), time.localtime()) + + v = (True, -3, 123456789012, 5.7, "hello'\" world", u"Espa\xc3\xb1ol", "binary\x00data".encode(conn.charset), datetime.date(1988,2,2), datetime.datetime(2014, 5, 15, 7, 45, 57), datetime.timedelta(5,6), datetime.time(16,32), time.localtime()) c.execute("insert into test_datatypes (b,i,l,f,s,u,bb,d,dt,td,t,st) values (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)", v) c.execute("select b,i,l,f,s,u,bb,d,dt,td,t,st from test_datatypes") r = c.fetchone() self.assertEqual(util.int2byte(1), r[0]) - self.assertEqual(v[1:8], r[1:8]) - # mysql throws away microseconds so we need to check datetimes - # specially. additionally times are turned into timedeltas. - self.assertEqual(datetime.datetime(*v[8].timetuple()[:6]), r[8]) - self.assertEqual(v[9], r[9]) # just timedeltas + self.assertEqual(v[1:10], r[1:10]) self.assertEqual(datetime.timedelta(0, 60 * (v[10].hour * 60 + v[10].minute)), r[10]) self.assertEqual(datetime.datetime(*v[-1][:6]), r[-1]) @@ -35,11 +43,15 @@ class TestConversion(base.PyMySQLTestCase): c.execute("delete from test_datatypes") - # check sequence type - c.execute("insert into test_datatypes (i, l) values (2,4), (6,8), (10,12)") - c.execute("select l from test_datatypes where i in %s order by i", ((2,6),)) - r = c.fetchall() - self.assertEqual(((4,),(8,)), r) + # check sequences type + for seq_type in (tuple, list, set, frozenset): + c.execute("insert into test_datatypes (i, l) values (2,4), (6,8), (10,12)") + seq = seq_type([2,6]) + c.execute("select l from test_datatypes where i in %s order by i", (seq,)) + r = c.fetchall() + self.assertEqual(((4,),(8,)), r) + c.execute("delete from test_datatypes") + finally: c.execute("drop table test_datatypes") @@ -79,20 +91,18 @@ class TestConversion(base.PyMySQLTestCase): finally: c.execute("drop table test_dict") - - def test_big_blob(self): - """ test tons of data """ + def test_blob(self): + """test binary data""" + data = bytes(bytearray(range(256)) * 4) conn = self.connections[0] - c = conn.cursor() - c.execute("create table test_big_blob (b blob)") - try: - data = "pymysql" * 1024 - c.execute("insert into test_big_blob (b) values (%s)", (data,)) - c.execute("select b from test_big_blob") - self.assertEqual(data.encode(conn.charset), c.fetchone()[0]) - finally: - c.execute("drop table test_big_blob") - + self.safe_create_table( + conn, "test_blob", "create table test_blob (b blob)") + + with conn.cursor() as c: + c.execute("insert into test_blob (b) values (%s)", (data,)) + c.execute("select b from test_blob") + self.assertEqual(data, c.fetchone()[0]) + def test_untyped(self): """ test conversion of null, empty string """ conn = self.connections[0] @@ -101,17 +111,40 @@ class TestConversion(base.PyMySQLTestCase): self.assertEqual((None,u''), c.fetchone()) c.execute("select '',null") self.assertEqual((u'',None), c.fetchone()) - - def test_datetime(self): - """ test conversion of null, empty string """ + + def test_timedelta(self): + """ test timedelta conversion """ conn = self.connections[0] c = conn.cursor() - c.execute("select time('12:30'), time('23:12:59'), time('23:12:59.05100')") + c.execute("select time('12:30'), time('23:12:59'), time('23:12:59.05100'), time('-12:30'), time('-23:12:59'), time('-23:12:59.05100'), time('-00:30')") self.assertEqual((datetime.timedelta(0, 45000), datetime.timedelta(0, 83579), - datetime.timedelta(0, 83579, 51000)), + datetime.timedelta(0, 83579, 51000), + -datetime.timedelta(0, 45000), + -datetime.timedelta(0, 83579), + -datetime.timedelta(0, 83579, 51000), + -datetime.timedelta(0, 1800)), c.fetchone()) + def test_datetime_microseconds(self): + """ test datetime conversion w microseconds""" + + conn = self.connections[0] + if not self.mysql_server_is(conn, (5, 6, 4)): + raise SkipTest("target backend does not support microseconds") + c = conn.cursor() + dt = datetime.datetime(2013, 11, 12, 9, 9, 9, 123450) + c.execute("create table test_datetime (id int, ts datetime(6))") + try: + c.execute( + "insert into test_datetime values (%s, %s)", + (1, dt) + ) + c.execute("select ts from test_datetime") + self.assertEqual((dt,), c.fetchone()) + finally: + c.execute("drop table test_datetime") + class TestCursor(base.PyMySQLTestCase): # this test case does not work quite right yet, however, @@ -185,7 +218,7 @@ class TestCursor(base.PyMySQLTestCase): c = conn.cursor() try: c.execute('create table test_aggregates (i integer)') - for i in xrange(0, 10): + for i in range(0, 10): c.execute('insert into test_aggregates (i) values (%s)', (i,)) c.execute('select sum(i) from test_aggregates') r, = c.fetchone() @@ -197,17 +230,150 @@ class TestCursor(base.PyMySQLTestCase): """ test a single tuple """ conn = self.connections[0] c = conn.cursor() - try: - c.execute("create table mystuff (id integer primary key)") - c.execute("insert into mystuff (id) values (1)") - c.execute("insert into mystuff (id) values (2)") - c.execute("select id from mystuff where id in %s", ((1,),)) - self.assertEqual([(1,)], list(c.fetchall())) - finally: - c.execute("drop table mystuff") + self.safe_create_table( + conn, 'mystuff', + "create table mystuff (id integer primary key)") + c.execute("insert into mystuff (id) values (1)") + c.execute("insert into mystuff (id) values (2)") + c.execute("select id from mystuff where id in %s", ((1,),)) + self.assertEqual([(1,)], list(c.fetchall())) + c.close() -__all__ = ["TestConversion","TestCursor"] + def test_json(self): + args = self.databases[0].copy() + args["charset"] = "utf8mb4" + conn = pymysql.connect(**args) + if not self.mysql_server_is(conn, (5, 7, 0)): + raise SkipTest("JSON type is not supported on MySQL <= 5.6") -if __name__ == "__main__": - import unittest - unittest.main() + self.safe_create_table(conn, "test_json", """\ +create table test_json ( + id int not null, + json JSON not null, + primary key (id) +);""") + cur = conn.cursor() + + json_str = u'{"hello": "こんにちは"}' + cur.execute("INSERT INTO test_json (id, `json`) values (42, %s)", (json_str,)) + cur.execute("SELECT `json` from `test_json` WHERE `id`=42") + res = cur.fetchone()[0] + self.assertEqual(json.loads(res), json.loads(json_str)) + + cur.execute("SELECT CAST(%s AS JSON) AS x", (json_str,)) + res = cur.fetchone()[0] + self.assertEqual(json.loads(res), json.loads(json_str)) + + +class TestBulkInserts(base.PyMySQLTestCase): + + cursor_type = pymysql.cursors.DictCursor + + def setUp(self): + super(TestBulkInserts, self).setUp() + self.conn = conn = self.connections[0] + c = conn.cursor(self.cursor_type) + + # create a table ane some data to query + self.safe_create_table(conn, 'bulkinsert', """\ +CREATE TABLE bulkinsert +( +id int(11), +name char(20), +age int, +height int, +PRIMARY KEY (id) +) +""") + + def _verify_records(self, data): + conn = self.connections[0] + cursor = conn.cursor() + cursor.execute("SELECT id, name, age, height from bulkinsert") + result = cursor.fetchall() + self.assertEqual(sorted(data), sorted(result)) + + def test_bulk_insert(self): + conn = self.connections[0] + cursor = conn.cursor() + + data = [(0, "bob", 21, 123), (1, "jim", 56, 45), (2, "fred", 100, 180)] + cursor.executemany("insert into bulkinsert (id, name, age, height) " + "values (%s,%s,%s,%s)", data) + self.assertEqual( + cursor._last_executed, bytearray( + b"insert into bulkinsert (id, name, age, height) values " + b"(0,'bob',21,123),(1,'jim',56,45),(2,'fred',100,180)")) + cursor.execute('commit') + self._verify_records(data) + + def test_bulk_insert_multiline_statement(self): + conn = self.connections[0] + cursor = conn.cursor() + data = [(0, "bob", 21, 123), (1, "jim", 56, 45), (2, "fred", 100, 180)] + cursor.executemany("""insert +into bulkinsert (id, name, +age, height) +values (%s, +%s , %s, +%s ) + """, data) + self.assertEqual(cursor._last_executed.strip(), bytearray(b"""insert +into bulkinsert (id, name, +age, height) +values (0, +'bob' , 21, +123 ),(1, +'jim' , 56, +45 ),(2, +'fred' , 100, +180 )""")) + cursor.execute('commit') + self._verify_records(data) + + def test_bulk_insert_single_record(self): + conn = self.connections[0] + cursor = conn.cursor() + data = [(0, "bob", 21, 123)] + cursor.executemany("insert into bulkinsert (id, name, age, height) " + "values (%s,%s,%s,%s)", data) + cursor.execute('commit') + self._verify_records(data) + + def test_issue_288(self): + """executemany should work with "insert ... on update" """ + conn = self.connections[0] + cursor = conn.cursor() + data = [(0, "bob", 21, 123), (1, "jim", 56, 45), (2, "fred", 100, 180)] + cursor.executemany("""insert +into bulkinsert (id, name, +age, height) +values (%s, +%s , %s, +%s ) on duplicate key update +age = values(age) + """, data) + self.assertEqual(cursor._last_executed.strip(), bytearray(b"""insert +into bulkinsert (id, name, +age, height) +values (0, +'bob' , 21, +123 ),(1, +'jim' , 56, +45 ),(2, +'fred' , 100, +180 ) on duplicate key update +age = values(age)""")) + cursor.execute('commit') + self._verify_records(data) + + def test_warnings(self): + con = self.connections[0] + cur = con.cursor() + with warnings.catch_warnings(record=True) as ws: + warnings.simplefilter("always") + cur.execute("drop table if exists no_exists_table") + self.assertEqual(len(ws), 1) + self.assertEqual(ws[0].category, pymysql.Warning) + if u"no_exists_table" not in str(ws[0].message): + self.fail("'no_exists_table' not in %s" % (str(ws[0].message),)) diff --git a/gluon/contrib/pymysql/tests/test_connection.py b/gluon/contrib/pymysql/tests/test_connection.py new file mode 100755 index 00000000..518b6fe7 --- /dev/null +++ b/gluon/contrib/pymysql/tests/test_connection.py @@ -0,0 +1,576 @@ +import datetime +import sys +import time +import unittest2 +import pymysql +from pymysql.tests import base +from pymysql._compat import text_type + + +class TempUser: + def __init__(self, c, user, db, auth=None, authdata=None, password=None): + self._c = c + self._user = user + self._db = db + create = "CREATE USER " + user + if password is not None: + create += " IDENTIFIED BY '%s'" % password + elif auth is not None: + create += " IDENTIFIED WITH %s" % auth + if authdata is not None: + create += " AS '%s'" % authdata + try: + c.execute(create) + self._created = True + except pymysql.err.InternalError: + # already exists - TODO need to check the same plugin applies + self._created = False + try: + c.execute("GRANT SELECT ON %s.* TO %s" % (db, user)) + self._grant = True + except pymysql.err.InternalError: + self._grant = False + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_value, traceback): + if self._grant: + self._c.execute("REVOKE SELECT ON %s.* FROM %s" % (self._db, self._user)) + if self._created: + self._c.execute("DROP USER %s" % self._user) + + +class TestAuthentication(base.PyMySQLTestCase): + + socket_auth = False + socket_found = False + two_questions_found = False + three_attempts_found = False + pam_found = False + mysql_old_password_found = False + sha256_password_found = False + + import os + osuser = os.environ.get('USER') + + # socket auth requires the current user and for the connection to be a socket + # rest do grants @localhost due to incomplete logic - TODO change to @% then + db = base.PyMySQLTestCase.databases[0].copy() + + socket_auth = db.get('unix_socket') is not None \ + and db.get('host') in ('localhost', '127.0.0.1') + + cur = pymysql.connect(**db).cursor() + del db['user'] + cur.execute("SHOW PLUGINS") + for r in cur: + if (r[1], r[2]) != (u'ACTIVE', u'AUTHENTICATION'): + continue + if r[3] == u'auth_socket.so': + socket_plugin_name = r[0] + socket_found = True + elif r[3] == u'dialog_examples.so': + if r[0] == 'two_questions': + two_questions_found = True + elif r[0] == 'three_attempts': + three_attempts_found = True + elif r[0] == u'pam': + pam_found = True + pam_plugin_name = r[3].split('.')[0] + if pam_plugin_name == 'auth_pam': + pam_plugin_name = 'pam' + # MySQL: authentication_pam + # https://dev.mysql.com/doc/refman/5.5/en/pam-authentication-plugin.html + + # MariaDB: pam + # https://mariadb.com/kb/en/mariadb/pam-authentication-plugin/ + + # Names differ but functionality is close + elif r[0] == u'mysql_old_password': + mysql_old_password_found = True + elif r[0] == u'sha256_password': + sha256_password_found = True + #else: + # print("plugin: %r" % r[0]) + + def test_plugin(self): + # Bit of an assumption that the current user is a native password + self.assertEqual('mysql_native_password', self.connections[0]._auth_plugin_name) + + @unittest2.skipUnless(socket_auth, "connection to unix_socket required") + @unittest2.skipIf(socket_found, "socket plugin already installed") + def testSocketAuthInstallPlugin(self): + # needs plugin. lets install it. + cur = self.connections[0].cursor() + try: + cur.execute("install plugin auth_socket soname 'auth_socket.so'") + TestAuthentication.socket_found = True + self.socket_plugin_name = 'auth_socket' + self.realtestSocketAuth() + except pymysql.err.InternalError: + try: + cur.execute("install soname 'auth_socket'") + TestAuthentication.socket_found = True + self.socket_plugin_name = 'unix_socket' + self.realtestSocketAuth() + except pymysql.err.InternalError: + TestAuthentication.socket_found = False + raise unittest2.SkipTest('we couldn\'t install the socket plugin') + finally: + if TestAuthentication.socket_found: + cur.execute("uninstall plugin %s" % self.socket_plugin_name) + + @unittest2.skipUnless(socket_auth, "connection to unix_socket required") + @unittest2.skipUnless(socket_found, "no socket plugin") + def testSocketAuth(self): + self.realtestSocketAuth() + + def realtestSocketAuth(self): + with TempUser(self.connections[0].cursor(), TestAuthentication.osuser + '@localhost', + self.databases[0]['db'], self.socket_plugin_name) as u: + c = pymysql.connect(user=TestAuthentication.osuser, **self.db) + + class Dialog(object): + fail=False + + def __init__(self, con): + self.fail=TestAuthentication.Dialog.fail + pass + + def prompt(self, echo, prompt): + if self.fail: + self.fail=False + return b'bad guess at a password' + return self.m.get(prompt) + + class DialogHandler(object): + + def __init__(self, con): + self.con=con + + def authenticate(self, pkt): + while True: + flag = pkt.read_uint8() + echo = (flag & 0x06) == 0x02 + last = (flag & 0x01) == 0x01 + prompt = pkt.read_all() + + if prompt == b'Password, please:': + self.con.write_packet(b'stillnotverysecret\0') + else: + self.con.write_packet(b'no idea what to do with this prompt\0') + pkt = self.con._read_packet() + pkt.check_error() + if pkt.is_ok_packet() or last: + break + return pkt + + class DefectiveHandler(object): + def __init__(self, con): + self.con=con + + + @unittest2.skipUnless(socket_auth, "connection to unix_socket required") + @unittest2.skipIf(two_questions_found, "two_questions plugin already installed") + def testDialogAuthTwoQuestionsInstallPlugin(self): + # needs plugin. lets install it. + cur = self.connections[0].cursor() + try: + cur.execute("install plugin two_questions soname 'dialog_examples.so'") + TestAuthentication.two_questions_found = True + self.realTestDialogAuthTwoQuestions() + except pymysql.err.InternalError: + raise unittest2.SkipTest('we couldn\'t install the two_questions plugin') + finally: + if TestAuthentication.two_questions_found: + cur.execute("uninstall plugin two_questions") + + @unittest2.skipUnless(socket_auth, "connection to unix_socket required") + @unittest2.skipUnless(two_questions_found, "no two questions auth plugin") + def testDialogAuthTwoQuestions(self): + self.realTestDialogAuthTwoQuestions() + + def realTestDialogAuthTwoQuestions(self): + TestAuthentication.Dialog.fail=False + TestAuthentication.Dialog.m = {b'Password, please:': b'notverysecret', + b'Are you sure ?': b'yes, of course'} + with TempUser(self.connections[0].cursor(), 'pymysql_2q@localhost', + self.databases[0]['db'], 'two_questions', 'notverysecret') as u: + with self.assertRaises(pymysql.err.OperationalError): + pymysql.connect(user='pymysql_2q', **self.db) + pymysql.connect(user='pymysql_2q', auth_plugin_map={b'dialog': TestAuthentication.Dialog}, **self.db) + + @unittest2.skipUnless(socket_auth, "connection to unix_socket required") + @unittest2.skipIf(three_attempts_found, "three_attempts plugin already installed") + def testDialogAuthThreeAttemptsQuestionsInstallPlugin(self): + # needs plugin. lets install it. + cur = self.connections[0].cursor() + try: + cur.execute("install plugin three_attempts soname 'dialog_examples.so'") + TestAuthentication.three_attempts_found = True + self.realTestDialogAuthThreeAttempts() + except pymysql.err.InternalError: + raise unittest2.SkipTest('we couldn\'t install the three_attempts plugin') + finally: + if TestAuthentication.three_attempts_found: + cur.execute("uninstall plugin three_attempts") + + @unittest2.skipUnless(socket_auth, "connection to unix_socket required") + @unittest2.skipUnless(three_attempts_found, "no three attempts plugin") + def testDialogAuthThreeAttempts(self): + self.realTestDialogAuthThreeAttempts() + + def realTestDialogAuthThreeAttempts(self): + TestAuthentication.Dialog.m = {b'Password, please:': b'stillnotverysecret'} + TestAuthentication.Dialog.fail=True # fail just once. We've got three attempts after all + with TempUser(self.connections[0].cursor(), 'pymysql_3a@localhost', + self.databases[0]['db'], 'three_attempts', 'stillnotverysecret') as u: + pymysql.connect(user='pymysql_3a', auth_plugin_map={b'dialog': TestAuthentication.Dialog}, **self.db) + pymysql.connect(user='pymysql_3a', auth_plugin_map={b'dialog': TestAuthentication.DialogHandler}, **self.db) + with self.assertRaises(pymysql.err.OperationalError): + pymysql.connect(user='pymysql_3a', auth_plugin_map={b'dialog': object}, **self.db) + + with self.assertRaises(pymysql.err.OperationalError): + pymysql.connect(user='pymysql_3a', auth_plugin_map={b'dialog': TestAuthentication.DefectiveHandler}, **self.db) + with self.assertRaises(pymysql.err.OperationalError): + pymysql.connect(user='pymysql_3a', auth_plugin_map={b'notdialogplugin': TestAuthentication.Dialog}, **self.db) + TestAuthentication.Dialog.m = {b'Password, please:': b'I do not know'} + with self.assertRaises(pymysql.err.OperationalError): + pymysql.connect(user='pymysql_3a', auth_plugin_map={b'dialog': TestAuthentication.Dialog}, **self.db) + TestAuthentication.Dialog.m = {b'Password, please:': None} + with self.assertRaises(pymysql.err.OperationalError): + pymysql.connect(user='pymysql_3a', auth_plugin_map={b'dialog': TestAuthentication.Dialog}, **self.db) + + @unittest2.skipUnless(socket_auth, "connection to unix_socket required") + @unittest2.skipIf(pam_found, "pam plugin already installed") + @unittest2.skipIf(os.environ.get('PASSWORD') is None, "PASSWORD env var required") + @unittest2.skipIf(os.environ.get('PAMSERVICE') is None, "PAMSERVICE env var required") + def testPamAuthInstallPlugin(self): + # needs plugin. lets install it. + cur = self.connections[0].cursor() + try: + cur.execute("install plugin pam soname 'auth_pam.so'") + TestAuthentication.pam_found = True + self.realTestPamAuth() + except pymysql.err.InternalError: + raise unittest2.SkipTest('we couldn\'t install the auth_pam plugin') + finally: + if TestAuthentication.pam_found: + cur.execute("uninstall plugin pam") + + + @unittest2.skipUnless(socket_auth, "connection to unix_socket required") + @unittest2.skipUnless(pam_found, "no pam plugin") + @unittest2.skipIf(os.environ.get('PASSWORD') is None, "PASSWORD env var required") + @unittest2.skipIf(os.environ.get('PAMSERVICE') is None, "PAMSERVICE env var required") + def testPamAuth(self): + self.realTestPamAuth() + + def realTestPamAuth(self): + db = self.db.copy() + import os + db['password'] = os.environ.get('PASSWORD') + cur = self.connections[0].cursor() + try: + cur.execute('show grants for ' + TestAuthentication.osuser + '@localhost') + grants = cur.fetchone()[0] + cur.execute('drop user ' + TestAuthentication.osuser + '@localhost') + except pymysql.OperationalError as e: + # assuming the user doesn't exist which is ok too + self.assertEqual(1045, e.args[0]) + grants = None + with TempUser(cur, TestAuthentication.osuser + '@localhost', + self.databases[0]['db'], 'pam', os.environ.get('PAMSERVICE')) as u: + try: + c = pymysql.connect(user=TestAuthentication.osuser, **db) + db['password'] = 'very bad guess at password' + with self.assertRaises(pymysql.err.OperationalError): + pymysql.connect(user=TestAuthentication.osuser, + auth_plugin_map={b'mysql_cleartext_password': TestAuthentication.DefectiveHandler}, + **self.db) + except pymysql.OperationalError as e: + self.assertEqual(1045, e.args[0]) + # we had 'bad guess at password' work with pam. Well at least we get a permission denied here + with self.assertRaises(pymysql.err.OperationalError): + pymysql.connect(user=TestAuthentication.osuser, + auth_plugin_map={b'mysql_cleartext_password': TestAuthentication.DefectiveHandler}, + **self.db) + if grants: + # recreate the user + cur.execute(grants) + + # select old_password("crummy p\tassword"); + #| old_password("crummy p\tassword") | + #| 2a01785203b08770 | + @unittest2.skipUnless(socket_auth, "connection to unix_socket required") + @unittest2.skipUnless(mysql_old_password_found, "no mysql_old_password plugin") + def testMySQLOldPasswordAuth(self): + if self.mysql_server_is(self.connections[0], (5, 7, 0)): + raise unittest2.SkipTest('Old passwords aren\'t supported in 5.7') + # pymysql.err.OperationalError: (1045, "Access denied for user 'old_pass_user'@'localhost' (using password: YES)") + # from login in MySQL-5.6 + if self.mysql_server_is(self.connections[0], (5, 6, 0)): + raise unittest2.SkipTest('Old passwords don\'t authenticate in 5.6') + db = self.db.copy() + db['password'] = "crummy p\tassword" + with self.connections[0] as c: + # deprecated in 5.6 + if sys.version_info[0:2] >= (3,2) and self.mysql_server_is(self.connections[0], (5, 6, 0)): + with self.assertWarns(pymysql.err.Warning) as cm: + c.execute("SELECT OLD_PASSWORD('%s')" % db['password']) + else: + c.execute("SELECT OLD_PASSWORD('%s')" % db['password']) + v = c.fetchone()[0] + self.assertEqual(v, '2a01785203b08770') + # only works in MariaDB and MySQL-5.6 - can't separate out by version + #if self.mysql_server_is(self.connections[0], (5, 5, 0)): + # with TempUser(c, 'old_pass_user@localhost', + # self.databases[0]['db'], 'mysql_old_password', '2a01785203b08770') as u: + # cur = pymysql.connect(user='old_pass_user', **db).cursor() + # cur.execute("SELECT VERSION()") + c.execute("SELECT @@secure_auth") + secure_auth_setting = c.fetchone()[0] + c.execute('set old_passwords=1') + # pymysql.err.Warning: 'pre-4.1 password hash' is deprecated and will be removed in a future release. Please use post-4.1 password hash instead + if sys.version_info[0:2] >= (3,2) and self.mysql_server_is(self.connections[0], (5, 6, 0)): + with self.assertWarns(pymysql.err.Warning) as cm: + c.execute('set global secure_auth=0') + else: + c.execute('set global secure_auth=0') + with TempUser(c, 'old_pass_user@localhost', + self.databases[0]['db'], password=db['password']) as u: + cur = pymysql.connect(user='old_pass_user', **db).cursor() + cur.execute("SELECT VERSION()") + c.execute('set global secure_auth=%r' % secure_auth_setting) + + @unittest2.skipUnless(socket_auth, "connection to unix_socket required") + @unittest2.skipUnless(sha256_password_found, "no sha256 password authentication plugin found") + def testAuthSHA256(self): + c = self.connections[0].cursor() + with TempUser(c, 'pymysql_sha256@localhost', + self.databases[0]['db'], 'sha256_password') as u: + if self.mysql_server_is(self.connections[0], (5, 7, 0)): + c.execute("SET PASSWORD FOR 'pymysql_sha256'@'localhost' ='Sh@256Pa33'") + else: + c.execute('SET old_passwords = 2') + c.execute("SET PASSWORD FOR 'pymysql_sha256'@'localhost' = PASSWORD('Sh@256Pa33')") + db = self.db.copy() + db['password'] = "Sh@256Pa33" + # not implemented yet so thows error + with self.assertRaises(pymysql.err.OperationalError): + pymysql.connect(user='pymysql_256', **db) + +class TestConnection(base.PyMySQLTestCase): + + def test_utf8mb4(self): + """This test requires MySQL >= 5.5""" + arg = self.databases[0].copy() + arg['charset'] = 'utf8mb4' + conn = pymysql.connect(**arg) + + def test_largedata(self): + """Large query and response (>=16MB)""" + cur = self.connections[0].cursor() + cur.execute("SELECT @@max_allowed_packet") + if cur.fetchone()[0] < 16*1024*1024 + 10: + print("Set max_allowed_packet to bigger than 17MB") + return + t = 'a' * (16*1024*1024) + cur.execute("SELECT '" + t + "'") + assert cur.fetchone()[0] == t + + def test_autocommit(self): + con = self.connections[0] + self.assertFalse(con.get_autocommit()) + + cur = con.cursor() + cur.execute("SET AUTOCOMMIT=1") + self.assertTrue(con.get_autocommit()) + + con.autocommit(False) + self.assertFalse(con.get_autocommit()) + cur.execute("SELECT @@AUTOCOMMIT") + self.assertEqual(cur.fetchone()[0], 0) + + def test_select_db(self): + con = self.connections[0] + current_db = self.databases[0]['db'] + other_db = self.databases[1]['db'] + + cur = con.cursor() + cur.execute('SELECT database()') + self.assertEqual(cur.fetchone()[0], current_db) + + con.select_db(other_db) + cur.execute('SELECT database()') + self.assertEqual(cur.fetchone()[0], other_db) + + def test_connection_gone_away(self): + """ + http://dev.mysql.com/doc/refman/5.0/en/gone-away.html + http://dev.mysql.com/doc/refman/5.0/en/error-messages-client.html#error_cr_server_gone_error + """ + con = self.connections[0] + cur = con.cursor() + cur.execute("SET wait_timeout=1") + time.sleep(2) + with self.assertRaises(pymysql.OperationalError) as cm: + cur.execute("SELECT 1+1") + # error occures while reading, not writing because of socket buffer. + #self.assertEqual(cm.exception.args[0], 2006) + self.assertIn(cm.exception.args[0], (2006, 2013)) + + def test_init_command(self): + conn = pymysql.connect( + init_command='SELECT "bar"; SELECT "baz"', + **self.databases[0] + ) + c = conn.cursor() + c.execute('select "foobar";') + self.assertEqual(('foobar',), c.fetchone()) + conn.close() + with self.assertRaises(pymysql.err.Error): + conn.ping(reconnect=False) + + def test_read_default_group(self): + conn = pymysql.connect( + read_default_group='client', + **self.databases[0] + ) + self.assertTrue(conn.open) + + def test_context(self): + with self.assertRaises(ValueError): + c = pymysql.connect(**self.databases[0]) + with c as cur: + cur.execute('create table test ( a int )') + c.begin() + cur.execute('insert into test values ((1))') + raise ValueError('pseudo abort') + c.commit() + c = pymysql.connect(**self.databases[0]) + with c as cur: + cur.execute('select count(*) from test') + self.assertEqual(0, cur.fetchone()[0]) + cur.execute('insert into test values ((1))') + with c as cur: + cur.execute('select count(*) from test') + self.assertEqual(1,cur.fetchone()[0]) + cur.execute('drop table test') + + def test_set_charset(self): + c = pymysql.connect(**self.databases[0]) + c.set_charset('utf8') + # TODO validate setting here + + def test_defer_connect(self): + import socket + for db in self.databases: + d = db.copy() + try: + sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + sock.connect(d['unix_socket']) + except KeyError: + sock = socket.create_connection( + (d.get('host', 'localhost'), d.get('port', 3306))) + for k in ['unix_socket', 'host', 'port']: + try: + del d[k] + except KeyError: + pass + + c = pymysql.connect(defer_connect=True, **d) + self.assertFalse(c.open) + c.connect(sock) + c.close() + sock.close() + + @unittest2.skipUnless(sys.version_info[0:2] >= (3,2), "required py-3.2") + def test_no_delay_warning(self): + current_db = self.databases[0].copy() + current_db['no_delay'] = True + with self.assertWarns(DeprecationWarning) as cm: + conn = pymysql.connect(**current_db) + + +# A custom type and function to escape it +class Foo(object): + value = "bar" + + +def escape_foo(x, d): + return x.value + + +class TestEscape(base.PyMySQLTestCase): + def test_escape_string(self): + con = self.connections[0] + cur = con.cursor() + + self.assertEqual(con.escape("foo'bar"), "'foo\\'bar'") + # added NO_AUTO_CREATE_USER as not including it in 5.7 generates warnings + cur.execute("SET sql_mode='NO_BACKSLASH_ESCAPES,NO_AUTO_CREATE_USER'") + self.assertEqual(con.escape("foo'bar"), "'foo''bar'") + + def test_escape_builtin_encoders(self): + con = self.connections[0] + cur = con.cursor() + + val = datetime.datetime(2012, 3, 4, 5, 6) + self.assertEqual(con.escape(val, con.encoders), "'2012-03-04 05:06:00'") + + def test_escape_custom_object(self): + con = self.connections[0] + cur = con.cursor() + + mapping = {Foo: escape_foo} + self.assertEqual(con.escape(Foo(), mapping), "bar") + + def test_escape_fallback_encoder(self): + con = self.connections[0] + cur = con.cursor() + + class Custom(str): + pass + + mapping = {text_type: pymysql.escape_string} + self.assertEqual(con.escape(Custom('foobar'), mapping), "'foobar'") + + def test_escape_no_default(self): + con = self.connections[0] + cur = con.cursor() + + self.assertRaises(TypeError, con.escape, 42, {}) + + def test_escape_dict_value(self): + con = self.connections[0] + cur = con.cursor() + + mapping = con.encoders.copy() + mapping[Foo] = escape_foo + self.assertEqual(con.escape({'foo': Foo()}, mapping), {'foo': "bar"}) + + def test_escape_list_item(self): + con = self.connections[0] + cur = con.cursor() + + mapping = con.encoders.copy() + mapping[Foo] = escape_foo + self.assertEqual(con.escape([Foo()], mapping), "(bar)") + + def test_previous_cursor_not_closed(self): + con = self.connections[0] + cur1 = con.cursor() + cur1.execute("SELECT 1; SELECT 2") + cur2 = con.cursor() + cur2.execute("SELECT 3") + self.assertEqual(cur2.fetchone()[0], 3) + + def test_commit_during_multi_result(self): + con = self.connections[0] + cur = con.cursor() + cur.execute("SELECT 1; SELECT 2") + con.commit() + cur.execute("SELECT 3") + self.assertEqual(cur.fetchone()[0], 3) diff --git a/gluon/contrib/pymysql/tests/test_converters.py b/gluon/contrib/pymysql/tests/test_converters.py new file mode 100755 index 00000000..b7b5a984 --- /dev/null +++ b/gluon/contrib/pymysql/tests/test_converters.py @@ -0,0 +1,67 @@ +import datetime +from unittest import TestCase + +from pymysql._compat import PY2 +from pymysql import converters + + +__all__ = ["TestConverter"] + + +class TestConverter(TestCase): + + def test_escape_string(self): + self.assertEqual( + converters.escape_string(u"foo\nbar"), + u"foo\\nbar" + ) + + if PY2: + def test_escape_string_bytes(self): + self.assertEqual( + converters.escape_string(b"foo\nbar"), + b"foo\\nbar" + ) + + def test_convert_datetime(self): + expected = datetime.datetime(2007, 2, 24, 23, 6, 20) + dt = converters.convert_datetime('2007-02-24 23:06:20') + self.assertEqual(dt, expected) + + def test_convert_datetime_with_fsp(self): + expected = datetime.datetime(2007, 2, 24, 23, 6, 20, 511581) + dt = converters.convert_datetime('2007-02-24 23:06:20.511581') + self.assertEqual(dt, expected) + + def _test_convert_timedelta(self, with_negate=False, with_fsp=False): + d = {'hours': 789, 'minutes': 12, 'seconds': 34} + s = '%(hours)s:%(minutes)s:%(seconds)s' % d + if with_fsp: + d['microseconds'] = 511581 + s += '.%(microseconds)s' % d + + expected = datetime.timedelta(**d) + if with_negate: + expected = -expected + s = '-' + s + + tdelta = converters.convert_timedelta(s) + self.assertEqual(tdelta, expected) + + def test_convert_timedelta(self): + self._test_convert_timedelta(with_negate=False, with_fsp=False) + self._test_convert_timedelta(with_negate=True, with_fsp=False) + + def test_convert_timedelta_with_fsp(self): + self._test_convert_timedelta(with_negate=False, with_fsp=True) + self._test_convert_timedelta(with_negate=False, with_fsp=True) + + def test_convert_time(self): + expected = datetime.time(23, 6, 20) + time_obj = converters.convert_time('23:06:20') + self.assertEqual(time_obj, expected) + + def test_convert_time_with_fsp(self): + expected = datetime.time(23, 6, 20, 511581) + time_obj = converters.convert_time('23:06:20.511581') + self.assertEqual(time_obj, expected) diff --git a/gluon/contrib/pymysql/tests/test_cursor.py b/gluon/contrib/pymysql/tests/test_cursor.py new file mode 100755 index 00000000..431ef4dd --- /dev/null +++ b/gluon/contrib/pymysql/tests/test_cursor.py @@ -0,0 +1,104 @@ +import warnings + +from pymysql.tests import base +import pymysql.cursors + +class CursorTest(base.PyMySQLTestCase): + def setUp(self): + super(CursorTest, self).setUp() + + conn = self.connections[0] + self.safe_create_table( + conn, + "test", "create table test (data varchar(10))", + ) + cursor = conn.cursor() + cursor.execute( + "insert into test (data) values " + "('row1'), ('row2'), ('row3'), ('row4'), ('row5')") + cursor.close() + self.test_connection = pymysql.connect(**self.databases[0]) + self.addCleanup(self.test_connection.close) + + def test_cleanup_rows_unbuffered(self): + conn = self.test_connection + cursor = conn.cursor(pymysql.cursors.SSCursor) + + cursor.execute("select * from test as t1, test as t2") + for counter, row in enumerate(cursor): + if counter > 10: + break + + del cursor + self.safe_gc_collect() + + c2 = conn.cursor() + + c2.execute("select 1") + self.assertEqual(c2.fetchone(), (1,)) + self.assertIsNone(c2.fetchone()) + + def test_cleanup_rows_buffered(self): + conn = self.test_connection + cursor = conn.cursor(pymysql.cursors.Cursor) + + cursor.execute("select * from test as t1, test as t2") + for counter, row in enumerate(cursor): + if counter > 10: + break + + del cursor + self.safe_gc_collect() + + c2 = conn.cursor() + + c2.execute("select 1") + + self.assertEqual( + c2.fetchone(), (1,) + ) + self.assertIsNone(c2.fetchone()) + + def test_executemany(self): + conn = self.test_connection + cursor = conn.cursor(pymysql.cursors.Cursor) + + m = pymysql.cursors.RE_INSERT_VALUES.match("INSERT INTO TEST (ID, NAME) VALUES (%s, %s)") + self.assertIsNotNone(m, 'error parse %s') + self.assertEqual(m.group(3), '', 'group 3 not blank, bug in RE_INSERT_VALUES?') + + m = pymysql.cursors.RE_INSERT_VALUES.match("INSERT INTO TEST (ID, NAME) VALUES (%(id)s, %(name)s)") + self.assertIsNotNone(m, 'error parse %(name)s') + self.assertEqual(m.group(3), '', 'group 3 not blank, bug in RE_INSERT_VALUES?') + + m = pymysql.cursors.RE_INSERT_VALUES.match("INSERT INTO TEST (ID, NAME) VALUES (%(id_name)s, %(name)s)") + self.assertIsNotNone(m, 'error parse %(id_name)s') + self.assertEqual(m.group(3), '', 'group 3 not blank, bug in RE_INSERT_VALUES?') + + m = pymysql.cursors.RE_INSERT_VALUES.match("INSERT INTO TEST (ID, NAME) VALUES (%(id_name)s, %(name)s) ON duplicate update") + self.assertIsNotNone(m, 'error parse %(id_name)s') + self.assertEqual(m.group(3), ' ON duplicate update', 'group 3 not ON duplicate update, bug in RE_INSERT_VALUES?') + + # cursor._executed must bee "insert into test (data) values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9)" + # list args + data = range(10) + cursor.executemany("insert into test (data) values (%s)", data) + self.assertTrue(cursor._executed.endswith(b",(7),(8),(9)"), 'execute many with %s not in one query') + + # dict args + data_dict = [{'data': i} for i in range(10)] + cursor.executemany("insert into test (data) values (%(data)s)", data_dict) + self.assertTrue(cursor._executed.endswith(b",(7),(8),(9)"), 'execute many with %(data)s not in one query') + + # %% in column set + cursor.execute("""\ + CREATE TABLE percent_test ( + `A%` INTEGER, + `B%` INTEGER)""") + try: + q = "INSERT INTO percent_test (`A%%`, `B%%`) VALUES (%s, %s)" + self.assertIsNotNone(pymysql.cursors.RE_INSERT_VALUES.match(q)) + cursor.executemany(q, [(3, 4), (5, 6)]) + self.assertTrue(cursor._executed.endswith(b"(3, 4),(5, 6)"), "executemany with %% not in one query") + finally: + cursor.execute("DROP TABLE IF EXISTS percent_test") diff --git a/gluon/contrib/pymysql/tests/test_err.py b/gluon/contrib/pymysql/tests/test_err.py new file mode 100755 index 00000000..3468d1b1 --- /dev/null +++ b/gluon/contrib/pymysql/tests/test_err.py @@ -0,0 +1,21 @@ +import unittest2 + +from pymysql import err + + +__all__ = ["TestRaiseException"] + + +class TestRaiseException(unittest2.TestCase): + + def test_raise_mysql_exception(self): + data = b"\xff\x15\x04Access denied" + with self.assertRaises(err.OperationalError) as cm: + err.raise_mysql_exception(data) + self.assertEqual(cm.exception.args, (1045, 'Access denied')) + + def test_raise_mysql_exception_client_protocol_41(self): + data = b"\xff\x15\x04#28000Access denied" + with self.assertRaises(err.OperationalError) as cm: + err.raise_mysql_exception(data) + self.assertEqual(cm.exception.args, (1045, 'Access denied')) diff --git a/gluon/contrib/pymysql/tests/test_issues.py b/gluon/contrib/pymysql/tests/test_issues.py index 6f7fc3d1..fe3e2984 100644 --- a/gluon/contrib/pymysql/tests/test_issues.py +++ b/gluon/contrib/pymysql/tests/test_issues.py @@ -1,26 +1,31 @@ -import pymysql -from pymysql.tests import base -import unittest - +import datetime +import time +import warnings import sys +import pymysql +from pymysql import cursors +from pymysql._compat import text_type +from pymysql.tests import base +import unittest2 + try: import imp reload = imp.reload except AttributeError: pass -import datetime -# backwards compatibility: -if not hasattr(unittest, "skip"): - unittest.skip = lambda message: lambda f: f +__all__ = ["TestOldIssues", "TestNewIssues", "TestGitHubIssues"] class TestOldIssues(base.PyMySQLTestCase): def test_issue_3(self): """ undefined methods datetime_or_None, date_or_None """ conn = self.connections[0] c = conn.cursor() + with warnings.catch_warnings(): + warnings.filterwarnings("ignore") + c.execute("drop table if exists issue3") c.execute("create table issue3 (d date, t time, dt datetime, ts timestamp)") try: c.execute("insert into issue3 (d, t, dt, ts) values (%s,%s,%s,%s)", (None, None, None, None)) @@ -39,6 +44,9 @@ class TestOldIssues(base.PyMySQLTestCase): """ can't retrieve TIMESTAMP fields """ conn = self.connections[0] c = conn.cursor() + with warnings.catch_warnings(): + warnings.filterwarnings("ignore") + c.execute("drop table if exists issue4") c.execute("create table issue4 (ts timestamp)") try: c.execute("insert into issue4 (ts) values (now())") @@ -55,7 +63,10 @@ class TestOldIssues(base.PyMySQLTestCase): def test_issue_6(self): """ exception: TypeError: ord() expected a character, but string of length 0 found """ - conn = pymysql.connect(host="localhost",user="root",passwd="",db="mysql") + # ToDo: this test requires access to db 'mysql'. + kwargs = self.databases[0].copy() + kwargs['db'] = "mysql" + conn = pymysql.connect(**kwargs) c = conn.cursor() c.execute("select * from user") conn.close() @@ -64,8 +75,11 @@ class TestOldIssues(base.PyMySQLTestCase): """ Primary Key and Index error when selecting data """ conn = self.connections[0] c = conn.cursor() + with warnings.catch_warnings(): + warnings.filterwarnings("ignore") + c.execute("drop table if exists test") c.execute("""CREATE TABLE `test` (`station` int(10) NOT NULL DEFAULT '0', `dh` -datetime NOT NULL DEFAULT '0000-00-00 00:00:00', `echeance` int(1) NOT NULL +datetime NOT NULL DEFAULT '2015-01-01 00:00:00', `echeance` int(1) NOT NULL DEFAULT '0', `me` double DEFAULT NULL, `mo` double DEFAULT NULL, PRIMARY KEY (`station`,`dh`,`echeance`)) ENGINE=MyISAM DEFAULT CHARSET=latin1;""") try: @@ -82,18 +96,13 @@ KEY (`station`,`dh`,`echeance`)) ENGINE=MyISAM DEFAULT CHARSET=latin1;""") except DeprecationWarning: self.fail() - def test_issue_10(self): - """ Allocate a variable to return when the exception handler is permissive """ - conn = self.connections[0] - conn.errorhandler = lambda cursor, errorclass, errorvalue: None - cur = conn.cursor() - cur.execute( "create table t( n int )" ) - cur.execute( "create table t( n int )" ) - def test_issue_13(self): """ can't handle large result fields """ conn = self.connections[0] cur = conn.cursor() + with warnings.catch_warnings(): + warnings.filterwarnings("ignore") + cur.execute("drop table if exists issue13") try: cur.execute("create table issue13 (t text)") # ticket says 18k @@ -106,18 +115,13 @@ KEY (`station`,`dh`,`echeance`)) ENGINE=MyISAM DEFAULT CHARSET=latin1;""") finally: cur.execute("drop table issue13") - def test_issue_14(self): - """ typo in converters.py """ - self.assertEqual('1', pymysql.converters.escape_item(1, "utf8")) - self.assertEqual('1', pymysql.converters.escape_item(1L, "utf8")) - - self.assertEqual('1', pymysql.converters.escape_object(1)) - self.assertEqual('1', pymysql.converters.escape_object(1L)) - def test_issue_15(self): """ query should be expanded before perform character encoding """ conn = self.connections[0] c = conn.cursor() + with warnings.catch_warnings(): + warnings.filterwarnings("ignore") + c.execute("drop table if exists issue15") c.execute("create table issue15 (t varchar(32))") try: c.execute("insert into issue15 (t) values (%s)", (u'\xe4\xf6\xfc',)) @@ -130,6 +134,9 @@ KEY (`station`,`dh`,`echeance`)) ENGINE=MyISAM DEFAULT CHARSET=latin1;""") """ Patch for string and tuple escaping """ conn = self.connections[0] c = conn.cursor() + with warnings.catch_warnings(): + warnings.filterwarnings("ignore") + c.execute("drop table if exists issue16") c.execute("create table issue16 (name varchar(32) primary key, email varchar(32))") try: c.execute("insert into issue16 (name, email) values ('pete', 'floydophone')") @@ -138,20 +145,24 @@ KEY (`station`,`dh`,`echeance`)) ENGINE=MyISAM DEFAULT CHARSET=latin1;""") finally: c.execute("drop table issue16") - @unittest.skip("test_issue_17() requires a custom, legacy MySQL configuration and will not be run.") + @unittest2.skip("test_issue_17() requires a custom, legacy MySQL configuration and will not be run.") def test_issue_17(self): - """ could not connect mysql use passwod """ + """could not connect mysql use passwod""" conn = self.connections[0] host = self.databases[0]["host"] db = self.databases[0]["db"] c = conn.cursor() + # grant access to a table to a user with a password try: + with warnings.catch_warnings(): + warnings.filterwarnings("ignore") + c.execute("drop table if exists issue17") c.execute("create table issue17 (x varchar(32) primary key)") c.execute("insert into issue17 (x) values ('hello, world!')") c.execute("grant all privileges on %s.issue17 to 'issue17user'@'%%' identified by '1234'" % db) conn.commit() - + conn2 = pymysql.connect(host=host, user="issue17user", passwd="1234", db=db) c2 = conn2.cursor() c2.execute("select x from issue17") @@ -159,71 +170,71 @@ KEY (`station`,`dh`,`echeance`)) ENGINE=MyISAM DEFAULT CHARSET=latin1;""") finally: c.execute("drop table issue17") -def _uni(s, e): - # hack for py3 - if sys.version_info[0] > 2: - return unicode(bytes(s, sys.getdefaultencoding()), e) - else: - return unicode(s, e) - class TestNewIssues(base.PyMySQLTestCase): def test_issue_34(self): try: pymysql.connect(host="localhost", port=1237, user="root") self.fail() - except pymysql.OperationalError, e: + except pymysql.OperationalError as e: self.assertEqual(2003, e.args[0]) - except: + except Exception: self.fail() def test_issue_33(self): - conn = pymysql.connect(host="localhost", user="root", db=self.databases[0]["db"], charset="utf8") + conn = pymysql.connect(charset="utf8", **self.databases[0]) + self.safe_create_table(conn, u'hei\xdfe', + u'create table hei\xdfe (name varchar(32))') c = conn.cursor() - try: - c.execute(_uni("create table hei\xc3\x9fe (name varchar(32))", "utf8")) - c.execute(_uni("insert into hei\xc3\x9fe (name) values ('Pi\xc3\xb1ata')", "utf8")) - c.execute(_uni("select name from hei\xc3\x9fe", "utf8")) - self.assertEqual(_uni("Pi\xc3\xb1ata","utf8"), c.fetchone()[0]) - finally: - c.execute(_uni("drop table hei\xc3\x9fe", "utf8")) + c.execute(u"insert into hei\xdfe (name) values ('Pi\xdfata')") + c.execute(u"select name from hei\xdfe") + self.assertEqual(u"Pi\xdfata", c.fetchone()[0]) - @unittest.skip("This test requires manual intervention") + @unittest2.skip("This test requires manual intervention") def test_issue_35(self): conn = self.connections[0] c = conn.cursor() - print "sudo killall -9 mysqld within the next 10 seconds" + print("sudo killall -9 mysqld within the next 10 seconds") try: c.execute("select sleep(10)") self.fail() - except pymysql.OperationalError, e: + except pymysql.OperationalError as e: self.assertEqual(2013, e.args[0]) def test_issue_36(self): - conn = self.connections[0] + # connection 0 is super user, connection 1 isn't + conn = self.connections[1] c = conn.cursor() - # kill connections[0] c.execute("show processlist") kill_id = None - for id,user,host,db,command,time,state,info in c.fetchall(): + for row in c.fetchall(): + id = row[0] + info = row[7] if info == "show processlist": kill_id = id break + self.assertEqual(kill_id, conn.thread_id()) # now nuke the connection - conn.kill(kill_id) + self.connections[0].kill(kill_id) # make sure this connection has broken try: c.execute("show tables") self.fail() - except: + except Exception: pass + c.close() + conn.close() + # check the process list from the other connection try: - c = self.connections[1].cursor() + # Wait since Travis-CI sometimes fail this test. + time.sleep(0.1) + + c = self.connections[0].cursor() c.execute("show processlist") ids = [row[0] for row in c.fetchall()] self.assertFalse(kill_id in ids) finally: - del self.connections[0] + del self.connections[1] def test_issue_37(self): conn = self.connections[0] @@ -237,8 +248,11 @@ class TestNewIssues(base.PyMySQLTestCase): conn = self.connections[0] c = conn.cursor() datum = "a" * 1024 * 1023 # reduced size for most default mysql installs - + try: + with warnings.catch_warnings(): + warnings.filterwarnings("ignore") + c.execute("drop table if exists issue38") c.execute("create table issue38 (id integer, data mediumblob)") c.execute("insert into issue38 values (1, %s)", (datum,)) finally: @@ -247,8 +261,11 @@ class TestNewIssues(base.PyMySQLTestCase): def disabled_test_issue_54(self): conn = self.connections[0] c = conn.cursor() + with warnings.catch_warnings(): + warnings.filterwarnings("ignore") + c.execute("drop table if exists issue54") big_sql = "select * from issue54 where " - big_sql += " and ".join("%d=%d" % (i,i) for i in xrange(0, 100000)) + big_sql += " and ".join("%d=%d" % (i,i) for i in range(0, 100000)) try: c.execute("create table issue54 (id integer primary key)") @@ -260,10 +277,14 @@ class TestNewIssues(base.PyMySQLTestCase): class TestGitHubIssues(base.PyMySQLTestCase): def test_issue_66(self): + """ 'Connection' object has no attribute 'insert_id' """ conn = self.connections[0] c = conn.cursor() self.assertEqual(0, conn.insert_id()) try: + with warnings.catch_warnings(): + warnings.filterwarnings("ignore") + c.execute("drop table if exists issue66") c.execute("create table issue66 (id integer primary key auto_increment, x integer)") c.execute("insert into issue66 (x) values (1)") c.execute("insert into issue66 (x) values (1)") @@ -271,8 +292,224 @@ class TestGitHubIssues(base.PyMySQLTestCase): finally: c.execute("drop table issue66") -__all__ = ["TestOldIssues", "TestNewIssues", "TestGitHubIssues"] + def test_issue_79(self): + """ Duplicate field overwrites the previous one in the result of DictCursor """ + conn = self.connections[0] + c = conn.cursor(pymysql.cursors.DictCursor) -if __name__ == "__main__": - import unittest - unittest.main() + with warnings.catch_warnings(): + warnings.filterwarnings("ignore") + c.execute("drop table if exists a") + c.execute("drop table if exists b") + c.execute("""CREATE TABLE a (id int, value int)""") + c.execute("""CREATE TABLE b (id int, value int)""") + + a=(1,11) + b=(1,22) + try: + c.execute("insert into a values (%s, %s)", a) + c.execute("insert into b values (%s, %s)", b) + + c.execute("SELECT * FROM a inner join b on a.id = b.id") + r = c.fetchall()[0] + self.assertEqual(r['id'], 1) + self.assertEqual(r['value'], 11) + self.assertEqual(r['b.value'], 22) + finally: + c.execute("drop table a") + c.execute("drop table b") + + def test_issue_95(self): + """ Leftover trailing OK packet for "CALL my_sp" queries """ + conn = self.connections[0] + cur = conn.cursor() + with warnings.catch_warnings(): + warnings.filterwarnings("ignore") + cur.execute("DROP PROCEDURE IF EXISTS `foo`") + cur.execute("""CREATE PROCEDURE `foo` () + BEGIN + SELECT 1; + END""") + try: + cur.execute("""CALL foo()""") + cur.execute("""SELECT 1""") + self.assertEqual(cur.fetchone()[0], 1) + finally: + with warnings.catch_warnings(): + warnings.filterwarnings("ignore") + cur.execute("DROP PROCEDURE IF EXISTS `foo`") + + def test_issue_114(self): + """ autocommit is not set after reconnecting with ping() """ + conn = pymysql.connect(charset="utf8", **self.databases[0]) + conn.autocommit(False) + c = conn.cursor() + c.execute("""select @@autocommit;""") + self.assertFalse(c.fetchone()[0]) + conn.close() + conn.ping() + c.execute("""select @@autocommit;""") + self.assertFalse(c.fetchone()[0]) + conn.close() + + # Ensure autocommit() is still working + conn = pymysql.connect(charset="utf8", **self.databases[0]) + c = conn.cursor() + c.execute("""select @@autocommit;""") + self.assertFalse(c.fetchone()[0]) + conn.close() + conn.ping() + conn.autocommit(True) + c.execute("""select @@autocommit;""") + self.assertTrue(c.fetchone()[0]) + conn.close() + + def test_issue_175(self): + """ The number of fields returned by server is read in wrong way """ + conn = self.connections[0] + cur = conn.cursor() + for length in (200, 300): + columns = ', '.join('c{0} integer'.format(i) for i in range(length)) + sql = 'create table test_field_count ({0})'.format(columns) + try: + cur.execute(sql) + cur.execute('select * from test_field_count') + assert len(cur.description) == length + finally: + with warnings.catch_warnings(): + warnings.filterwarnings("ignore") + cur.execute('drop table if exists test_field_count') + + def test_issue_321(self): + """ Test iterable as query argument. """ + conn = pymysql.connect(charset="utf8", **self.databases[0]) + self.safe_create_table( + conn, "issue321", + "create table issue321 (value_1 varchar(1), value_2 varchar(1))") + + sql_insert = "insert into issue321 (value_1, value_2) values (%s, %s)" + sql_dict_insert = ("insert into issue321 (value_1, value_2) " + "values (%(value_1)s, %(value_2)s)") + sql_select = ("select * from issue321 where " + "value_1 in %s and value_2=%s") + data = [ + [(u"a", ), u"\u0430"], + [[u"b"], u"\u0430"], + {"value_1": [[u"c"]], "value_2": u"\u0430"} + ] + cur = conn.cursor() + self.assertEqual(cur.execute(sql_insert, data[0]), 1) + self.assertEqual(cur.execute(sql_insert, data[1]), 1) + self.assertEqual(cur.execute(sql_dict_insert, data[2]), 1) + self.assertEqual( + cur.execute(sql_select, [(u"a", u"b", u"c"), u"\u0430"]), 3) + self.assertEqual(cur.fetchone(), (u"a", u"\u0430")) + self.assertEqual(cur.fetchone(), (u"b", u"\u0430")) + self.assertEqual(cur.fetchone(), (u"c", u"\u0430")) + + def test_issue_364(self): + """ Test mixed unicode/binary arguments in executemany. """ + conn = pymysql.connect(charset="utf8", **self.databases[0]) + self.safe_create_table( + conn, "issue364", + "create table issue364 (value_1 binary(3), value_2 varchar(3)) " + "engine=InnoDB default charset=utf8") + + sql = "insert into issue364 (value_1, value_2) values (%s, %s)" + usql = u"insert into issue364 (value_1, value_2) values (%s, %s)" + values = [pymysql.Binary(b"\x00\xff\x00"), u"\xe4\xf6\xfc"] + + # test single insert and select + cur = conn.cursor() + cur.execute(sql, args=values) + cur.execute("select * from issue364") + self.assertEqual(cur.fetchone(), tuple(values)) + + # test single insert unicode query + cur.execute(usql, args=values) + + # test multi insert and select + cur.executemany(sql, args=(values, values, values)) + cur.execute("select * from issue364") + for row in cur.fetchall(): + self.assertEqual(row, tuple(values)) + + # test multi insert with unicode query + cur.executemany(usql, args=(values, values, values)) + + def test_issue_363(self): + """ Test binary / geometry types. """ + conn = pymysql.connect(charset="utf8", **self.databases[0]) + self.safe_create_table( + conn, "issue363", + "CREATE TABLE issue363 ( " + "id INTEGER PRIMARY KEY, geom LINESTRING NOT NULL, " + "SPATIAL KEY geom (geom)) " + "ENGINE=MyISAM default charset=utf8") + + cur = conn.cursor() + query = ("INSERT INTO issue363 (id, geom) VALUES" + "(1998, GeomFromText('LINESTRING(1.1 1.1,2.2 2.2)'))") + # From MySQL 5.7, ST_GeomFromText is added and GeomFromText is deprecated. + if self.mysql_server_is(conn, (5, 7, 0)): + with self.assertWarns(pymysql.err.Warning) as cm: + cur.execute(query) + else: + cur.execute(query) + + # select WKT + query = "SELECT AsText(geom) FROM issue363" + if self.mysql_server_is(conn, (5, 7, 0)): + with self.assertWarns(pymysql.err.Warning) as cm: + cur.execute(query) + else: + cur.execute(query) + row = cur.fetchone() + self.assertEqual(row, ("LINESTRING(1.1 1.1,2.2 2.2)", )) + + # select WKB + query = "SELECT AsBinary(geom) FROM issue363" + if self.mysql_server_is(conn, (5, 7, 0)): + with self.assertWarns(pymysql.err.Warning) as cm: + cur.execute(query) + else: + cur.execute(query) + row = cur.fetchone() + self.assertEqual(row, + (b"\x01\x02\x00\x00\x00\x02\x00\x00\x00" + b"\x9a\x99\x99\x99\x99\x99\xf1?" + b"\x9a\x99\x99\x99\x99\x99\xf1?" + b"\x9a\x99\x99\x99\x99\x99\x01@" + b"\x9a\x99\x99\x99\x99\x99\x01@", )) + + # select internal binary + cur.execute("SELECT geom FROM issue363") + row = cur.fetchone() + # don't assert the exact internal binary value, as it could + # vary across implementations + self.assertTrue(isinstance(row[0], bytes)) + + def test_issue_491(self): + """ Test warning propagation """ + conn = pymysql.connect(charset="utf8", **self.databases[0]) + + with warnings.catch_warnings(): + # Ignore all warnings other than pymysql generated ones + warnings.simplefilter("ignore") + warnings.simplefilter("error", category=pymysql.Warning) + + # verify for both buffered and unbuffered cursor types + for cursor_class in (cursors.Cursor, cursors.SSCursor): + c = conn.cursor(cursor_class) + try: + c.execute("SELECT CAST('124b' AS SIGNED)") + c.fetchall() + except pymysql.Warning as e: + # Warnings should have errorcode and string message, just like exceptions + self.assertEqual(len(e.args), 2) + self.assertEqual(e.args[0], 1292) + self.assertTrue(isinstance(e.args[1], text_type)) + else: + self.fail("Should raise Warning") + finally: + c.close() diff --git a/gluon/contrib/pymysql/tests/test_load_local.py b/gluon/contrib/pymysql/tests/test_load_local.py new file mode 100755 index 00000000..85fd94ea --- /dev/null +++ b/gluon/contrib/pymysql/tests/test_load_local.py @@ -0,0 +1,93 @@ +from pymysql import cursors, OperationalError, Warning +from pymysql.tests import base + +import os +import warnings + +__all__ = ["TestLoadLocal"] + + +class TestLoadLocal(base.PyMySQLTestCase): + def test_no_file(self): + """Test load local infile when the file does not exist""" + conn = self.connections[0] + c = conn.cursor() + c.execute("CREATE TABLE test_load_local (a INTEGER, b INTEGER)") + try: + self.assertRaises( + OperationalError, + c.execute, + ("LOAD DATA LOCAL INFILE 'no_data.txt' INTO TABLE " + "test_load_local fields terminated by ','") + ) + finally: + c.execute("DROP TABLE test_load_local") + c.close() + + def test_load_file(self): + """Test load local infile with a valid file""" + conn = self.connections[0] + c = conn.cursor() + c.execute("CREATE TABLE test_load_local (a INTEGER, b INTEGER)") + filename = os.path.join(os.path.dirname(os.path.realpath(__file__)), + 'data', + 'load_local_data.txt') + try: + c.execute( + ("LOAD DATA LOCAL INFILE '{0}' INTO TABLE " + + "test_load_local FIELDS TERMINATED BY ','").format(filename) + ) + c.execute("SELECT COUNT(*) FROM test_load_local") + self.assertEqual(22749, c.fetchone()[0]) + finally: + c.execute("DROP TABLE test_load_local") + + def test_unbuffered_load_file(self): + """Test unbuffered load local infile with a valid file""" + conn = self.connections[0] + c = conn.cursor(cursors.SSCursor) + c.execute("CREATE TABLE test_load_local (a INTEGER, b INTEGER)") + filename = os.path.join(os.path.dirname(os.path.realpath(__file__)), + 'data', + 'load_local_data.txt') + try: + c.execute( + ("LOAD DATA LOCAL INFILE '{0}' INTO TABLE " + + "test_load_local FIELDS TERMINATED BY ','").format(filename) + ) + c.execute("SELECT COUNT(*) FROM test_load_local") + self.assertEqual(22749, c.fetchone()[0]) + finally: + c.close() + conn.close() + conn.connect() + c = conn.cursor() + c.execute("DROP TABLE test_load_local") + + def test_load_warnings(self): + """Test load local infile produces the appropriate warnings""" + conn = self.connections[0] + c = conn.cursor() + c.execute("CREATE TABLE test_load_local (a INTEGER, b INTEGER)") + filename = os.path.join(os.path.dirname(os.path.realpath(__file__)), + 'data', + 'load_local_warn_data.txt') + try: + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter('always') + c.execute( + ("LOAD DATA LOCAL INFILE '{0}' INTO TABLE " + + "test_load_local FIELDS TERMINATED BY ','").format(filename) + ) + self.assertEqual(w[0].category, Warning) + expected_message = "Incorrect integer value" + if expected_message not in str(w[-1].message): + self.fail("%r not in %r" % (expected_message, w[-1].message)) + finally: + c.execute("DROP TABLE test_load_local") + c.close() + + +if __name__ == "__main__": + import unittest + unittest.main() diff --git a/gluon/contrib/pymysql/tests/test_nextset.py b/gluon/contrib/pymysql/tests/test_nextset.py new file mode 100755 index 00000000..cdb6754f --- /dev/null +++ b/gluon/contrib/pymysql/tests/test_nextset.py @@ -0,0 +1,68 @@ +import unittest2 + +from pymysql.tests import base +from pymysql import util + + +class TestNextset(base.PyMySQLTestCase): + + def setUp(self): + super(TestNextset, self).setUp() + self.con = self.connections[0] + + def test_nextset(self): + cur = self.con.cursor() + cur.execute("SELECT 1; SELECT 2;") + self.assertEqual([(1,)], list(cur)) + + r = cur.nextset() + self.assertTrue(r) + + self.assertEqual([(2,)], list(cur)) + self.assertIsNone(cur.nextset()) + + def test_skip_nextset(self): + cur = self.con.cursor() + cur.execute("SELECT 1; SELECT 2;") + self.assertEqual([(1,)], list(cur)) + + cur.execute("SELECT 42") + self.assertEqual([(42,)], list(cur)) + + def test_ok_and_next(self): + cur = self.con.cursor() + cur.execute("SELECT 1; commit; SELECT 2;") + self.assertEqual([(1,)], list(cur)) + self.assertTrue(cur.nextset()) + self.assertTrue(cur.nextset()) + self.assertEqual([(2,)], list(cur)) + self.assertFalse(bool(cur.nextset())) + + @unittest2.expectedFailure + def test_multi_cursor(self): + cur1 = self.con.cursor() + cur2 = self.con.cursor() + + cur1.execute("SELECT 1; SELECT 2;") + cur2.execute("SELECT 42") + + self.assertEqual([(1,)], list(cur1)) + self.assertEqual([(42,)], list(cur2)) + + r = cur1.nextset() + self.assertTrue(r) + + self.assertEqual([(2,)], list(cur1)) + self.assertIsNone(cur1.nextset()) + + def test_multi_statement_warnings(self): + cursor = self.con.cursor() + + try: + cursor.execute('DROP TABLE IF EXISTS a; ' + 'DROP TABLE IF EXISTS b;') + except TypeError: + self.fail() + + #TODO: How about SSCursor and nextset? + # It's very hard to implement correctly... diff --git a/gluon/contrib/pymysql/tests/test_optionfile.py b/gluon/contrib/pymysql/tests/test_optionfile.py new file mode 100755 index 00000000..abc63ea1 --- /dev/null +++ b/gluon/contrib/pymysql/tests/test_optionfile.py @@ -0,0 +1,32 @@ +from pymysql.optionfile import Parser +from unittest import TestCase +from pymysql._compat import PY2 + +try: + from cStringIO import StringIO +except ImportError: + from io import StringIO + + +__all__ = ['TestParser'] + + +_cfg_file = (r""" +[default] +string = foo +quoted = "bar" +single_quoted = 'foobar' +""") + + +class TestParser(TestCase): + + def test_string(self): + parser = Parser() + if PY2: + parser.readfp(StringIO(_cfg_file)) + else: + parser.read_file(StringIO(_cfg_file)) + self.assertEqual(parser.get("default", "string"), "foo") + self.assertEqual(parser.get("default", "quoted"), "bar") + self.assertEqual(parser.get("default", "single_quoted"), "foobar") diff --git a/gluon/contrib/pymysql/tests/thirdparty/__init__.py b/gluon/contrib/pymysql/tests/thirdparty/__init__.py new file mode 100755 index 00000000..6d59e112 --- /dev/null +++ b/gluon/contrib/pymysql/tests/thirdparty/__init__.py @@ -0,0 +1,8 @@ +from .test_MySQLdb import * + +if __name__ == "__main__": + try: + import unittest2 as unittest + except ImportError: + import unittest + unittest.main() diff --git a/gluon/contrib/pymysql/tests/thirdparty/test_MySQLdb/__init__.py b/gluon/contrib/pymysql/tests/thirdparty/test_MySQLdb/__init__.py new file mode 100755 index 00000000..e4237c69 --- /dev/null +++ b/gluon/contrib/pymysql/tests/thirdparty/test_MySQLdb/__init__.py @@ -0,0 +1,7 @@ +from .test_MySQLdb_capabilities import test_MySQLdb as test_capabilities +from .test_MySQLdb_nonstandard import * +from .test_MySQLdb_dbapi20 import test_MySQLdb as test_dbapi2 + +if __name__ == "__main__": + import unittest + unittest.main() diff --git a/gluon/contrib/pymysql/tests/thirdparty/test_MySQLdb/capabilities.py b/gluon/contrib/pymysql/tests/thirdparty/test_MySQLdb/capabilities.py new file mode 100755 index 00000000..e4aae206 --- /dev/null +++ b/gluon/contrib/pymysql/tests/thirdparty/test_MySQLdb/capabilities.py @@ -0,0 +1,298 @@ +#!/usr/bin/env python -O +""" Script to test database capabilities and the DB-API interface + for functionality and memory leaks. + + Adapted from a script by M-A Lemburg. + +""" +import sys +from time import time +try: + import unittest2 as unittest +except ImportError: + import unittest + +PY2 = sys.version_info[0] == 2 + +class DatabaseTest(unittest.TestCase): + + db_module = None + connect_args = () + connect_kwargs = dict(use_unicode=True, charset="utf8") + create_table_extra = "ENGINE=INNODB CHARACTER SET UTF8" + rows = 10 + debug = False + + def setUp(self): + db = self.db_module.connect(*self.connect_args, **self.connect_kwargs) + self.connection = db + self.cursor = db.cursor() + self.BLOBText = ''.join([chr(i) for i in range(256)] * 100); + if PY2: + self.BLOBUText = unicode().join(unichr(i) for i in range(16834)) + else: + self.BLOBUText = "".join(chr(i) for i in range(16834)) + data = bytearray(range(256)) * 16 + self.BLOBBinary = self.db_module.Binary(data) + + leak_test = True + + def tearDown(self): + if self.leak_test: + import gc + del self.cursor + orphans = gc.collect() + self.assertFalse(orphans, "%d orphaned objects found after deleting cursor" % orphans) + + del self.connection + orphans = gc.collect() + self.assertFalse(orphans, "%d orphaned objects found after deleting connection" % orphans) + + def table_exists(self, name): + try: + self.cursor.execute('select * from %s where 1=0' % name) + except Exception: + return False + else: + return True + + def quote_identifier(self, ident): + return '"%s"' % ident + + def new_table_name(self): + i = id(self.cursor) + while True: + name = self.quote_identifier('tb%08x' % i) + if not self.table_exists(name): + return name + i = i + 1 + + def create_table(self, columndefs): + + """ Create a table using a list of column definitions given in + columndefs. + + generator must be a function taking arguments (row_number, + col_number) returning a suitable data object for insertion + into the table. + + """ + self.table = self.new_table_name() + self.cursor.execute('CREATE TABLE %s (%s) %s' % + (self.table, + ',\n'.join(columndefs), + self.create_table_extra)) + + def check_data_integrity(self, columndefs, generator): + # insert + self.create_table(columndefs) + insert_statement = ('INSERT INTO %s VALUES (%s)' % + (self.table, + ','.join(['%s'] * len(columndefs)))) + data = [ [ generator(i,j) for j in range(len(columndefs)) ] + for i in range(self.rows) ] + if self.debug: + print(data) + self.cursor.executemany(insert_statement, data) + self.connection.commit() + # verify + self.cursor.execute('select * from %s' % self.table) + l = self.cursor.fetchall() + if self.debug: + print(l) + self.assertEqual(len(l), self.rows) + try: + for i in range(self.rows): + for j in range(len(columndefs)): + self.assertEqual(l[i][j], generator(i,j)) + finally: + if not self.debug: + self.cursor.execute('drop table %s' % (self.table)) + + def test_transactions(self): + columndefs = ( 'col1 INT', 'col2 VARCHAR(255)') + def generator(row, col): + if col == 0: return row + else: return ('%i' % (row%10))*255 + self.create_table(columndefs) + insert_statement = ('INSERT INTO %s VALUES (%s)' % + (self.table, + ','.join(['%s'] * len(columndefs)))) + data = [ [ generator(i,j) for j in range(len(columndefs)) ] + for i in range(self.rows) ] + self.cursor.executemany(insert_statement, data) + # verify + self.connection.commit() + self.cursor.execute('select * from %s' % self.table) + l = self.cursor.fetchall() + self.assertEqual(len(l), self.rows) + for i in range(self.rows): + for j in range(len(columndefs)): + self.assertEqual(l[i][j], generator(i,j)) + delete_statement = 'delete from %s where col1=%%s' % self.table + self.cursor.execute(delete_statement, (0,)) + self.cursor.execute('select col1 from %s where col1=%s' % \ + (self.table, 0)) + l = self.cursor.fetchall() + self.assertFalse(l, "DELETE didn't work") + self.connection.rollback() + self.cursor.execute('select col1 from %s where col1=%s' % \ + (self.table, 0)) + l = self.cursor.fetchall() + self.assertTrue(len(l) == 1, "ROLLBACK didn't work") + self.cursor.execute('drop table %s' % (self.table)) + + def test_truncation(self): + columndefs = ( 'col1 INT', 'col2 VARCHAR(255)') + def generator(row, col): + if col == 0: return row + else: return ('%i' % (row%10))*((255-self.rows//2)+row) + self.create_table(columndefs) + insert_statement = ('INSERT INTO %s VALUES (%s)' % + (self.table, + ','.join(['%s'] * len(columndefs)))) + + try: + self.cursor.execute(insert_statement, (0, '0'*256)) + except Warning: + if self.debug: print(self.cursor.messages) + except self.connection.DataError: + pass + else: + self.fail("Over-long column did not generate warnings/exception with single insert") + + self.connection.rollback() + + try: + for i in range(self.rows): + data = [] + for j in range(len(columndefs)): + data.append(generator(i,j)) + self.cursor.execute(insert_statement,tuple(data)) + except Warning: + if self.debug: print(self.cursor.messages) + except self.connection.DataError: + pass + else: + self.fail("Over-long columns did not generate warnings/exception with execute()") + + self.connection.rollback() + + try: + data = [ [ generator(i,j) for j in range(len(columndefs)) ] + for i in range(self.rows) ] + self.cursor.executemany(insert_statement, data) + except Warning: + if self.debug: print(self.cursor.messages) + except self.connection.DataError: + pass + else: + self.fail("Over-long columns did not generate warnings/exception with executemany()") + + self.connection.rollback() + self.cursor.execute('drop table %s' % (self.table)) + + def test_CHAR(self): + # Character data + def generator(row,col): + return ('%i' % ((row+col) % 10)) * 255 + self.check_data_integrity( + ('col1 char(255)','col2 char(255)'), + generator) + + def test_INT(self): + # Number data + def generator(row,col): + return row*row + self.check_data_integrity( + ('col1 INT',), + generator) + + def test_DECIMAL(self): + # DECIMAL + def generator(row,col): + from decimal import Decimal + return Decimal("%d.%02d" % (row, col)) + self.check_data_integrity( + ('col1 DECIMAL(5,2)',), + generator) + + def test_DATE(self): + ticks = time() + def generator(row,col): + return self.db_module.DateFromTicks(ticks+row*86400-col*1313) + self.check_data_integrity( + ('col1 DATE',), + generator) + + def test_TIME(self): + ticks = time() + def generator(row,col): + return self.db_module.TimeFromTicks(ticks+row*86400-col*1313) + self.check_data_integrity( + ('col1 TIME',), + generator) + + def test_DATETIME(self): + ticks = time() + def generator(row,col): + return self.db_module.TimestampFromTicks(ticks+row*86400-col*1313) + self.check_data_integrity( + ('col1 DATETIME',), + generator) + + def test_TIMESTAMP(self): + ticks = time() + def generator(row,col): + return self.db_module.TimestampFromTicks(ticks+row*86400-col*1313) + self.check_data_integrity( + ('col1 TIMESTAMP',), + generator) + + def test_fractional_TIMESTAMP(self): + ticks = time() + def generator(row,col): + return self.db_module.TimestampFromTicks(ticks+row*86400-col*1313+row*0.7*col/3.0) + self.check_data_integrity( + ('col1 TIMESTAMP',), + generator) + + def test_LONG(self): + def generator(row,col): + if col == 0: + return row + else: + return self.BLOBUText # 'BLOB Text ' * 1024 + self.check_data_integrity( + ('col1 INT', 'col2 LONG'), + generator) + + def test_TEXT(self): + def generator(row,col): + if col == 0: + return row + else: + return self.BLOBUText[:5192] # 'BLOB Text ' * 1024 + self.check_data_integrity( + ('col1 INT', 'col2 TEXT'), + generator) + + def test_LONG_BYTE(self): + def generator(row,col): + if col == 0: + return row + else: + return self.BLOBBinary # 'BLOB\000Binary ' * 1024 + self.check_data_integrity( + ('col1 INT','col2 LONG BYTE'), + generator) + + def test_BLOB(self): + def generator(row,col): + if col == 0: + return row + else: + return self.BLOBBinary # 'BLOB\000Binary ' * 1024 + self.check_data_integrity( + ('col1 INT','col2 BLOB'), + generator) diff --git a/gluon/contrib/pymysql/tests/thirdparty/test_MySQLdb/dbapi20.py b/gluon/contrib/pymysql/tests/thirdparty/test_MySQLdb/dbapi20.py new file mode 100755 index 00000000..e8665248 --- /dev/null +++ b/gluon/contrib/pymysql/tests/thirdparty/test_MySQLdb/dbapi20.py @@ -0,0 +1,856 @@ +#!/usr/bin/env python +''' Python DB API 2.0 driver compliance unit test suite. + + This software is Public Domain and may be used without restrictions. + + "Now we have booze and barflies entering the discussion, plus rumours of + DBAs on drugs... and I won't tell you what flashes through my mind each + time I read the subject line with 'Anal Compliance' in it. All around + this is turning out to be a thoroughly unwholesome unit test." + + -- Ian Bicking +''' + +__rcs_id__ = '$Id$' +__version__ = '$Revision$'[11:-2] +__author__ = 'Stuart Bishop ' + +try: + import unittest2 as unittest +except ImportError: + import unittest + +import time + +# $Log$ +# Revision 1.1.2.1 2006/02/25 03:44:32 adustman +# Generic DB-API unit test module +# +# Revision 1.10 2003/10/09 03:14:14 zenzen +# Add test for DB API 2.0 optional extension, where database exceptions +# are exposed as attributes on the Connection object. +# +# Revision 1.9 2003/08/13 01:16:36 zenzen +# Minor tweak from Stefan Fleiter +# +# Revision 1.8 2003/04/10 00:13:25 zenzen +# Changes, as per suggestions by M.-A. Lemburg +# - Add a table prefix, to ensure namespace collisions can always be avoided +# +# Revision 1.7 2003/02/26 23:33:37 zenzen +# Break out DDL into helper functions, as per request by David Rushby +# +# Revision 1.6 2003/02/21 03:04:33 zenzen +# Stuff from Henrik Ekelund: +# added test_None +# added test_nextset & hooks +# +# Revision 1.5 2003/02/17 22:08:43 zenzen +# Implement suggestions and code from Henrik Eklund - test that cursor.arraysize +# defaults to 1 & generic cursor.callproc test added +# +# Revision 1.4 2003/02/15 00:16:33 zenzen +# Changes, as per suggestions and bug reports by M.-A. Lemburg, +# Matthew T. Kromer, Federico Di Gregorio and Daniel Dittmar +# - Class renamed +# - Now a subclass of TestCase, to avoid requiring the driver stub +# to use multiple inheritance +# - Reversed the polarity of buggy test in test_description +# - Test exception heirarchy correctly +# - self.populate is now self._populate(), so if a driver stub +# overrides self.ddl1 this change propogates +# - VARCHAR columns now have a width, which will hopefully make the +# DDL even more portible (this will be reversed if it causes more problems) +# - cursor.rowcount being checked after various execute and fetchXXX methods +# - Check for fetchall and fetchmany returning empty lists after results +# are exhausted (already checking for empty lists if select retrieved +# nothing +# - Fix bugs in test_setoutputsize_basic and test_setinputsizes +# + +class DatabaseAPI20Test(unittest.TestCase): + ''' Test a database self.driver for DB API 2.0 compatibility. + This implementation tests Gadfly, but the TestCase + is structured so that other self.drivers can subclass this + test case to ensure compiliance with the DB-API. It is + expected that this TestCase may be expanded in the future + if ambiguities or edge conditions are discovered. + + The 'Optional Extensions' are not yet being tested. + + self.drivers should subclass this test, overriding setUp, tearDown, + self.driver, connect_args and connect_kw_args. Class specification + should be as follows: + + import dbapi20 + class mytest(dbapi20.DatabaseAPI20Test): + [...] + + Don't 'import DatabaseAPI20Test from dbapi20', or you will + confuse the unit tester - just 'import dbapi20'. + ''' + + # The self.driver module. This should be the module where the 'connect' + # method is to be found + driver = None + connect_args = () # List of arguments to pass to connect + connect_kw_args = {} # Keyword arguments for connect + table_prefix = 'dbapi20test_' # If you need to specify a prefix for tables + + ddl1 = 'create table %sbooze (name varchar(20))' % table_prefix + ddl2 = 'create table %sbarflys (name varchar(20))' % table_prefix + xddl1 = 'drop table %sbooze' % table_prefix + xddl2 = 'drop table %sbarflys' % table_prefix + + lowerfunc = 'lower' # Name of stored procedure to convert string->lowercase + + # Some drivers may need to override these helpers, for example adding + # a 'commit' after the execute. + def executeDDL1(self,cursor): + cursor.execute(self.ddl1) + + def executeDDL2(self,cursor): + cursor.execute(self.ddl2) + + def setUp(self): + ''' self.drivers should override this method to perform required setup + if any is necessary, such as creating the database. + ''' + pass + + def tearDown(self): + ''' self.drivers should override this method to perform required cleanup + if any is necessary, such as deleting the test database. + The default drops the tables that may be created. + ''' + con = self._connect() + try: + cur = con.cursor() + for ddl in (self.xddl1,self.xddl2): + try: + cur.execute(ddl) + con.commit() + except self.driver.Error: + # Assume table didn't exist. Other tests will check if + # execute is busted. + pass + finally: + con.close() + + def _connect(self): + try: + return self.driver.connect( + *self.connect_args,**self.connect_kw_args + ) + except AttributeError: + self.fail("No connect method found in self.driver module") + + def test_connect(self): + con = self._connect() + con.close() + + def test_apilevel(self): + try: + # Must exist + apilevel = self.driver.apilevel + # Must equal 2.0 + self.assertEqual(apilevel,'2.0') + except AttributeError: + self.fail("Driver doesn't define apilevel") + + def test_threadsafety(self): + try: + # Must exist + threadsafety = self.driver.threadsafety + # Must be a valid value + self.assertTrue(threadsafety in (0,1,2,3)) + except AttributeError: + self.fail("Driver doesn't define threadsafety") + + def test_paramstyle(self): + try: + # Must exist + paramstyle = self.driver.paramstyle + # Must be a valid value + self.assertTrue(paramstyle in ( + 'qmark','numeric','named','format','pyformat' + )) + except AttributeError: + self.fail("Driver doesn't define paramstyle") + + def test_Exceptions(self): + # Make sure required exceptions exist, and are in the + # defined heirarchy. + self.assertTrue(issubclass(self.driver.Warning,Exception)) + self.assertTrue(issubclass(self.driver.Error,Exception)) + self.assertTrue( + issubclass(self.driver.InterfaceError,self.driver.Error) + ) + self.assertTrue( + issubclass(self.driver.DatabaseError,self.driver.Error) + ) + self.assertTrue( + issubclass(self.driver.OperationalError,self.driver.Error) + ) + self.assertTrue( + issubclass(self.driver.IntegrityError,self.driver.Error) + ) + self.assertTrue( + issubclass(self.driver.InternalError,self.driver.Error) + ) + self.assertTrue( + issubclass(self.driver.ProgrammingError,self.driver.Error) + ) + self.assertTrue( + issubclass(self.driver.NotSupportedError,self.driver.Error) + ) + + def test_ExceptionsAsConnectionAttributes(self): + # OPTIONAL EXTENSION + # Test for the optional DB API 2.0 extension, where the exceptions + # are exposed as attributes on the Connection object + # I figure this optional extension will be implemented by any + # driver author who is using this test suite, so it is enabled + # by default. + con = self._connect() + drv = self.driver + self.assertTrue(con.Warning is drv.Warning) + self.assertTrue(con.Error is drv.Error) + self.assertTrue(con.InterfaceError is drv.InterfaceError) + self.assertTrue(con.DatabaseError is drv.DatabaseError) + self.assertTrue(con.OperationalError is drv.OperationalError) + self.assertTrue(con.IntegrityError is drv.IntegrityError) + self.assertTrue(con.InternalError is drv.InternalError) + self.assertTrue(con.ProgrammingError is drv.ProgrammingError) + self.assertTrue(con.NotSupportedError is drv.NotSupportedError) + + + def test_commit(self): + con = self._connect() + try: + # Commit must work, even if it doesn't do anything + con.commit() + finally: + con.close() + + def test_rollback(self): + con = self._connect() + # If rollback is defined, it should either work or throw + # the documented exception + if hasattr(con,'rollback'): + try: + con.rollback() + except self.driver.NotSupportedError: + pass + + def test_cursor(self): + con = self._connect() + try: + cur = con.cursor() + finally: + con.close() + + def test_cursor_isolation(self): + con = self._connect() + try: + # Make sure cursors created from the same connection have + # the documented transaction isolation level + cur1 = con.cursor() + cur2 = con.cursor() + self.executeDDL1(cur1) + cur1.execute("insert into %sbooze values ('Victoria Bitter')" % ( + self.table_prefix + )) + cur2.execute("select name from %sbooze" % self.table_prefix) + booze = cur2.fetchall() + self.assertEqual(len(booze),1) + self.assertEqual(len(booze[0]),1) + self.assertEqual(booze[0][0],'Victoria Bitter') + finally: + con.close() + + def test_description(self): + con = self._connect() + try: + cur = con.cursor() + self.executeDDL1(cur) + self.assertEqual(cur.description,None, + 'cursor.description should be none after executing a ' + 'statement that can return no rows (such as DDL)' + ) + cur.execute('select name from %sbooze' % self.table_prefix) + self.assertEqual(len(cur.description),1, + 'cursor.description describes too many columns' + ) + self.assertEqual(len(cur.description[0]),7, + 'cursor.description[x] tuples must have 7 elements' + ) + self.assertEqual(cur.description[0][0].lower(),'name', + 'cursor.description[x][0] must return column name' + ) + self.assertEqual(cur.description[0][1],self.driver.STRING, + 'cursor.description[x][1] must return column type. Got %r' + % cur.description[0][1] + ) + + # Make sure self.description gets reset + self.executeDDL2(cur) + self.assertEqual(cur.description,None, + 'cursor.description not being set to None when executing ' + 'no-result statements (eg. DDL)' + ) + finally: + con.close() + + def test_rowcount(self): + con = self._connect() + try: + cur = con.cursor() + self.executeDDL1(cur) + self.assertEqual(cur.rowcount,-1, + 'cursor.rowcount should be -1 after executing no-result ' + 'statements' + ) + cur.execute("insert into %sbooze values ('Victoria Bitter')" % ( + self.table_prefix + )) + self.assertTrue(cur.rowcount in (-1,1), + 'cursor.rowcount should == number or rows inserted, or ' + 'set to -1 after executing an insert statement' + ) + cur.execute("select name from %sbooze" % self.table_prefix) + self.assertTrue(cur.rowcount in (-1,1), + 'cursor.rowcount should == number of rows returned, or ' + 'set to -1 after executing a select statement' + ) + self.executeDDL2(cur) + self.assertEqual(cur.rowcount,-1, + 'cursor.rowcount not being reset to -1 after executing ' + 'no-result statements' + ) + finally: + con.close() + + lower_func = 'lower' + def test_callproc(self): + con = self._connect() + try: + cur = con.cursor() + if self.lower_func and hasattr(cur,'callproc'): + r = cur.callproc(self.lower_func,('FOO',)) + self.assertEqual(len(r),1) + self.assertEqual(r[0],'FOO') + r = cur.fetchall() + self.assertEqual(len(r),1,'callproc produced no result set') + self.assertEqual(len(r[0]),1, + 'callproc produced invalid result set' + ) + self.assertEqual(r[0][0],'foo', + 'callproc produced invalid results' + ) + finally: + con.close() + + def test_close(self): + con = self._connect() + try: + cur = con.cursor() + finally: + con.close() + + # cursor.execute should raise an Error if called after connection + # closed + self.assertRaises(self.driver.Error,self.executeDDL1,cur) + + # connection.commit should raise an Error if called after connection' + # closed.' + self.assertRaises(self.driver.Error,con.commit) + + # connection.close should raise an Error if called more than once + self.assertRaises(self.driver.Error,con.close) + + def test_execute(self): + con = self._connect() + try: + cur = con.cursor() + self._paraminsert(cur) + finally: + con.close() + + def _paraminsert(self,cur): + self.executeDDL1(cur) + cur.execute("insert into %sbooze values ('Victoria Bitter')" % ( + self.table_prefix + )) + self.assertTrue(cur.rowcount in (-1,1)) + + if self.driver.paramstyle == 'qmark': + cur.execute( + 'insert into %sbooze values (?)' % self.table_prefix, + ("Cooper's",) + ) + elif self.driver.paramstyle == 'numeric': + cur.execute( + 'insert into %sbooze values (:1)' % self.table_prefix, + ("Cooper's",) + ) + elif self.driver.paramstyle == 'named': + cur.execute( + 'insert into %sbooze values (:beer)' % self.table_prefix, + {'beer':"Cooper's"} + ) + elif self.driver.paramstyle == 'format': + cur.execute( + 'insert into %sbooze values (%%s)' % self.table_prefix, + ("Cooper's",) + ) + elif self.driver.paramstyle == 'pyformat': + cur.execute( + 'insert into %sbooze values (%%(beer)s)' % self.table_prefix, + {'beer':"Cooper's"} + ) + else: + self.fail('Invalid paramstyle') + self.assertTrue(cur.rowcount in (-1,1)) + + cur.execute('select name from %sbooze' % self.table_prefix) + res = cur.fetchall() + self.assertEqual(len(res),2,'cursor.fetchall returned too few rows') + beers = [res[0][0],res[1][0]] + beers.sort() + self.assertEqual(beers[0],"Cooper's", + 'cursor.fetchall retrieved incorrect data, or data inserted ' + 'incorrectly' + ) + self.assertEqual(beers[1],"Victoria Bitter", + 'cursor.fetchall retrieved incorrect data, or data inserted ' + 'incorrectly' + ) + + def test_executemany(self): + con = self._connect() + try: + cur = con.cursor() + self.executeDDL1(cur) + largs = [ ("Cooper's",) , ("Boag's",) ] + margs = [ {'beer': "Cooper's"}, {'beer': "Boag's"} ] + if self.driver.paramstyle == 'qmark': + cur.executemany( + 'insert into %sbooze values (?)' % self.table_prefix, + largs + ) + elif self.driver.paramstyle == 'numeric': + cur.executemany( + 'insert into %sbooze values (:1)' % self.table_prefix, + largs + ) + elif self.driver.paramstyle == 'named': + cur.executemany( + 'insert into %sbooze values (:beer)' % self.table_prefix, + margs + ) + elif self.driver.paramstyle == 'format': + cur.executemany( + 'insert into %sbooze values (%%s)' % self.table_prefix, + largs + ) + elif self.driver.paramstyle == 'pyformat': + cur.executemany( + 'insert into %sbooze values (%%(beer)s)' % ( + self.table_prefix + ), + margs + ) + else: + self.fail('Unknown paramstyle') + self.assertTrue(cur.rowcount in (-1,2), + 'insert using cursor.executemany set cursor.rowcount to ' + 'incorrect value %r' % cur.rowcount + ) + cur.execute('select name from %sbooze' % self.table_prefix) + res = cur.fetchall() + self.assertEqual(len(res),2, + 'cursor.fetchall retrieved incorrect number of rows' + ) + beers = [res[0][0],res[1][0]] + beers.sort() + self.assertEqual(beers[0],"Boag's",'incorrect data retrieved') + self.assertEqual(beers[1],"Cooper's",'incorrect data retrieved') + finally: + con.close() + + def test_fetchone(self): + con = self._connect() + try: + cur = con.cursor() + + # cursor.fetchone should raise an Error if called before + # executing a select-type query + self.assertRaises(self.driver.Error,cur.fetchone) + + # cursor.fetchone should raise an Error if called after + # executing a query that cannnot return rows + self.executeDDL1(cur) + self.assertRaises(self.driver.Error,cur.fetchone) + + cur.execute('select name from %sbooze' % self.table_prefix) + self.assertEqual(cur.fetchone(),None, + 'cursor.fetchone should return None if a query retrieves ' + 'no rows' + ) + self.assertTrue(cur.rowcount in (-1,0)) + + # cursor.fetchone should raise an Error if called after + # executing a query that cannnot return rows + cur.execute("insert into %sbooze values ('Victoria Bitter')" % ( + self.table_prefix + )) + self.assertRaises(self.driver.Error,cur.fetchone) + + cur.execute('select name from %sbooze' % self.table_prefix) + r = cur.fetchone() + self.assertEqual(len(r),1, + 'cursor.fetchone should have retrieved a single row' + ) + self.assertEqual(r[0],'Victoria Bitter', + 'cursor.fetchone retrieved incorrect data' + ) + self.assertEqual(cur.fetchone(),None, + 'cursor.fetchone should return None if no more rows available' + ) + self.assertTrue(cur.rowcount in (-1,1)) + finally: + con.close() + + samples = [ + 'Carlton Cold', + 'Carlton Draft', + 'Mountain Goat', + 'Redback', + 'Victoria Bitter', + 'XXXX' + ] + + def _populate(self): + ''' Return a list of sql commands to setup the DB for the fetch + tests. + ''' + populate = [ + "insert into %sbooze values ('%s')" % (self.table_prefix,s) + for s in self.samples + ] + return populate + + def test_fetchmany(self): + con = self._connect() + try: + cur = con.cursor() + + # cursor.fetchmany should raise an Error if called without + #issuing a query + self.assertRaises(self.driver.Error,cur.fetchmany,4) + + self.executeDDL1(cur) + for sql in self._populate(): + cur.execute(sql) + + cur.execute('select name from %sbooze' % self.table_prefix) + r = cur.fetchmany() + self.assertEqual(len(r),1, + 'cursor.fetchmany retrieved incorrect number of rows, ' + 'default of arraysize is one.' + ) + cur.arraysize=10 + r = cur.fetchmany(3) # Should get 3 rows + self.assertEqual(len(r),3, + 'cursor.fetchmany retrieved incorrect number of rows' + ) + r = cur.fetchmany(4) # Should get 2 more + self.assertEqual(len(r),2, + 'cursor.fetchmany retrieved incorrect number of rows' + ) + r = cur.fetchmany(4) # Should be an empty sequence + self.assertEqual(len(r),0, + 'cursor.fetchmany should return an empty sequence after ' + 'results are exhausted' + ) + self.assertTrue(cur.rowcount in (-1,6)) + + # Same as above, using cursor.arraysize + cur.arraysize=4 + cur.execute('select name from %sbooze' % self.table_prefix) + r = cur.fetchmany() # Should get 4 rows + self.assertEqual(len(r),4, + 'cursor.arraysize not being honoured by fetchmany' + ) + r = cur.fetchmany() # Should get 2 more + self.assertEqual(len(r),2) + r = cur.fetchmany() # Should be an empty sequence + self.assertEqual(len(r),0) + self.assertTrue(cur.rowcount in (-1,6)) + + cur.arraysize=6 + cur.execute('select name from %sbooze' % self.table_prefix) + rows = cur.fetchmany() # Should get all rows + self.assertTrue(cur.rowcount in (-1,6)) + self.assertEqual(len(rows),6) + self.assertEqual(len(rows),6) + rows = [r[0] for r in rows] + rows.sort() + + # Make sure we get the right data back out + for i in range(0,6): + self.assertEqual(rows[i],self.samples[i], + 'incorrect data retrieved by cursor.fetchmany' + ) + + rows = cur.fetchmany() # Should return an empty list + self.assertEqual(len(rows),0, + 'cursor.fetchmany should return an empty sequence if ' + 'called after the whole result set has been fetched' + ) + self.assertTrue(cur.rowcount in (-1,6)) + + self.executeDDL2(cur) + cur.execute('select name from %sbarflys' % self.table_prefix) + r = cur.fetchmany() # Should get empty sequence + self.assertEqual(len(r),0, + 'cursor.fetchmany should return an empty sequence if ' + 'query retrieved no rows' + ) + self.assertTrue(cur.rowcount in (-1,0)) + + finally: + con.close() + + def test_fetchall(self): + con = self._connect() + try: + cur = con.cursor() + # cursor.fetchall should raise an Error if called + # without executing a query that may return rows (such + # as a select) + self.assertRaises(self.driver.Error, cur.fetchall) + + self.executeDDL1(cur) + for sql in self._populate(): + cur.execute(sql) + + # cursor.fetchall should raise an Error if called + # after executing a a statement that cannot return rows + self.assertRaises(self.driver.Error,cur.fetchall) + + cur.execute('select name from %sbooze' % self.table_prefix) + rows = cur.fetchall() + self.assertTrue(cur.rowcount in (-1,len(self.samples))) + self.assertEqual(len(rows),len(self.samples), + 'cursor.fetchall did not retrieve all rows' + ) + rows = [r[0] for r in rows] + rows.sort() + for i in range(0,len(self.samples)): + self.assertEqual(rows[i],self.samples[i], + 'cursor.fetchall retrieved incorrect rows' + ) + rows = cur.fetchall() + self.assertEqual( + len(rows),0, + 'cursor.fetchall should return an empty list if called ' + 'after the whole result set has been fetched' + ) + self.assertTrue(cur.rowcount in (-1,len(self.samples))) + + self.executeDDL2(cur) + cur.execute('select name from %sbarflys' % self.table_prefix) + rows = cur.fetchall() + self.assertTrue(cur.rowcount in (-1,0)) + self.assertEqual(len(rows),0, + 'cursor.fetchall should return an empty list if ' + 'a select query returns no rows' + ) + + finally: + con.close() + + def test_mixedfetch(self): + con = self._connect() + try: + cur = con.cursor() + self.executeDDL1(cur) + for sql in self._populate(): + cur.execute(sql) + + cur.execute('select name from %sbooze' % self.table_prefix) + rows1 = cur.fetchone() + rows23 = cur.fetchmany(2) + rows4 = cur.fetchone() + rows56 = cur.fetchall() + self.assertTrue(cur.rowcount in (-1,6)) + self.assertEqual(len(rows23),2, + 'fetchmany returned incorrect number of rows' + ) + self.assertEqual(len(rows56),2, + 'fetchall returned incorrect number of rows' + ) + + rows = [rows1[0]] + rows.extend([rows23[0][0],rows23[1][0]]) + rows.append(rows4[0]) + rows.extend([rows56[0][0],rows56[1][0]]) + rows.sort() + for i in range(0,len(self.samples)): + self.assertEqual(rows[i],self.samples[i], + 'incorrect data retrieved or inserted' + ) + finally: + con.close() + + def help_nextset_setUp(self,cur): + ''' Should create a procedure called deleteme + that returns two result sets, first the + number of rows in booze then "name from booze" + ''' + raise NotImplementedError('Helper not implemented') + #sql=""" + # create procedure deleteme as + # begin + # select count(*) from booze + # select name from booze + # end + #""" + #cur.execute(sql) + + def help_nextset_tearDown(self,cur): + 'If cleaning up is needed after nextSetTest' + raise NotImplementedError('Helper not implemented') + #cur.execute("drop procedure deleteme") + + def test_nextset(self): + con = self._connect() + try: + cur = con.cursor() + if not hasattr(cur,'nextset'): + return + + try: + self.executeDDL1(cur) + sql=self._populate() + for sql in self._populate(): + cur.execute(sql) + + self.help_nextset_setUp(cur) + + cur.callproc('deleteme') + numberofrows=cur.fetchone() + assert numberofrows[0]== len(self.samples) + assert cur.nextset() + names=cur.fetchall() + assert len(names) == len(self.samples) + s=cur.nextset() + assert s == None,'No more return sets, should return None' + finally: + self.help_nextset_tearDown(cur) + + finally: + con.close() + + def test_nextset(self): + raise NotImplementedError('Drivers need to override this test') + + def test_arraysize(self): + # Not much here - rest of the tests for this are in test_fetchmany + con = self._connect() + try: + cur = con.cursor() + self.assertTrue(hasattr(cur,'arraysize'), + 'cursor.arraysize must be defined' + ) + finally: + con.close() + + def test_setinputsizes(self): + con = self._connect() + try: + cur = con.cursor() + cur.setinputsizes( (25,) ) + self._paraminsert(cur) # Make sure cursor still works + finally: + con.close() + + def test_setoutputsize_basic(self): + # Basic test is to make sure setoutputsize doesn't blow up + con = self._connect() + try: + cur = con.cursor() + cur.setoutputsize(1000) + cur.setoutputsize(2000,0) + self._paraminsert(cur) # Make sure the cursor still works + finally: + con.close() + + def test_setoutputsize(self): + # Real test for setoutputsize is driver dependant + raise NotImplementedError('Driver need to override this test') + + def test_None(self): + con = self._connect() + try: + cur = con.cursor() + self.executeDDL1(cur) + cur.execute('insert into %sbooze values (NULL)' % self.table_prefix) + cur.execute('select name from %sbooze' % self.table_prefix) + r = cur.fetchall() + self.assertEqual(len(r),1) + self.assertEqual(len(r[0]),1) + self.assertEqual(r[0][0],None,'NULL value not returned as None') + finally: + con.close() + + def test_Date(self): + d1 = self.driver.Date(2002,12,25) + d2 = self.driver.DateFromTicks(time.mktime((2002,12,25,0,0,0,0,0,0))) + # Can we assume this? API doesn't specify, but it seems implied + # self.assertEqual(str(d1),str(d2)) + + def test_Time(self): + t1 = self.driver.Time(13,45,30) + t2 = self.driver.TimeFromTicks(time.mktime((2001,1,1,13,45,30,0,0,0))) + # Can we assume this? API doesn't specify, but it seems implied + # self.assertEqual(str(t1),str(t2)) + + def test_Timestamp(self): + t1 = self.driver.Timestamp(2002,12,25,13,45,30) + t2 = self.driver.TimestampFromTicks( + time.mktime((2002,12,25,13,45,30,0,0,0)) + ) + # Can we assume this? API doesn't specify, but it seems implied + # self.assertEqual(str(t1),str(t2)) + + def test_Binary(self): + b = self.driver.Binary(b'Something') + b = self.driver.Binary(b'') + + def test_STRING(self): + self.assertTrue(hasattr(self.driver,'STRING'), + 'module.STRING must be defined' + ) + + def test_BINARY(self): + self.assertTrue(hasattr(self.driver,'BINARY'), + 'module.BINARY must be defined.' + ) + + def test_NUMBER(self): + self.assertTrue(hasattr(self.driver,'NUMBER'), + 'module.NUMBER must be defined.' + ) + + def test_DATETIME(self): + self.assertTrue(hasattr(self.driver,'DATETIME'), + 'module.DATETIME must be defined.' + ) + + def test_ROWID(self): + self.assertTrue(hasattr(self.driver,'ROWID'), + 'module.ROWID must be defined.' + ) diff --git a/gluon/contrib/pymysql/tests/thirdparty/test_MySQLdb/test_MySQLdb_capabilities.py b/gluon/contrib/pymysql/tests/thirdparty/test_MySQLdb/test_MySQLdb_capabilities.py new file mode 100755 index 00000000..9cacbbd3 --- /dev/null +++ b/gluon/contrib/pymysql/tests/thirdparty/test_MySQLdb/test_MySQLdb_capabilities.py @@ -0,0 +1,109 @@ +#!/usr/bin/env python +from . import capabilities +try: + import unittest2 as unittest +except ImportError: + import unittest +import pymysql +from pymysql.tests import base +import warnings + +warnings.filterwarnings('error') + +class test_MySQLdb(capabilities.DatabaseTest): + + db_module = pymysql + connect_args = () + connect_kwargs = base.PyMySQLTestCase.databases[0].copy() + connect_kwargs.update(dict(read_default_file='~/.my.cnf', + use_unicode=True, + charset='utf8', sql_mode="ANSI,STRICT_TRANS_TABLES,TRADITIONAL")) + + create_table_extra = "ENGINE=INNODB CHARACTER SET UTF8" + leak_test = False + + def quote_identifier(self, ident): + return "`%s`" % ident + + def test_TIME(self): + from datetime import timedelta + def generator(row,col): + return timedelta(0, row*8000) + self.check_data_integrity( + ('col1 TIME',), + generator) + + def test_TINYINT(self): + # Number data + def generator(row,col): + v = (row*row) % 256 + if v > 127: + v = v-256 + return v + self.check_data_integrity( + ('col1 TINYINT',), + generator) + + def test_stored_procedures(self): + db = self.connection + c = self.cursor + try: + self.create_table(('pos INT', 'tree CHAR(20)')) + c.executemany("INSERT INTO %s (pos,tree) VALUES (%%s,%%s)" % self.table, + list(enumerate('ash birch cedar larch pine'.split()))) + db.commit() + + c.execute(""" + CREATE PROCEDURE test_sp(IN t VARCHAR(255)) + BEGIN + SELECT pos FROM %s WHERE tree = t; + END + """ % self.table) + db.commit() + + c.callproc('test_sp', ('larch',)) + rows = c.fetchall() + self.assertEqual(len(rows), 1) + self.assertEqual(rows[0][0], 3) + c.nextset() + finally: + c.execute("DROP PROCEDURE IF EXISTS test_sp") + c.execute('drop table %s' % (self.table)) + + def test_small_CHAR(self): + # Character data + def generator(row,col): + i = ((row+1)*(col+1)+62)%256 + if i == 62: return '' + if i == 63: return None + return chr(i) + self.check_data_integrity( + ('col1 char(1)','col2 char(1)'), + generator) + + def test_bug_2671682(self): + from pymysql.constants import ER + try: + self.cursor.execute("describe some_non_existent_table"); + except self.connection.ProgrammingError as msg: + self.assertEqual(msg.args[0], ER.NO_SUCH_TABLE) + + def test_ping(self): + self.connection.ping() + + def test_literal_int(self): + self.assertTrue("2" == self.connection.literal(2)) + + def test_literal_float(self): + self.assertTrue("3.1415" == self.connection.literal(3.1415)) + + def test_literal_string(self): + self.assertTrue("'foo'" == self.connection.literal("foo")) + + +if __name__ == '__main__': + if test_MySQLdb.leak_test: + import gc + gc.enable() + gc.set_debug(gc.DEBUG_LEAK) + unittest.main() diff --git a/gluon/contrib/pymysql/tests/thirdparty/test_MySQLdb/test_MySQLdb_dbapi20.py b/gluon/contrib/pymysql/tests/thirdparty/test_MySQLdb/test_MySQLdb_dbapi20.py new file mode 100755 index 00000000..ca430fd0 --- /dev/null +++ b/gluon/contrib/pymysql/tests/thirdparty/test_MySQLdb/test_MySQLdb_dbapi20.py @@ -0,0 +1,210 @@ +#!/usr/bin/env python +from . import dbapi20 +import pymysql +from pymysql.tests import base + +try: + import unittest2 as unittest +except ImportError: + import unittest + + +class test_MySQLdb(dbapi20.DatabaseAPI20Test): + driver = pymysql + connect_args = () + connect_kw_args = base.PyMySQLTestCase.databases[0].copy() + connect_kw_args.update(dict(read_default_file='~/.my.cnf', + charset='utf8', + sql_mode="ANSI,STRICT_TRANS_TABLES,TRADITIONAL")) + + def test_setoutputsize(self): pass + def test_setoutputsize_basic(self): pass + def test_nextset(self): pass + + """The tests on fetchone and fetchall and rowcount bogusly + test for an exception if the statement cannot return a + result set. MySQL always returns a result set; it's just that + some things return empty result sets.""" + + def test_fetchall(self): + con = self._connect() + try: + cur = con.cursor() + # cursor.fetchall should raise an Error if called + # without executing a query that may return rows (such + # as a select) + self.assertRaises(self.driver.Error, cur.fetchall) + + self.executeDDL1(cur) + for sql in self._populate(): + cur.execute(sql) + + # cursor.fetchall should raise an Error if called + # after executing a a statement that cannot return rows +## self.assertRaises(self.driver.Error,cur.fetchall) + + cur.execute('select name from %sbooze' % self.table_prefix) + rows = cur.fetchall() + self.assertTrue(cur.rowcount in (-1,len(self.samples))) + self.assertEqual(len(rows),len(self.samples), + 'cursor.fetchall did not retrieve all rows' + ) + rows = [r[0] for r in rows] + rows.sort() + for i in range(0,len(self.samples)): + self.assertEqual(rows[i],self.samples[i], + 'cursor.fetchall retrieved incorrect rows' + ) + rows = cur.fetchall() + self.assertEqual( + len(rows),0, + 'cursor.fetchall should return an empty list if called ' + 'after the whole result set has been fetched' + ) + self.assertTrue(cur.rowcount in (-1,len(self.samples))) + + self.executeDDL2(cur) + cur.execute('select name from %sbarflys' % self.table_prefix) + rows = cur.fetchall() + self.assertTrue(cur.rowcount in (-1,0)) + self.assertEqual(len(rows),0, + 'cursor.fetchall should return an empty list if ' + 'a select query returns no rows' + ) + + finally: + con.close() + + def test_fetchone(self): + con = self._connect() + try: + cur = con.cursor() + + # cursor.fetchone should raise an Error if called before + # executing a select-type query + self.assertRaises(self.driver.Error,cur.fetchone) + + # cursor.fetchone should raise an Error if called after + # executing a query that cannnot return rows + self.executeDDL1(cur) +## self.assertRaises(self.driver.Error,cur.fetchone) + + cur.execute('select name from %sbooze' % self.table_prefix) + self.assertEqual(cur.fetchone(),None, + 'cursor.fetchone should return None if a query retrieves ' + 'no rows' + ) + self.assertTrue(cur.rowcount in (-1,0)) + + # cursor.fetchone should raise an Error if called after + # executing a query that cannnot return rows + cur.execute("insert into %sbooze values ('Victoria Bitter')" % ( + self.table_prefix + )) +## self.assertRaises(self.driver.Error,cur.fetchone) + + cur.execute('select name from %sbooze' % self.table_prefix) + r = cur.fetchone() + self.assertEqual(len(r),1, + 'cursor.fetchone should have retrieved a single row' + ) + self.assertEqual(r[0],'Victoria Bitter', + 'cursor.fetchone retrieved incorrect data' + ) +## self.assertEqual(cur.fetchone(),None, +## 'cursor.fetchone should return None if no more rows available' +## ) + self.assertTrue(cur.rowcount in (-1,1)) + finally: + con.close() + + # Same complaint as for fetchall and fetchone + def test_rowcount(self): + con = self._connect() + try: + cur = con.cursor() + self.executeDDL1(cur) +## self.assertEqual(cur.rowcount,-1, +## 'cursor.rowcount should be -1 after executing no-result ' +## 'statements' +## ) + cur.execute("insert into %sbooze values ('Victoria Bitter')" % ( + self.table_prefix + )) +## self.assertTrue(cur.rowcount in (-1,1), +## 'cursor.rowcount should == number or rows inserted, or ' +## 'set to -1 after executing an insert statement' +## ) + cur.execute("select name from %sbooze" % self.table_prefix) + self.assertTrue(cur.rowcount in (-1,1), + 'cursor.rowcount should == number of rows returned, or ' + 'set to -1 after executing a select statement' + ) + self.executeDDL2(cur) +## self.assertEqual(cur.rowcount,-1, +## 'cursor.rowcount not being reset to -1 after executing ' +## 'no-result statements' +## ) + finally: + con.close() + + def test_callproc(self): + pass # performed in test_MySQL_capabilities + + def help_nextset_setUp(self,cur): + ''' Should create a procedure called deleteme + that returns two result sets, first the + number of rows in booze then "name from booze" + ''' + sql=""" + create procedure deleteme() + begin + select count(*) from %(tp)sbooze; + select name from %(tp)sbooze; + end + """ % dict(tp=self.table_prefix) + cur.execute(sql) + + def help_nextset_tearDown(self,cur): + 'If cleaning up is needed after nextSetTest' + cur.execute("drop procedure deleteme") + + def test_nextset(self): + from warnings import warn + con = self._connect() + try: + cur = con.cursor() + if not hasattr(cur,'nextset'): + return + + try: + self.executeDDL1(cur) + sql=self._populate() + for sql in self._populate(): + cur.execute(sql) + + self.help_nextset_setUp(cur) + + cur.callproc('deleteme') + numberofrows=cur.fetchone() + assert numberofrows[0]== len(self.samples) + assert cur.nextset() + names=cur.fetchall() + assert len(names) == len(self.samples) + s=cur.nextset() + if s: + empty = cur.fetchall() + self.assertEqual(len(empty), 0, + "non-empty result set after other result sets") + #warn("Incompatibility: MySQL returns an empty result set for the CALL itself", + # Warning) + #assert s == None,'No more return sets, should return None' + finally: + self.help_nextset_tearDown(cur) + + finally: + con.close() + + +if __name__ == '__main__': + unittest.main() diff --git a/gluon/contrib/pymysql/tests/thirdparty/test_MySQLdb/test_MySQLdb_nonstandard.py b/gluon/contrib/pymysql/tests/thirdparty/test_MySQLdb/test_MySQLdb_nonstandard.py new file mode 100755 index 00000000..17fc2cde --- /dev/null +++ b/gluon/contrib/pymysql/tests/thirdparty/test_MySQLdb/test_MySQLdb_nonstandard.py @@ -0,0 +1,101 @@ +import sys +try: + import unittest2 as unittest +except ImportError: + import unittest + +import pymysql +_mysql = pymysql +from pymysql.constants import FIELD_TYPE +from pymysql.tests import base +from pymysql._compat import PY2, long_type + +if not PY2: + basestring = str + + +class TestDBAPISet(unittest.TestCase): + def test_set_equality(self): + self.assertTrue(pymysql.STRING == pymysql.STRING) + + def test_set_inequality(self): + self.assertTrue(pymysql.STRING != pymysql.NUMBER) + + def test_set_equality_membership(self): + self.assertTrue(FIELD_TYPE.VAR_STRING == pymysql.STRING) + + def test_set_inequality_membership(self): + self.assertTrue(FIELD_TYPE.DATE != pymysql.STRING) + + +class CoreModule(unittest.TestCase): + """Core _mysql module features.""" + + def test_NULL(self): + """Should have a NULL constant.""" + self.assertEqual(_mysql.NULL, 'NULL') + + def test_version(self): + """Version information sanity.""" + self.assertTrue(isinstance(_mysql.__version__, basestring)) + + self.assertTrue(isinstance(_mysql.version_info, tuple)) + self.assertEqual(len(_mysql.version_info), 5) + + def test_client_info(self): + self.assertTrue(isinstance(_mysql.get_client_info(), basestring)) + + def test_thread_safe(self): + self.assertTrue(isinstance(_mysql.thread_safe(), int)) + + +class CoreAPI(unittest.TestCase): + """Test _mysql interaction internals.""" + + def setUp(self): + kwargs = base.PyMySQLTestCase.databases[0].copy() + kwargs["read_default_file"] = "~/.my.cnf" + self.conn = _mysql.connect(**kwargs) + + def tearDown(self): + self.conn.close() + + def test_thread_id(self): + tid = self.conn.thread_id() + self.assertTrue(isinstance(tid, (int, long_type)), + "thread_id didn't return an integral value.") + + self.assertRaises(TypeError, self.conn.thread_id, ('evil',), + "thread_id shouldn't accept arguments.") + + def test_affected_rows(self): + self.assertEqual(self.conn.affected_rows(), 0, + "Should return 0 before we do anything.") + + + #def test_debug(self): + ## FIXME Only actually tests if you lack SUPER + #self.assertRaises(pymysql.OperationalError, + #self.conn.dump_debug_info) + + def test_charset_name(self): + self.assertTrue(isinstance(self.conn.character_set_name(), basestring), + "Should return a string.") + + def test_host_info(self): + assert isinstance(self.conn.get_host_info(), basestring), "should return a string" + + def test_proto_info(self): + self.assertTrue(isinstance(self.conn.get_proto_info(), int), + "Should return an int.") + + def test_server_info(self): + if sys.version_info[0] == 2: + self.assertTrue(isinstance(self.conn.get_server_info(), basestring), + "Should return an str.") + else: + self.assertTrue(isinstance(self.conn.get_server_info(), basestring), + "Should return an str.") + +if __name__ == "__main__": + unittest.main() diff --git a/gluon/contrib/pymysql/times.py b/gluon/contrib/pymysql/times.py index c47db09e..4497dacf 100644 --- a/gluon/contrib/pymysql/times.py +++ b/gluon/contrib/pymysql/times.py @@ -1,16 +1,20 @@ from time import localtime from datetime import date, datetime, time, timedelta + Date = date Time = time TimeDelta = timedelta Timestamp = datetime + def DateFromTicks(ticks): return date(*localtime(ticks)[:3]) + def TimeFromTicks(ticks): return time(*localtime(ticks)[3:6]) + def TimestampFromTicks(ticks): return datetime(*localtime(ticks)[:6]) diff --git a/gluon/contrib/pymysql/util.py b/gluon/contrib/pymysql/util.py index cc622e57..3e82ac7b 100644 --- a/gluon/contrib/pymysql/util.py +++ b/gluon/contrib/pymysql/util.py @@ -1,14 +1,17 @@ import struct + def byte2int(b): if isinstance(b, int): return b else: return struct.unpack("!B", b)[0] + def int2byte(i): return struct.pack("!B", i) + def join_bytes(bs): if len(bs) == 0: return "" From 9539cc7542b2e1f09dc84feec5d840be9b0c21ce Mon Sep 17 00:00:00 2001 From: niphlod Date: Sat, 1 Oct 2016 00:15:47 +0200 Subject: [PATCH 42/49] make pymysql usable inside web2py --- CHANGELOG | 1 + gluon/contrib/pymysql/__init__.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index e4701ea0..22406bdd 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -10,6 +10,7 @@ "from gluon.storage import Storage" - tests can only be run with the usual web2py.py --run_system_tests OR with python -m unittest -v gluon.tests on the root dir +- updated pymysql driver ## 2.14.6 diff --git a/gluon/contrib/pymysql/__init__.py b/gluon/contrib/pymysql/__init__.py index bf34c558..7bf34c1c 100644 --- a/gluon/contrib/pymysql/__init__.py +++ b/gluon/contrib/pymysql/__init__.py @@ -89,7 +89,7 @@ def Connect(*args, **kwargs): from .connections import Connection return Connection(*args, **kwargs) -from pymysql import connections as _orig_conn +from . import connections as _orig_conn if _orig_conn.Connection.__init__.__doc__ is not None: Connect.__doc__ = _orig_conn.Connection.__init__.__doc__ del _orig_conn From 9256d67ec7e11fc8ba9ad74a0933273b95b7ab3a Mon Sep 17 00:00:00 2001 From: niphlod Date: Sat, 1 Oct 2016 11:25:52 +0200 Subject: [PATCH 43/49] remove pymysql dependency --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 9f276d6f..2907e30e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,7 +25,7 @@ install: virtualenv --python="$PYENV_ROOT/versions/pypy-$PYPY_VERSION/bin/python" "$HOME/virtualenvs/pypy-$PYPY_VERSION" source "$HOME/virtualenvs/pypy-$PYPY_VERSION/bin/activate" fi - - if [[ $TRAVIS_PYTHON_VERSION == '3.5' ]]; then pip install pycrypto pg8000 pymysql; fi; + - if [[ $TRAVIS_PYTHON_VERSION == '3.5' ]]; then pip install pycrypto pg8000; fi; - if [[ $TRAVIS_PYTHON_VERSION != '3.5' ]]; then pip install -e .; fi; before_script: From b7219ba2fd524a67e2b5a43d18d2b6da49ee6a7f Mon Sep 17 00:00:00 2001 From: niphlod Date: Mon, 3 Oct 2016 21:09:27 +0200 Subject: [PATCH 44/49] fixes #1484, thanks @abastardi --- gluon/scheduler.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gluon/scheduler.py b/gluon/scheduler.py index a68152b5..e758c379 100644 --- a/gluon/scheduler.py +++ b/gluon/scheduler.py @@ -477,7 +477,8 @@ def executor(queue, task, out): # Get controller-specific subdirectory if task.app is of # form 'app/controller' (a, c, f) = parse_path_info(task.app) - _env = env(a=a, c=c, import_models=True) + _env = env(a=a, c=c, import_models=True, + extra_request={'is_scheduler': True}) logging.getLogger().setLevel(level) f = task.function functions = current._scheduler.tasks From 15769857cb576f59dc68174f98db780a87790d71 Mon Sep 17 00:00:00 2001 From: niphlod Date: Mon, 3 Oct 2016 22:10:20 +0200 Subject: [PATCH 45/49] 1st trial --- .travis.yml | 19 +- gluon/contrib/pg8000/__init__.py | 374 ++---------------- gluon/contrib/pg8000/_version.py | 391 ++++++++++++++++--- gluon/contrib/pg8000/core.py | 643 +++++++++++++++++++++++-------- gluon/contrib/pg8000/six.py | 504 ++++++++++++++++++------ 5 files changed, 1217 insertions(+), 714 deletions(-) diff --git a/.travis.yml b/.travis.yml index 2907e30e..18bb51e7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,9 +2,7 @@ language: python sudo: false -cache: - directories: - - $HOME/.pip-cache/ +cache: pip python: - '2.7' @@ -12,20 +10,7 @@ python: - '3.5' install: - - | - if [ "$TRAVIS_PYTHON_VERSION" = "pypy" ]; then - export PYENV_ROOT="$HOME/.pyenv" - if [ -f "$PYENV_ROOT/bin/pyenv" ]; then - pushd "$PYENV_ROOT" && git pull && popd - else - rm -rf "$PYENV_ROOT" && git clone --depth 1 https://github.com/yyuu/pyenv.git "$PYENV_ROOT" - fi - export PYPY_VERSION="5.0.1" - "$PYENV_ROOT/bin/pyenv" install --skip-existing "pypy-$PYPY_VERSION" - virtualenv --python="$PYENV_ROOT/versions/pypy-$PYPY_VERSION/bin/python" "$HOME/virtualenvs/pypy-$PYPY_VERSION" - source "$HOME/virtualenvs/pypy-$PYPY_VERSION/bin/activate" - fi - - if [[ $TRAVIS_PYTHON_VERSION == '3.5' ]]; then pip install pycrypto pg8000; fi; + - if [[ $TRAVIS_PYTHON_VERSION == '3.5' ]]; then pip install pycrypto; fi; - if [[ $TRAVIS_PYTHON_VERSION != '3.5' ]]; then pip install -e .; fi; before_script: diff --git a/gluon/contrib/pg8000/__init__.py b/gluon/contrib/pg8000/__init__.py index c30a8cb6..4a997174 100644 --- a/gluon/contrib/pg8000/__init__.py +++ b/gluon/contrib/pg8000/__init__.py @@ -1,3 +1,14 @@ +from .core import ( + Warning, Bytea, DataError, DatabaseError, InterfaceError, ProgrammingError, + Error, OperationalError, IntegrityError, InternalError, NotSupportedError, + ArrayContentNotHomogenousError, ArrayContentEmptyError, + ArrayDimensionsNotConsistentError, ArrayContentNotSupportedError, utc, + Connection, Cursor, Binary, Date, DateFromTicks, Time, TimeFromTicks, + Timestamp, TimestampFromTicks, BINARY, Interval) +from ._version import get_versions +__version__ = get_versions()['version'] +del get_versions + # Copyright (c) 2007-2009, Mathieu Fenniak # All rights reserved. # @@ -28,258 +39,9 @@ __author__ = "Mathieu Fenniak" -exec("from struct import Struct") -for fmt in ( - "i", "h", "q", "d", "f", "iii", "ii", "qii", "dii", "ihihih", "ci", - "bh", "cccc"): - exec(fmt + "_struct = Struct('!" + fmt + "')") - exec(fmt + "_unpack = " + fmt + "_struct.unpack_from") - exec(fmt + "_pack = " + fmt + "_struct.pack") - -import datetime -import time -from .six import binary_type, integer_types, PY2 - -min_int2, max_int2 = -2 ** 15, 2 ** 15 -min_int4, max_int4 = -2 ** 31, 2 ** 31 -min_int8, max_int8 = -2 ** 63, 2 ** 63 - - -class Warning(Exception): - """Generic exception raised for important database warnings like data - truncations. This exception is not currently used by pg8000. - - This exception is part of the `DBAPI 2.0 specification - `_. - """ - pass - - -class Error(Exception): - """Generic exception that is the base exception of all other error - exceptions. - - This exception is part of the `DBAPI 2.0 specification - `_. - """ - pass - - -class InterfaceError(Error): - """Generic exception raised for errors that are related to the database - interface rather than the database itself. For example, if the interface - attempts to use an SSL connection but the server refuses, an InterfaceError - will be raised. - - This exception is part of the `DBAPI 2.0 specification - `_. - """ - pass - - -class DatabaseError(Error): - """Generic exception raised for errors that are related to the database. - This exception is currently never raised by pg8000. - - This exception is part of the `DBAPI 2.0 specification - `_. - """ - pass - - -class DataError(DatabaseError): - """Generic exception raised for errors that are due to problems with the - processed data. This exception is not currently raised by pg8000. - - This exception is part of the `DBAPI 2.0 specification - `_. - """ - pass - - -class OperationalError(DatabaseError): - """ - Generic exception raised for errors that are related to the database's - operation and not necessarily under the control of the programmer. This - exception is currently never raised by pg8000. - - This exception is part of the `DBAPI 2.0 specification - `_. - """ - pass - - -class IntegrityError(DatabaseError): - """ - Generic exception raised when the relational integrity of the database is - affected. This exception is not currently raised by pg8000. - - This exception is part of the `DBAPI 2.0 specification - `_. - """ - pass - - -class InternalError(DatabaseError): - """Generic exception raised when the database encounters an internal error. - This is currently only raised when unexpected state occurs in the pg8000 - interface itself, and is typically the result of a interface bug. - - This exception is part of the `DBAPI 2.0 specification - `_. - """ - pass - - -class ProgrammingError(DatabaseError): - """Generic exception raised for programming errors. For example, this - exception is raised if more parameter fields are in a query string than - there are available parameters. - - This exception is part of the `DBAPI 2.0 specification - `_. - """ - pass - - -class NotSupportedError(DatabaseError): - """Generic exception raised in case a method or database API was used which - is not supported by the database. - - This exception is part of the `DBAPI 2.0 specification - `_. - """ - pass - - -class ArrayContentNotSupportedError(NotSupportedError): - """ - Raised when attempting to transmit an array where the base type is not - supported for binary data transfer by the interface. - """ - pass - - -class ArrayContentNotHomogenousError(ProgrammingError): - """ - Raised when attempting to transmit an array that doesn't contain only a - single type of object. - """ - pass - - -class ArrayContentEmptyError(ProgrammingError): - """Raised when attempting to transmit an empty array. The type oid of an - empty array cannot be determined, and so sending them is not permitted. - """ - pass - - -class ArrayDimensionsNotConsistentError(ProgrammingError): - """ - Raised when attempting to transmit an array that has inconsistent - multi-dimension sizes. - """ - pass - - -class Bytea(binary_type): - """Bytea is a str-derived class that is mapped to a PostgreSQL byte array. - This class is only used in Python 2, the built-in ``bytes`` type is used in - Python 3. - """ - pass - - -class Interval(object): - """An Interval represents a measurement of time. In PostgreSQL, an interval - is defined in the measure of months, days, and microseconds; as such, the - pg8000 interval type represents the same information. - - Note that values of the :attr:`microseconds`, :attr:`days` and - :attr:`months` properties are independently measured and cannot be - converted to each other. A month may be 28, 29, 30, or 31 days, and a day - may occasionally be lengthened slightly by a leap second. - - .. attribute:: microseconds - - Measure of microseconds in the interval. - - The microseconds value is constrained to fit into a signed 64-bit - integer. Any attempt to set a value too large or too small will result - in an OverflowError being raised. - - .. attribute:: days - - Measure of days in the interval. - - The days value is constrained to fit into a signed 32-bit integer. - Any attempt to set a value too large or too small will result in an - OverflowError being raised. - - .. attribute:: months - - Measure of months in the interval. - - The months value is constrained to fit into a signed 32-bit integer. - Any attempt to set a value too large or too small will result in an - OverflowError being raised. - """ - - def __init__(self, microseconds=0, days=0, months=0): - self.microseconds = microseconds - self.days = days - self.months = months - - def _setMicroseconds(self, value): - if not isinstance(value, integer_types): - raise TypeError("microseconds must be an integer type") - elif not (min_int8 < value < max_int8): - raise OverflowError( - "microseconds must be representable as a 64-bit integer") - else: - self._microseconds = value - - def _setDays(self, value): - if not isinstance(value, integer_types): - raise TypeError("days must be an integer type") - elif not (min_int4 < value < max_int4): - raise OverflowError( - "days must be representable as a 32-bit integer") - else: - self._days = value - - def _setMonths(self, value): - if not isinstance(value, integer_types): - raise TypeError("months must be an integer type") - elif not (min_int4 < value < max_int4): - raise OverflowError( - "months must be representable as a 32-bit integer") - else: - self._months = value - - microseconds = property(lambda self: self._microseconds, _setMicroseconds) - days = property(lambda self: self._days, _setDays) - months = property(lambda self: self._months, _setMonths) - - def __repr__(self): - return "" % ( - self.months, self.days, self.microseconds) - - def __eq__(self, other): - return other is not None and isinstance(other, Interval) and \ - self.months == other.months and self.days == other.days and \ - self.microseconds == other.microseconds - - def __neq__(self, other): - return not self.__eq__(other) - -from .core import Connection - - def connect( user=None, host='localhost', unix_sock=None, port=5432, database=None, - password=None, ssl=False, **kwargs): + password=None, ssl=False, timeout=None, **kwargs): """Creates a connection to a PostgreSQL database. This function is part of the `DBAPI 2.0 specification @@ -287,9 +49,7 @@ def connect( function are not defined by the specification. :param user: - The username to connect to the PostgreSQL server with. If this is not - provided, pg8000 looks first for the PGUSER then the USER environment - variables. + The username to connect to the PostgreSQL server with. If your server character encoding is not ``ascii`` or ``utf8``, then you need to provide ``user`` as bytes, eg. @@ -325,15 +85,24 @@ def connect( authentication, the connection will fail to open. If this parameter is provided but not requested by the server, no error will occur. + If your server character encoding is not ``ascii`` or ``utf8``, then + you need to provide ``user`` as bytes, eg. + ``"my_password".encode('EUC-JP')``. + :keyword ssl: Use SSL encryption for TCP/IP sockets if ``True``. Defaults to ``False``. + :keyword timeout: + Only used with Python 3, this is the time in seconds before the + connection to the database will time out. The default is ``None`` which + means no timeout. + :rtype: A :class:`Connection` object. """ return Connection( - user, host, unix_sock, port, database, password, ssl) + user, host, unix_sock, port, database, password, ssl, timeout) apilevel = "2.0" """The DBAPI level supported, currently "2.0". @@ -382,10 +151,6 @@ can be changed to any of the following values: STRING = 1043 """String type oid.""" -if PY2: - BINARY = Bytea -else: - BINARY = bytes NUMBER = 1700 """Numeric type oid""" @@ -396,104 +161,15 @@ DATETIME = 1114 ROWID = 26 """ROWID type oid""" - -def Date(year, month, day): - """Constuct an object holding a date value. - - This function is part of the `DBAPI 2.0 specification - `_. - - :rtype: :class:`datetime.date` - """ - return datetime.date(year, month, day) - - -def Time(hour, minute, second): - """Construct an object holding a time value. - - This function is part of the `DBAPI 2.0 specification - `_. - - :rtype: :class:`datetime.time` - """ - return datetime.time(hour, minute, second) - - -def Timestamp(year, month, day, hour, minute, second): - """Construct an object holding a timestamp value. - - This function is part of the `DBAPI 2.0 specification - `_. - - :rtype: :class:`datetime.datetime` - """ - return datetime.datetime(year, month, day, hour, minute, second) - - -def DateFromTicks(ticks): - """Construct an object holding a date value from the given ticks value - (number of seconds since the epoch). - - This function is part of the `DBAPI 2.0 specification - `_. - - :rtype: :class:`datetime.date` - """ - return Date(*time.localtime(ticks)[:3]) - - -def TimeFromTicks(ticks): - """Construct an objet holding a time value from the given ticks value - (number of seconds since the epoch). - - This function is part of the `DBAPI 2.0 specification - `_. - - :rtype: :class:`datetime.time` - """ - return Time(*time.localtime(ticks)[3:6]) - - -def TimestampFromTicks(ticks): - """Construct an object holding a timestamp value from the given ticks value - (number of seconds since the epoch). - - This function is part of the `DBAPI 2.0 specification - `_. - - :rtype: :class:`datetime.datetime` - """ - return Timestamp(*time.localtime(ticks)[:6]) - - -def Binary(value): - """Construct an object holding binary data. - - This function is part of the `DBAPI 2.0 specification - `_. - - :rtype: :class:`pg8000.types.Bytea` for Python 2, otherwise :class:`bytes` - """ - if PY2: - return Bytea(value) - else: - return value - - -from .core import utc, Cursor - __all__ = [ Warning, Bytea, DataError, DatabaseError, connect, InterfaceError, ProgrammingError, Error, OperationalError, IntegrityError, InternalError, NotSupportedError, ArrayContentNotHomogenousError, ArrayContentEmptyError, ArrayDimensionsNotConsistentError, ArrayContentNotSupportedError, utc, - Connection, Cursor] + Connection, Cursor, Binary, Date, DateFromTicks, Time, TimeFromTicks, + Timestamp, TimestampFromTicks, BINARY, Interval] """Version string for pg8000. .. versionadded:: 1.9.11 """ - -from ._version import get_versions -__version__ = get_versions()['version'] -del get_versions diff --git a/gluon/contrib/pg8000/_version.py b/gluon/contrib/pg8000/_version.py index 982cf246..5677d1e0 100644 --- a/gluon/contrib/pg8000/_version.py +++ b/gluon/contrib/pg8000/_version.py @@ -6,22 +6,58 @@ # that just contains the computed version number. # This file is released into the public domain. Generated by -# versioneer-0.12 (https://github.com/warner/python-versioneer) - -# these strings will be replaced by git during git-archive -git_refnames = "$Format:%d$" -git_full = "$Format:%H$" - -# these strings are filled in when 'setup.py versioneer' creates _version.py -tag_prefix = "" -parentdir_prefix = "pg8000-" -versionfile_source = "pg8000/_version.py" +# versioneer-0.15 (https://github.com/warner/python-versioneer) +import errno import os -import sys import re import subprocess -import errno +import sys + + +def get_keywords(): + # these strings will be replaced by git during git-archive. + # setup.py/versioneer.py will grep for the variable names, so they must + # each be defined on a line of their own. _version.py will just call + # get_keywords(). + git_refnames = " (tag: 1.10.6)" + git_full = "4098abf6be90683ab10b7b080983ed6f08476485" + keywords = {"refnames": git_refnames, "full": git_full} + return keywords + + +class VersioneerConfig: + pass + + +def get_config(): + # these strings are filled in when 'setup.py versioneer' creates + # _version.py + cfg = VersioneerConfig() + cfg.VCS = "git" + cfg.style = "pep440" + cfg.tag_prefix = "" + cfg.parentdir_prefix = "pg8000-" + cfg.versionfile_source = "pg8000/_version.py" + cfg.verbose = False + return cfg + + +class NotThisMethod(Exception): + pass + + +LONG_VERSION_PY = {} +HANDLERS = {} + + +def register_vcs_handler(vcs, method): # decorator + def decorate(f): + if vcs not in HANDLERS: + HANDLERS[vcs] = {} + HANDLERS[vcs][method] = f + return f + return decorate def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False): @@ -29,6 +65,7 @@ def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False): p = None for c in commands: try: + dispcmd = str([c] + args) # remember shell=False, so use git.cmd on windows, not just git p = subprocess.Popen([c] + args, cwd=cwd, stdout=subprocess.PIPE, stderr=(subprocess.PIPE if hide_stderr @@ -39,7 +76,7 @@ def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False): if e.errno == errno.ENOENT: continue if verbose: - print("unable to run %s" % args[0]) + print("unable to run %s" % dispcmd) print(e) return None else: @@ -47,28 +84,30 @@ def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False): print("unable to find command, tried %s" % (commands,)) return None stdout = p.communicate()[0].strip() - if sys.version >= '3': + if sys.version_info[0] >= 3: stdout = stdout.decode() if p.returncode != 0: if verbose: - print("unable to run %s (error)" % args[0]) + print("unable to run %s (error)" % dispcmd) return None return stdout -def versions_from_parentdir(parentdir_prefix, root, verbose=False): +def versions_from_parentdir(parentdir_prefix, root, verbose): # Source tarballs conventionally unpack into a directory that includes # both the project name and a version string. dirname = os.path.basename(root) if not dirname.startswith(parentdir_prefix): if verbose: - print( - "guessing rootdir is '%s', but '%s' doesn't start with " - "prefix '%s'" % (root, dirname, parentdir_prefix)) - return None - return {"version": dirname[len(parentdir_prefix):], "full": ""} + print("guessing rootdir is '%s', but '%s' doesn't start with " + "prefix '%s'" % (root, dirname, parentdir_prefix)) + raise NotThisMethod("rootdir doesn't start with parentdir_prefix") + return {"version": dirname[len(parentdir_prefix):], + "full-revisionid": None, + "dirty": False, "error": None} +@register_vcs_handler("git", "get_keywords") def git_get_keywords(versionfile_abs): # the code embedded in _version.py can just fetch the value of these # keywords. When used from setup.py, we don't want to import _version.py, @@ -92,14 +131,15 @@ def git_get_keywords(versionfile_abs): return keywords -def git_versions_from_keywords(keywords, tag_prefix, verbose=False): +@register_vcs_handler("git", "keywords") +def git_versions_from_keywords(keywords, tag_prefix, verbose): if not keywords: - return {} # keyword-finding function failed to find keywords + raise NotThisMethod("no keywords at all, weird") refnames = keywords["refnames"].strip() if refnames.startswith("$Format"): if verbose: print("keywords are unexpanded, not using") - return {} # unexpanded, so not in an unpacked git-archive tarball + raise NotThisMethod("unexpanded keywords, not a git-archive tarball") refs = set([r.strip() for r in refnames.strip("()").split(",")]) # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of # just "foo-1.0". If we see a "tag: " prefix, prefer those. @@ -124,18 +164,20 @@ def git_versions_from_keywords(keywords, tag_prefix, verbose=False): r = ref[len(tag_prefix):] if verbose: print("picking %s" % r) - return { - "version": r, - "full": keywords["full"].strip()} - # no suitable tags, so we use the full revision id + return {"version": r, + "full-revisionid": keywords["full"].strip(), + "dirty": False, "error": None + } + # no suitable tags, so version is "0+unknown", but full hex is still there if verbose: - print("no suitable tags, using full revision id") - return { - "version": keywords["full"].strip(), - "full": keywords["full"].strip()} + print("no suitable tags, using unknown + full revision id") + return {"version": "0+unknown", + "full-revisionid": keywords["full"].strip(), + "dirty": False, "error": "no suitable tags"} -def git_versions_from_vcs(tag_prefix, root, verbose=False): +@register_vcs_handler("git", "pieces_from_vcs") +def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): # this runs 'git' from the root of the source tree. This only gets called # if the git-archive 'subst' keywords were *not* expanded, and # _version.py hasn't already been rewritten with a short version string, @@ -144,52 +186,275 @@ def git_versions_from_vcs(tag_prefix, root, verbose=False): if not os.path.exists(os.path.join(root, ".git")): if verbose: print("no .git in %s" % root) - return {} + raise NotThisMethod("no .git directory") GITS = ["git"] if sys.platform == "win32": GITS = ["git.cmd", "git.exe"] - stdout = run_command(GITS, ["describe", "--tags", "--dirty", "--always"], - cwd=root) - if stdout is None: - return {} - if not stdout.startswith(tag_prefix): - if verbose: - print( - "tag '%s' doesn't start with prefix '%s'" % - (stdout, tag_prefix)) - return {} - tag = stdout[len(tag_prefix):] - stdout = run_command(GITS, ["rev-parse", "HEAD"], cwd=root) - if stdout is None: - return {} - full = stdout.strip() - if tag.endswith("-dirty"): - full += "-dirty" - return {"version": tag, "full": full} + # if there is a tag, this yields TAG-NUM-gHEX[-dirty] + # if there are no tags, this yields HEX[-dirty] (no NUM) + describe_out = run_command(GITS, ["describe", "--tags", "--dirty", + "--always", "--long"], + cwd=root) + # --long was added in git-1.5.5 + if describe_out is None: + raise NotThisMethod("'git describe' failed") + describe_out = describe_out.strip() + full_out = run_command(GITS, ["rev-parse", "HEAD"], cwd=root) + if full_out is None: + raise NotThisMethod("'git rev-parse' failed") + full_out = full_out.strip() + + pieces = {} + pieces["long"] = full_out + pieces["short"] = full_out[:7] # maybe improved later + pieces["error"] = None + + # parse describe_out. It will be like TAG-NUM-gHEX[-dirty] or HEX[-dirty] + # TAG might have hyphens. + git_describe = describe_out + + # look for -dirty suffix + dirty = git_describe.endswith("-dirty") + pieces["dirty"] = dirty + if dirty: + git_describe = git_describe[:git_describe.rindex("-dirty")] + + # now we have TAG-NUM-gHEX or HEX + + if "-" in git_describe: + # TAG-NUM-gHEX + mo = re.search(r'^(.+)-(\d+)-g([0-9a-f]+)$', git_describe) + if not mo: + # unparseable. Maybe git-describe is misbehaving? + pieces["error"] = ("unable to parse git-describe output: '%s'" + % describe_out) + return pieces + + # tag + full_tag = mo.group(1) + if not full_tag.startswith(tag_prefix): + if verbose: + fmt = "tag '%s' doesn't start with prefix '%s'" + print(fmt % (full_tag, tag_prefix)) + pieces["error"] = ("tag '%s' doesn't start with prefix '%s'" + % (full_tag, tag_prefix)) + return pieces + pieces["closest-tag"] = full_tag[len(tag_prefix):] + + # distance: number of commits since tag + pieces["distance"] = int(mo.group(2)) + + # commit: short hex revision ID + pieces["short"] = mo.group(3) + + else: + # HEX: no tags + pieces["closest-tag"] = None + count_out = run_command(GITS, ["rev-list", "HEAD", "--count"], + cwd=root) + pieces["distance"] = int(count_out) # total number of commits + + return pieces -def get_versions(default={"version": "unknown", "full": ""}, verbose=False): +def plus_or_dot(pieces): + if "+" in pieces.get("closest-tag", ""): + return "." + return "+" + + +def render_pep440(pieces): + # now build up version string, with post-release "local version + # identifier". Our goal: TAG[+DISTANCE.gHEX[.dirty]] . Note that if you + # get a tagged build and then dirty it, you'll get TAG+0.gHEX.dirty + + # exceptions: + # 1: no tags. git_describe was just HEX. 0+untagged.DISTANCE.gHEX[.dirty] + + if pieces["closest-tag"]: + rendered = pieces["closest-tag"] + if pieces["distance"] or pieces["dirty"]: + rendered += plus_or_dot(pieces) + rendered += "%d.g%s" % (pieces["distance"], pieces["short"]) + if pieces["dirty"]: + rendered += ".dirty" + else: + # exception #1 + rendered = "0+untagged.%d.g%s" % (pieces["distance"], + pieces["short"]) + if pieces["dirty"]: + rendered += ".dirty" + return rendered + + +def render_pep440_pre(pieces): + # TAG[.post.devDISTANCE] . No -dirty + + # exceptions: + # 1: no tags. 0.post.devDISTANCE + + if pieces["closest-tag"]: + rendered = pieces["closest-tag"] + if pieces["distance"]: + rendered += ".post.dev%d" % pieces["distance"] + else: + # exception #1 + rendered = "0.post.dev%d" % pieces["distance"] + return rendered + + +def render_pep440_post(pieces): + # TAG[.postDISTANCE[.dev0]+gHEX] . The ".dev0" means dirty. Note that + # .dev0 sorts backwards (a dirty tree will appear "older" than the + # corresponding clean one), but you shouldn't be releasing software with + # -dirty anyways. + + # exceptions: + # 1: no tags. 0.postDISTANCE[.dev0] + + if pieces["closest-tag"]: + rendered = pieces["closest-tag"] + if pieces["distance"] or pieces["dirty"]: + rendered += ".post%d" % pieces["distance"] + if pieces["dirty"]: + rendered += ".dev0" + rendered += plus_or_dot(pieces) + rendered += "g%s" % pieces["short"] + else: + # exception #1 + rendered = "0.post%d" % pieces["distance"] + if pieces["dirty"]: + rendered += ".dev0" + rendered += "+g%s" % pieces["short"] + return rendered + + +def render_pep440_old(pieces): + # TAG[.postDISTANCE[.dev0]] . The ".dev0" means dirty. + + # exceptions: + # 1: no tags. 0.postDISTANCE[.dev0] + + if pieces["closest-tag"]: + rendered = pieces["closest-tag"] + if pieces["distance"] or pieces["dirty"]: + rendered += ".post%d" % pieces["distance"] + if pieces["dirty"]: + rendered += ".dev0" + else: + # exception #1 + rendered = "0.post%d" % pieces["distance"] + if pieces["dirty"]: + rendered += ".dev0" + return rendered + + +def render_git_describe(pieces): + # TAG[-DISTANCE-gHEX][-dirty], like 'git describe --tags --dirty + # --always' + + # exceptions: + # 1: no tags. HEX[-dirty] (note: no 'g' prefix) + + if pieces["closest-tag"]: + rendered = pieces["closest-tag"] + if pieces["distance"]: + rendered += "-%d-g%s" % (pieces["distance"], pieces["short"]) + else: + # exception #1 + rendered = pieces["short"] + if pieces["dirty"]: + rendered += "-dirty" + return rendered + + +def render_git_describe_long(pieces): + # TAG-DISTANCE-gHEX[-dirty], like 'git describe --tags --dirty + # --always -long'. The distance/hash is unconditional. + + # exceptions: + # 1: no tags. HEX[-dirty] (note: no 'g' prefix) + + if pieces["closest-tag"]: + rendered = pieces["closest-tag"] + rendered += "-%d-g%s" % (pieces["distance"], pieces["short"]) + else: + # exception #1 + rendered = pieces["short"] + if pieces["dirty"]: + rendered += "-dirty" + return rendered + + +def render(pieces, style): + if pieces["error"]: + return {"version": "unknown", + "full-revisionid": pieces.get("long"), + "dirty": None, + "error": pieces["error"]} + + if not style or style == "default": + style = "pep440" # the default + + if style == "pep440": + rendered = render_pep440(pieces) + elif style == "pep440-pre": + rendered = render_pep440_pre(pieces) + elif style == "pep440-post": + rendered = render_pep440_post(pieces) + elif style == "pep440-old": + rendered = render_pep440_old(pieces) + elif style == "git-describe": + rendered = render_git_describe(pieces) + elif style == "git-describe-long": + rendered = render_git_describe_long(pieces) + else: + raise ValueError("unknown style '%s'" % style) + + return {"version": rendered, "full-revisionid": pieces["long"], + "dirty": pieces["dirty"], "error": None} + + +def get_versions(): # I am in _version.py, which lives at ROOT/VERSIONFILE_SOURCE. If we have # __file__, we can work backwards from there to the root. Some # py2exe/bbfreeze/non-CPython implementations don't do __file__, in which # case we can only use expanded keywords. - keywords = {"refnames": git_refnames, "full": git_full} - ver = git_versions_from_keywords(keywords, tag_prefix, verbose) - if ver: - return ver + cfg = get_config() + verbose = cfg.verbose try: - root = os.path.abspath(__file__) + return git_versions_from_keywords(get_keywords(), cfg.tag_prefix, + verbose) + except NotThisMethod: + pass + + try: + root = os.path.realpath(__file__) # versionfile_source is the relative path from the top of the source # tree (where the .git directory might live) to this file. Invert # this to find the root from __file__. - for i in range(len(versionfile_source.split(os.sep))): + for i in cfg.versionfile_source.split('/'): root = os.path.dirname(root) except NameError: - return default + return {"version": "0+unknown", "full-revisionid": None, + "dirty": None, + "error": "unable to find root of source tree"} - return (git_versions_from_vcs(tag_prefix, root, verbose) - or versions_from_parentdir(parentdir_prefix, root, verbose) - or default) + try: + pieces = git_pieces_from_vcs(cfg.tag_prefix, root, verbose) + return render(pieces, cfg.style) + except NotThisMethod: + pass + + try: + if cfg.parentdir_prefix: + return versions_from_parentdir(cfg.parentdir_prefix, root, verbose) + except NotThisMethod: + pass + + return {"version": "0+unknown", "full-revisionid": None, + "dirty": None, + "error": "unable to compute version"} diff --git a/gluon/contrib/pg8000/core.py b/gluon/contrib/pg8000/core.py index f19481bd..29f88d9a 100644 --- a/gluon/contrib/pg8000/core.py +++ b/gluon/contrib/pg8000/core.py @@ -1,3 +1,23 @@ +import datetime +from datetime import timedelta +from warnings import warn +import socket +import threading +from struct import pack +from hashlib import md5 +from decimal import Decimal +from collections import deque, defaultdict +from itertools import count, islice +from .six.moves import map +from .six import b, PY2, integer_types, next, text_type, u, binary_type +from uuid import UUID +from copy import deepcopy +from calendar import timegm +from distutils.version import LooseVersion +from struct import Struct +import time + + # Copyright (c) 2007-2009, Mathieu Fenniak # All rights reserved. # @@ -27,34 +47,6 @@ __author__ = "Mathieu Fenniak" -import datetime -from datetime import timedelta -from . import ( - Interval, min_int2, max_int2, min_int4, max_int4, min_int8, max_int8, - Bytea, NotSupportedError, ProgrammingError, InternalError, IntegrityError, - OperationalError, DatabaseError, InterfaceError, Error, - ArrayContentNotHomogenousError, ArrayContentEmptyError, - ArrayDimensionsNotConsistentError, ArrayContentNotSupportedError, Warning, - i_unpack, ii_unpack, iii_unpack, h_pack, d_unpack, q_unpack, d_pack, - f_unpack, q_pack, i_pack, h_unpack, dii_unpack, qii_unpack, ci_unpack, - bh_unpack, ihihih_unpack, cccc_unpack, ii_pack, iii_pack, dii_pack, - qii_pack) -from warnings import warn -import socket -import threading -from struct import pack -from hashlib import md5 -from decimal import Decimal -from collections import deque, defaultdict -from itertools import count, islice -from .six.moves import map -from .six import b, PY2, integer_types, next, PRE_26, text_type, u -from sys import exc_info -from uuid import UUID -from copy import deepcopy -from calendar import timegm -import os -from distutils.version import LooseVersion try: from json import loads @@ -78,9 +70,350 @@ class UTC(datetime.tzinfo): utc = UTC() -if PRE_26: - bytearray = list +class Interval(object): + """An Interval represents a measurement of time. In PostgreSQL, an + interval is defined in the measure of months, days, and microseconds; as + such, the pg8000 interval type represents the same information. + + Note that values of the :attr:`microseconds`, :attr:`days` and + :attr:`months` properties are independently measured and cannot be + converted to each other. A month may be 28, 29, 30, or 31 days, and a day + may occasionally be lengthened slightly by a leap second. + + .. attribute:: microseconds + + Measure of microseconds in the interval. + + The microseconds value is constrained to fit into a signed 64-bit + integer. Any attempt to set a value too large or too small will result + in an OverflowError being raised. + + .. attribute:: days + + Measure of days in the interval. + + The days value is constrained to fit into a signed 32-bit integer. + Any attempt to set a value too large or too small will result in an + OverflowError being raised. + + .. attribute:: months + + Measure of months in the interval. + + The months value is constrained to fit into a signed 32-bit integer. + Any attempt to set a value too large or too small will result in an + OverflowError being raised. + """ + + def __init__(self, microseconds=0, days=0, months=0): + self.microseconds = microseconds + self.days = days + self.months = months + + def _setMicroseconds(self, value): + if not isinstance(value, integer_types): + raise TypeError("microseconds must be an integer type") + elif not (min_int8 < value < max_int8): + raise OverflowError( + "microseconds must be representable as a 64-bit integer") + else: + self._microseconds = value + + def _setDays(self, value): + if not isinstance(value, integer_types): + raise TypeError("days must be an integer type") + elif not (min_int4 < value < max_int4): + raise OverflowError( + "days must be representable as a 32-bit integer") + else: + self._days = value + + def _setMonths(self, value): + if not isinstance(value, integer_types): + raise TypeError("months must be an integer type") + elif not (min_int4 < value < max_int4): + raise OverflowError( + "months must be representable as a 32-bit integer") + else: + self._months = value + + microseconds = property(lambda self: self._microseconds, _setMicroseconds) + days = property(lambda self: self._days, _setDays) + months = property(lambda self: self._months, _setMonths) + + def __repr__(self): + return "" % ( + self.months, self.days, self.microseconds) + + def __eq__(self, other): + return other is not None and isinstance(other, Interval) and \ + self.months == other.months and self.days == other.days and \ + self.microseconds == other.microseconds + + def __neq__(self, other): + return not self.__eq__(other) + + +def pack_funcs(fmt): + struc = Struct('!' + fmt) + return struc.pack, struc.unpack_from + +i_pack, i_unpack = pack_funcs('i') +h_pack, h_unpack = pack_funcs('h') +q_pack, q_unpack = pack_funcs('q') +d_pack, d_unpack = pack_funcs('d') +f_pack, f_unpack = pack_funcs('f') +iii_pack, iii_unpack = pack_funcs('iii') +ii_pack, ii_unpack = pack_funcs('ii') +qii_pack, qii_unpack = pack_funcs('qii') +dii_pack, dii_unpack = pack_funcs('dii') +ihihih_pack, ihihih_unpack = pack_funcs('ihihih') +ci_pack, ci_unpack = pack_funcs('ci') +bh_pack, bh_unpack = pack_funcs('bh') +cccc_pack, cccc_unpack = pack_funcs('cccc') + + +Struct('!i') + + +min_int2, max_int2 = -2 ** 15, 2 ** 15 +min_int4, max_int4 = -2 ** 31, 2 ** 31 +min_int8, max_int8 = -2 ** 63, 2 ** 63 + + +class Warning(Exception): + """Generic exception raised for important database warnings like data + truncations. This exception is not currently used by pg8000. + + This exception is part of the `DBAPI 2.0 specification + `_. + """ + pass + + +class Error(Exception): + """Generic exception that is the base exception of all other error + exceptions. + + This exception is part of the `DBAPI 2.0 specification + `_. + """ + pass + + +class InterfaceError(Error): + """Generic exception raised for errors that are related to the database + interface rather than the database itself. For example, if the interface + attempts to use an SSL connection but the server refuses, an InterfaceError + will be raised. + + This exception is part of the `DBAPI 2.0 specification + `_. + """ + pass + + +class DatabaseError(Error): + """Generic exception raised for errors that are related to the database. + This exception is currently never raised by pg8000. + + This exception is part of the `DBAPI 2.0 specification + `_. + """ + pass + + +class DataError(DatabaseError): + """Generic exception raised for errors that are due to problems with the + processed data. This exception is not currently raised by pg8000. + + This exception is part of the `DBAPI 2.0 specification + `_. + """ + pass + + +class OperationalError(DatabaseError): + """ + Generic exception raised for errors that are related to the database's + operation and not necessarily under the control of the programmer. This + exception is currently never raised by pg8000. + + This exception is part of the `DBAPI 2.0 specification + `_. + """ + pass + + +class IntegrityError(DatabaseError): + """ + Generic exception raised when the relational integrity of the database is + affected. This exception is not currently raised by pg8000. + + This exception is part of the `DBAPI 2.0 specification + `_. + """ + pass + + +class InternalError(DatabaseError): + """Generic exception raised when the database encounters an internal error. + This is currently only raised when unexpected state occurs in the pg8000 + interface itself, and is typically the result of a interface bug. + + This exception is part of the `DBAPI 2.0 specification + `_. + """ + pass + + +class ProgrammingError(DatabaseError): + """Generic exception raised for programming errors. For example, this + exception is raised if more parameter fields are in a query string than + there are available parameters. + + This exception is part of the `DBAPI 2.0 specification + `_. + """ + pass + + +class NotSupportedError(DatabaseError): + """Generic exception raised in case a method or database API was used which + is not supported by the database. + + This exception is part of the `DBAPI 2.0 specification + `_. + """ + pass + + +class ArrayContentNotSupportedError(NotSupportedError): + """ + Raised when attempting to transmit an array where the base type is not + supported for binary data transfer by the interface. + """ + pass + + +class ArrayContentNotHomogenousError(ProgrammingError): + """ + Raised when attempting to transmit an array that doesn't contain only a + single type of object. + """ + pass + + +class ArrayContentEmptyError(ProgrammingError): + """Raised when attempting to transmit an empty array. The type oid of an + empty array cannot be determined, and so sending them is not permitted. + """ + pass + + +class ArrayDimensionsNotConsistentError(ProgrammingError): + """ + Raised when attempting to transmit an array that has inconsistent + multi-dimension sizes. + """ + pass + + +class Bytea(binary_type): + """Bytea is a str-derived class that is mapped to a PostgreSQL byte array. + This class is only used in Python 2, the built-in ``bytes`` type is used in + Python 3. + """ + pass + + +def Date(year, month, day): + """Constuct an object holding a date value. + + This function is part of the `DBAPI 2.0 specification + `_. + + :rtype: :class:`datetime.date` + """ + return datetime.date(year, month, day) + + +def Time(hour, minute, second): + """Construct an object holding a time value. + + This function is part of the `DBAPI 2.0 specification + `_. + + :rtype: :class:`datetime.time` + """ + return datetime.time(hour, minute, second) + + +def Timestamp(year, month, day, hour, minute, second): + """Construct an object holding a timestamp value. + + This function is part of the `DBAPI 2.0 specification + `_. + + :rtype: :class:`datetime.datetime` + """ + return datetime.datetime(year, month, day, hour, minute, second) + + +def DateFromTicks(ticks): + """Construct an object holding a date value from the given ticks value + (number of seconds since the epoch). + + This function is part of the `DBAPI 2.0 specification + `_. + + :rtype: :class:`datetime.date` + """ + return Date(*time.localtime(ticks)[:3]) + + +def TimeFromTicks(ticks): + """Construct an objet holding a time value from the given ticks value + (number of seconds since the epoch). + + This function is part of the `DBAPI 2.0 specification + `_. + + :rtype: :class:`datetime.time` + """ + return Time(*time.localtime(ticks)[3:6]) + + +def TimestampFromTicks(ticks): + """Construct an object holding a timestamp value from the given ticks value + (number of seconds since the epoch). + + This function is part of the `DBAPI 2.0 specification + `_. + + :rtype: :class:`datetime.datetime` + """ + return Timestamp(*time.localtime(ticks)[:6]) + + +def Binary(value): + """Construct an object holding binary data. + + This function is part of the `DBAPI 2.0 specification + `_. + + :rtype: :class:`pg8000.types.Bytea` for Python 2, otherwise :class:`bytes` + """ + if PY2: + return Bytea(value) + else: + return value + +if PY2: + BINARY = Bytea +else: + BINARY = bytes FC_TEXT = 0 FC_BINARY = 1 @@ -271,13 +604,13 @@ def timestamp_recv_integer(data, offset, length): micros = q_unpack(data, offset)[0] try: return EPOCH + timedelta(microseconds=micros) - except OverflowError: + except OverflowError as e: if micros == INFINITY_MICROSECONDS: return datetime.datetime.max elif micros == MINUS_INFINITY_MICROSECONDS: return datetime.datetime.min else: - raise exc_info()[1] + raise e # data is double-precision float representing seconds since 2000-01-01 @@ -299,7 +632,7 @@ def timestamp_send_integer(v): # data is double-precision float representing seconds since 2000-01-01 def timestamp_send_float(v): - return d_pack(timegm(v.timetuple) + v.microsecond / 1e6 - EPOCH_SECONDS) + return d_pack(timegm(v.timetuple()) + v.microsecond / 1e6 - EPOCH_SECONDS) def timestamptz_send_integer(v): @@ -325,13 +658,13 @@ def timestamptz_recv_integer(data, offset, length): micros = q_unpack(data, offset)[0] try: return EPOCH_TZ + timedelta(microseconds=micros) - except OverflowError: + except OverflowError as e: if micros == INFINITY_MICROSECONDS: return DATETIME_MAX_TZ elif micros == MINUS_INFINITY_MICROSECONDS: return DATETIME_MIN_TZ else: - raise exc_info()[1] + raise e def timestamptz_recv_float(data, offset, length): @@ -565,21 +898,19 @@ class Cursor(): .. versionadded:: 1.9.11 """ try: - self._c._lock.acquire() - self.stream = stream + with self._c._lock: + self.stream = stream - if not self._c.in_transaction and not self._c.autocommit: - self._c.execute(self, "begin transaction", None) - self._c.execute(self, operation, args) - except AttributeError: + if not self._c.in_transaction and not self._c.autocommit: + self._c.execute(self, "begin transaction", None) + self._c.execute(self, operation, args) + except AttributeError as e: if self._c is None: raise InterfaceError("Cursor closed") elif self._c._sock is None: raise InterfaceError("connection is closed") else: - raise exc_info()[1] - finally: - self._c._lock.release() + raise e def executemany(self, operation, param_sets): """Prepare a database operation, and then execute it against all @@ -690,28 +1021,26 @@ class Cursor(): pass def __next__(self): - try: - self._c._lock.acquire() - return self._cached_rows.popleft() - except IndexError: - if self.portal_suspended: - self._c.send_EXECUTE(self) - self._c._write(SYNC_MSG) - self._c._flush() - self._c.handle_messages(self) - if not self.portal_suspended: - self._c.close_portal(self) + with self._c._lock: try: return self._cached_rows.popleft() except IndexError: - if self.ps is None: - raise ProgrammingError("A query hasn't been issued.") - elif len(self.ps['row_desc']) == 0: - raise ProgrammingError("no result set") - else: - raise StopIteration() - finally: - self._c._lock.release() + if self.portal_suspended: + self._c.send_EXECUTE(self) + self._c._write(SYNC_MSG) + self._c._flush() + self._c.handle_messages(self) + if not self.portal_suspended: + self._c.close_portal(self) + try: + return self._cached_rows.popleft() + except IndexError: + if self.ps is None: + raise ProgrammingError("A query hasn't been issued.") + elif len(self.ps['row_desc']) == 0: + raise ProgrammingError("no result set") + else: + raise StopIteration() if PY2: Cursor.next = Cursor.__next__ @@ -737,6 +1066,7 @@ COPY_DONE = b("c") COPY_DATA = b("d") COPY_IN_RESPONSE = b("G") COPY_OUT_RESPONSE = b("H") +EMPTY_QUERY_RESPONSE = b("I") BIND = b("B") PARSE = b("P") @@ -776,14 +1106,6 @@ IDLE_IN_TRANSACTION = b("T") IDLE_IN_FAILED_TRANSACTION = b("E") -# Byte1('N') - Identifier -# Int32 - Message length -# Any number of these, followed by a zero byte: -# Byte1 - code identifying the field type (see responseKeys) -# String - field value -def data_into_dict(data): - return dict((s[0:1], s[1:]) for s in data.split(NULL_BYTE)) - arr_trans = dict(zip(map(ord, u("[] 'u")), list(u('{}')) + [None] * 3)) @@ -895,7 +1217,9 @@ class Connection(object): error.__name__, stacklevel=3) return error - def __init__(self, user, host, unix_sock, port, database, password, ssl): + def __init__( + self, user, host, unix_sock, port, database, password, ssl, + timeout): self._client_encoding = "utf8" self._commands_with_count = ( b("INSERT"), b("DELETE"), b("UPDATE"), b("MOVE"), @@ -903,23 +1227,19 @@ class Connection(object): self._lock = threading.Lock() if user is None: - try: - self.user = os.environ['PGUSER'] - except KeyError: - try: - self.user = os.environ['USER'] - except KeyError: - raise InterfaceError( - "The 'user' connection parameter was omitted, and " - "neither the PGUSER or USER environment variables " - "were set.") + raise InterfaceError( + "The 'user' connection parameter cannot be None") + + if isinstance(user, text_type): + self.user = user.encode('utf8') else: self.user = user - if isinstance(self.user, text_type): - self.user = self.user.encode('utf8') + if isinstance(password, text_type): + self.password = password.encode('utf8') + else: + self.password = password - self.password = password self.autocommit = False self._xid = None @@ -939,41 +1259,38 @@ class Connection(object): else: raise ProgrammingError( "one of host or unix_sock must be provided") + if not PY2 and timeout is not None: + self._usock.settimeout(timeout) + if unix_sock is None and host is not None: self._usock.connect((host, port)) elif unix_sock is not None: self._usock.connect(unix_sock) if ssl: - try: - self._lock.acquire() - import ssl as sslmodule - # Int32(8) - Message length, including self. - # Int32(80877103) - The SSL request code. - self._usock.sendall(ii_pack(8, 80877103)) - resp = self._usock.recv(1) - if resp == b('S'): - self._usock = sslmodule.wrap_socket(self._usock) - else: - raise InterfaceError("Server refuses SSL") - except ImportError: - raise InterfaceError( - "SSL required but ssl module not available in " - "this python installation") - finally: - self._lock.release() + with self._lock: + try: + import ssl as sslmodule + # Int32(8) - Message length, including self. + # Int32(80877103) - The SSL request code. + self._usock.sendall(ii_pack(8, 80877103)) + resp = self._usock.recv(1) + if resp == b('S'): + self._usock = sslmodule.wrap_socket(self._usock) + else: + raise InterfaceError("Server refuses SSL") + except ImportError: + raise InterfaceError( + "SSL required but ssl module not available in " + "this python installation") self._sock = self._usock.makefile(mode="rwb") - except socket.error: + except socket.error as e: self._usock.close() - raise InterfaceError("communication error", exc_info()[1]) + raise InterfaceError("communication error", e) self._flush = self._sock.flush self._read = self._sock.read - - if PRE_26: - self._write = self._sock.writelines - else: - self._write = self._sock.write + self._write = self._sock.write self._backend_key_data = None ## @@ -1182,7 +1499,6 @@ class Connection(object): bool: (16, FC_BINARY, bool_send), int: (705, FC_TEXT, unknown_out), float: (701, FC_BINARY, d_pack), # float8 - str: (705, FC_TEXT, text_out), # unknown datetime.date: (1082, FC_TEXT, date_out), # date datetime.time: (1083, FC_TEXT, time_out), # time 1114: (1114, FC_BINARY, timestamp_send_integer), # timestamp @@ -1203,10 +1519,12 @@ class Connection(object): if PY2: self.py_types[Bytea] = (17, FC_BINARY, bytea_send) # bytea self.py_types[text_type] = (705, FC_TEXT, text_out) # unknown + self.py_types[str] = (705, FC_TEXT, bytea_send) # unknown self.py_types[long] = (705, FC_TEXT, unknown_out) # noqa else: self.py_types[bytes] = (17, FC_BINARY, bytea_send) # bytea + self.py_types[str] = (705, FC_TEXT, text_out) # unknown try: from ipaddress import ( @@ -1240,6 +1558,7 @@ class Connection(object): READY_FOR_QUERY: self.handle_READY_FOR_QUERY, ROW_DESCRIPTION: self.handle_ROW_DESCRIPTION, ERROR_RESPONSE: self.handle_ERROR_RESPONSE, + EMPTY_QUERY_RESPONSE: self.handle_EMPTY_QUERY_RESPONSE, DATA_ROW: self.handle_DATA_ROW, COMMAND_COMPLETE: self.handle_COMMAND_COMPLETE, PARSE_COMPLETE: self.handle_PARSE_COMPLETE, @@ -1272,32 +1591,37 @@ class Connection(object): self._flush() self._cursor = self.cursor() - try: - self._lock.acquire() - code = self.error = None - while code not in (READY_FOR_QUERY, ERROR_RESPONSE): - code, data_len = ci_unpack(self._read(5)) - self.message_types[code](self._read(data_len - 4), None) - if self.error is not None: - raise self.error - except: - self._close() - raise - finally: - self._lock.release() + with self._lock: + try: + code = self.error = None + while code not in (READY_FOR_QUERY, ERROR_RESPONSE): + code, data_len = ci_unpack(self._read(5)) + self.message_types[code](self._read(data_len - 4), None) + if self.error is not None: + raise self.error + except Exception as e: + try: + self._close() + except Exception: + pass + raise e self.in_transaction = False self.notifies = [] self.notifies_lock = threading.Lock() def handle_ERROR_RESPONSE(self, data, ps): - msg_dict = data_into_dict(data) + responses = tuple( + (s[0:1], s[1:].decode(self._client_encoding)) for s in + data.split(NULL_BYTE)) + msg_dict = dict(responses) if msg_dict[RESPONSE_CODE] == "28000": self.error = InterfaceError("md5 password authentication failed") else: - self.error = ProgrammingError( - msg_dict[RESPONSE_SEVERITY], msg_dict[RESPONSE_CODE], - msg_dict[RESPONSE_MSG]) + self.error = ProgrammingError(*tuple(v for k, v in responses)) + + def handle_EMPTY_QUERY_RESPONSE(self, data, ps): + self.error = ProgrammingError("query was empty") def handle_CLOSE_COMPLETE(self, data, ps): pass @@ -1391,11 +1715,8 @@ class Connection(object): # additional_info = data[idx:idx + null] # psycopg2 compatible notification interface - try: - self.notifies_lock.acquire() + with self.notifies_lock: self.notifies.append((backend_pid, condition)) - finally: - self.notifies_lock.release() def cursor(self): """Creates a :class:`Cursor` object bound to this @@ -1412,11 +1733,8 @@ class Connection(object): This function is part of the `DBAPI 2.0 specification `_. """ - try: - self._lock.acquire() + with self._lock: self.execute(self._cursor, "commit", None) - finally: - self._lock.release() def rollback(self): """Rolls back the current database transaction. @@ -1424,11 +1742,8 @@ class Connection(object): This function is part of the `DBAPI 2.0 specification `_. """ - try: - self._lock.acquire() + with self._lock: self.execute(self._cursor, "rollback", None) - finally: - self._lock.release() def _close(self): try: @@ -1437,12 +1752,15 @@ class Connection(object): self._write(TERMINATE_MSG) self._flush() self._sock.close() - self._usock.close() - self._sock = None except AttributeError: raise InterfaceError("connection is closed") except ValueError: raise InterfaceError("connection is closed") + except socket.error as e: + raise OperationalError(str(e)) + finally: + self._usock.close() + self._sock = None def close(self): """Closes the database connection. @@ -1450,11 +1768,8 @@ class Connection(object): This function is part of the `DBAPI 2.0 specification `_. """ - try: - self._lock.acquire() + with self._lock: self._close() - finally: - self._lock.release() def handle_AUTHENTICATION_REQUEST(self, data, cursor): assert self._lock.locked() @@ -1463,7 +1778,7 @@ class Connection(object): # 0 = AuthenticationOk # 5 = MD5 pwd # 2 = Kerberos v5 (not supported by pg8000) - # 3 = Cleartext pwd (not supported by pg8000) + # 3 = Cleartext pwd # 4 = crypt() pwd (not supported by pg8000) # 6 = SCM credential (not supported by pg8000) # 7 = GSSAPI (not supported by pg8000) @@ -1480,8 +1795,7 @@ class Connection(object): raise InterfaceError( "server requesting password authentication, but no " "password was provided") - self._send_message( - PASSWORD, self.password.encode("ascii") + NULL_BYTE) + self._send_message(PASSWORD, self.password + NULL_BYTE) self._flush() elif auth_code == 5: ## @@ -1497,8 +1811,8 @@ class Connection(object): "server requesting MD5 password authentication, but no " "password was provided") pwd = b("md5") + md5( - md5(self.password.encode("ascii") + self.user). - hexdigest().encode("ascii") + salt).hexdigest().encode("ascii") + md5(self.password + self.user).hexdigest().encode("ascii") + + salt).hexdigest().encode("ascii") # Byte1('p') - Identifies the message as a password message. # Int32 - Message length including self. # String - The password. Password may be encrypted. @@ -1536,11 +1850,10 @@ class Connection(object): except KeyError: try: params.append(self.inspect_funcs[typ](value)) - except KeyError: + except KeyError as e: raise NotSupportedError( - "type " + str(exc_info()[1]) + - "not mapped to pg type") - return params + "type " + str(e) + "not mapped to pg type") + return tuple(params) def handle_ROW_DESCRIPTION(self, data, cursor): count = h_unpack(data)[0] @@ -1572,8 +1885,7 @@ class Connection(object): args = make_args(vals) params = self.make_params(args) - - key = tuple(oid for oid, x, y in params), operation + key = operation, params try: ps = cache['ps'][key] @@ -1617,11 +1929,13 @@ class Connection(object): try: self._flush() - except AttributeError: + except AttributeError as e: if self._sock is None: raise InterfaceError("connection is closed") else: - raise exc_info()[1] + raise e + except socket.error as e: + raise OperationalError(str(e)) self.handle_messages(cursor) @@ -1711,11 +2025,11 @@ class Connection(object): self._write(i_pack(len(data) + 4)) self._write(data) self._write(FLUSH_MSG) - except ValueError: - if str(exc_info()[1]) == "write to closed file": + except ValueError as e: + if str(e) == "write to closed file": raise InterfaceError("connection is closed") else: - raise exc_info()[1] + raise e except AttributeError: raise InterfaceError("connection is closed") @@ -1783,8 +2097,13 @@ class Connection(object): self._flush() self.handle_messages(cursor) + # Byte1('N') - Identifier + # Int32 - Message length + # Any number of these, followed by a zero byte: + # Byte1 - code identifying the field type (see responseKeys) + # String - field value def handle_NOTICE_RESPONSE(self, data, ps): - resp = data_into_dict(data) + resp = dict((s[0:1], s[1:]) for s in data.split(NULL_BYTE)) self.NoticeReceived(resp) def handle_PARAMETER_STATUS(self, data, ps): diff --git a/gluon/contrib/pg8000/six.py b/gluon/contrib/pg8000/six.py index 6ec96ed8..190c0239 100644 --- a/gluon/contrib/pg8000/six.py +++ b/gluon/contrib/pg8000/six.py @@ -1,6 +1,6 @@ """Utilities for writing code that runs on Python 2 and 3""" -# Copyright (c) 2010-2013 Benjamin Peterson +# Copyright (c) 2010-2015 Benjamin Peterson # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal @@ -9,8 +9,8 @@ # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, @@ -21,22 +21,21 @@ # SOFTWARE. from __future__ import absolute_import + +import functools +import itertools import operator import sys import types __author__ = "Benjamin Peterson " -__version__ = "1.4.1" +__version__ = "1.10.0" # Useful for very coarse version differentiation. PY2 = sys.version_info[0] == 2 PY3 = sys.version_info[0] == 3 - -PRE_26 = PY2 and sys.version_info[1] < 6 - -IS_JYTHON = sys.platform.lower().count('java') > 0 - +PY34 = sys.version_info[0:2] >= (3, 4) if PY3: string_types = str, @@ -47,10 +46,10 @@ if PY3: MAXSIZE = sys.maxsize else: - string_types = basestring, # noqa - integer_types = (int, long) # noqa + string_types = basestring, + integer_types = (int, long) class_types = (type, types.ClassType) - text_type = unicode # noqa + text_type = unicode binary_type = str if sys.platform.startswith("java"): @@ -59,6 +58,7 @@ else: else: # It's possible to have sizeof(long) != sizeof(Py_ssize_t). class X(object): + def __len__(self): return 1 << 31 try: @@ -90,9 +90,13 @@ class _LazyDescr(object): def __get__(self, obj, tp): result = self._resolve() - setattr(obj, self.name, result) - # This is a bit ugly, but it avoids running this again. - delattr(tp, self.name) + setattr(obj, self.name, result) # Invokes __set__. + try: + # This is a bit ugly, but it avoids running this again by + # removing this descriptor. + delattr(obj.__class__, self.name) + except AttributeError: + pass return result @@ -110,6 +114,27 @@ class MovedModule(_LazyDescr): def _resolve(self): return _import_module(self.mod) + def __getattr__(self, attr): + _module = self._resolve() + value = getattr(_module, attr) + setattr(self, attr, value) + return value + + +class _LazyModule(types.ModuleType): + + def __init__(self, name): + super(_LazyModule, self).__init__(name) + self.__doc__ = self.__class__.__doc__ + + def __dir__(self): + attrs = ["__doc__", "__name__"] + attrs += [attr.name for attr in self._moved_attributes] + return attrs + + # Subclasses should override this + _moved_attributes = [] + class MovedAttribute(_LazyDescr): @@ -136,38 +161,109 @@ class MovedAttribute(_LazyDescr): return getattr(module, self.attr) -class _MovedItems(types.ModuleType): +class _SixMetaPathImporter(object): + + """ + A meta path importer to import six.moves and its submodules. + + This class implements a PEP302 finder and loader. It should be compatible + with Python 2.5 and all existing versions of Python3 + """ + + def __init__(self, six_module_name): + self.name = six_module_name + self.known_modules = {} + + def _add_module(self, mod, *fullnames): + for fullname in fullnames: + self.known_modules[self.name + "." + fullname] = mod + + def _get_module(self, fullname): + return self.known_modules[self.name + "." + fullname] + + def find_module(self, fullname, path=None): + if fullname in self.known_modules: + return self + return None + + def __get_module(self, fullname): + try: + return self.known_modules[fullname] + except KeyError: + raise ImportError("This loader does not know module " + fullname) + + def load_module(self, fullname): + try: + # in case of a reload + return sys.modules[fullname] + except KeyError: + pass + mod = self.__get_module(fullname) + if isinstance(mod, MovedModule): + mod = mod._resolve() + else: + mod.__loader__ = self + sys.modules[fullname] = mod + return mod + + def is_package(self, fullname): + """ + Return true, if the named module is a package. + + We need this method to get correct spec objects with + Python 3.4 (see PEP451) + """ + return hasattr(self.__get_module(fullname), "__path__") + + def get_code(self, fullname): + """Return None + + Required, if is_package is implemented""" + self.__get_module(fullname) # eventually raises ImportError + return None + get_source = get_code # same as get_code + +_importer = _SixMetaPathImporter(__name__) + + +class _MovedItems(_LazyModule): + """Lazy loading of moved objects""" + __path__ = [] # mark as package _moved_attributes = [ MovedAttribute("cStringIO", "cStringIO", "io", "StringIO"), MovedAttribute("filter", "itertools", "builtins", "ifilter", "filter"), - MovedAttribute( - "filterfalse", "itertools", "itertools", "ifilterfalse", - "filterfalse"), + MovedAttribute("filterfalse", "itertools", "itertools", "ifilterfalse", "filterfalse"), MovedAttribute("input", "__builtin__", "builtins", "raw_input", "input"), + MovedAttribute("intern", "__builtin__", "sys"), MovedAttribute("map", "itertools", "builtins", "imap", "map"), + MovedAttribute("getcwd", "os", "os", "getcwdu", "getcwd"), + MovedAttribute("getcwdb", "os", "os", "getcwd", "getcwdb"), MovedAttribute("range", "__builtin__", "builtins", "xrange", "range"), - MovedAttribute("reload_module", "__builtin__", "imp", "reload"), + MovedAttribute("reload_module", "__builtin__", "importlib" if PY34 else "imp", "reload"), MovedAttribute("reduce", "__builtin__", "functools"), + MovedAttribute("shlex_quote", "pipes", "shlex", "quote"), MovedAttribute("StringIO", "StringIO", "io"), + MovedAttribute("UserDict", "UserDict", "collections"), + MovedAttribute("UserList", "UserList", "collections"), MovedAttribute("UserString", "UserString", "collections"), MovedAttribute("xrange", "__builtin__", "builtins", "xrange", "range"), MovedAttribute("zip", "itertools", "builtins", "izip", "zip"), - MovedAttribute( - "zip_longest", "itertools", "itertools", "izip_longest", - "zip_longest"), + MovedAttribute("zip_longest", "itertools", "itertools", "izip_longest", "zip_longest"), MovedModule("builtins", "__builtin__"), MovedModule("configparser", "ConfigParser"), MovedModule("copyreg", "copy_reg"), + MovedModule("dbm_gnu", "gdbm", "dbm.gnu"), + MovedModule("_dummy_thread", "dummy_thread", "_dummy_thread"), MovedModule("http_cookiejar", "cookielib", "http.cookiejar"), MovedModule("http_cookies", "Cookie", "http.cookies"), MovedModule("html_entities", "htmlentitydefs", "html.entities"), MovedModule("html_parser", "HTMLParser", "html.parser"), MovedModule("http_client", "httplib", "http.client"), - MovedModule( - "email_mime_multipart", "email.MIMEMultipart", "email.mime.multipart"), + MovedModule("email_mime_multipart", "email.MIMEMultipart", "email.mime.multipart"), + MovedModule("email_mime_nonmultipart", "email.MIMENonMultipart", "email.mime.nonmultipart"), MovedModule("email_mime_text", "email.MIMEText", "email.mime.text"), MovedModule("email_mime_base", "email.MIMEBase", "email.mime.base"), MovedModule("BaseHTTPServer", "BaseHTTPServer", "http.server"), @@ -177,14 +273,14 @@ _moved_attributes = [ MovedModule("queue", "Queue"), MovedModule("reprlib", "repr"), MovedModule("socketserver", "SocketServer"), + MovedModule("_thread", "thread", "_thread"), MovedModule("tkinter", "Tkinter"), MovedModule("tkinter_dialog", "Dialog", "tkinter.dialog"), MovedModule("tkinter_filedialog", "FileDialog", "tkinter.filedialog"), - MovedModule( - "tkinter_scrolledtext", "ScrolledText", "tkinter.scrolledtext"), - MovedModule( - "tkinter_simpledialog", "SimpleDialog", "tkinter.simpledialog"), + MovedModule("tkinter_scrolledtext", "ScrolledText", "tkinter.scrolledtext"), + MovedModule("tkinter_simpledialog", "SimpleDialog", "tkinter.simpledialog"), MovedModule("tkinter_tix", "Tix", "tkinter.tix"), + MovedModule("tkinter_ttk", "ttk", "tkinter.ttk"), MovedModule("tkinter_constants", "Tkconstants", "tkinter.constants"), MovedModule("tkinter_dnd", "Tkdnd", "tkinter.dnd"), MovedModule("tkinter_colorchooser", "tkColorChooser", @@ -194,30 +290,41 @@ _moved_attributes = [ MovedModule("tkinter_tkfiledialog", "tkFileDialog", "tkinter.filedialog"), MovedModule("tkinter_font", "tkFont", "tkinter.font"), MovedModule("tkinter_messagebox", "tkMessageBox", "tkinter.messagebox"), - MovedModule( - "tkinter_tksimpledialog", "tkSimpleDialog", "tkinter.simpledialog"), - MovedModule( - "urllib_parse", __name__ + ".moves.urllib_parse", "urllib.parse"), - MovedModule( - "urllib_error", __name__ + ".moves.urllib_error", "urllib.error"), - MovedModule( - "urllib", __name__ + ".moves.urllib", __name__ + ".moves.urllib"), + MovedModule("tkinter_tksimpledialog", "tkSimpleDialog", + "tkinter.simpledialog"), + MovedModule("urllib_parse", __name__ + ".moves.urllib_parse", "urllib.parse"), + MovedModule("urllib_error", __name__ + ".moves.urllib_error", "urllib.error"), + MovedModule("urllib", __name__ + ".moves.urllib", __name__ + ".moves.urllib"), MovedModule("urllib_robotparser", "robotparser", "urllib.robotparser"), - MovedModule("winreg", "_winreg"), + MovedModule("xmlrpc_client", "xmlrpclib", "xmlrpc.client"), + MovedModule("xmlrpc_server", "SimpleXMLRPCServer", "xmlrpc.server"), ] +# Add windows specific modules. +if sys.platform == "win32": + _moved_attributes += [ + MovedModule("winreg", "_winreg"), + ] + for attr in _moved_attributes: setattr(_MovedItems, attr.name, attr) + if isinstance(attr, MovedModule): + _importer._add_module(attr, "moves." + attr.name) del attr -moves = sys.modules[__name__ + ".moves"] = _MovedItems(__name__ + ".moves") +_MovedItems._moved_attributes = _moved_attributes + +moves = _MovedItems(__name__ + ".moves") +_importer._add_module(moves, "moves") -class Module_six_moves_urllib_parse(types.ModuleType): +class Module_six_moves_urllib_parse(_LazyModule): + """Lazy loading of moved objects in six.moves.urllib_parse""" _urllib_parse_moved_attributes = [ MovedAttribute("ParseResult", "urlparse", "urllib.parse"), + MovedAttribute("SplitResult", "urlparse", "urllib.parse"), MovedAttribute("parse_qs", "urlparse", "urllib.parse"), MovedAttribute("parse_qsl", "urlparse", "urllib.parse"), MovedAttribute("urldefrag", "urlparse", "urllib.parse"), @@ -231,18 +338,27 @@ _urllib_parse_moved_attributes = [ MovedAttribute("unquote", "urllib", "urllib.parse"), MovedAttribute("unquote_plus", "urllib", "urllib.parse"), MovedAttribute("urlencode", "urllib", "urllib.parse"), + MovedAttribute("splitquery", "urllib", "urllib.parse"), + MovedAttribute("splittag", "urllib", "urllib.parse"), + MovedAttribute("splituser", "urllib", "urllib.parse"), + MovedAttribute("uses_fragment", "urlparse", "urllib.parse"), + MovedAttribute("uses_netloc", "urlparse", "urllib.parse"), + MovedAttribute("uses_params", "urlparse", "urllib.parse"), + MovedAttribute("uses_query", "urlparse", "urllib.parse"), + MovedAttribute("uses_relative", "urlparse", "urllib.parse"), ] for attr in _urllib_parse_moved_attributes: setattr(Module_six_moves_urllib_parse, attr.name, attr) del attr -sys.modules[__name__ + ".moves.urllib_parse"] = Module_six_moves_urllib_parse( - __name__ + ".moves.urllib_parse") -sys.modules[__name__ + ".moves.urllib.parse"] = Module_six_moves_urllib_parse( - __name__ + ".moves.urllib.parse") +Module_six_moves_urllib_parse._moved_attributes = _urllib_parse_moved_attributes + +_importer._add_module(Module_six_moves_urllib_parse(__name__ + ".moves.urllib_parse"), + "moves.urllib_parse", "moves.urllib.parse") -class Module_six_moves_urllib_error(types.ModuleType): +class Module_six_moves_urllib_error(_LazyModule): + """Lazy loading of moved objects in six.moves.urllib_error""" @@ -255,13 +371,14 @@ for attr in _urllib_error_moved_attributes: setattr(Module_six_moves_urllib_error, attr.name, attr) del attr -sys.modules[__name__ + ".moves.urllib_error"] = Module_six_moves_urllib_error( - __name__ + ".moves.urllib_error") -sys.modules[__name__ + ".moves.urllib.error"] = Module_six_moves_urllib_error( - __name__ + ".moves.urllib.error") +Module_six_moves_urllib_error._moved_attributes = _urllib_error_moved_attributes + +_importer._add_module(Module_six_moves_urllib_error(__name__ + ".moves.urllib.error"), + "moves.urllib_error", "moves.urllib.error") -class Module_six_moves_urllib_request(types.ModuleType): +class Module_six_moves_urllib_request(_LazyModule): + """Lazy loading of moved objects in six.moves.urllib_request""" @@ -280,8 +397,7 @@ _urllib_request_moved_attributes = [ MovedAttribute("ProxyHandler", "urllib2", "urllib.request"), MovedAttribute("BaseHandler", "urllib2", "urllib.request"), MovedAttribute("HTTPPasswordMgr", "urllib2", "urllib.request"), - MovedAttribute( - "HTTPPasswordMgrWithDefaultRealm", "urllib2", "urllib.request"), + MovedAttribute("HTTPPasswordMgrWithDefaultRealm", "urllib2", "urllib.request"), MovedAttribute("AbstractBasicAuthHandler", "urllib2", "urllib.request"), MovedAttribute("HTTPBasicAuthHandler", "urllib2", "urllib.request"), MovedAttribute("ProxyBasicAuthHandler", "urllib2", "urllib.request"), @@ -299,18 +415,20 @@ _urllib_request_moved_attributes = [ MovedAttribute("urlcleanup", "urllib", "urllib.request"), MovedAttribute("URLopener", "urllib", "urllib.request"), MovedAttribute("FancyURLopener", "urllib", "urllib.request"), + MovedAttribute("proxy_bypass", "urllib", "urllib.request"), ] for attr in _urllib_request_moved_attributes: setattr(Module_six_moves_urllib_request, attr.name, attr) del attr -sys.modules[__name__ + ".moves.urllib_request"] = \ - Module_six_moves_urllib_request(__name__ + ".moves.urllib_request") -sys.modules[__name__ + ".moves.urllib.request"] = \ - Module_six_moves_urllib_request(__name__ + ".moves.urllib.request") +Module_six_moves_urllib_request._moved_attributes = _urllib_request_moved_attributes + +_importer._add_module(Module_six_moves_urllib_request(__name__ + ".moves.urllib.request"), + "moves.urllib_request", "moves.urllib.request") -class Module_six_moves_urllib_response(types.ModuleType): +class Module_six_moves_urllib_response(_LazyModule): + """Lazy loading of moved objects in six.moves.urllib_response""" @@ -324,13 +442,14 @@ for attr in _urllib_response_moved_attributes: setattr(Module_six_moves_urllib_response, attr.name, attr) del attr -sys.modules[__name__ + ".moves.urllib_response"] = \ - Module_six_moves_urllib_response(__name__ + ".moves.urllib_response") -sys.modules[__name__ + ".moves.urllib.response"] = \ - Module_six_moves_urllib_response(__name__ + ".moves.urllib.response") +Module_six_moves_urllib_response._moved_attributes = _urllib_response_moved_attributes + +_importer._add_module(Module_six_moves_urllib_response(__name__ + ".moves.urllib.response"), + "moves.urllib_response", "moves.urllib.response") -class Module_six_moves_urllib_robotparser(types.ModuleType): +class Module_six_moves_urllib_robotparser(_LazyModule): + """Lazy loading of moved objects in six.moves.urllib_robotparser""" @@ -341,25 +460,27 @@ for attr in _urllib_robotparser_moved_attributes: setattr(Module_six_moves_urllib_robotparser, attr.name, attr) del attr -sys.modules[__name__ + ".moves.urllib_robotparser"] = \ - Module_six_moves_urllib_robotparser(__name__ + ".moves.urllib_robotparser") -sys.modules[__name__ + ".moves.urllib.robotparser"] = \ - Module_six_moves_urllib_robotparser( - __name__ + ".moves.urllib.robotparser") +Module_six_moves_urllib_robotparser._moved_attributes = _urllib_robotparser_moved_attributes + +_importer._add_module(Module_six_moves_urllib_robotparser(__name__ + ".moves.urllib.robotparser"), + "moves.urllib_robotparser", "moves.urllib.robotparser") class Module_six_moves_urllib(types.ModuleType): - """Create a six.moves.urllib namespace that resembles the Python 3 - namespace""" - parse = sys.modules[__name__ + ".moves.urllib_parse"] - error = sys.modules[__name__ + ".moves.urllib_error"] - request = sys.modules[__name__ + ".moves.urllib_request"] - response = sys.modules[__name__ + ".moves.urllib_response"] - robotparser = sys.modules[__name__ + ".moves.urllib_robotparser"] + """Create a six.moves.urllib namespace that resembles the Python 3 namespace""" + __path__ = [] # mark as package + parse = _importer._get_module("moves.urllib_parse") + error = _importer._get_module("moves.urllib_error") + request = _importer._get_module("moves.urllib_request") + response = _importer._get_module("moves.urllib_response") + robotparser = _importer._get_module("moves.urllib_robotparser") -sys.modules[__name__ + ".moves.urllib"] = Module_six_moves_urllib( - __name__ + ".moves.urllib") + def __dir__(self): + return ['parse', 'error', 'request', 'response', 'robotparser'] + +_importer._add_module(Module_six_moves_urllib(__name__ + ".moves.urllib"), + "moves.urllib") def add_move(move): @@ -386,11 +507,6 @@ if PY3: _func_code = "__code__" _func_defaults = "__defaults__" _func_globals = "__globals__" - - _iterkeys = "keys" - _itervalues = "values" - _iteritems = "items" - _iterlists = "lists" else: _meth_func = "im_func" _meth_self = "im_self" @@ -400,11 +516,6 @@ else: _func_defaults = "func_defaults" _func_globals = "func_globals" - _iterkeys = "iterkeys" - _itervalues = "itervalues" - _iteritems = "iteritems" - _iterlists = "iterlists" - try: advance_iterator = next @@ -427,6 +538,9 @@ if PY3: create_bound_method = types.MethodType + def create_unbound_method(func, cls): + return func + Iterator = object else: def get_unbound_function(unbound): @@ -435,6 +549,9 @@ else: def create_bound_method(func, obj): return types.MethodType(func, obj, obj.__class__) + def create_unbound_method(func, cls): + return types.MethodType(func, None, cls) + class Iterator(object): def next(self): @@ -453,24 +570,49 @@ get_function_defaults = operator.attrgetter(_func_defaults) get_function_globals = operator.attrgetter(_func_globals) -def iterkeys(d, **kw): - """Return an iterator over the keys of a dictionary.""" - return iter(getattr(d, _iterkeys)(**kw)) +if PY3: + def iterkeys(d, **kw): + return iter(d.keys(**kw)) + def itervalues(d, **kw): + return iter(d.values(**kw)) -def itervalues(d, **kw): - """Return an iterator over the values of a dictionary.""" - return iter(getattr(d, _itervalues)(**kw)) + def iteritems(d, **kw): + return iter(d.items(**kw)) + def iterlists(d, **kw): + return iter(d.lists(**kw)) -def iteritems(d, **kw): - """Return an iterator over the (key, value) pairs of a dictionary.""" - return iter(getattr(d, _iteritems)(**kw)) + viewkeys = operator.methodcaller("keys") + viewvalues = operator.methodcaller("values") -def iterlists(d, **kw): - """Return an iterator over the (key, [values]) pairs of a dictionary.""" - return iter(getattr(d, _iterlists)(**kw)) + viewitems = operator.methodcaller("items") +else: + def iterkeys(d, **kw): + return d.iterkeys(**kw) + + def itervalues(d, **kw): + return d.itervalues(**kw) + + def iteritems(d, **kw): + return d.iteritems(**kw) + + def iterlists(d, **kw): + return d.iterlists(**kw) + + viewkeys = operator.methodcaller("viewkeys") + + viewvalues = operator.methodcaller("viewvalues") + + viewitems = operator.methodcaller("viewitems") + +_add_doc(iterkeys, "Return an iterator over the keys of a dictionary.") +_add_doc(itervalues, "Return an iterator over the values of a dictionary.") +_add_doc(iteritems, + "Return an iterator over the (key, value) pairs of a dictionary.") +_add_doc(iterlists, + "Return an iterator over the (key, [values]) pairs of a dictionary.") if PY3: @@ -480,24 +622,29 @@ if PY3: def u(s): return s unichr = chr - if sys.version_info[1] <= 1: - def int2byte(i): - return bytes((i,)) - else: - # This is about 2x faster than the implementation above on 3.2+ - int2byte = operator.methodcaller("to_bytes", 1, "big") + import struct + int2byte = struct.Struct(">B").pack + del struct byte2int = operator.itemgetter(0) indexbytes = operator.getitem iterbytes = iter import io StringIO = io.StringIO BytesIO = io.BytesIO + _assertCountEqual = "assertCountEqual" + if sys.version_info[1] <= 1: + _assertRaisesRegex = "assertRaisesRegexp" + _assertRegex = "assertRegexpMatches" + else: + _assertRaisesRegex = "assertRaisesRegex" + _assertRegex = "assertRegex" else: def b(s): return s + # Workaround for standalone backslash def u(s): - return unicode(s, "unicode_escape") # noqa + return unicode(s.replace(r'\\', r'\\\\'), "unicode_escape") unichr = unichr int2byte = chr @@ -506,27 +653,38 @@ else: def indexbytes(buf, i): return ord(buf[i]) - - def iterbytes(buf): - return (ord(byte) for byte in buf) + iterbytes = functools.partial(itertools.imap, ord) import StringIO StringIO = BytesIO = StringIO.StringIO + _assertCountEqual = "assertItemsEqual" + _assertRaisesRegex = "assertRaisesRegexp" + _assertRegex = "assertRegexpMatches" _add_doc(b, """Byte literal""") _add_doc(u, """Text literal""") +def assertCountEqual(self, *args, **kwargs): + return getattr(self, _assertCountEqual)(*args, **kwargs) + + +def assertRaisesRegex(self, *args, **kwargs): + return getattr(self, _assertRaisesRegex)(*args, **kwargs) + + +def assertRegex(self, *args, **kwargs): + return getattr(self, _assertRegex)(*args, **kwargs) + + if PY3: - import builtins - exec_ = getattr(builtins, "exec") + exec_ = getattr(moves.builtins, "exec") def reraise(tp, value, tb=None): + if value is None: + value = tp() if value.__traceback__ is not tb: raise value.with_traceback(tb) raise value - print_ = getattr(builtins, "print") - del builtins - else: def exec_(_code_, _globs_=None, _locs_=None): """Execute code in a namespace.""" @@ -544,26 +702,52 @@ else: raise tp, value, tb """) + +if sys.version_info[:2] == (3, 2): + exec_("""def raise_from(value, from_value): + if from_value is None: + raise value + raise value from from_value +""") +elif sys.version_info[:2] > (3, 2): + exec_("""def raise_from(value, from_value): + raise value from from_value +""") +else: + def raise_from(value, from_value): + raise value + + +print_ = getattr(moves.builtins, "print", None) +if print_ is None: def print_(*args, **kwargs): - """The new-style print function.""" + """The new-style print function for Python 2.4 and 2.5.""" fp = kwargs.pop("file", sys.stdout) if fp is None: return def write(data): - if not isinstance(data, basestring): # noqa + if not isinstance(data, basestring): data = str(data) + # If the file has an encoding, encode unicode with it. + if (isinstance(fp, file) and + isinstance(data, unicode) and + fp.encoding is not None): + errors = getattr(fp, "errors", None) + if errors is None: + errors = "strict" + data = data.encode(fp.encoding, errors) fp.write(data) want_unicode = False sep = kwargs.pop("sep", None) if sep is not None: - if isinstance(sep, unicode): # noqa + if isinstance(sep, unicode): want_unicode = True elif not isinstance(sep, str): raise TypeError("sep must be None or a string") end = kwargs.pop("end", None) if end is not None: - if isinstance(end, unicode): # noqa + if isinstance(end, unicode): want_unicode = True elif not isinstance(end, str): raise TypeError("end must be None or a string") @@ -571,12 +755,12 @@ else: raise TypeError("invalid keyword arguments to print()") if not want_unicode: for arg in args: - if isinstance(arg, unicode): # noqa + if isinstance(arg, unicode): want_unicode = True break if want_unicode: - newline = unicode("\n") # noqa - space = unicode(" ") # noqa + newline = unicode("\n") + space = unicode(" ") else: newline = "\n" space = " " @@ -589,22 +773,96 @@ else: write(sep) write(arg) write(end) +if sys.version_info[:2] < (3, 3): + _print = print_ + + def print_(*args, **kwargs): + fp = kwargs.get("file", sys.stdout) + flush = kwargs.pop("flush", False) + _print(*args, **kwargs) + if flush and fp is not None: + fp.flush() _add_doc(reraise, """Reraise an exception.""") +if sys.version_info[0:2] < (3, 4): + def wraps(wrapped, assigned=functools.WRAPPER_ASSIGNMENTS, + updated=functools.WRAPPER_UPDATES): + def wrapper(f): + f = functools.wraps(wrapped, assigned, updated)(f) + f.__wrapped__ = wrapped + return f + return wrapper +else: + wraps = functools.wraps + def with_metaclass(meta, *bases): """Create a base class with a metaclass.""" - return meta("NewBase", bases, {}) + # This requires a bit of explanation: the basic idea is to make a dummy + # metaclass for one level of class instantiation that replaces itself with + # the actual metaclass. + class metaclass(meta): + + def __new__(cls, name, this_bases, d): + return meta(name, bases, d) + return type.__new__(metaclass, 'temporary_class', (), {}) def add_metaclass(metaclass): """Class decorator for creating a class with a metaclass.""" def wrapper(cls): orig_vars = cls.__dict__.copy() + slots = orig_vars.get('__slots__') + if slots is not None: + if isinstance(slots, str): + slots = [slots] + for slots_var in slots: + orig_vars.pop(slots_var) orig_vars.pop('__dict__', None) orig_vars.pop('__weakref__', None) - for slots_var in orig_vars.get('__slots__', ()): - orig_vars.pop(slots_var) return metaclass(cls.__name__, cls.__bases__, orig_vars) return wrapper + + +def python_2_unicode_compatible(klass): + """ + A decorator that defines __unicode__ and __str__ methods under Python 2. + Under Python 3 it does nothing. + + To support Python 2 and 3 with a single code base, define a __str__ method + returning text and apply this decorator to the class. + """ + if PY2: + if '__str__' not in klass.__dict__: + raise ValueError("@python_2_unicode_compatible cannot be applied " + "to %s because it doesn't define __str__()." % + klass.__name__) + klass.__unicode__ = klass.__str__ + klass.__str__ = lambda self: self.__unicode__().encode('utf-8') + return klass + + +# Complete the moves implementation. +# This code is at the end of this module to speed up module loading. +# Turn this module into a package. +__path__ = [] # required for PEP 302 and PEP 451 +__package__ = __name__ # see PEP 366 @ReservedAssignment +if globals().get("__spec__") is not None: + __spec__.submodule_search_locations = [] # PEP 451 @UndefinedVariable +# Remove other six meta path importers, since they cause problems. This can +# happen if six is removed from sys.modules and then reloaded. (Setuptools does +# this for some reason.) +if sys.meta_path: + for i, importer in enumerate(sys.meta_path): + # Here's some real nastiness: Another "instance" of the six module might + # be floating around. Therefore, we can't use isinstance() to check for + # the six meta path importer, since the other six instance will have + # inserted an importer with different class. + if (type(importer).__name__ == "_SixMetaPathImporter" and + importer.name == __name__): + del sys.meta_path[i] + break + del i, importer +# Finally, add the importer to the meta path import hook. +sys.meta_path.append(_importer) From bcc237ead871df46f614e358bfb35c44fe2cee38 Mon Sep 17 00:00:00 2001 From: niphlod Date: Mon, 3 Oct 2016 22:55:21 +0200 Subject: [PATCH 46/49] removing pycrypto hard dep --- .travis.yml | 20 +- README.markdown | 4 +- gluon/contrib/aes.py | 502 ------------------------ gluon/contrib/pbkdf2.py | 48 +-- gluon/contrib/pbkdf2_ctypes.py | 3 +- gluon/contrib/pyaes/LICENSE.txt | 22 ++ gluon/contrib/pyaes/README.md | 363 ++++++++++++++++++ gluon/contrib/pyaes/__init__.py | 53 +++ gluon/contrib/pyaes/aes.py | 589 +++++++++++++++++++++++++++++ gluon/contrib/pyaes/blockfeeder.py | 227 +++++++++++ gluon/contrib/pyaes/util.py | 60 +++ gluon/utils.py | 86 +++-- requirements.txt | 1 - 13 files changed, 1390 insertions(+), 588 deletions(-) delete mode 100644 gluon/contrib/aes.py create mode 100644 gluon/contrib/pyaes/LICENSE.txt create mode 100644 gluon/contrib/pyaes/README.md create mode 100644 gluon/contrib/pyaes/__init__.py create mode 100644 gluon/contrib/pyaes/aes.py create mode 100644 gluon/contrib/pyaes/blockfeeder.py create mode 100644 gluon/contrib/pyaes/util.py delete mode 100644 requirements.txt diff --git a/.travis.yml b/.travis.yml index 2907e30e..472896fd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,9 +2,7 @@ language: python sudo: false -cache: - directories: - - $HOME/.pip-cache/ +cache: pip python: - '2.7' @@ -12,21 +10,7 @@ python: - '3.5' install: - - | - if [ "$TRAVIS_PYTHON_VERSION" = "pypy" ]; then - export PYENV_ROOT="$HOME/.pyenv" - if [ -f "$PYENV_ROOT/bin/pyenv" ]; then - pushd "$PYENV_ROOT" && git pull && popd - else - rm -rf "$PYENV_ROOT" && git clone --depth 1 https://github.com/yyuu/pyenv.git "$PYENV_ROOT" - fi - export PYPY_VERSION="5.0.1" - "$PYENV_ROOT/bin/pyenv" install --skip-existing "pypy-$PYPY_VERSION" - virtualenv --python="$PYENV_ROOT/versions/pypy-$PYPY_VERSION/bin/python" "$HOME/virtualenvs/pypy-$PYPY_VERSION" - source "$HOME/virtualenvs/pypy-$PYPY_VERSION/bin/activate" - fi - - if [[ $TRAVIS_PYTHON_VERSION == '3.5' ]]; then pip install pycrypto pg8000; fi; - - if [[ $TRAVIS_PYTHON_VERSION != '3.5' ]]; then pip install -e .; fi; + - pip install -e . before_script: - pip install coverage diff --git a/README.markdown b/README.markdown index 1c906755..27fa2369 100644 --- a/README.markdown +++ b/README.markdown @@ -1,6 +1,6 @@ ## Readme -web2py is a free open source full-stack framework for rapid development of fast, scalable, secure and portable database-driven web-based applications. +web2py is a free open source full-stack framework for rapid development of fast, scalable, secure and portable database-driven web-based applications. It is written and programmable in Python. LGPLv3 License @@ -10,7 +10,7 @@ Learn more at http://web2py.com cp examples/app.yaml ./ cp handlers/gaehandler.py ./ - + Then edit ./app.yaml and replace "yourappname" with yourappname. ## Important reminder about this GIT repo diff --git a/gluon/contrib/aes.py b/gluon/contrib/aes.py deleted file mode 100644 index cecf2d90..00000000 --- a/gluon/contrib/aes.py +++ /dev/null @@ -1,502 +0,0 @@ -"""Simple AES cipher implementation in pure Python following PEP-272 API - -Homepage: https://bitbucket.org/intgr/pyaes/ - -The goal of this module is to be as fast as reasonable in Python while still -being Pythonic and readable/understandable. It is licensed under the permissive -MIT license. - -Hopefully the code is readable and commented enough that it can serve as an -introduction to the AES cipher for Python coders. In fact, it should go along -well with the Stick Figure Guide to AES: -http://www.moserware.com/2009/09/stick-figure-guide-to-advanced.html - -Contrary to intuition, this implementation numbers the 4x4 matrices from top to -bottom for efficiency reasons:: - - 0 4 8 12 - 1 5 9 13 - 2 6 10 14 - 3 7 11 15 - -Effectively it's the transposition of what you'd expect. This actually makes -the code simpler -- except the ShiftRows step, but hopefully the explanation -there clears it up. - -""" - -#### -# Copyright (c) 2010 Marti Raudsepp -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. -#### - - -from array import array - -# Globals mandated by PEP 272: -# http://www.python.org/dev/peps/pep-0272/ -MODE_ECB = 1 -MODE_CBC = 2 -#MODE_CTR = 6 - -block_size = 16 -key_size = None - -def new(key, mode=MODE_CBC, IV=None): - if mode == MODE_ECB: - return ECBMode(AES(key)) - elif mode == MODE_CBC: - if IV is None: - raise ValueError("CBC mode needs an IV value!") - - return CBCMode(AES(key), IV) - else: - raise NotImplementedError - -#### AES cipher implementation - -class AES(object): - block_size = 16 - - def __init__(self, key): - self.setkey(key) - - def setkey(self, key): - """Sets the key and performs key expansion.""" - - self.key = key - self.key_size = len(key) - - if self.key_size == 16: - self.rounds = 10 - elif self.key_size == 24: - self.rounds = 12 - elif self.key_size == 32: - self.rounds = 14 - else: - raise ValueError("Key length must be 16, 24 or 32 bytes") - - self.expand_key() - - def expand_key(self): - """Performs AES key expansion on self.key and stores in self.exkey""" - - # The key schedule specifies how parts of the key are fed into the - # cipher's round functions. "Key expansion" means performing this - # schedule in advance. Almost all implementations do this. - # - # Here's a description of AES key schedule: - # http://en.wikipedia.org/wiki/Rijndael_key_schedule - - # The expanded key starts with the actual key itself - exkey = array('B', self.key) - - # extra key expansion steps - if self.key_size == 16: - extra_cnt = 0 - elif self.key_size == 24: - extra_cnt = 2 - else: - extra_cnt = 3 - - # 4-byte temporary variable for key expansion - word = exkey[-4:] - # Each expansion cycle uses 'i' once for Rcon table lookup - for i in xrange(1, 11): - - #### key schedule core: - # left-rotate by 1 byte - word = word[1:4] + word[0:1] - - # apply S-box to all bytes - for j in xrange(4): - word[j] = aes_sbox[word[j]] - - # apply the Rcon table to the leftmost byte - word[0] = word[0] ^ aes_Rcon[i] - #### end key schedule core - - for z in xrange(4): - for j in xrange(4): - # mix in bytes from the last subkey - word[j] ^= exkey[-self.key_size + j] - exkey.extend(word) - - # Last key expansion cycle always finishes here - if len(exkey) >= (self.rounds+1) * self.block_size: - break - - # Special substitution step for 256-bit key - if self.key_size == 32: - for j in xrange(4): - # mix in bytes from the last subkey XORed with S-box of - # current word bytes - word[j] = aes_sbox[word[j]] ^ exkey[-self.key_size + j] - exkey.extend(word) - - # Twice for 192-bit key, thrice for 256-bit key - for z in xrange(extra_cnt): - for j in xrange(4): - # mix in bytes from the last subkey - word[j] ^= exkey[-self.key_size + j] - exkey.extend(word) - - self.exkey = exkey - - def add_round_key(self, block, round): - """AddRoundKey step in AES. This is where the key is mixed into plaintext""" - - offset = round * 16 - exkey = self.exkey - - for i in xrange(16): - block[i] ^= exkey[offset + i] - - #print 'AddRoundKey:', block - - def sub_bytes(self, block, sbox): - """SubBytes step, apply S-box to all bytes - - Depending on whether encrypting or decrypting, a different sbox array - is passed in. - """ - - for i in xrange(16): - block[i] = sbox[block[i]] - - #print 'SubBytes :', block - - def shift_rows(self, b): - """ShiftRows step. Shifts 2nd row to left by 1, 3rd row by 2, 4th row by 3 - - Since we're performing this on a transposed matrix, cells are numbered - from top to bottom:: - - 0 4 8 12 -> 0 4 8 12 -- 1st row doesn't change - 1 5 9 13 -> 5 9 13 1 -- row shifted to left by 1 (wraps around) - 2 6 10 14 -> 10 14 2 6 -- shifted by 2 - 3 7 11 15 -> 15 3 7 11 -- shifted by 3 - """ - - b[1], b[5], b[ 9], b[13] = b[ 5], b[ 9], b[13], b[ 1] - b[2], b[6], b[10], b[14] = b[10], b[14], b[ 2], b[ 6] - b[3], b[7], b[11], b[15] = b[15], b[ 3], b[ 7], b[11] - - #print 'ShiftRows :', b - - def shift_rows_inv(self, b): - """Similar to shift_rows above, but performed in inverse for decryption.""" - - b[ 5], b[ 9], b[13], b[ 1] = b[1], b[5], b[ 9], b[13] - b[10], b[14], b[ 2], b[ 6] = b[2], b[6], b[10], b[14] - b[15], b[ 3], b[ 7], b[11] = b[3], b[7], b[11], b[15] - - #print 'ShiftRows :', b - - def mix_columns(self, block): - """MixColumns step. Mixes the values in each column""" - - # Cache global multiplication tables (see below) - mul_by_2 = gf_mul_by_2 - mul_by_3 = gf_mul_by_3 - - # Since we're dealing with a transposed matrix, columns are already - # sequential - for i in xrange(4): - col = i * 4 - - #v0, v1, v2, v3 = block[col : col+4] - v0, v1, v2, v3 = (block[col], block[col + 1], block[col + 2], - block[col + 3]) - - block[col ] = mul_by_2[v0] ^ v3 ^ v2 ^ mul_by_3[v1] - block[col+1] = mul_by_2[v1] ^ v0 ^ v3 ^ mul_by_3[v2] - block[col+2] = mul_by_2[v2] ^ v1 ^ v0 ^ mul_by_3[v3] - block[col+3] = mul_by_2[v3] ^ v2 ^ v1 ^ mul_by_3[v0] - - #print 'MixColumns :', block - - def mix_columns_inv(self, block): - """Similar to mix_columns above, but performed in inverse for decryption.""" - - # Cache global multiplication tables (see below) - mul_9 = gf_mul_by_9 - mul_11 = gf_mul_by_11 - mul_13 = gf_mul_by_13 - mul_14 = gf_mul_by_14 - - # Since we're dealing with a transposed matrix, columns are already - # sequential - for i in xrange(4): - col = i * 4 - - v0, v1, v2, v3 = (block[col], block[col + 1], block[col + 2], - block[col + 3]) - #v0, v1, v2, v3 = block[col:col+4] - - block[col ] = mul_14[v0] ^ mul_9[v3] ^ mul_13[v2] ^ mul_11[v1] - block[col+1] = mul_14[v1] ^ mul_9[v0] ^ mul_13[v3] ^ mul_11[v2] - block[col+2] = mul_14[v2] ^ mul_9[v1] ^ mul_13[v0] ^ mul_11[v3] - block[col+3] = mul_14[v3] ^ mul_9[v2] ^ mul_13[v1] ^ mul_11[v0] - - #print 'MixColumns :', block - - def encrypt_block(self, block): - """Encrypts a single block. This is the main AES function""" - - # For efficiency reasons, the state between steps is transmitted via a - # mutable array, not returned. - self.add_round_key(block, 0) - - for round in xrange(1, self.rounds): - self.sub_bytes(block, aes_sbox) - self.shift_rows(block) - self.mix_columns(block) - self.add_round_key(block, round) - - self.sub_bytes(block, aes_sbox) - self.shift_rows(block) - # no mix_columns step in the last round - self.add_round_key(block, self.rounds) - - def decrypt_block(self, block): - """Decrypts a single block. This is the main AES decryption function""" - - # For efficiency reasons, the state between steps is transmitted via a - # mutable array, not returned. - self.add_round_key(block, self.rounds) - - # count rounds down from 15 ... 1 - for round in xrange(self.rounds-1, 0, -1): - self.shift_rows_inv(block) - self.sub_bytes(block, aes_inv_sbox) - self.add_round_key(block, round) - self.mix_columns_inv(block) - - self.shift_rows_inv(block) - self.sub_bytes(block, aes_inv_sbox) - self.add_round_key(block, 0) - # no mix_columns step in the last round - - -#### ECB mode implementation - -class ECBMode(object): - """Electronic CodeBook (ECB) mode encryption. - - Basically this mode applies the cipher function to each block individually; - no feedback is done. NB! This is insecure for almost all purposes - """ - - def __init__(self, cipher): - self.cipher = cipher - self.block_size = cipher.block_size - - def ecb(self, data, block_func): - """Perform ECB mode with the given function""" - - if len(data) % self.block_size != 0: - raise ValueError("Plaintext length must be multiple of 16") - - block_size = self.block_size - data = array('B', data) - - for offset in xrange(0, len(data), block_size): - block = data[offset : offset+block_size] - block_func(block) - data[offset : offset+block_size] = block - - return data.tostring() - - def encrypt(self, data): - """Encrypt data in ECB mode""" - - return self.ecb(data, self.cipher.encrypt_block) - - def decrypt(self, data): - """Decrypt data in ECB mode""" - - return self.ecb(data, self.cipher.decrypt_block) - -#### CBC mode - -class CBCMode(object): - """Cipher Block Chaining (CBC) mode encryption. This mode avoids content leaks. - - In CBC encryption, each plaintext block is XORed with the ciphertext block - preceding it; decryption is simply the inverse. - """ - - # A better explanation of CBC can be found here: - # http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29 - - def __init__(self, cipher, IV): - self.cipher = cipher - self.block_size = cipher.block_size - self.IV = array('B', IV) - - def encrypt(self, data): - """Encrypt data in CBC mode""" - - block_size = self.block_size - if len(data) % block_size != 0: - raise ValueError("Plaintext length must be multiple of 16") - - data = array('B', data) - IV = self.IV - - for offset in xrange(0, len(data), block_size): - block = data[offset : offset+block_size] - - # Perform CBC chaining - for i in xrange(block_size): - block[i] ^= IV[i] - - self.cipher.encrypt_block(block) - data[offset : offset+block_size] = block - IV = block - - self.IV = IV - return data.tostring() - - def decrypt(self, data): - """Decrypt data in CBC mode""" - - block_size = self.block_size - if len(data) % block_size != 0: - raise ValueError("Ciphertext length must be multiple of 16") - - data = array('B', data) - IV = self.IV - - for offset in xrange(0, len(data), block_size): - ctext = data[offset : offset+block_size] - block = ctext[:] - self.cipher.decrypt_block(block) - - # Perform CBC chaining - #for i in xrange(block_size): - # data[offset + i] ^= IV[i] - for i in xrange(block_size): - block[i] ^= IV[i] - data[offset : offset+block_size] = block - - IV = ctext - #data[offset : offset+block_size] = block - - self.IV = IV - return data.tostring() - -#### - -def galois_multiply(a, b): - """Galois Field multiplicaiton for AES""" - p = 0 - while b: - if b & 1: - p ^= a - a <<= 1 - if a & 0x100: - a ^= 0x1b - b >>= 1 - - return p & 0xff - -# Precompute the multiplication tables for encryption -gf_mul_by_2 = array('B', [galois_multiply(x, 2) for x in range(256)]) -gf_mul_by_3 = array('B', [galois_multiply(x, 3) for x in range(256)]) -# ... for decryption -gf_mul_by_9 = array('B', [galois_multiply(x, 9) for x in range(256)]) -gf_mul_by_11 = array('B', [galois_multiply(x, 11) for x in range(256)]) -gf_mul_by_13 = array('B', [galois_multiply(x, 13) for x in range(256)]) -gf_mul_by_14 = array('B', [galois_multiply(x, 14) for x in range(256)]) - -#### - -# The S-box is a 256-element array, that maps a single byte value to another -# byte value. Since it's designed to be reversible, each value occurs only once -# in the S-box -# -# More information: http://en.wikipedia.org/wiki/Rijndael_S-box - -aes_sbox = array('B', - '637c777bf26b6fc53001672bfed7ab76' - 'ca82c97dfa5947f0add4a2af9ca472c0' - 'b7fd9326363ff7cc34a5e5f171d83115' - '04c723c31896059a071280e2eb27b275' - '09832c1a1b6e5aa0523bd6b329e32f84' - '53d100ed20fcb15b6acbbe394a4c58cf' - 'd0efaafb434d338545f9027f503c9fa8' - '51a3408f929d38f5bcb6da2110fff3d2' - 'cd0c13ec5f974417c4a77e3d645d1973' - '60814fdc222a908846eeb814de5e0bdb' - 'e0323a0a4906245cc2d3ac629195e479' - 'e7c8376d8dd54ea96c56f4ea657aae08' - 'ba78252e1ca6b4c6e8dd741f4bbd8b8a' - '703eb5664803f60e613557b986c11d9e' - 'e1f8981169d98e949b1e87e9ce5528df' - '8ca1890dbfe6426841992d0fb054bb16'.decode('hex') -) - -# This is the inverse of the above. In other words: -# aes_inv_sbox[aes_sbox[val]] == val - -aes_inv_sbox = array('B', - '52096ad53036a538bf40a39e81f3d7fb' - '7ce339829b2fff87348e4344c4dee9cb' - '547b9432a6c2233dee4c950b42fac34e' - '082ea16628d924b2765ba2496d8bd125' - '72f8f66486689816d4a45ccc5d65b692' - '6c704850fdedb9da5e154657a78d9d84' - '90d8ab008cbcd30af7e45805b8b34506' - 'd02c1e8fca3f0f02c1afbd0301138a6b' - '3a9111414f67dcea97f2cfcef0b4e673' - '96ac7422e7ad3585e2f937e81c75df6e' - '47f11a711d29c5896fb7620eaa18be1b' - 'fc563e4bc6d279209adbc0fe78cd5af4' - '1fdda8338807c731b11210592780ec5f' - '60517fa919b54a0d2de57a9f93c99cef' - 'a0e03b4dae2af5b0c8ebbb3c83539961' - '172b047eba77d626e169146355210c7d'.decode('hex') -) - -# The Rcon table is used in AES's key schedule (key expansion) -# It's a pre-computed table of exponentation of 2 in AES's finite field -# -# More information: http://en.wikipedia.org/wiki/Rijndael_key_schedule - -aes_Rcon = array('B', - '8d01020408102040801b366cd8ab4d9a' - '2f5ebc63c697356ad4b37dfaefc59139' - '72e4d3bd61c29f254a943366cc831d3a' - '74e8cb8d01020408102040801b366cd8' - 'ab4d9a2f5ebc63c697356ad4b37dfaef' - 'c5913972e4d3bd61c29f254a943366cc' - '831d3a74e8cb8d01020408102040801b' - '366cd8ab4d9a2f5ebc63c697356ad4b3' - '7dfaefc5913972e4d3bd61c29f254a94' - '3366cc831d3a74e8cb8d010204081020' - '40801b366cd8ab4d9a2f5ebc63c69735' - '6ad4b37dfaefc5913972e4d3bd61c29f' - '254a943366cc831d3a74e8cb8d010204' - '08102040801b366cd8ab4d9a2f5ebc63' - 'c697356ad4b37dfaefc5913972e4d3bd' - '61c29f254a943366cc831d3a74e8cb'.decode('hex') -) diff --git a/gluon/contrib/pbkdf2.py b/gluon/contrib/pbkdf2.py index 66b8b287..b7a7dd42 100644 --- a/gluon/contrib/pbkdf2.py +++ b/gluon/contrib/pbkdf2.py @@ -40,26 +40,15 @@ :copyright: (c) Copyright 2011 by Armin Ronacher. :license: BSD, see LICENSE for more details. """ -from __future__ import print_function import hmac -try: - from hashlib import sha1 -except ImportError: - # hashlib not available. Use the old sha module. - import sha as sha1 - +import hashlib from struct import Struct from operator import xor from itertools import izip, starmap -from collections import deque + _pack_int = Struct('>I').pack -try: - from Crypto.Util.strxor import strxor -except ImportError: - def strxor(a, b): - return ''.join(chr(xor(ord(x), ord(y))) for x,y in izip(a, b)) def pbkdf2_hex(data, salt, iterations=1000, keylen=24, hashfunc=None): """Like :func:`pbkdf2_bin` but returns a hex encoded string.""" @@ -72,20 +61,20 @@ def pbkdf2_bin(data, salt, iterations=1000, keylen=24, hashfunc=None): key of `keylen` bytes. By default SHA-1 is used as hash function, a different hashlib `hashfunc` can be provided. """ - hashfunc = hashfunc or sha1 + hashfunc = hashfunc or hashlib.sha1 mac = hmac.new(data, None, hashfunc) def _pseudorandom(x, mac=mac): h = mac.copy() h.update(x) - return h.digest() - buf = deque() + return map(ord, h.digest()) + buf = [] for block in xrange(1, -(-keylen // mac.digest_size) + 1): rv = u = _pseudorandom(salt + _pack_int(block)) for i in xrange(iterations - 1): - u = _pseudorandom(u) - rv = strxor(rv, u) + u = _pseudorandom(''.join(map(chr, u))) + rv = starmap(xor, izip(rv, u)) buf.extend(rv) - return ''.join(buf)[:keylen] + return ''.join(map(chr, buf))[:keylen] def test(): @@ -93,14 +82,14 @@ def test(): def check(data, salt, iterations, keylen, expected): rv = pbkdf2_hex(data, salt, iterations, keylen) if rv != expected: - print('Test failed:') - print(' Expected: %s' % expected) - print(' Got: %s' % rv) - print(' Parameters:') - print(' data=%s' % data) - print(' salt=%s' % salt) - print(' iterations=%d' % iterations) - print() + print 'Test failed:' + print ' Expected: %s' % expected + print ' Got: %s' % rv + print ' Parameters:' + print ' data=%s' % data + print ' salt=%s' % salt + print ' iterations=%d' % iterations + print failed.append(1) # From RFC 6070 @@ -115,8 +104,9 @@ def test(): check('pass\x00word', 'sa\x00lt', 4096, 16, '56fa6aa75548099dcc37d7f03425e0c3') # This one is from the RFC but it just takes for ages - check('password', 'salt', 16777216, 20, - 'eefe3d61cd4da4e4e9945b3d6ba2158c2634e984') + ##check('password', 'salt', 16777216, 20, + ## 'eefe3d61cd4da4e4e9945b3d6ba2158c2634e984') + # From Crypt-PBKDF2 check('password', 'ATHENA.MIT.EDUraeburn', 1, 16, 'cdedb5281bb2f801565a1122b2563515') diff --git a/gluon/contrib/pbkdf2_ctypes.py b/gluon/contrib/pbkdf2_ctypes.py index 4d64a12f..b2a36de3 100644 --- a/gluon/contrib/pbkdf2_ctypes.py +++ b/gluon/contrib/pbkdf2_ctypes.py @@ -18,7 +18,6 @@ :license: LGPLv3 """ -from __future__ import print_function import ctypes import ctypes.util @@ -29,7 +28,7 @@ import binascii import sys __all__ = ['pkcs5_pbkdf2_hmac', 'pbkdf2_bin', 'pbkdf2_hex'] -__version__ = '0.99.3' +__version__ = '0.99.4' def _commoncrypto_hashlib_to_crypto_map_get(hashfunc): hashlib_to_crypto_map = {hashlib.sha1: 1, diff --git a/gluon/contrib/pyaes/LICENSE.txt b/gluon/contrib/pyaes/LICENSE.txt new file mode 100644 index 00000000..0417a6c2 --- /dev/null +++ b/gluon/contrib/pyaes/LICENSE.txt @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2014 Richard Moore + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + diff --git a/gluon/contrib/pyaes/README.md b/gluon/contrib/pyaes/README.md new file mode 100644 index 00000000..05b39f3f --- /dev/null +++ b/gluon/contrib/pyaes/README.md @@ -0,0 +1,363 @@ +pyaes +===== + +A pure-Python implmentation of the AES block cipher algorithm and the common modes of operation (CBC, CFB, CTR, ECB and OFB). + + +Features +-------- + +* Supports all AES key sizes +* Supports all AES common modes +* Pure-Python (no external dependancies) +* BlockFeeder API allows streams to easily be encrypted and decrypted +* Python 2.x and 3.x support (make sure you pass in bytes(), not strings for Python 3) + + +API +--- + +All keys may be 128 bits (16 bytes), 192 bits (24 bytes) or 256 bits (32 bytes) long. + +To generate a random key use: +```python +import os + +# 128 bit, 192 bit and 256 bit keys +key_128 = os.urandom(16) +key_192 = os.urandom(24) +key_256 = os.urandom(32) +``` + +To generate keys from simple-to-remember passwords, consider using a _password-based key-derivation function_ such as [scrypt](https://github.com/ricmoo/pyscrypt). + + +### Common Modes of Operation + +There are many modes of operations, each with various pros and cons. In general though, the **CBC** and **CTR** modes are recommended. The **ECB is NOT recommended.**, and is included primarilty for completeness. + +Each of the following examples assumes the following key: +```python +import pyaes + +# A 256 bit (32 byte) key +key = "This_key_for_demo_purposes_only!" + +# For some modes of operation we need a random initialization vector +# of 16 bytes +iv = "InitializationVe" +``` + + +#### Counter Mode of Operation (recommended) + +```python +aes = pyaes.AESModeOfOperationCTR(key) +plaintext = "Text may be any length you wish, no padding is required" +ciphertext = aes.encrypt(plaintext) + +# '''\xb6\x99\x10=\xa4\x96\x88\xd1\x89\x1co\xe6\x1d\xef;\x11\x03\xe3\xee +# \xa9V?wY\xbfe\xcdO\xe3\xdf\x9dV\x19\xe5\x8dk\x9fh\xb87>\xdb\xa3\xd6 +# \x86\xf4\xbd\xb0\x97\xf1\t\x02\xe9 \xed''' +print repr(ciphertext) + +# The counter mode of operation maintains state, so decryption requires +# a new instance be created +aes = pyaes.AESModeOfOperationCTR(key) +decrypted = aes.decrypt(ciphertext) + +# True +print decrypted == plaintext + +# To use a custom initial value +counter = pyaes.Counter(initial_value = 100) +aes = pyaes.AESModeOfOperationCTR(key, counter = counter) +ciphertext = aes.encrypt(plaintext) + +# '''WZ\x844\x02\xbfoY\x1f\x12\xa6\xce\x03\x82Ei)\xf6\x97mX\x86\xe3\x9d +# _1\xdd\xbd\x87\xb5\xccEM_4\x01$\xa6\x81\x0b\xd5\x04\xd7Al\x07\xe5 +# \xb2\x0e\\\x0f\x00\x13,\x07''' +print repr(ciphertext) +``` + + +#### Cipher-Block Chaining (recommended) + +```python +aes = pyaes.AESModeOfOperationCBC(key, iv = iv) +plaintext = "TextMustBe16Byte" +ciphertext = aes.encrypt(plaintext) + +# '\xd6:\x18\xe6\xb1\xb3\xc3\xdc\x87\xdf\xa7|\x08{k\xb6' +print repr(ciphertext) + + +# The cipher-block chaining mode of operation maintains state, so +# decryption requires a new instance be created +aes = pyaes.AESModeOfOperationCBC(key, iv = iv) +decrypted = aes.decrypt(ciphertext) + +# True +print decrypted == plaintext +``` + + +#### Cipher Feedback + +```python +# Each block into the mode of operation must be a multiple of the segment +# size. For this example we choose 8 bytes. +aes = pyaes.AESModeOfOperationCFB(key, iv = iv, segment_size = 8) +plaintext = "TextMustBeAMultipleOfSegmentSize" +ciphertext = aes.encrypt(plaintext) + +# '''v\xa9\xc1w"\x8aL\x93\xcb\xdf\xa0/\xf8Y\x0b\x8d\x88i\xcb\x85rmp +# \x85\xfe\xafM\x0c)\xd5\xeb\xaf''' +print repr(ciphertext) + + +# The cipher-block chaining mode of operation maintains state, so +# decryption requires a new instance be created +aes = pyaes.AESModeOfOperationCFB(key, iv = iv, segment_size = 8) +decrypted = aes.decrypt(ciphertext) + +# True +print decrypted == plaintext +``` + + +#### Output Feedback Mode of Operation + +```python +aes = pyaes.AESModeOfOperationOFB(key, iv = iv) +plaintext = "Text may be any length you wish, no padding is required" +ciphertext = aes.encrypt(plaintext) + +# '''v\xa9\xc1wO\x92^\x9e\rR\x1e\xf7\xb1\xa2\x9d"l1\xc7\xe7\x9d\x87(\xc26s +# \xdd8\xc8@\xb6\xd9!\xf5\x0cM\xaa\x9b\xc4\xedLD\xe4\xb9\xd8\xdf\x9e\xac +# \xa1\xb8\xea\x0f\x8ev\xb5''' +print repr(ciphertext) + +# The counter mode of operation maintains state, so decryption requires +# a new instance be created +aes = pyaes.AESModeOfOperationOFB(key, iv = iv) +decrypted = aes.decrypt(ciphertext) + +# True +print decrypted == plaintext +``` + + +#### Electronic Codebook (NOT recommended) + +```python +aes = pyaes.AESModeOfOperationECB(key) +plaintext = "TextMustBe16Byte" +ciphertext = aes.encrypt(plaintext) + +# 'L6\x95\x85\xe4\xd9\xf1\x8a\xfb\xe5\x94X\x80|\x19\xc3' +print repr(ciphertext) + +# Since there is no state stored in this mode of operation, it +# is not necessary to create a new aes object for decryption. +#aes = pyaes.AESModeOfOperationECB(key) +decrypted = aes.decrypt(ciphertext) + +# True +print decrypted == plaintext +``` + + +### BlockFeeder + +Since most of the modes of operations require data in specific block-sized or segment-sized blocks, it can be difficult when working with large arbitrary streams or strings of data. + +The BlockFeeder class is meant to make life easier for you, by buffering bytes across multiple calls and returning bytes as they are available, as well as padding or stripping the output when finished, if necessary. + +```python +import pyaes + +# Any mode of operation can be used; for this example CBC +key = "This_key_for_demo_purposes_only!" +iv = "InitializationVe" + +ciphertext = '' + +# We can encrypt one line at a time, regardles of length +encrypter = pyaes.Encrypter(pyaes.AESModeOfOperationCBC(key, iv)) +for line in file('/etc/passwd'): + ciphertext += encrypter.feed(line) + +# Make a final call to flush any remaining bytes and add paddin +ciphertext += encrypter.feed() + +# We can decrypt the cipher text in chunks (here we split it in half) +decrypter = pyaes.Decrypter(pyaes.AESModeOfOperationCBC(key, iv)) +decrypted = decrypter.feed(ciphertext[:len(ciphertext) / 2]) +decrypted += decrypter.feed(ciphertext[len(ciphertext) / 2:]) + +# Again, make a final call to flush any remaining bytes and strip padding +decrypted += decrypter.feed() + +print file('/etc/passwd').read() == decrypted +``` + +### Stream Feeder + +This is meant to make it even easier to encrypt and decrypt streams and large files. + +```python +import pyaes + +# Any mode of operation can be used; for this example CTR +key = "This_key_for_demo_purposes_only!" + +# Create the mode of operation to encrypt with +mode = pyaes.AESModeOfOperationCTR(key) + +# The input and output files +file_in = file('/etc/passwd') +file_out = file('/tmp/encrypted.bin', 'wb') + +# Encrypt the data as a stream, the file is read in 8kb chunks, be default +pyaes.encrypt_stream(mode, file_in, file_out) + +# Close the files +file_in.close() +file_out.close() +``` + +Decrypting is identical, except you would use `pyaes.decrypt_stream`, and the encrypted file would be the `file_in` and target for decryption the `file_out`. + +### AES block cipher + +Generally you should use one of the modes of operation above. This may however be useful for experimenting with a custom mode of operation or dealing with encrypted blocks. + +The block cipher requires exactly one block of data to encrypt or decrypt, and each block should be an array with each element an integer representation of a byte. + +```python +import pyaes + +# 16 byte block of plain text +plaintext = "Hello World!!!!!" +plaintext_bytes = [ ord(c) for c in plaintext ] + +# 32 byte key (256 bit) +key = "This_key_for_demo_purposes_only!" + +# Our AES instance +aes = pyaes.AES(key) + +# Encrypt! +ciphertext = aes.encrypt(plaintext_bytes) + +# [55, 250, 182, 25, 185, 208, 186, 95, 206, 115, 50, 115, 108, 58, 174, 115] +print repr(ciphertext) + +# Decrypt! +decrypted = aes.decrypt(ciphertext) + +# True +print decrypted == plaintext_bytes +``` + +What is a key? +-------------- + +This seems to be a point of confusion for many people new to using encryption. You can think of the key as the *"password"*. However, these algorithms require the *"password"* to be a specific length. + +With AES, there are three possible key lengths, 16-bytes, 24-bytes or 32-bytes. When you create an AES object, the key size is automatically detected, so it is important to pass in a key of the correct length. + +Often, you wish to provide a password of arbitrary length, for example, something easy to remember or write down. In these cases, you must come up with a way to transform the password into a key, of a specific length. A **Password-Based Key Derivation Function** (PBKDF) is an algorithm designed for this exact purpose. + +Here is an example, using the popular (possibly obsolete?) *crypt* PBKDF: + +``` +# See: https://www.dlitz.net/software/python-pbkdf2/ +import pbkdf2 + +password = "HelloWorld" + +# The crypt PBKDF returns a 48-byte string +key = pbkdf2.crypt(password) + +# A 16-byte, 24-byte and 32-byte key, respectively +key_16 = key[:16] +key_24 = key[:24] +key_32 = key[:32] +``` + +The [scrypt](https://github.com/ricmoo/pyscrypt) PBKDF is intentionally slow, to make it more difficult to brute-force guess a password: + +``` +# See: https://github.com/ricmoo/pyscrypt +import pyscrypt + +password = "HelloWorld" + +# Salt is required, and prevents Rainbow Table attacks +salt = "SeaSalt" + +# N, r, and p are parameters to specify how difficult it should be to +# generate a key; bigger numbers take longer and more memory +N = 1024 +r = 1 +p = 1 + +# A 16-byte, 24-byte and 32-byte key, respectively; the scrypt algorithm takes +# a 6-th parameter, indicating key length +key_16 = pyscrypt.hash(password, salt, N, r, p, 16) +key_24 = pyscrypt.hash(password, salt, N, r, p, 24) +key_32 = pyscrypt.hash(password, salt, N, r, p, 32) +``` + +Another possibility, is to use a hashing function, such as SHA256 to hash the password, but this method may be vulnerable to [Rainbow Attacks](http://en.wikipedia.org/wiki/Rainbow_table), unless you use a [salt](http://en.wikipedia.org/wiki/Salt_(cryptography)). + +```python +import hashlib + +password = "HelloWorld" + +# The SHA256 hash algorithm returns a 32-byte string +hashed = hashlib.sha256(password).digest() + +# A 16-byte, 24-byte and 32-byte key, respectively +key_16 = hashed[:16] +key_24 = hashed[:24] +key_32 = hashed +``` + + + + +Performance +----------- + +There is a test case provided in _/tests/test-aes.py_ which does some basic performance testing (its primary purpose is moreso as a regression test). + +Based on that test, in **CPython**, this library is about 30x slower than [PyCrypto](https://www.dlitz.net/software/pycrypto/) for CBC, ECB and OFB; about 80x slower for CFB; and 300x slower for CTR. + +Based on that same test, in **Pypy**, this library is about 4x slower than [PyCrypto](https://www.dlitz.net/software/pycrypto/) for CBC, ECB and OFB; about 12x slower for CFB; and 19x slower for CTR. + +The PyCrypto documentation makes reference to the counter call being responsible for the speed problems of the counter (CTR) mode of operation, which is why they use a specially optimized counter. I will investigate this problem further in the future. + + +FAQ +--- + +#### Why do this? + +The short answer, *why not?* + +The longer answer, is for my [pyscrypt](https://github.com/ricmoo/pyscrypt) library. I required a pure-Python AES implementation that supported 256-bit keys with the counter (CTR) mode of operation. After searching, I found several implementations, but all were missing CTR or only supported 128 bit keys. After all the work of learning AES inside and out to implement the library, it was only a marginal amount of extra work to library-ify a more general solution. So, *why not?* + +#### How do I get a question I have added? + +E-mail me at pyaes@ricmoo.com with any questions, suggestions, comments, et cetera. + + +#### Can I give you my money? + +Umm... Ok? :-) + +_Bitcoin_ - `18UDs4qV1shu2CgTS2tKojhCtM69kpnWg9` diff --git a/gluon/contrib/pyaes/__init__.py b/gluon/contrib/pyaes/__init__.py new file mode 100644 index 00000000..5712f794 --- /dev/null +++ b/gluon/contrib/pyaes/__init__.py @@ -0,0 +1,53 @@ +# The MIT License (MIT) +# +# Copyright (c) 2014 Richard Moore +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +# This is a pure-Python implementation of the AES algorithm and AES common +# modes of operation. + +# See: https://en.wikipedia.org/wiki/Advanced_Encryption_Standard +# See: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation + + +# Supported key sizes: +# 128-bit +# 192-bit +# 256-bit + + +# Supported modes of operation: +# ECB - Electronic Codebook +# CBC - Cipher-Block Chaining +# CFB - Cipher Feedback +# OFB - Output Feedback +# CTR - Counter + +# See the README.md for API details and general information. + +# Also useful, PyCrypto, a crypto library implemented in C with Python bindings: +# https://www.dlitz.net/software/pycrypto/ + + +VERSION = [1, 3, 0] + +from .aes import AES, AESModeOfOperationCTR, AESModeOfOperationCBC, AESModeOfOperationCFB, AESModeOfOperationECB, AESModeOfOperationOFB, AESModesOfOperation, Counter +from .blockfeeder import decrypt_stream, Decrypter, encrypt_stream, Encrypter +from .blockfeeder import PADDING_NONE, PADDING_DEFAULT diff --git a/gluon/contrib/pyaes/aes.py b/gluon/contrib/pyaes/aes.py new file mode 100644 index 00000000..c6e8bc02 --- /dev/null +++ b/gluon/contrib/pyaes/aes.py @@ -0,0 +1,589 @@ +# The MIT License (MIT) +# +# Copyright (c) 2014 Richard Moore +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +# This is a pure-Python implementation of the AES algorithm and AES common +# modes of operation. + +# See: https://en.wikipedia.org/wiki/Advanced_Encryption_Standard + +# Honestly, the best description of the modes of operations are the wonderful +# diagrams on Wikipedia. They explain in moments what my words could never +# achieve. Hence the inline documentation here is sparer than I'd prefer. +# See: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation + +# Also useful, PyCrypto, a crypto library implemented in C with Python bindings: +# https://www.dlitz.net/software/pycrypto/ + + +# Supported key sizes: +# 128-bit +# 192-bit +# 256-bit + + +# Supported modes of operation: +# ECB - Electronic Codebook +# CBC - Cipher-Block Chaining +# CFB - Cipher Feedback +# OFB - Output Feedback +# CTR - Counter + + +# See the README.md for API details and general information. + + +import copy +import struct + +__all__ = ["AES", "AESModeOfOperationCTR", "AESModeOfOperationCBC", "AESModeOfOperationCFB", + "AESModeOfOperationECB", "AESModeOfOperationOFB", "AESModesOfOperation", "Counter"] + + +def _compact_word(word): + return (word[0] << 24) | (word[1] << 16) | (word[2] << 8) | word[3] + +def _string_to_bytes(text): + return list(ord(c) for c in text) + +def _bytes_to_string(binary): + return "".join(chr(b) for b in binary) + +def _concat_list(a, b): + return a + b + + +# Python 3 compatibility +try: + xrange +except Exception: + xrange = range + + # Python 3 supports bytes, which is already an array of integers + def _string_to_bytes(text): + if isinstance(text, bytes): + return text + return [ord(c) for c in text] + + # In Python 3, we return bytes + def _bytes_to_string(binary): + return bytes(binary) + + # Python 3 cannot concatenate a list onto a bytes, so we bytes-ify it first + def _concat_list(a, b): + return a + bytes(b) + + +# Based *largely* on the Rijndael implementation +# See: http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf +class AES(object): + '''Encapsulates the AES block cipher. + + You generally should not need this. Use the AESModeOfOperation classes + below instead.''' + + # Number of rounds by keysize + number_of_rounds = {16: 10, 24: 12, 32: 14} + + # Round constant words + rcon = [ 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91 ] + + # S-box and Inverse S-box (S is for Substitution) + S = [ 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 ] + Si =[ 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d ] + + # Transformations for encryption + T1 = [ 0xc66363a5, 0xf87c7c84, 0xee777799, 0xf67b7b8d, 0xfff2f20d, 0xd66b6bbd, 0xde6f6fb1, 0x91c5c554, 0x60303050, 0x02010103, 0xce6767a9, 0x562b2b7d, 0xe7fefe19, 0xb5d7d762, 0x4dababe6, 0xec76769a, 0x8fcaca45, 0x1f82829d, 0x89c9c940, 0xfa7d7d87, 0xeffafa15, 0xb25959eb, 0x8e4747c9, 0xfbf0f00b, 0x41adadec, 0xb3d4d467, 0x5fa2a2fd, 0x45afafea, 0x239c9cbf, 0x53a4a4f7, 0xe4727296, 0x9bc0c05b, 0x75b7b7c2, 0xe1fdfd1c, 0x3d9393ae, 0x4c26266a, 0x6c36365a, 0x7e3f3f41, 0xf5f7f702, 0x83cccc4f, 0x6834345c, 0x51a5a5f4, 0xd1e5e534, 0xf9f1f108, 0xe2717193, 0xabd8d873, 0x62313153, 0x2a15153f, 0x0804040c, 0x95c7c752, 0x46232365, 0x9dc3c35e, 0x30181828, 0x379696a1, 0x0a05050f, 0x2f9a9ab5, 0x0e070709, 0x24121236, 0x1b80809b, 0xdfe2e23d, 0xcdebeb26, 0x4e272769, 0x7fb2b2cd, 0xea75759f, 0x1209091b, 0x1d83839e, 0x582c2c74, 0x341a1a2e, 0x361b1b2d, 0xdc6e6eb2, 0xb45a5aee, 0x5ba0a0fb, 0xa45252f6, 0x763b3b4d, 0xb7d6d661, 0x7db3b3ce, 0x5229297b, 0xdde3e33e, 0x5e2f2f71, 0x13848497, 0xa65353f5, 0xb9d1d168, 0x00000000, 0xc1eded2c, 0x40202060, 0xe3fcfc1f, 0x79b1b1c8, 0xb65b5bed, 0xd46a6abe, 0x8dcbcb46, 0x67bebed9, 0x7239394b, 0x944a4ade, 0x984c4cd4, 0xb05858e8, 0x85cfcf4a, 0xbbd0d06b, 0xc5efef2a, 0x4faaaae5, 0xedfbfb16, 0x864343c5, 0x9a4d4dd7, 0x66333355, 0x11858594, 0x8a4545cf, 0xe9f9f910, 0x04020206, 0xfe7f7f81, 0xa05050f0, 0x783c3c44, 0x259f9fba, 0x4ba8a8e3, 0xa25151f3, 0x5da3a3fe, 0x804040c0, 0x058f8f8a, 0x3f9292ad, 0x219d9dbc, 0x70383848, 0xf1f5f504, 0x63bcbcdf, 0x77b6b6c1, 0xafdada75, 0x42212163, 0x20101030, 0xe5ffff1a, 0xfdf3f30e, 0xbfd2d26d, 0x81cdcd4c, 0x180c0c14, 0x26131335, 0xc3ecec2f, 0xbe5f5fe1, 0x359797a2, 0x884444cc, 0x2e171739, 0x93c4c457, 0x55a7a7f2, 0xfc7e7e82, 0x7a3d3d47, 0xc86464ac, 0xba5d5de7, 0x3219192b, 0xe6737395, 0xc06060a0, 0x19818198, 0x9e4f4fd1, 0xa3dcdc7f, 0x44222266, 0x542a2a7e, 0x3b9090ab, 0x0b888883, 0x8c4646ca, 0xc7eeee29, 0x6bb8b8d3, 0x2814143c, 0xa7dede79, 0xbc5e5ee2, 0x160b0b1d, 0xaddbdb76, 0xdbe0e03b, 0x64323256, 0x743a3a4e, 0x140a0a1e, 0x924949db, 0x0c06060a, 0x4824246c, 0xb85c5ce4, 0x9fc2c25d, 0xbdd3d36e, 0x43acacef, 0xc46262a6, 0x399191a8, 0x319595a4, 0xd3e4e437, 0xf279798b, 0xd5e7e732, 0x8bc8c843, 0x6e373759, 0xda6d6db7, 0x018d8d8c, 0xb1d5d564, 0x9c4e4ed2, 0x49a9a9e0, 0xd86c6cb4, 0xac5656fa, 0xf3f4f407, 0xcfeaea25, 0xca6565af, 0xf47a7a8e, 0x47aeaee9, 0x10080818, 0x6fbabad5, 0xf0787888, 0x4a25256f, 0x5c2e2e72, 0x381c1c24, 0x57a6a6f1, 0x73b4b4c7, 0x97c6c651, 0xcbe8e823, 0xa1dddd7c, 0xe874749c, 0x3e1f1f21, 0x964b4bdd, 0x61bdbddc, 0x0d8b8b86, 0x0f8a8a85, 0xe0707090, 0x7c3e3e42, 0x71b5b5c4, 0xcc6666aa, 0x904848d8, 0x06030305, 0xf7f6f601, 0x1c0e0e12, 0xc26161a3, 0x6a35355f, 0xae5757f9, 0x69b9b9d0, 0x17868691, 0x99c1c158, 0x3a1d1d27, 0x279e9eb9, 0xd9e1e138, 0xebf8f813, 0x2b9898b3, 0x22111133, 0xd26969bb, 0xa9d9d970, 0x078e8e89, 0x339494a7, 0x2d9b9bb6, 0x3c1e1e22, 0x15878792, 0xc9e9e920, 0x87cece49, 0xaa5555ff, 0x50282878, 0xa5dfdf7a, 0x038c8c8f, 0x59a1a1f8, 0x09898980, 0x1a0d0d17, 0x65bfbfda, 0xd7e6e631, 0x844242c6, 0xd06868b8, 0x824141c3, 0x299999b0, 0x5a2d2d77, 0x1e0f0f11, 0x7bb0b0cb, 0xa85454fc, 0x6dbbbbd6, 0x2c16163a ] + T2 = [ 0xa5c66363, 0x84f87c7c, 0x99ee7777, 0x8df67b7b, 0x0dfff2f2, 0xbdd66b6b, 0xb1de6f6f, 0x5491c5c5, 0x50603030, 0x03020101, 0xa9ce6767, 0x7d562b2b, 0x19e7fefe, 0x62b5d7d7, 0xe64dabab, 0x9aec7676, 0x458fcaca, 0x9d1f8282, 0x4089c9c9, 0x87fa7d7d, 0x15effafa, 0xebb25959, 0xc98e4747, 0x0bfbf0f0, 0xec41adad, 0x67b3d4d4, 0xfd5fa2a2, 0xea45afaf, 0xbf239c9c, 0xf753a4a4, 0x96e47272, 0x5b9bc0c0, 0xc275b7b7, 0x1ce1fdfd, 0xae3d9393, 0x6a4c2626, 0x5a6c3636, 0x417e3f3f, 0x02f5f7f7, 0x4f83cccc, 0x5c683434, 0xf451a5a5, 0x34d1e5e5, 0x08f9f1f1, 0x93e27171, 0x73abd8d8, 0x53623131, 0x3f2a1515, 0x0c080404, 0x5295c7c7, 0x65462323, 0x5e9dc3c3, 0x28301818, 0xa1379696, 0x0f0a0505, 0xb52f9a9a, 0x090e0707, 0x36241212, 0x9b1b8080, 0x3ddfe2e2, 0x26cdebeb, 0x694e2727, 0xcd7fb2b2, 0x9fea7575, 0x1b120909, 0x9e1d8383, 0x74582c2c, 0x2e341a1a, 0x2d361b1b, 0xb2dc6e6e, 0xeeb45a5a, 0xfb5ba0a0, 0xf6a45252, 0x4d763b3b, 0x61b7d6d6, 0xce7db3b3, 0x7b522929, 0x3edde3e3, 0x715e2f2f, 0x97138484, 0xf5a65353, 0x68b9d1d1, 0x00000000, 0x2cc1eded, 0x60402020, 0x1fe3fcfc, 0xc879b1b1, 0xedb65b5b, 0xbed46a6a, 0x468dcbcb, 0xd967bebe, 0x4b723939, 0xde944a4a, 0xd4984c4c, 0xe8b05858, 0x4a85cfcf, 0x6bbbd0d0, 0x2ac5efef, 0xe54faaaa, 0x16edfbfb, 0xc5864343, 0xd79a4d4d, 0x55663333, 0x94118585, 0xcf8a4545, 0x10e9f9f9, 0x06040202, 0x81fe7f7f, 0xf0a05050, 0x44783c3c, 0xba259f9f, 0xe34ba8a8, 0xf3a25151, 0xfe5da3a3, 0xc0804040, 0x8a058f8f, 0xad3f9292, 0xbc219d9d, 0x48703838, 0x04f1f5f5, 0xdf63bcbc, 0xc177b6b6, 0x75afdada, 0x63422121, 0x30201010, 0x1ae5ffff, 0x0efdf3f3, 0x6dbfd2d2, 0x4c81cdcd, 0x14180c0c, 0x35261313, 0x2fc3ecec, 0xe1be5f5f, 0xa2359797, 0xcc884444, 0x392e1717, 0x5793c4c4, 0xf255a7a7, 0x82fc7e7e, 0x477a3d3d, 0xacc86464, 0xe7ba5d5d, 0x2b321919, 0x95e67373, 0xa0c06060, 0x98198181, 0xd19e4f4f, 0x7fa3dcdc, 0x66442222, 0x7e542a2a, 0xab3b9090, 0x830b8888, 0xca8c4646, 0x29c7eeee, 0xd36bb8b8, 0x3c281414, 0x79a7dede, 0xe2bc5e5e, 0x1d160b0b, 0x76addbdb, 0x3bdbe0e0, 0x56643232, 0x4e743a3a, 0x1e140a0a, 0xdb924949, 0x0a0c0606, 0x6c482424, 0xe4b85c5c, 0x5d9fc2c2, 0x6ebdd3d3, 0xef43acac, 0xa6c46262, 0xa8399191, 0xa4319595, 0x37d3e4e4, 0x8bf27979, 0x32d5e7e7, 0x438bc8c8, 0x596e3737, 0xb7da6d6d, 0x8c018d8d, 0x64b1d5d5, 0xd29c4e4e, 0xe049a9a9, 0xb4d86c6c, 0xfaac5656, 0x07f3f4f4, 0x25cfeaea, 0xafca6565, 0x8ef47a7a, 0xe947aeae, 0x18100808, 0xd56fbaba, 0x88f07878, 0x6f4a2525, 0x725c2e2e, 0x24381c1c, 0xf157a6a6, 0xc773b4b4, 0x5197c6c6, 0x23cbe8e8, 0x7ca1dddd, 0x9ce87474, 0x213e1f1f, 0xdd964b4b, 0xdc61bdbd, 0x860d8b8b, 0x850f8a8a, 0x90e07070, 0x427c3e3e, 0xc471b5b5, 0xaacc6666, 0xd8904848, 0x05060303, 0x01f7f6f6, 0x121c0e0e, 0xa3c26161, 0x5f6a3535, 0xf9ae5757, 0xd069b9b9, 0x91178686, 0x5899c1c1, 0x273a1d1d, 0xb9279e9e, 0x38d9e1e1, 0x13ebf8f8, 0xb32b9898, 0x33221111, 0xbbd26969, 0x70a9d9d9, 0x89078e8e, 0xa7339494, 0xb62d9b9b, 0x223c1e1e, 0x92158787, 0x20c9e9e9, 0x4987cece, 0xffaa5555, 0x78502828, 0x7aa5dfdf, 0x8f038c8c, 0xf859a1a1, 0x80098989, 0x171a0d0d, 0xda65bfbf, 0x31d7e6e6, 0xc6844242, 0xb8d06868, 0xc3824141, 0xb0299999, 0x775a2d2d, 0x111e0f0f, 0xcb7bb0b0, 0xfca85454, 0xd66dbbbb, 0x3a2c1616 ] + T3 = [ 0x63a5c663, 0x7c84f87c, 0x7799ee77, 0x7b8df67b, 0xf20dfff2, 0x6bbdd66b, 0x6fb1de6f, 0xc55491c5, 0x30506030, 0x01030201, 0x67a9ce67, 0x2b7d562b, 0xfe19e7fe, 0xd762b5d7, 0xabe64dab, 0x769aec76, 0xca458fca, 0x829d1f82, 0xc94089c9, 0x7d87fa7d, 0xfa15effa, 0x59ebb259, 0x47c98e47, 0xf00bfbf0, 0xadec41ad, 0xd467b3d4, 0xa2fd5fa2, 0xafea45af, 0x9cbf239c, 0xa4f753a4, 0x7296e472, 0xc05b9bc0, 0xb7c275b7, 0xfd1ce1fd, 0x93ae3d93, 0x266a4c26, 0x365a6c36, 0x3f417e3f, 0xf702f5f7, 0xcc4f83cc, 0x345c6834, 0xa5f451a5, 0xe534d1e5, 0xf108f9f1, 0x7193e271, 0xd873abd8, 0x31536231, 0x153f2a15, 0x040c0804, 0xc75295c7, 0x23654623, 0xc35e9dc3, 0x18283018, 0x96a13796, 0x050f0a05, 0x9ab52f9a, 0x07090e07, 0x12362412, 0x809b1b80, 0xe23ddfe2, 0xeb26cdeb, 0x27694e27, 0xb2cd7fb2, 0x759fea75, 0x091b1209, 0x839e1d83, 0x2c74582c, 0x1a2e341a, 0x1b2d361b, 0x6eb2dc6e, 0x5aeeb45a, 0xa0fb5ba0, 0x52f6a452, 0x3b4d763b, 0xd661b7d6, 0xb3ce7db3, 0x297b5229, 0xe33edde3, 0x2f715e2f, 0x84971384, 0x53f5a653, 0xd168b9d1, 0x00000000, 0xed2cc1ed, 0x20604020, 0xfc1fe3fc, 0xb1c879b1, 0x5bedb65b, 0x6abed46a, 0xcb468dcb, 0xbed967be, 0x394b7239, 0x4ade944a, 0x4cd4984c, 0x58e8b058, 0xcf4a85cf, 0xd06bbbd0, 0xef2ac5ef, 0xaae54faa, 0xfb16edfb, 0x43c58643, 0x4dd79a4d, 0x33556633, 0x85941185, 0x45cf8a45, 0xf910e9f9, 0x02060402, 0x7f81fe7f, 0x50f0a050, 0x3c44783c, 0x9fba259f, 0xa8e34ba8, 0x51f3a251, 0xa3fe5da3, 0x40c08040, 0x8f8a058f, 0x92ad3f92, 0x9dbc219d, 0x38487038, 0xf504f1f5, 0xbcdf63bc, 0xb6c177b6, 0xda75afda, 0x21634221, 0x10302010, 0xff1ae5ff, 0xf30efdf3, 0xd26dbfd2, 0xcd4c81cd, 0x0c14180c, 0x13352613, 0xec2fc3ec, 0x5fe1be5f, 0x97a23597, 0x44cc8844, 0x17392e17, 0xc45793c4, 0xa7f255a7, 0x7e82fc7e, 0x3d477a3d, 0x64acc864, 0x5de7ba5d, 0x192b3219, 0x7395e673, 0x60a0c060, 0x81981981, 0x4fd19e4f, 0xdc7fa3dc, 0x22664422, 0x2a7e542a, 0x90ab3b90, 0x88830b88, 0x46ca8c46, 0xee29c7ee, 0xb8d36bb8, 0x143c2814, 0xde79a7de, 0x5ee2bc5e, 0x0b1d160b, 0xdb76addb, 0xe03bdbe0, 0x32566432, 0x3a4e743a, 0x0a1e140a, 0x49db9249, 0x060a0c06, 0x246c4824, 0x5ce4b85c, 0xc25d9fc2, 0xd36ebdd3, 0xacef43ac, 0x62a6c462, 0x91a83991, 0x95a43195, 0xe437d3e4, 0x798bf279, 0xe732d5e7, 0xc8438bc8, 0x37596e37, 0x6db7da6d, 0x8d8c018d, 0xd564b1d5, 0x4ed29c4e, 0xa9e049a9, 0x6cb4d86c, 0x56faac56, 0xf407f3f4, 0xea25cfea, 0x65afca65, 0x7a8ef47a, 0xaee947ae, 0x08181008, 0xbad56fba, 0x7888f078, 0x256f4a25, 0x2e725c2e, 0x1c24381c, 0xa6f157a6, 0xb4c773b4, 0xc65197c6, 0xe823cbe8, 0xdd7ca1dd, 0x749ce874, 0x1f213e1f, 0x4bdd964b, 0xbddc61bd, 0x8b860d8b, 0x8a850f8a, 0x7090e070, 0x3e427c3e, 0xb5c471b5, 0x66aacc66, 0x48d89048, 0x03050603, 0xf601f7f6, 0x0e121c0e, 0x61a3c261, 0x355f6a35, 0x57f9ae57, 0xb9d069b9, 0x86911786, 0xc15899c1, 0x1d273a1d, 0x9eb9279e, 0xe138d9e1, 0xf813ebf8, 0x98b32b98, 0x11332211, 0x69bbd269, 0xd970a9d9, 0x8e89078e, 0x94a73394, 0x9bb62d9b, 0x1e223c1e, 0x87921587, 0xe920c9e9, 0xce4987ce, 0x55ffaa55, 0x28785028, 0xdf7aa5df, 0x8c8f038c, 0xa1f859a1, 0x89800989, 0x0d171a0d, 0xbfda65bf, 0xe631d7e6, 0x42c68442, 0x68b8d068, 0x41c38241, 0x99b02999, 0x2d775a2d, 0x0f111e0f, 0xb0cb7bb0, 0x54fca854, 0xbbd66dbb, 0x163a2c16 ] + T4 = [ 0x6363a5c6, 0x7c7c84f8, 0x777799ee, 0x7b7b8df6, 0xf2f20dff, 0x6b6bbdd6, 0x6f6fb1de, 0xc5c55491, 0x30305060, 0x01010302, 0x6767a9ce, 0x2b2b7d56, 0xfefe19e7, 0xd7d762b5, 0xababe64d, 0x76769aec, 0xcaca458f, 0x82829d1f, 0xc9c94089, 0x7d7d87fa, 0xfafa15ef, 0x5959ebb2, 0x4747c98e, 0xf0f00bfb, 0xadadec41, 0xd4d467b3, 0xa2a2fd5f, 0xafafea45, 0x9c9cbf23, 0xa4a4f753, 0x727296e4, 0xc0c05b9b, 0xb7b7c275, 0xfdfd1ce1, 0x9393ae3d, 0x26266a4c, 0x36365a6c, 0x3f3f417e, 0xf7f702f5, 0xcccc4f83, 0x34345c68, 0xa5a5f451, 0xe5e534d1, 0xf1f108f9, 0x717193e2, 0xd8d873ab, 0x31315362, 0x15153f2a, 0x04040c08, 0xc7c75295, 0x23236546, 0xc3c35e9d, 0x18182830, 0x9696a137, 0x05050f0a, 0x9a9ab52f, 0x0707090e, 0x12123624, 0x80809b1b, 0xe2e23ddf, 0xebeb26cd, 0x2727694e, 0xb2b2cd7f, 0x75759fea, 0x09091b12, 0x83839e1d, 0x2c2c7458, 0x1a1a2e34, 0x1b1b2d36, 0x6e6eb2dc, 0x5a5aeeb4, 0xa0a0fb5b, 0x5252f6a4, 0x3b3b4d76, 0xd6d661b7, 0xb3b3ce7d, 0x29297b52, 0xe3e33edd, 0x2f2f715e, 0x84849713, 0x5353f5a6, 0xd1d168b9, 0x00000000, 0xeded2cc1, 0x20206040, 0xfcfc1fe3, 0xb1b1c879, 0x5b5bedb6, 0x6a6abed4, 0xcbcb468d, 0xbebed967, 0x39394b72, 0x4a4ade94, 0x4c4cd498, 0x5858e8b0, 0xcfcf4a85, 0xd0d06bbb, 0xefef2ac5, 0xaaaae54f, 0xfbfb16ed, 0x4343c586, 0x4d4dd79a, 0x33335566, 0x85859411, 0x4545cf8a, 0xf9f910e9, 0x02020604, 0x7f7f81fe, 0x5050f0a0, 0x3c3c4478, 0x9f9fba25, 0xa8a8e34b, 0x5151f3a2, 0xa3a3fe5d, 0x4040c080, 0x8f8f8a05, 0x9292ad3f, 0x9d9dbc21, 0x38384870, 0xf5f504f1, 0xbcbcdf63, 0xb6b6c177, 0xdada75af, 0x21216342, 0x10103020, 0xffff1ae5, 0xf3f30efd, 0xd2d26dbf, 0xcdcd4c81, 0x0c0c1418, 0x13133526, 0xecec2fc3, 0x5f5fe1be, 0x9797a235, 0x4444cc88, 0x1717392e, 0xc4c45793, 0xa7a7f255, 0x7e7e82fc, 0x3d3d477a, 0x6464acc8, 0x5d5de7ba, 0x19192b32, 0x737395e6, 0x6060a0c0, 0x81819819, 0x4f4fd19e, 0xdcdc7fa3, 0x22226644, 0x2a2a7e54, 0x9090ab3b, 0x8888830b, 0x4646ca8c, 0xeeee29c7, 0xb8b8d36b, 0x14143c28, 0xdede79a7, 0x5e5ee2bc, 0x0b0b1d16, 0xdbdb76ad, 0xe0e03bdb, 0x32325664, 0x3a3a4e74, 0x0a0a1e14, 0x4949db92, 0x06060a0c, 0x24246c48, 0x5c5ce4b8, 0xc2c25d9f, 0xd3d36ebd, 0xacacef43, 0x6262a6c4, 0x9191a839, 0x9595a431, 0xe4e437d3, 0x79798bf2, 0xe7e732d5, 0xc8c8438b, 0x3737596e, 0x6d6db7da, 0x8d8d8c01, 0xd5d564b1, 0x4e4ed29c, 0xa9a9e049, 0x6c6cb4d8, 0x5656faac, 0xf4f407f3, 0xeaea25cf, 0x6565afca, 0x7a7a8ef4, 0xaeaee947, 0x08081810, 0xbabad56f, 0x787888f0, 0x25256f4a, 0x2e2e725c, 0x1c1c2438, 0xa6a6f157, 0xb4b4c773, 0xc6c65197, 0xe8e823cb, 0xdddd7ca1, 0x74749ce8, 0x1f1f213e, 0x4b4bdd96, 0xbdbddc61, 0x8b8b860d, 0x8a8a850f, 0x707090e0, 0x3e3e427c, 0xb5b5c471, 0x6666aacc, 0x4848d890, 0x03030506, 0xf6f601f7, 0x0e0e121c, 0x6161a3c2, 0x35355f6a, 0x5757f9ae, 0xb9b9d069, 0x86869117, 0xc1c15899, 0x1d1d273a, 0x9e9eb927, 0xe1e138d9, 0xf8f813eb, 0x9898b32b, 0x11113322, 0x6969bbd2, 0xd9d970a9, 0x8e8e8907, 0x9494a733, 0x9b9bb62d, 0x1e1e223c, 0x87879215, 0xe9e920c9, 0xcece4987, 0x5555ffaa, 0x28287850, 0xdfdf7aa5, 0x8c8c8f03, 0xa1a1f859, 0x89898009, 0x0d0d171a, 0xbfbfda65, 0xe6e631d7, 0x4242c684, 0x6868b8d0, 0x4141c382, 0x9999b029, 0x2d2d775a, 0x0f0f111e, 0xb0b0cb7b, 0x5454fca8, 0xbbbbd66d, 0x16163a2c ] + + # Transformations for decryption + T5 = [ 0x51f4a750, 0x7e416553, 0x1a17a4c3, 0x3a275e96, 0x3bab6bcb, 0x1f9d45f1, 0xacfa58ab, 0x4be30393, 0x2030fa55, 0xad766df6, 0x88cc7691, 0xf5024c25, 0x4fe5d7fc, 0xc52acbd7, 0x26354480, 0xb562a38f, 0xdeb15a49, 0x25ba1b67, 0x45ea0e98, 0x5dfec0e1, 0xc32f7502, 0x814cf012, 0x8d4697a3, 0x6bd3f9c6, 0x038f5fe7, 0x15929c95, 0xbf6d7aeb, 0x955259da, 0xd4be832d, 0x587421d3, 0x49e06929, 0x8ec9c844, 0x75c2896a, 0xf48e7978, 0x99583e6b, 0x27b971dd, 0xbee14fb6, 0xf088ad17, 0xc920ac66, 0x7dce3ab4, 0x63df4a18, 0xe51a3182, 0x97513360, 0x62537f45, 0xb16477e0, 0xbb6bae84, 0xfe81a01c, 0xf9082b94, 0x70486858, 0x8f45fd19, 0x94de6c87, 0x527bf8b7, 0xab73d323, 0x724b02e2, 0xe31f8f57, 0x6655ab2a, 0xb2eb2807, 0x2fb5c203, 0x86c57b9a, 0xd33708a5, 0x302887f2, 0x23bfa5b2, 0x02036aba, 0xed16825c, 0x8acf1c2b, 0xa779b492, 0xf307f2f0, 0x4e69e2a1, 0x65daf4cd, 0x0605bed5, 0xd134621f, 0xc4a6fe8a, 0x342e539d, 0xa2f355a0, 0x058ae132, 0xa4f6eb75, 0x0b83ec39, 0x4060efaa, 0x5e719f06, 0xbd6e1051, 0x3e218af9, 0x96dd063d, 0xdd3e05ae, 0x4de6bd46, 0x91548db5, 0x71c45d05, 0x0406d46f, 0x605015ff, 0x1998fb24, 0xd6bde997, 0x894043cc, 0x67d99e77, 0xb0e842bd, 0x07898b88, 0xe7195b38, 0x79c8eedb, 0xa17c0a47, 0x7c420fe9, 0xf8841ec9, 0x00000000, 0x09808683, 0x322bed48, 0x1e1170ac, 0x6c5a724e, 0xfd0efffb, 0x0f853856, 0x3daed51e, 0x362d3927, 0x0a0fd964, 0x685ca621, 0x9b5b54d1, 0x24362e3a, 0x0c0a67b1, 0x9357e70f, 0xb4ee96d2, 0x1b9b919e, 0x80c0c54f, 0x61dc20a2, 0x5a774b69, 0x1c121a16, 0xe293ba0a, 0xc0a02ae5, 0x3c22e043, 0x121b171d, 0x0e090d0b, 0xf28bc7ad, 0x2db6a8b9, 0x141ea9c8, 0x57f11985, 0xaf75074c, 0xee99ddbb, 0xa37f60fd, 0xf701269f, 0x5c72f5bc, 0x44663bc5, 0x5bfb7e34, 0x8b432976, 0xcb23c6dc, 0xb6edfc68, 0xb8e4f163, 0xd731dcca, 0x42638510, 0x13972240, 0x84c61120, 0x854a247d, 0xd2bb3df8, 0xaef93211, 0xc729a16d, 0x1d9e2f4b, 0xdcb230f3, 0x0d8652ec, 0x77c1e3d0, 0x2bb3166c, 0xa970b999, 0x119448fa, 0x47e96422, 0xa8fc8cc4, 0xa0f03f1a, 0x567d2cd8, 0x223390ef, 0x87494ec7, 0xd938d1c1, 0x8ccaa2fe, 0x98d40b36, 0xa6f581cf, 0xa57ade28, 0xdab78e26, 0x3fadbfa4, 0x2c3a9de4, 0x5078920d, 0x6a5fcc9b, 0x547e4662, 0xf68d13c2, 0x90d8b8e8, 0x2e39f75e, 0x82c3aff5, 0x9f5d80be, 0x69d0937c, 0x6fd52da9, 0xcf2512b3, 0xc8ac993b, 0x10187da7, 0xe89c636e, 0xdb3bbb7b, 0xcd267809, 0x6e5918f4, 0xec9ab701, 0x834f9aa8, 0xe6956e65, 0xaaffe67e, 0x21bccf08, 0xef15e8e6, 0xbae79bd9, 0x4a6f36ce, 0xea9f09d4, 0x29b07cd6, 0x31a4b2af, 0x2a3f2331, 0xc6a59430, 0x35a266c0, 0x744ebc37, 0xfc82caa6, 0xe090d0b0, 0x33a7d815, 0xf104984a, 0x41ecdaf7, 0x7fcd500e, 0x1791f62f, 0x764dd68d, 0x43efb04d, 0xccaa4d54, 0xe49604df, 0x9ed1b5e3, 0x4c6a881b, 0xc12c1fb8, 0x4665517f, 0x9d5eea04, 0x018c355d, 0xfa877473, 0xfb0b412e, 0xb3671d5a, 0x92dbd252, 0xe9105633, 0x6dd64713, 0x9ad7618c, 0x37a10c7a, 0x59f8148e, 0xeb133c89, 0xcea927ee, 0xb761c935, 0xe11ce5ed, 0x7a47b13c, 0x9cd2df59, 0x55f2733f, 0x1814ce79, 0x73c737bf, 0x53f7cdea, 0x5ffdaa5b, 0xdf3d6f14, 0x7844db86, 0xcaaff381, 0xb968c43e, 0x3824342c, 0xc2a3405f, 0x161dc372, 0xbce2250c, 0x283c498b, 0xff0d9541, 0x39a80171, 0x080cb3de, 0xd8b4e49c, 0x6456c190, 0x7bcb8461, 0xd532b670, 0x486c5c74, 0xd0b85742 ] + T6 = [ 0x5051f4a7, 0x537e4165, 0xc31a17a4, 0x963a275e, 0xcb3bab6b, 0xf11f9d45, 0xabacfa58, 0x934be303, 0x552030fa, 0xf6ad766d, 0x9188cc76, 0x25f5024c, 0xfc4fe5d7, 0xd7c52acb, 0x80263544, 0x8fb562a3, 0x49deb15a, 0x6725ba1b, 0x9845ea0e, 0xe15dfec0, 0x02c32f75, 0x12814cf0, 0xa38d4697, 0xc66bd3f9, 0xe7038f5f, 0x9515929c, 0xebbf6d7a, 0xda955259, 0x2dd4be83, 0xd3587421, 0x2949e069, 0x448ec9c8, 0x6a75c289, 0x78f48e79, 0x6b99583e, 0xdd27b971, 0xb6bee14f, 0x17f088ad, 0x66c920ac, 0xb47dce3a, 0x1863df4a, 0x82e51a31, 0x60975133, 0x4562537f, 0xe0b16477, 0x84bb6bae, 0x1cfe81a0, 0x94f9082b, 0x58704868, 0x198f45fd, 0x8794de6c, 0xb7527bf8, 0x23ab73d3, 0xe2724b02, 0x57e31f8f, 0x2a6655ab, 0x07b2eb28, 0x032fb5c2, 0x9a86c57b, 0xa5d33708, 0xf2302887, 0xb223bfa5, 0xba02036a, 0x5ced1682, 0x2b8acf1c, 0x92a779b4, 0xf0f307f2, 0xa14e69e2, 0xcd65daf4, 0xd50605be, 0x1fd13462, 0x8ac4a6fe, 0x9d342e53, 0xa0a2f355, 0x32058ae1, 0x75a4f6eb, 0x390b83ec, 0xaa4060ef, 0x065e719f, 0x51bd6e10, 0xf93e218a, 0x3d96dd06, 0xaedd3e05, 0x464de6bd, 0xb591548d, 0x0571c45d, 0x6f0406d4, 0xff605015, 0x241998fb, 0x97d6bde9, 0xcc894043, 0x7767d99e, 0xbdb0e842, 0x8807898b, 0x38e7195b, 0xdb79c8ee, 0x47a17c0a, 0xe97c420f, 0xc9f8841e, 0x00000000, 0x83098086, 0x48322bed, 0xac1e1170, 0x4e6c5a72, 0xfbfd0eff, 0x560f8538, 0x1e3daed5, 0x27362d39, 0x640a0fd9, 0x21685ca6, 0xd19b5b54, 0x3a24362e, 0xb10c0a67, 0x0f9357e7, 0xd2b4ee96, 0x9e1b9b91, 0x4f80c0c5, 0xa261dc20, 0x695a774b, 0x161c121a, 0x0ae293ba, 0xe5c0a02a, 0x433c22e0, 0x1d121b17, 0x0b0e090d, 0xadf28bc7, 0xb92db6a8, 0xc8141ea9, 0x8557f119, 0x4caf7507, 0xbbee99dd, 0xfda37f60, 0x9ff70126, 0xbc5c72f5, 0xc544663b, 0x345bfb7e, 0x768b4329, 0xdccb23c6, 0x68b6edfc, 0x63b8e4f1, 0xcad731dc, 0x10426385, 0x40139722, 0x2084c611, 0x7d854a24, 0xf8d2bb3d, 0x11aef932, 0x6dc729a1, 0x4b1d9e2f, 0xf3dcb230, 0xec0d8652, 0xd077c1e3, 0x6c2bb316, 0x99a970b9, 0xfa119448, 0x2247e964, 0xc4a8fc8c, 0x1aa0f03f, 0xd8567d2c, 0xef223390, 0xc787494e, 0xc1d938d1, 0xfe8ccaa2, 0x3698d40b, 0xcfa6f581, 0x28a57ade, 0x26dab78e, 0xa43fadbf, 0xe42c3a9d, 0x0d507892, 0x9b6a5fcc, 0x62547e46, 0xc2f68d13, 0xe890d8b8, 0x5e2e39f7, 0xf582c3af, 0xbe9f5d80, 0x7c69d093, 0xa96fd52d, 0xb3cf2512, 0x3bc8ac99, 0xa710187d, 0x6ee89c63, 0x7bdb3bbb, 0x09cd2678, 0xf46e5918, 0x01ec9ab7, 0xa8834f9a, 0x65e6956e, 0x7eaaffe6, 0x0821bccf, 0xe6ef15e8, 0xd9bae79b, 0xce4a6f36, 0xd4ea9f09, 0xd629b07c, 0xaf31a4b2, 0x312a3f23, 0x30c6a594, 0xc035a266, 0x37744ebc, 0xa6fc82ca, 0xb0e090d0, 0x1533a7d8, 0x4af10498, 0xf741ecda, 0x0e7fcd50, 0x2f1791f6, 0x8d764dd6, 0x4d43efb0, 0x54ccaa4d, 0xdfe49604, 0xe39ed1b5, 0x1b4c6a88, 0xb8c12c1f, 0x7f466551, 0x049d5eea, 0x5d018c35, 0x73fa8774, 0x2efb0b41, 0x5ab3671d, 0x5292dbd2, 0x33e91056, 0x136dd647, 0x8c9ad761, 0x7a37a10c, 0x8e59f814, 0x89eb133c, 0xeecea927, 0x35b761c9, 0xede11ce5, 0x3c7a47b1, 0x599cd2df, 0x3f55f273, 0x791814ce, 0xbf73c737, 0xea53f7cd, 0x5b5ffdaa, 0x14df3d6f, 0x867844db, 0x81caaff3, 0x3eb968c4, 0x2c382434, 0x5fc2a340, 0x72161dc3, 0x0cbce225, 0x8b283c49, 0x41ff0d95, 0x7139a801, 0xde080cb3, 0x9cd8b4e4, 0x906456c1, 0x617bcb84, 0x70d532b6, 0x74486c5c, 0x42d0b857 ] + T7 = [ 0xa75051f4, 0x65537e41, 0xa4c31a17, 0x5e963a27, 0x6bcb3bab, 0x45f11f9d, 0x58abacfa, 0x03934be3, 0xfa552030, 0x6df6ad76, 0x769188cc, 0x4c25f502, 0xd7fc4fe5, 0xcbd7c52a, 0x44802635, 0xa38fb562, 0x5a49deb1, 0x1b6725ba, 0x0e9845ea, 0xc0e15dfe, 0x7502c32f, 0xf012814c, 0x97a38d46, 0xf9c66bd3, 0x5fe7038f, 0x9c951592, 0x7aebbf6d, 0x59da9552, 0x832dd4be, 0x21d35874, 0x692949e0, 0xc8448ec9, 0x896a75c2, 0x7978f48e, 0x3e6b9958, 0x71dd27b9, 0x4fb6bee1, 0xad17f088, 0xac66c920, 0x3ab47dce, 0x4a1863df, 0x3182e51a, 0x33609751, 0x7f456253, 0x77e0b164, 0xae84bb6b, 0xa01cfe81, 0x2b94f908, 0x68587048, 0xfd198f45, 0x6c8794de, 0xf8b7527b, 0xd323ab73, 0x02e2724b, 0x8f57e31f, 0xab2a6655, 0x2807b2eb, 0xc2032fb5, 0x7b9a86c5, 0x08a5d337, 0x87f23028, 0xa5b223bf, 0x6aba0203, 0x825ced16, 0x1c2b8acf, 0xb492a779, 0xf2f0f307, 0xe2a14e69, 0xf4cd65da, 0xbed50605, 0x621fd134, 0xfe8ac4a6, 0x539d342e, 0x55a0a2f3, 0xe132058a, 0xeb75a4f6, 0xec390b83, 0xefaa4060, 0x9f065e71, 0x1051bd6e, 0x8af93e21, 0x063d96dd, 0x05aedd3e, 0xbd464de6, 0x8db59154, 0x5d0571c4, 0xd46f0406, 0x15ff6050, 0xfb241998, 0xe997d6bd, 0x43cc8940, 0x9e7767d9, 0x42bdb0e8, 0x8b880789, 0x5b38e719, 0xeedb79c8, 0x0a47a17c, 0x0fe97c42, 0x1ec9f884, 0x00000000, 0x86830980, 0xed48322b, 0x70ac1e11, 0x724e6c5a, 0xfffbfd0e, 0x38560f85, 0xd51e3dae, 0x3927362d, 0xd9640a0f, 0xa621685c, 0x54d19b5b, 0x2e3a2436, 0x67b10c0a, 0xe70f9357, 0x96d2b4ee, 0x919e1b9b, 0xc54f80c0, 0x20a261dc, 0x4b695a77, 0x1a161c12, 0xba0ae293, 0x2ae5c0a0, 0xe0433c22, 0x171d121b, 0x0d0b0e09, 0xc7adf28b, 0xa8b92db6, 0xa9c8141e, 0x198557f1, 0x074caf75, 0xddbbee99, 0x60fda37f, 0x269ff701, 0xf5bc5c72, 0x3bc54466, 0x7e345bfb, 0x29768b43, 0xc6dccb23, 0xfc68b6ed, 0xf163b8e4, 0xdccad731, 0x85104263, 0x22401397, 0x112084c6, 0x247d854a, 0x3df8d2bb, 0x3211aef9, 0xa16dc729, 0x2f4b1d9e, 0x30f3dcb2, 0x52ec0d86, 0xe3d077c1, 0x166c2bb3, 0xb999a970, 0x48fa1194, 0x642247e9, 0x8cc4a8fc, 0x3f1aa0f0, 0x2cd8567d, 0x90ef2233, 0x4ec78749, 0xd1c1d938, 0xa2fe8cca, 0x0b3698d4, 0x81cfa6f5, 0xde28a57a, 0x8e26dab7, 0xbfa43fad, 0x9de42c3a, 0x920d5078, 0xcc9b6a5f, 0x4662547e, 0x13c2f68d, 0xb8e890d8, 0xf75e2e39, 0xaff582c3, 0x80be9f5d, 0x937c69d0, 0x2da96fd5, 0x12b3cf25, 0x993bc8ac, 0x7da71018, 0x636ee89c, 0xbb7bdb3b, 0x7809cd26, 0x18f46e59, 0xb701ec9a, 0x9aa8834f, 0x6e65e695, 0xe67eaaff, 0xcf0821bc, 0xe8e6ef15, 0x9bd9bae7, 0x36ce4a6f, 0x09d4ea9f, 0x7cd629b0, 0xb2af31a4, 0x23312a3f, 0x9430c6a5, 0x66c035a2, 0xbc37744e, 0xcaa6fc82, 0xd0b0e090, 0xd81533a7, 0x984af104, 0xdaf741ec, 0x500e7fcd, 0xf62f1791, 0xd68d764d, 0xb04d43ef, 0x4d54ccaa, 0x04dfe496, 0xb5e39ed1, 0x881b4c6a, 0x1fb8c12c, 0x517f4665, 0xea049d5e, 0x355d018c, 0x7473fa87, 0x412efb0b, 0x1d5ab367, 0xd25292db, 0x5633e910, 0x47136dd6, 0x618c9ad7, 0x0c7a37a1, 0x148e59f8, 0x3c89eb13, 0x27eecea9, 0xc935b761, 0xe5ede11c, 0xb13c7a47, 0xdf599cd2, 0x733f55f2, 0xce791814, 0x37bf73c7, 0xcdea53f7, 0xaa5b5ffd, 0x6f14df3d, 0xdb867844, 0xf381caaf, 0xc43eb968, 0x342c3824, 0x405fc2a3, 0xc372161d, 0x250cbce2, 0x498b283c, 0x9541ff0d, 0x017139a8, 0xb3de080c, 0xe49cd8b4, 0xc1906456, 0x84617bcb, 0xb670d532, 0x5c74486c, 0x5742d0b8 ] + T8 = [ 0xf4a75051, 0x4165537e, 0x17a4c31a, 0x275e963a, 0xab6bcb3b, 0x9d45f11f, 0xfa58abac, 0xe303934b, 0x30fa5520, 0x766df6ad, 0xcc769188, 0x024c25f5, 0xe5d7fc4f, 0x2acbd7c5, 0x35448026, 0x62a38fb5, 0xb15a49de, 0xba1b6725, 0xea0e9845, 0xfec0e15d, 0x2f7502c3, 0x4cf01281, 0x4697a38d, 0xd3f9c66b, 0x8f5fe703, 0x929c9515, 0x6d7aebbf, 0x5259da95, 0xbe832dd4, 0x7421d358, 0xe0692949, 0xc9c8448e, 0xc2896a75, 0x8e7978f4, 0x583e6b99, 0xb971dd27, 0xe14fb6be, 0x88ad17f0, 0x20ac66c9, 0xce3ab47d, 0xdf4a1863, 0x1a3182e5, 0x51336097, 0x537f4562, 0x6477e0b1, 0x6bae84bb, 0x81a01cfe, 0x082b94f9, 0x48685870, 0x45fd198f, 0xde6c8794, 0x7bf8b752, 0x73d323ab, 0x4b02e272, 0x1f8f57e3, 0x55ab2a66, 0xeb2807b2, 0xb5c2032f, 0xc57b9a86, 0x3708a5d3, 0x2887f230, 0xbfa5b223, 0x036aba02, 0x16825ced, 0xcf1c2b8a, 0x79b492a7, 0x07f2f0f3, 0x69e2a14e, 0xdaf4cd65, 0x05bed506, 0x34621fd1, 0xa6fe8ac4, 0x2e539d34, 0xf355a0a2, 0x8ae13205, 0xf6eb75a4, 0x83ec390b, 0x60efaa40, 0x719f065e, 0x6e1051bd, 0x218af93e, 0xdd063d96, 0x3e05aedd, 0xe6bd464d, 0x548db591, 0xc45d0571, 0x06d46f04, 0x5015ff60, 0x98fb2419, 0xbde997d6, 0x4043cc89, 0xd99e7767, 0xe842bdb0, 0x898b8807, 0x195b38e7, 0xc8eedb79, 0x7c0a47a1, 0x420fe97c, 0x841ec9f8, 0x00000000, 0x80868309, 0x2bed4832, 0x1170ac1e, 0x5a724e6c, 0x0efffbfd, 0x8538560f, 0xaed51e3d, 0x2d392736, 0x0fd9640a, 0x5ca62168, 0x5b54d19b, 0x362e3a24, 0x0a67b10c, 0x57e70f93, 0xee96d2b4, 0x9b919e1b, 0xc0c54f80, 0xdc20a261, 0x774b695a, 0x121a161c, 0x93ba0ae2, 0xa02ae5c0, 0x22e0433c, 0x1b171d12, 0x090d0b0e, 0x8bc7adf2, 0xb6a8b92d, 0x1ea9c814, 0xf1198557, 0x75074caf, 0x99ddbbee, 0x7f60fda3, 0x01269ff7, 0x72f5bc5c, 0x663bc544, 0xfb7e345b, 0x4329768b, 0x23c6dccb, 0xedfc68b6, 0xe4f163b8, 0x31dccad7, 0x63851042, 0x97224013, 0xc6112084, 0x4a247d85, 0xbb3df8d2, 0xf93211ae, 0x29a16dc7, 0x9e2f4b1d, 0xb230f3dc, 0x8652ec0d, 0xc1e3d077, 0xb3166c2b, 0x70b999a9, 0x9448fa11, 0xe9642247, 0xfc8cc4a8, 0xf03f1aa0, 0x7d2cd856, 0x3390ef22, 0x494ec787, 0x38d1c1d9, 0xcaa2fe8c, 0xd40b3698, 0xf581cfa6, 0x7ade28a5, 0xb78e26da, 0xadbfa43f, 0x3a9de42c, 0x78920d50, 0x5fcc9b6a, 0x7e466254, 0x8d13c2f6, 0xd8b8e890, 0x39f75e2e, 0xc3aff582, 0x5d80be9f, 0xd0937c69, 0xd52da96f, 0x2512b3cf, 0xac993bc8, 0x187da710, 0x9c636ee8, 0x3bbb7bdb, 0x267809cd, 0x5918f46e, 0x9ab701ec, 0x4f9aa883, 0x956e65e6, 0xffe67eaa, 0xbccf0821, 0x15e8e6ef, 0xe79bd9ba, 0x6f36ce4a, 0x9f09d4ea, 0xb07cd629, 0xa4b2af31, 0x3f23312a, 0xa59430c6, 0xa266c035, 0x4ebc3774, 0x82caa6fc, 0x90d0b0e0, 0xa7d81533, 0x04984af1, 0xecdaf741, 0xcd500e7f, 0x91f62f17, 0x4dd68d76, 0xefb04d43, 0xaa4d54cc, 0x9604dfe4, 0xd1b5e39e, 0x6a881b4c, 0x2c1fb8c1, 0x65517f46, 0x5eea049d, 0x8c355d01, 0x877473fa, 0x0b412efb, 0x671d5ab3, 0xdbd25292, 0x105633e9, 0xd647136d, 0xd7618c9a, 0xa10c7a37, 0xf8148e59, 0x133c89eb, 0xa927eece, 0x61c935b7, 0x1ce5ede1, 0x47b13c7a, 0xd2df599c, 0xf2733f55, 0x14ce7918, 0xc737bf73, 0xf7cdea53, 0xfdaa5b5f, 0x3d6f14df, 0x44db8678, 0xaff381ca, 0x68c43eb9, 0x24342c38, 0xa3405fc2, 0x1dc37216, 0xe2250cbc, 0x3c498b28, 0x0d9541ff, 0xa8017139, 0x0cb3de08, 0xb4e49cd8, 0x56c19064, 0xcb84617b, 0x32b670d5, 0x6c5c7448, 0xb85742d0 ] + + # Transformations for decryption key expansion + U1 = [ 0x00000000, 0x0e090d0b, 0x1c121a16, 0x121b171d, 0x3824342c, 0x362d3927, 0x24362e3a, 0x2a3f2331, 0x70486858, 0x7e416553, 0x6c5a724e, 0x62537f45, 0x486c5c74, 0x4665517f, 0x547e4662, 0x5a774b69, 0xe090d0b0, 0xee99ddbb, 0xfc82caa6, 0xf28bc7ad, 0xd8b4e49c, 0xd6bde997, 0xc4a6fe8a, 0xcaaff381, 0x90d8b8e8, 0x9ed1b5e3, 0x8ccaa2fe, 0x82c3aff5, 0xa8fc8cc4, 0xa6f581cf, 0xb4ee96d2, 0xbae79bd9, 0xdb3bbb7b, 0xd532b670, 0xc729a16d, 0xc920ac66, 0xe31f8f57, 0xed16825c, 0xff0d9541, 0xf104984a, 0xab73d323, 0xa57ade28, 0xb761c935, 0xb968c43e, 0x9357e70f, 0x9d5eea04, 0x8f45fd19, 0x814cf012, 0x3bab6bcb, 0x35a266c0, 0x27b971dd, 0x29b07cd6, 0x038f5fe7, 0x0d8652ec, 0x1f9d45f1, 0x119448fa, 0x4be30393, 0x45ea0e98, 0x57f11985, 0x59f8148e, 0x73c737bf, 0x7dce3ab4, 0x6fd52da9, 0x61dc20a2, 0xad766df6, 0xa37f60fd, 0xb16477e0, 0xbf6d7aeb, 0x955259da, 0x9b5b54d1, 0x894043cc, 0x87494ec7, 0xdd3e05ae, 0xd33708a5, 0xc12c1fb8, 0xcf2512b3, 0xe51a3182, 0xeb133c89, 0xf9082b94, 0xf701269f, 0x4de6bd46, 0x43efb04d, 0x51f4a750, 0x5ffdaa5b, 0x75c2896a, 0x7bcb8461, 0x69d0937c, 0x67d99e77, 0x3daed51e, 0x33a7d815, 0x21bccf08, 0x2fb5c203, 0x058ae132, 0x0b83ec39, 0x1998fb24, 0x1791f62f, 0x764dd68d, 0x7844db86, 0x6a5fcc9b, 0x6456c190, 0x4e69e2a1, 0x4060efaa, 0x527bf8b7, 0x5c72f5bc, 0x0605bed5, 0x080cb3de, 0x1a17a4c3, 0x141ea9c8, 0x3e218af9, 0x302887f2, 0x223390ef, 0x2c3a9de4, 0x96dd063d, 0x98d40b36, 0x8acf1c2b, 0x84c61120, 0xaef93211, 0xa0f03f1a, 0xb2eb2807, 0xbce2250c, 0xe6956e65, 0xe89c636e, 0xfa877473, 0xf48e7978, 0xdeb15a49, 0xd0b85742, 0xc2a3405f, 0xccaa4d54, 0x41ecdaf7, 0x4fe5d7fc, 0x5dfec0e1, 0x53f7cdea, 0x79c8eedb, 0x77c1e3d0, 0x65daf4cd, 0x6bd3f9c6, 0x31a4b2af, 0x3fadbfa4, 0x2db6a8b9, 0x23bfa5b2, 0x09808683, 0x07898b88, 0x15929c95, 0x1b9b919e, 0xa17c0a47, 0xaf75074c, 0xbd6e1051, 0xb3671d5a, 0x99583e6b, 0x97513360, 0x854a247d, 0x8b432976, 0xd134621f, 0xdf3d6f14, 0xcd267809, 0xc32f7502, 0xe9105633, 0xe7195b38, 0xf5024c25, 0xfb0b412e, 0x9ad7618c, 0x94de6c87, 0x86c57b9a, 0x88cc7691, 0xa2f355a0, 0xacfa58ab, 0xbee14fb6, 0xb0e842bd, 0xea9f09d4, 0xe49604df, 0xf68d13c2, 0xf8841ec9, 0xd2bb3df8, 0xdcb230f3, 0xcea927ee, 0xc0a02ae5, 0x7a47b13c, 0x744ebc37, 0x6655ab2a, 0x685ca621, 0x42638510, 0x4c6a881b, 0x5e719f06, 0x5078920d, 0x0a0fd964, 0x0406d46f, 0x161dc372, 0x1814ce79, 0x322bed48, 0x3c22e043, 0x2e39f75e, 0x2030fa55, 0xec9ab701, 0xe293ba0a, 0xf088ad17, 0xfe81a01c, 0xd4be832d, 0xdab78e26, 0xc8ac993b, 0xc6a59430, 0x9cd2df59, 0x92dbd252, 0x80c0c54f, 0x8ec9c844, 0xa4f6eb75, 0xaaffe67e, 0xb8e4f163, 0xb6edfc68, 0x0c0a67b1, 0x02036aba, 0x10187da7, 0x1e1170ac, 0x342e539d, 0x3a275e96, 0x283c498b, 0x26354480, 0x7c420fe9, 0x724b02e2, 0x605015ff, 0x6e5918f4, 0x44663bc5, 0x4a6f36ce, 0x587421d3, 0x567d2cd8, 0x37a10c7a, 0x39a80171, 0x2bb3166c, 0x25ba1b67, 0x0f853856, 0x018c355d, 0x13972240, 0x1d9e2f4b, 0x47e96422, 0x49e06929, 0x5bfb7e34, 0x55f2733f, 0x7fcd500e, 0x71c45d05, 0x63df4a18, 0x6dd64713, 0xd731dcca, 0xd938d1c1, 0xcb23c6dc, 0xc52acbd7, 0xef15e8e6, 0xe11ce5ed, 0xf307f2f0, 0xfd0efffb, 0xa779b492, 0xa970b999, 0xbb6bae84, 0xb562a38f, 0x9f5d80be, 0x91548db5, 0x834f9aa8, 0x8d4697a3 ] + U2 = [ 0x00000000, 0x0b0e090d, 0x161c121a, 0x1d121b17, 0x2c382434, 0x27362d39, 0x3a24362e, 0x312a3f23, 0x58704868, 0x537e4165, 0x4e6c5a72, 0x4562537f, 0x74486c5c, 0x7f466551, 0x62547e46, 0x695a774b, 0xb0e090d0, 0xbbee99dd, 0xa6fc82ca, 0xadf28bc7, 0x9cd8b4e4, 0x97d6bde9, 0x8ac4a6fe, 0x81caaff3, 0xe890d8b8, 0xe39ed1b5, 0xfe8ccaa2, 0xf582c3af, 0xc4a8fc8c, 0xcfa6f581, 0xd2b4ee96, 0xd9bae79b, 0x7bdb3bbb, 0x70d532b6, 0x6dc729a1, 0x66c920ac, 0x57e31f8f, 0x5ced1682, 0x41ff0d95, 0x4af10498, 0x23ab73d3, 0x28a57ade, 0x35b761c9, 0x3eb968c4, 0x0f9357e7, 0x049d5eea, 0x198f45fd, 0x12814cf0, 0xcb3bab6b, 0xc035a266, 0xdd27b971, 0xd629b07c, 0xe7038f5f, 0xec0d8652, 0xf11f9d45, 0xfa119448, 0x934be303, 0x9845ea0e, 0x8557f119, 0x8e59f814, 0xbf73c737, 0xb47dce3a, 0xa96fd52d, 0xa261dc20, 0xf6ad766d, 0xfda37f60, 0xe0b16477, 0xebbf6d7a, 0xda955259, 0xd19b5b54, 0xcc894043, 0xc787494e, 0xaedd3e05, 0xa5d33708, 0xb8c12c1f, 0xb3cf2512, 0x82e51a31, 0x89eb133c, 0x94f9082b, 0x9ff70126, 0x464de6bd, 0x4d43efb0, 0x5051f4a7, 0x5b5ffdaa, 0x6a75c289, 0x617bcb84, 0x7c69d093, 0x7767d99e, 0x1e3daed5, 0x1533a7d8, 0x0821bccf, 0x032fb5c2, 0x32058ae1, 0x390b83ec, 0x241998fb, 0x2f1791f6, 0x8d764dd6, 0x867844db, 0x9b6a5fcc, 0x906456c1, 0xa14e69e2, 0xaa4060ef, 0xb7527bf8, 0xbc5c72f5, 0xd50605be, 0xde080cb3, 0xc31a17a4, 0xc8141ea9, 0xf93e218a, 0xf2302887, 0xef223390, 0xe42c3a9d, 0x3d96dd06, 0x3698d40b, 0x2b8acf1c, 0x2084c611, 0x11aef932, 0x1aa0f03f, 0x07b2eb28, 0x0cbce225, 0x65e6956e, 0x6ee89c63, 0x73fa8774, 0x78f48e79, 0x49deb15a, 0x42d0b857, 0x5fc2a340, 0x54ccaa4d, 0xf741ecda, 0xfc4fe5d7, 0xe15dfec0, 0xea53f7cd, 0xdb79c8ee, 0xd077c1e3, 0xcd65daf4, 0xc66bd3f9, 0xaf31a4b2, 0xa43fadbf, 0xb92db6a8, 0xb223bfa5, 0x83098086, 0x8807898b, 0x9515929c, 0x9e1b9b91, 0x47a17c0a, 0x4caf7507, 0x51bd6e10, 0x5ab3671d, 0x6b99583e, 0x60975133, 0x7d854a24, 0x768b4329, 0x1fd13462, 0x14df3d6f, 0x09cd2678, 0x02c32f75, 0x33e91056, 0x38e7195b, 0x25f5024c, 0x2efb0b41, 0x8c9ad761, 0x8794de6c, 0x9a86c57b, 0x9188cc76, 0xa0a2f355, 0xabacfa58, 0xb6bee14f, 0xbdb0e842, 0xd4ea9f09, 0xdfe49604, 0xc2f68d13, 0xc9f8841e, 0xf8d2bb3d, 0xf3dcb230, 0xeecea927, 0xe5c0a02a, 0x3c7a47b1, 0x37744ebc, 0x2a6655ab, 0x21685ca6, 0x10426385, 0x1b4c6a88, 0x065e719f, 0x0d507892, 0x640a0fd9, 0x6f0406d4, 0x72161dc3, 0x791814ce, 0x48322bed, 0x433c22e0, 0x5e2e39f7, 0x552030fa, 0x01ec9ab7, 0x0ae293ba, 0x17f088ad, 0x1cfe81a0, 0x2dd4be83, 0x26dab78e, 0x3bc8ac99, 0x30c6a594, 0x599cd2df, 0x5292dbd2, 0x4f80c0c5, 0x448ec9c8, 0x75a4f6eb, 0x7eaaffe6, 0x63b8e4f1, 0x68b6edfc, 0xb10c0a67, 0xba02036a, 0xa710187d, 0xac1e1170, 0x9d342e53, 0x963a275e, 0x8b283c49, 0x80263544, 0xe97c420f, 0xe2724b02, 0xff605015, 0xf46e5918, 0xc544663b, 0xce4a6f36, 0xd3587421, 0xd8567d2c, 0x7a37a10c, 0x7139a801, 0x6c2bb316, 0x6725ba1b, 0x560f8538, 0x5d018c35, 0x40139722, 0x4b1d9e2f, 0x2247e964, 0x2949e069, 0x345bfb7e, 0x3f55f273, 0x0e7fcd50, 0x0571c45d, 0x1863df4a, 0x136dd647, 0xcad731dc, 0xc1d938d1, 0xdccb23c6, 0xd7c52acb, 0xe6ef15e8, 0xede11ce5, 0xf0f307f2, 0xfbfd0eff, 0x92a779b4, 0x99a970b9, 0x84bb6bae, 0x8fb562a3, 0xbe9f5d80, 0xb591548d, 0xa8834f9a, 0xa38d4697 ] + U3 = [ 0x00000000, 0x0d0b0e09, 0x1a161c12, 0x171d121b, 0x342c3824, 0x3927362d, 0x2e3a2436, 0x23312a3f, 0x68587048, 0x65537e41, 0x724e6c5a, 0x7f456253, 0x5c74486c, 0x517f4665, 0x4662547e, 0x4b695a77, 0xd0b0e090, 0xddbbee99, 0xcaa6fc82, 0xc7adf28b, 0xe49cd8b4, 0xe997d6bd, 0xfe8ac4a6, 0xf381caaf, 0xb8e890d8, 0xb5e39ed1, 0xa2fe8cca, 0xaff582c3, 0x8cc4a8fc, 0x81cfa6f5, 0x96d2b4ee, 0x9bd9bae7, 0xbb7bdb3b, 0xb670d532, 0xa16dc729, 0xac66c920, 0x8f57e31f, 0x825ced16, 0x9541ff0d, 0x984af104, 0xd323ab73, 0xde28a57a, 0xc935b761, 0xc43eb968, 0xe70f9357, 0xea049d5e, 0xfd198f45, 0xf012814c, 0x6bcb3bab, 0x66c035a2, 0x71dd27b9, 0x7cd629b0, 0x5fe7038f, 0x52ec0d86, 0x45f11f9d, 0x48fa1194, 0x03934be3, 0x0e9845ea, 0x198557f1, 0x148e59f8, 0x37bf73c7, 0x3ab47dce, 0x2da96fd5, 0x20a261dc, 0x6df6ad76, 0x60fda37f, 0x77e0b164, 0x7aebbf6d, 0x59da9552, 0x54d19b5b, 0x43cc8940, 0x4ec78749, 0x05aedd3e, 0x08a5d337, 0x1fb8c12c, 0x12b3cf25, 0x3182e51a, 0x3c89eb13, 0x2b94f908, 0x269ff701, 0xbd464de6, 0xb04d43ef, 0xa75051f4, 0xaa5b5ffd, 0x896a75c2, 0x84617bcb, 0x937c69d0, 0x9e7767d9, 0xd51e3dae, 0xd81533a7, 0xcf0821bc, 0xc2032fb5, 0xe132058a, 0xec390b83, 0xfb241998, 0xf62f1791, 0xd68d764d, 0xdb867844, 0xcc9b6a5f, 0xc1906456, 0xe2a14e69, 0xefaa4060, 0xf8b7527b, 0xf5bc5c72, 0xbed50605, 0xb3de080c, 0xa4c31a17, 0xa9c8141e, 0x8af93e21, 0x87f23028, 0x90ef2233, 0x9de42c3a, 0x063d96dd, 0x0b3698d4, 0x1c2b8acf, 0x112084c6, 0x3211aef9, 0x3f1aa0f0, 0x2807b2eb, 0x250cbce2, 0x6e65e695, 0x636ee89c, 0x7473fa87, 0x7978f48e, 0x5a49deb1, 0x5742d0b8, 0x405fc2a3, 0x4d54ccaa, 0xdaf741ec, 0xd7fc4fe5, 0xc0e15dfe, 0xcdea53f7, 0xeedb79c8, 0xe3d077c1, 0xf4cd65da, 0xf9c66bd3, 0xb2af31a4, 0xbfa43fad, 0xa8b92db6, 0xa5b223bf, 0x86830980, 0x8b880789, 0x9c951592, 0x919e1b9b, 0x0a47a17c, 0x074caf75, 0x1051bd6e, 0x1d5ab367, 0x3e6b9958, 0x33609751, 0x247d854a, 0x29768b43, 0x621fd134, 0x6f14df3d, 0x7809cd26, 0x7502c32f, 0x5633e910, 0x5b38e719, 0x4c25f502, 0x412efb0b, 0x618c9ad7, 0x6c8794de, 0x7b9a86c5, 0x769188cc, 0x55a0a2f3, 0x58abacfa, 0x4fb6bee1, 0x42bdb0e8, 0x09d4ea9f, 0x04dfe496, 0x13c2f68d, 0x1ec9f884, 0x3df8d2bb, 0x30f3dcb2, 0x27eecea9, 0x2ae5c0a0, 0xb13c7a47, 0xbc37744e, 0xab2a6655, 0xa621685c, 0x85104263, 0x881b4c6a, 0x9f065e71, 0x920d5078, 0xd9640a0f, 0xd46f0406, 0xc372161d, 0xce791814, 0xed48322b, 0xe0433c22, 0xf75e2e39, 0xfa552030, 0xb701ec9a, 0xba0ae293, 0xad17f088, 0xa01cfe81, 0x832dd4be, 0x8e26dab7, 0x993bc8ac, 0x9430c6a5, 0xdf599cd2, 0xd25292db, 0xc54f80c0, 0xc8448ec9, 0xeb75a4f6, 0xe67eaaff, 0xf163b8e4, 0xfc68b6ed, 0x67b10c0a, 0x6aba0203, 0x7da71018, 0x70ac1e11, 0x539d342e, 0x5e963a27, 0x498b283c, 0x44802635, 0x0fe97c42, 0x02e2724b, 0x15ff6050, 0x18f46e59, 0x3bc54466, 0x36ce4a6f, 0x21d35874, 0x2cd8567d, 0x0c7a37a1, 0x017139a8, 0x166c2bb3, 0x1b6725ba, 0x38560f85, 0x355d018c, 0x22401397, 0x2f4b1d9e, 0x642247e9, 0x692949e0, 0x7e345bfb, 0x733f55f2, 0x500e7fcd, 0x5d0571c4, 0x4a1863df, 0x47136dd6, 0xdccad731, 0xd1c1d938, 0xc6dccb23, 0xcbd7c52a, 0xe8e6ef15, 0xe5ede11c, 0xf2f0f307, 0xfffbfd0e, 0xb492a779, 0xb999a970, 0xae84bb6b, 0xa38fb562, 0x80be9f5d, 0x8db59154, 0x9aa8834f, 0x97a38d46 ] + U4 = [ 0x00000000, 0x090d0b0e, 0x121a161c, 0x1b171d12, 0x24342c38, 0x2d392736, 0x362e3a24, 0x3f23312a, 0x48685870, 0x4165537e, 0x5a724e6c, 0x537f4562, 0x6c5c7448, 0x65517f46, 0x7e466254, 0x774b695a, 0x90d0b0e0, 0x99ddbbee, 0x82caa6fc, 0x8bc7adf2, 0xb4e49cd8, 0xbde997d6, 0xa6fe8ac4, 0xaff381ca, 0xd8b8e890, 0xd1b5e39e, 0xcaa2fe8c, 0xc3aff582, 0xfc8cc4a8, 0xf581cfa6, 0xee96d2b4, 0xe79bd9ba, 0x3bbb7bdb, 0x32b670d5, 0x29a16dc7, 0x20ac66c9, 0x1f8f57e3, 0x16825ced, 0x0d9541ff, 0x04984af1, 0x73d323ab, 0x7ade28a5, 0x61c935b7, 0x68c43eb9, 0x57e70f93, 0x5eea049d, 0x45fd198f, 0x4cf01281, 0xab6bcb3b, 0xa266c035, 0xb971dd27, 0xb07cd629, 0x8f5fe703, 0x8652ec0d, 0x9d45f11f, 0x9448fa11, 0xe303934b, 0xea0e9845, 0xf1198557, 0xf8148e59, 0xc737bf73, 0xce3ab47d, 0xd52da96f, 0xdc20a261, 0x766df6ad, 0x7f60fda3, 0x6477e0b1, 0x6d7aebbf, 0x5259da95, 0x5b54d19b, 0x4043cc89, 0x494ec787, 0x3e05aedd, 0x3708a5d3, 0x2c1fb8c1, 0x2512b3cf, 0x1a3182e5, 0x133c89eb, 0x082b94f9, 0x01269ff7, 0xe6bd464d, 0xefb04d43, 0xf4a75051, 0xfdaa5b5f, 0xc2896a75, 0xcb84617b, 0xd0937c69, 0xd99e7767, 0xaed51e3d, 0xa7d81533, 0xbccf0821, 0xb5c2032f, 0x8ae13205, 0x83ec390b, 0x98fb2419, 0x91f62f17, 0x4dd68d76, 0x44db8678, 0x5fcc9b6a, 0x56c19064, 0x69e2a14e, 0x60efaa40, 0x7bf8b752, 0x72f5bc5c, 0x05bed506, 0x0cb3de08, 0x17a4c31a, 0x1ea9c814, 0x218af93e, 0x2887f230, 0x3390ef22, 0x3a9de42c, 0xdd063d96, 0xd40b3698, 0xcf1c2b8a, 0xc6112084, 0xf93211ae, 0xf03f1aa0, 0xeb2807b2, 0xe2250cbc, 0x956e65e6, 0x9c636ee8, 0x877473fa, 0x8e7978f4, 0xb15a49de, 0xb85742d0, 0xa3405fc2, 0xaa4d54cc, 0xecdaf741, 0xe5d7fc4f, 0xfec0e15d, 0xf7cdea53, 0xc8eedb79, 0xc1e3d077, 0xdaf4cd65, 0xd3f9c66b, 0xa4b2af31, 0xadbfa43f, 0xb6a8b92d, 0xbfa5b223, 0x80868309, 0x898b8807, 0x929c9515, 0x9b919e1b, 0x7c0a47a1, 0x75074caf, 0x6e1051bd, 0x671d5ab3, 0x583e6b99, 0x51336097, 0x4a247d85, 0x4329768b, 0x34621fd1, 0x3d6f14df, 0x267809cd, 0x2f7502c3, 0x105633e9, 0x195b38e7, 0x024c25f5, 0x0b412efb, 0xd7618c9a, 0xde6c8794, 0xc57b9a86, 0xcc769188, 0xf355a0a2, 0xfa58abac, 0xe14fb6be, 0xe842bdb0, 0x9f09d4ea, 0x9604dfe4, 0x8d13c2f6, 0x841ec9f8, 0xbb3df8d2, 0xb230f3dc, 0xa927eece, 0xa02ae5c0, 0x47b13c7a, 0x4ebc3774, 0x55ab2a66, 0x5ca62168, 0x63851042, 0x6a881b4c, 0x719f065e, 0x78920d50, 0x0fd9640a, 0x06d46f04, 0x1dc37216, 0x14ce7918, 0x2bed4832, 0x22e0433c, 0x39f75e2e, 0x30fa5520, 0x9ab701ec, 0x93ba0ae2, 0x88ad17f0, 0x81a01cfe, 0xbe832dd4, 0xb78e26da, 0xac993bc8, 0xa59430c6, 0xd2df599c, 0xdbd25292, 0xc0c54f80, 0xc9c8448e, 0xf6eb75a4, 0xffe67eaa, 0xe4f163b8, 0xedfc68b6, 0x0a67b10c, 0x036aba02, 0x187da710, 0x1170ac1e, 0x2e539d34, 0x275e963a, 0x3c498b28, 0x35448026, 0x420fe97c, 0x4b02e272, 0x5015ff60, 0x5918f46e, 0x663bc544, 0x6f36ce4a, 0x7421d358, 0x7d2cd856, 0xa10c7a37, 0xa8017139, 0xb3166c2b, 0xba1b6725, 0x8538560f, 0x8c355d01, 0x97224013, 0x9e2f4b1d, 0xe9642247, 0xe0692949, 0xfb7e345b, 0xf2733f55, 0xcd500e7f, 0xc45d0571, 0xdf4a1863, 0xd647136d, 0x31dccad7, 0x38d1c1d9, 0x23c6dccb, 0x2acbd7c5, 0x15e8e6ef, 0x1ce5ede1, 0x07f2f0f3, 0x0efffbfd, 0x79b492a7, 0x70b999a9, 0x6bae84bb, 0x62a38fb5, 0x5d80be9f, 0x548db591, 0x4f9aa883, 0x4697a38d ] + + def __init__(self, key): + + if len(key) not in (16, 24, 32): + raise ValueError('Invalid key size') + + rounds = self.number_of_rounds[len(key)] + + # Encryption round keys + self._Ke = [[0] * 4 for i in xrange(rounds + 1)] + + # Decryption round keys + self._Kd = [[0] * 4 for i in xrange(rounds + 1)] + + round_key_count = (rounds + 1) * 4 + KC = len(key) // 4 + + # Convert the key into ints + tk = [ struct.unpack('>i', key[i:i + 4])[0] for i in xrange(0, len(key), 4) ] + + # Copy values into round key arrays + for i in xrange(0, KC): + self._Ke[i // 4][i % 4] = tk[i] + self._Kd[rounds - (i // 4)][i % 4] = tk[i] + + # Key expansion (fips-197 section 5.2) + rconpointer = 0 + t = KC + while t < round_key_count: + + tt = tk[KC - 1] + tk[0] ^= ((self.S[(tt >> 16) & 0xFF] << 24) ^ + (self.S[(tt >> 8) & 0xFF] << 16) ^ + (self.S[ tt & 0xFF] << 8) ^ + self.S[(tt >> 24) & 0xFF] ^ + (self.rcon[rconpointer] << 24)) + rconpointer += 1 + + if KC != 8: + for i in xrange(1, KC): + tk[i] ^= tk[i - 1] + + # Key expansion for 256-bit keys is "slightly different" (fips-197) + else: + for i in xrange(1, KC // 2): + tk[i] ^= tk[i - 1] + tt = tk[KC // 2 - 1] + + tk[KC // 2] ^= (self.S[ tt & 0xFF] ^ + (self.S[(tt >> 8) & 0xFF] << 8) ^ + (self.S[(tt >> 16) & 0xFF] << 16) ^ + (self.S[(tt >> 24) & 0xFF] << 24)) + + for i in xrange(KC // 2 + 1, KC): + tk[i] ^= tk[i - 1] + + # Copy values into round key arrays + j = 0 + while j < KC and t < round_key_count: + self._Ke[t // 4][t % 4] = tk[j] + self._Kd[rounds - (t // 4)][t % 4] = tk[j] + j += 1 + t += 1 + + # Inverse-Cipher-ify the decryption round key (fips-197 section 5.3) + for r in xrange(1, rounds): + for j in xrange(0, 4): + tt = self._Kd[r][j] + self._Kd[r][j] = (self.U1[(tt >> 24) & 0xFF] ^ + self.U2[(tt >> 16) & 0xFF] ^ + self.U3[(tt >> 8) & 0xFF] ^ + self.U4[ tt & 0xFF]) + + def encrypt(self, plaintext): + 'Encrypt a block of plain text using the AES block cipher.' + + if len(plaintext) != 16: + raise ValueError('wrong block length') + + rounds = len(self._Ke) - 1 + (s1, s2, s3) = [1, 2, 3] + a = [0, 0, 0, 0] + + # Convert plaintext to (ints ^ key) + t = [(_compact_word(plaintext[4 * i:4 * i + 4]) ^ self._Ke[0][i]) for i in xrange(0, 4)] + + # Apply round transforms + for r in xrange(1, rounds): + for i in xrange(0, 4): + a[i] = (self.T1[(t[ i ] >> 24) & 0xFF] ^ + self.T2[(t[(i + s1) % 4] >> 16) & 0xFF] ^ + self.T3[(t[(i + s2) % 4] >> 8) & 0xFF] ^ + self.T4[ t[(i + s3) % 4] & 0xFF] ^ + self._Ke[r][i]) + t = copy.copy(a) + + # The last round is special + result = [ ] + for i in xrange(0, 4): + tt = self._Ke[rounds][i] + result.append((self.S[(t[ i ] >> 24) & 0xFF] ^ (tt >> 24)) & 0xFF) + result.append((self.S[(t[(i + s1) % 4] >> 16) & 0xFF] ^ (tt >> 16)) & 0xFF) + result.append((self.S[(t[(i + s2) % 4] >> 8) & 0xFF] ^ (tt >> 8)) & 0xFF) + result.append((self.S[ t[(i + s3) % 4] & 0xFF] ^ tt ) & 0xFF) + + return result + + def decrypt(self, ciphertext): + 'Decrypt a block of cipher text using the AES block cipher.' + + if len(ciphertext) != 16: + raise ValueError('wrong block length') + + rounds = len(self._Kd) - 1 + (s1, s2, s3) = [3, 2, 1] + a = [0, 0, 0, 0] + + # Convert ciphertext to (ints ^ key) + t = [(_compact_word(ciphertext[4 * i:4 * i + 4]) ^ self._Kd[0][i]) for i in xrange(0, 4)] + + # Apply round transforms + for r in xrange(1, rounds): + for i in xrange(0, 4): + a[i] = (self.T5[(t[ i ] >> 24) & 0xFF] ^ + self.T6[(t[(i + s1) % 4] >> 16) & 0xFF] ^ + self.T7[(t[(i + s2) % 4] >> 8) & 0xFF] ^ + self.T8[ t[(i + s3) % 4] & 0xFF] ^ + self._Kd[r][i]) + t = copy.copy(a) + + # The last round is special + result = [ ] + for i in xrange(0, 4): + tt = self._Kd[rounds][i] + result.append((self.Si[(t[ i ] >> 24) & 0xFF] ^ (tt >> 24)) & 0xFF) + result.append((self.Si[(t[(i + s1) % 4] >> 16) & 0xFF] ^ (tt >> 16)) & 0xFF) + result.append((self.Si[(t[(i + s2) % 4] >> 8) & 0xFF] ^ (tt >> 8)) & 0xFF) + result.append((self.Si[ t[(i + s3) % 4] & 0xFF] ^ tt ) & 0xFF) + + return result + + +class Counter(object): + '''A counter object for the Counter (CTR) mode of operation. + + To create a custom counter, you can usually just override the + increment method.''' + + def __init__(self, initial_value = 1): + + # Convert the value into an array of bytes long + self._counter = [ ((initial_value >> i) % 256) for i in xrange(128 - 8, -1, -8) ] + + value = property(lambda s: s._counter) + + def increment(self): + '''Increment the counter (overflow rolls back to 0).''' + + for i in xrange(len(self._counter) - 1, -1, -1): + self._counter[i] += 1 + + if self._counter[i] < 256: break + + # Carry the one + self._counter[i] = 0 + + # Overflow + else: + self._counter = [ 0 ] * len(self._counter) + + +class AESBlockModeOfOperation(object): + '''Super-class for AES modes of operation that require blocks.''' + def __init__(self, key): + self._aes = AES(key) + + def decrypt(self, ciphertext): + raise Exception('not implemented') + + def encrypt(self, plaintext): + raise Exception('not implemented') + + +class AESStreamModeOfOperation(AESBlockModeOfOperation): + '''Super-class for AES modes of operation that are stream-ciphers.''' + +class AESSegmentModeOfOperation(AESStreamModeOfOperation): + '''Super-class for AES modes of operation that segment data.''' + + segment_bytes = 16 + + + +class AESModeOfOperationECB(AESBlockModeOfOperation): + '''AES Electronic Codebook Mode of Operation. + + o Block-cipher, so data must be padded to 16 byte boundaries + + Security Notes: + o This mode is not recommended + o Any two identical blocks produce identical encrypted values, + exposing data patterns. (See the image of Tux on wikipedia) + + Also see: + o https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Electronic_codebook_.28ECB.29 + o See NIST SP800-38A (http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf); section 6.1''' + + + name = "Electronic Codebook (ECB)" + + def encrypt(self, plaintext): + if len(plaintext) != 16: + raise ValueError('plaintext block must be 16 bytes') + + plaintext = _string_to_bytes(plaintext) + return _bytes_to_string(self._aes.encrypt(plaintext)) + + def decrypt(self, ciphertext): + if len(ciphertext) != 16: + raise ValueError('ciphertext block must be 16 bytes') + + ciphertext = _string_to_bytes(ciphertext) + return _bytes_to_string(self._aes.decrypt(ciphertext)) + + + +class AESModeOfOperationCBC(AESBlockModeOfOperation): + '''AES Cipher-Block Chaining Mode of Operation. + + o The Initialization Vector (IV) + o Block-cipher, so data must be padded to 16 byte boundaries + o An incorrect initialization vector will only cause the first + block to be corrupt; all other blocks will be intact + o A corrupt bit in the cipher text will cause a block to be + corrupted, and the next block to be inverted, but all other + blocks will be intact. + + Security Notes: + o This method (and CTR) ARE recommended. + + Also see: + o https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher-block_chaining_.28CBC.29 + o See NIST SP800-38A (http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf); section 6.2''' + + + name = "Cipher-Block Chaining (CBC)" + + def __init__(self, key, iv = None): + if iv is None: + self._last_cipherblock = [ 0 ] * 16 + elif len(iv) != 16: + raise ValueError('initialization vector must be 16 bytes') + else: + self._last_cipherblock = _string_to_bytes(iv) + + AESBlockModeOfOperation.__init__(self, key) + + def encrypt(self, plaintext): + if len(plaintext) != 16: + raise ValueError('plaintext block must be 16 bytes') + + plaintext = _string_to_bytes(plaintext) + precipherblock = [ (p ^ l) for (p, l) in zip(plaintext, self._last_cipherblock) ] + self._last_cipherblock = self._aes.encrypt(precipherblock) + + return _bytes_to_string(self._last_cipherblock) + + def decrypt(self, ciphertext): + if len(ciphertext) != 16: + raise ValueError('ciphertext block must be 16 bytes') + + cipherblock = _string_to_bytes(ciphertext) + plaintext = [ (p ^ l) for (p, l) in zip(self._aes.decrypt(cipherblock), self._last_cipherblock) ] + self._last_cipherblock = cipherblock + + return _bytes_to_string(plaintext) + + + +class AESModeOfOperationCFB(AESSegmentModeOfOperation): + '''AES Cipher Feedback Mode of Operation. + + o A stream-cipher, so input does not need to be padded to blocks, + but does need to be padded to segment_size + + Also see: + o https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher_feedback_.28CFB.29 + o See NIST SP800-38A (http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf); section 6.3''' + + + name = "Cipher Feedback (CFB)" + + def __init__(self, key, iv, segment_size = 1): + if segment_size == 0: segment_size = 1 + + if iv is None: + self._shift_register = [ 0 ] * 16 + elif len(iv) != 16: + raise ValueError('initialization vector must be 16 bytes') + else: + self._shift_register = _string_to_bytes(iv) + + self._segment_bytes = segment_size + + AESBlockModeOfOperation.__init__(self, key) + + segment_bytes = property(lambda s: s._segment_bytes) + + def encrypt(self, plaintext): + if len(plaintext) % self._segment_bytes != 0: + raise ValueError('plaintext block must be a multiple of segment_size') + + plaintext = _string_to_bytes(plaintext) + + # Break block into segments + encrypted = [ ] + for i in xrange(0, len(plaintext), self._segment_bytes): + plaintext_segment = plaintext[i: i + self._segment_bytes] + xor_segment = self._aes.encrypt(self._shift_register)[:len(plaintext_segment)] + cipher_segment = [ (p ^ x) for (p, x) in zip(plaintext_segment, xor_segment) ] + + # Shift the top bits out and the ciphertext in + self._shift_register = _concat_list(self._shift_register[len(cipher_segment):], cipher_segment) + + encrypted.extend(cipher_segment) + + return _bytes_to_string(encrypted) + + def decrypt(self, ciphertext): + if len(ciphertext) % self._segment_bytes != 0: + raise ValueError('ciphertext block must be a multiple of segment_size') + + ciphertext = _string_to_bytes(ciphertext) + + # Break block into segments + decrypted = [ ] + for i in xrange(0, len(ciphertext), self._segment_bytes): + cipher_segment = ciphertext[i: i + self._segment_bytes] + xor_segment = self._aes.encrypt(self._shift_register)[:len(cipher_segment)] + plaintext_segment = [ (p ^ x) for (p, x) in zip(cipher_segment, xor_segment) ] + + # Shift the top bits out and the ciphertext in + self._shift_register = _concat_list(self._shift_register[len(cipher_segment):], cipher_segment) + + decrypted.extend(plaintext_segment) + + return _bytes_to_string(decrypted) + + + +class AESModeOfOperationOFB(AESStreamModeOfOperation): + '''AES Output Feedback Mode of Operation. + + o A stream-cipher, so input does not need to be padded to blocks, + allowing arbitrary length data. + o A bit twiddled in the cipher text, twiddles the same bit in the + same bit in the plain text, which can be useful for error + correction techniques. + + Also see: + o https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Output_feedback_.28OFB.29 + o See NIST SP800-38A (http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf); section 6.4''' + + + name = "Output Feedback (OFB)" + + def __init__(self, key, iv = None): + if iv is None: + self._last_precipherblock = [ 0 ] * 16 + elif len(iv) != 16: + raise ValueError('initialization vector must be 16 bytes') + else: + self._last_precipherblock = _string_to_bytes(iv) + + self._remaining_block = [ ] + + AESBlockModeOfOperation.__init__(self, key) + + def encrypt(self, plaintext): + encrypted = [ ] + for p in _string_to_bytes(plaintext): + if len(self._remaining_block) == 0: + self._remaining_block = self._aes.encrypt(self._last_precipherblock) + self._last_precipherblock = [ ] + precipherbyte = self._remaining_block.pop(0) + self._last_precipherblock.append(precipherbyte) + cipherbyte = p ^ precipherbyte + encrypted.append(cipherbyte) + + return _bytes_to_string(encrypted) + + def decrypt(self, ciphertext): + # AES-OFB is symetric + return self.encrypt(ciphertext) + + + +class AESModeOfOperationCTR(AESStreamModeOfOperation): + '''AES Counter Mode of Operation. + + o A stream-cipher, so input does not need to be padded to blocks, + allowing arbitrary length data. + o The counter must be the same size as the key size (ie. len(key)) + o Each block independant of the other, so a corrupt byte will not + damage future blocks. + o Each block has a uniue counter value associated with it, which + contributes to the encrypted value, so no data patterns are + leaked. + o Also known as: Counter Mode (CM), Integer Counter Mode (ICM) and + Segmented Integer Counter (SIC + + Security Notes: + o This method (and CBC) ARE recommended. + o Each message block is associated with a counter value which must be + unique for ALL messages with the same key. Otherwise security may be + compromised. + + Also see: + + o https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Counter_.28CTR.29 + o See NIST SP800-38A (http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf); section 6.5 + and Appendix B for managing the initial counter''' + + + name = "Counter (CTR)" + + def __init__(self, key, counter = None): + AESBlockModeOfOperation.__init__(self, key) + + if counter is None: + counter = Counter() + + self._counter = counter + self._remaining_counter = [ ] + + def encrypt(self, plaintext): + while len(self._remaining_counter) < len(plaintext): + self._remaining_counter += self._aes.encrypt(self._counter.value) + self._counter.increment() + + plaintext = _string_to_bytes(plaintext) + + encrypted = [ (p ^ c) for (p, c) in zip(plaintext, self._remaining_counter) ] + self._remaining_counter = self._remaining_counter[len(encrypted):] + + return _bytes_to_string(encrypted) + + def decrypt(self, crypttext): + # AES-CTR is symetric + return self.encrypt(crypttext) + + +# Simple lookup table for each mode +AESModesOfOperation = dict( + ctr = AESModeOfOperationCTR, + cbc = AESModeOfOperationCBC, + cfb = AESModeOfOperationCFB, + ecb = AESModeOfOperationECB, + ofb = AESModeOfOperationOFB, +) diff --git a/gluon/contrib/pyaes/blockfeeder.py b/gluon/contrib/pyaes/blockfeeder.py new file mode 100644 index 00000000..f4113c37 --- /dev/null +++ b/gluon/contrib/pyaes/blockfeeder.py @@ -0,0 +1,227 @@ +# The MIT License (MIT) +# +# Copyright (c) 2014 Richard Moore +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + + +from .aes import AESBlockModeOfOperation, AESSegmentModeOfOperation, AESStreamModeOfOperation +from .util import append_PKCS7_padding, strip_PKCS7_padding, to_bufferable + + +# First we inject three functions to each of the modes of operations +# +# _can_consume(size) +# - Given a size, determine how many bytes could be consumed in +# a single call to either the decrypt or encrypt method +# +# _final_encrypt(data, padding = PADDING_DEFAULT) +# - call and return encrypt on this (last) chunk of data, +# padding as necessary; this will always be at least 16 +# bytes unless the total incoming input was less than 16 +# bytes +# +# _final_decrypt(data, padding = PADDING_DEFAULT) +# - same as _final_encrypt except for decrypt, for +# stripping off padding +# + +PADDING_NONE = 'none' +PADDING_DEFAULT = 'default' + +# @TODO: Ciphertext stealing and explicit PKCS#7 +# PADDING_CIPHERTEXT_STEALING +# PADDING_PKCS7 + +# ECB and CBC are block-only ciphers + +def _block_can_consume(self, size): + if size >= 16: return 16 + return 0 + +# After padding, we may have more than one block +def _block_final_encrypt(self, data, padding = PADDING_DEFAULT): + if padding == PADDING_DEFAULT: + data = append_PKCS7_padding(data) + + elif padding == PADDING_NONE: + if len(data) != 16: + raise Exception('invalid data length for final block') + else: + raise Exception('invalid padding option') + + if len(data) == 32: + return self.encrypt(data[:16]) + self.encrypt(data[16:]) + + return self.encrypt(data) + + +def _block_final_decrypt(self, data, padding = PADDING_DEFAULT): + if padding == PADDING_DEFAULT: + return strip_PKCS7_padding(self.decrypt(data)) + + if padding == PADDING_NONE: + if len(data) != 16: + raise Exception('invalid data length for final block') + return self.decrypt(data) + + raise Exception('invalid padding option') + +AESBlockModeOfOperation._can_consume = _block_can_consume +AESBlockModeOfOperation._final_encrypt = _block_final_encrypt +AESBlockModeOfOperation._final_decrypt = _block_final_decrypt + + + +# CFB is a segment cipher + +def _segment_can_consume(self, size): + return self.segment_bytes * int(size // self.segment_bytes) + +# CFB can handle a non-segment-sized block at the end using the remaining cipherblock +def _segment_final_encrypt(self, data, padding = PADDING_DEFAULT): + if padding != PADDING_DEFAULT: + raise Exception('invalid padding option') + + faux_padding = (chr(0) * (self.segment_bytes - (len(data) % self.segment_bytes))) + padded = data + to_bufferable(faux_padding) + return self.encrypt(padded)[:len(data)] + +# CFB can handle a non-segment-sized block at the end using the remaining cipherblock +def _segment_final_decrypt(self, data, padding = PADDING_DEFAULT): + if padding != PADDING_DEFAULT: + raise Exception('invalid padding option') + + faux_padding = (chr(0) * (self.segment_bytes - (len(data) % self.segment_bytes))) + padded = data + to_bufferable(faux_padding) + return self.decrypt(padded)[:len(data)] + +AESSegmentModeOfOperation._can_consume = _segment_can_consume +AESSegmentModeOfOperation._final_encrypt = _segment_final_encrypt +AESSegmentModeOfOperation._final_decrypt = _segment_final_decrypt + + + +# OFB and CTR are stream ciphers + +def _stream_can_consume(self, size): + return size + +def _stream_final_encrypt(self, data, padding = PADDING_DEFAULT): + if padding not in [PADDING_NONE, PADDING_DEFAULT]: + raise Exception('invalid padding option') + + return self.encrypt(data) + +def _stream_final_decrypt(self, data, padding = PADDING_DEFAULT): + if padding not in [PADDING_NONE, PADDING_DEFAULT]: + raise Exception('invalid padding option') + + return self.decrypt(data) + +AESStreamModeOfOperation._can_consume = _stream_can_consume +AESStreamModeOfOperation._final_encrypt = _stream_final_encrypt +AESStreamModeOfOperation._final_decrypt = _stream_final_decrypt + + + +class BlockFeeder(object): + '''The super-class for objects to handle chunking a stream of bytes + into the appropriate block size for the underlying mode of operation + and applying (or stripping) padding, as necessary.''' + + def __init__(self, mode, feed, final, padding = PADDING_DEFAULT): + self._mode = mode + self._feed = feed + self._final = final + self._buffer = to_bufferable("") + self._padding = padding + + def feed(self, data = None): + '''Provide bytes to encrypt (or decrypt), returning any bytes + possible from this or any previous calls to feed. + + Call with None or an empty string to flush the mode of + operation and return any final bytes; no further calls to + feed may be made.''' + + if self._buffer is None: + raise ValueError('already finished feeder') + + # Finalize; process the spare bytes we were keeping + if not data: + result = self._final(self._buffer, self._padding) + self._buffer = None + return result + + self._buffer += to_bufferable(data) + + # We keep 16 bytes around so we can determine padding + result = to_bufferable('') + while len(self._buffer) > 16: + can_consume = self._mode._can_consume(len(self._buffer) - 16) + if can_consume == 0: break + result += self._feed(self._buffer[:can_consume]) + self._buffer = self._buffer[can_consume:] + + return result + + +class Encrypter(BlockFeeder): + 'Accepts bytes of plaintext and returns encrypted ciphertext.' + + def __init__(self, mode, padding = PADDING_DEFAULT): + BlockFeeder.__init__(self, mode, mode.encrypt, mode._final_encrypt, padding) + + +class Decrypter(BlockFeeder): + 'Accepts bytes of ciphertext and returns decrypted plaintext.' + + def __init__(self, mode, padding = PADDING_DEFAULT): + BlockFeeder.__init__(self, mode, mode.decrypt, mode._final_decrypt, padding) + + +# 8kb blocks +BLOCK_SIZE = (1 << 13) + +def _feed_stream(feeder, in_stream, out_stream, block_size = BLOCK_SIZE): + 'Uses feeder to read and convert from in_stream and write to out_stream.' + + while True: + chunk = in_stream.read(block_size) + if not chunk: + break + converted = feeder.feed(chunk) + out_stream.write(converted) + converted = feeder.feed() + out_stream.write(converted) + + +def encrypt_stream(mode, in_stream, out_stream, block_size = BLOCK_SIZE, padding = PADDING_DEFAULT): + 'Encrypts a stream of bytes from in_stream to out_stream using mode.' + + encrypter = Encrypter(mode, padding = padding) + _feed_stream(encrypter, in_stream, out_stream, block_size) + + +def decrypt_stream(mode, in_stream, out_stream, block_size = BLOCK_SIZE, padding = PADDING_DEFAULT): + 'Decrypts a stream of bytes from in_stream to out_stream using mode.' + + decrypter = Decrypter(mode, padding = padding) + _feed_stream(decrypter, in_stream, out_stream, block_size) diff --git a/gluon/contrib/pyaes/util.py b/gluon/contrib/pyaes/util.py new file mode 100644 index 00000000..081a3759 --- /dev/null +++ b/gluon/contrib/pyaes/util.py @@ -0,0 +1,60 @@ +# The MIT License (MIT) +# +# Copyright (c) 2014 Richard Moore +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +# Why to_bufferable? +# Python 3 is very different from Python 2.x when it comes to strings of text +# and strings of bytes; in Python 3, strings of bytes do not exist, instead to +# represent arbitrary binary data, we must use the "bytes" object. This method +# ensures the object behaves as we need it to. + +def to_bufferable(binary): + return binary + +def _get_byte(c): + return ord(c) + +try: + xrange +except: + + def to_bufferable(binary): + if isinstance(binary, bytes): + return binary + return bytes(ord(b) for b in binary) + + def _get_byte(c): + return c + +def append_PKCS7_padding(data): + pad = 16 - (len(data) % 16) + return data + to_bufferable(chr(pad) * pad) + +def strip_PKCS7_padding(data): + if len(data) % 16 != 0: + raise ValueError("invalid length") + + pad = _get_byte(data[-1]) + + if pad > 16: + raise ValueError("invalid padding byte") + + return data[:-pad] diff --git a/gluon/utils.py b/gluon/utils.py index a9e9f842..a7ffdeb6 100644 --- a/gluon/utils.py +++ b/gluon/utils.py @@ -18,24 +18,24 @@ import inspect import time import os import re -import sys import logging import socket import base64 import zlib +import hashlib +import binascii +import hmac +from hashlib import md5, sha1, sha224, sha256, sha384, sha512 from gluon._compat import basestring, pickle, PY2, xrange, to_bytes, to_native _struct_2_long_long = struct.Struct('=QQ') -import hashlib, binascii -from hashlib import md5, sha1, sha224, sha256, sha384, sha512 - try: from Crypto.Cipher import AES + HAVE_AES = True except ImportError: - import gluon.contrib.aes as AES - -import hmac + import gluon.contrib.pyaes as PYAES + HAVE_AES = False if hasattr(hashlib, "pbkdf2_hmac"): def pbkdf2_hex(data, salt, iterations=1000, keylen=24, hashfunc=None): @@ -66,11 +66,35 @@ logger = logging.getLogger("web2py") def AES_new(key, IV=None): - """ Returns an AES cipher object and random IV if None specified """ + """Return an AES cipher object and random IV if None specified.""" if IV is None: IV = fast_urandom16() + if HAVE_AES: + return AES.new(key, AES.MODE_CBC, IV), IV + else: + return PYAES.AESModeOfOperationCBC(key, iv=IV), IV - return AES.new(key, AES.MODE_CBC, IV), IV + +def AES_enc(cipher, data): + """Encrypt data with the cipher.""" + if HAVE_AES: + return cipher.encrypt(data) + else: + encrypter = PYAES.Encrypter(cipher) + enc = encrypter.feed(data) + enc += encrypter.feed() + return enc + + +def AES_dec(cipher, data): + """Decrypt data with the cipher.""" + if HAVE_AES: + return cipher.decrypt(data) + else: + decrypter = PYAES.Decrypter(cipher) + dec = decrypter.feed(data) + dec += decrypter.feed() + return dec def compare(a, b): @@ -79,20 +103,17 @@ def compare(a, b): return hmac.compare_digest(a, b) result = len(a) ^ len(b) for i in xrange(len(b)): - result |= ord(a[i%len(a)]) ^ ord(b[i]) + result |= ord(a[i % len(a)]) ^ ord(b[i]) return result == 0 def md5_hash(text): - """ Generates a md5 hash with the given text """ + """Generate an md5 hash with the given text.""" return md5(to_bytes(text)).hexdigest() def simple_hash(text, key='', salt='', digest_alg='md5'): - """ - Generates hash with the given text using the specified - digest hashing algorithm - """ + """Generate hash with the given text using the specified digest algorithm.""" text = to_bytes(text) key = to_bytes(key) salt = to_bytes(salt) @@ -114,9 +135,7 @@ def simple_hash(text, key='', salt='', digest_alg='md5'): def get_digest(value): - """ - Returns a hashlib digest algorithm from a string - """ + """Return a hashlib digest algorithm from a string.""" if not isinstance(value, str): return value value = value.lower() @@ -165,11 +184,11 @@ def pad(s, n=32): def unpad(s, n=32): padlen = s[-1] - if isinstance(padlen,str): - padlen = ord(padlen) # python2 - if (padlen < 1) | (padlen > n): # avoid short-circuit + if isinstance(padlen, str): + padlen = ord(padlen) # python2 + if (padlen < 1) | (padlen > n): # avoid short-circuit # return garbage to minimize side channels - return bytes(bytearray(len(s)*[0])) + return bytes(bytearray(len(s) * [0])) return s[:-padlen] @@ -181,7 +200,7 @@ def secure_dumps(data, encryption_key, hash_key=None, compression_level=None): if not hash_key: hash_key = hashlib.sha256(encryption_key).digest() cipher, IV = AES_new(pad(encryption_key)[:32]) - encrypted_data = base64.urlsafe_b64encode(IV + cipher.encrypt(pad(dump))) + encrypted_data = base64.urlsafe_b64encode(IV + AES_enc(cipher, pad(dump))) signature = to_bytes(hmac.new(to_bytes(hash_key), encrypted_data, hashlib.sha256).hexdigest()) return b'hmac256:' + signature + b':' + encrypted_data @@ -192,7 +211,7 @@ def secure_loads(data, encryption_key, hash_key=None, compression_level=None): return secure_loads_deprecated(data, encryption_key, hash_key, compression_level) if components != 2: return None - version,signature,encrypted_data = data.split(b':', 2) + version, signature, encrypted_data = data.split(b':', 2) if version != b'hmac256': return None encryption_key = to_bytes(encryption_key) @@ -205,7 +224,7 @@ def secure_loads(data, encryption_key, hash_key=None, compression_level=None): IV, encrypted_data = encrypted_data[:16], encrypted_data[16:] cipher, _ = AES_new(pad(encryption_key)[:32], IV=IV) try: - data = unpad(cipher.decrypt(encrypted_data)) + data = unpad(AES_dec(cipher, encrypted_data)) if compression_level: data = zlib.decompress(data) return pickle.loads(data) @@ -226,7 +245,7 @@ def secure_dumps_deprecated(data, encryption_key, hash_key=None, compression_lev dump = zlib.compress(dump, compression_level) key = __pad_deprecated(encryption_key)[:32] cipher, IV = AES_new(key) - encrypted_data = base64.urlsafe_b64encode(IV + cipher.encrypt(pad(dump))) + encrypted_data = base64.urlsafe_b64encode(IV + AES_enc(cipher, pad(dump))) signature = to_bytes(hmac.new(to_bytes(hash_key), encrypted_data, hashlib.md5).hexdigest()) return signature + b':' + encrypted_data @@ -248,7 +267,7 @@ def secure_loads_deprecated(data, encryption_key, hash_key=None, compression_lev IV, encrypted_data = encrypted_data[:16], encrypted_data[16:] cipher, _ = AES_new(key, IV=IV) try: - data = cipher.decrypt(encrypted_data) + data = AES_dec(cipher, encrypted_data) data = data.rstrip(b' ') if compression_level: data = zlib.decompress(data) @@ -285,9 +304,9 @@ def initialize_urandom(): frandom = open('/dev/urandom', 'wb') try: if PY2: - frandom.write(''.join(chr(t) for t in ctokens)) # python 2 + frandom.write(''.join(chr(t) for t in ctokens)) else: - frandom.write(bytes([]).join(bytes([t]) for t in ctokens)) # python 3 + frandom.write(bytes([]).join(bytes([t]) for t in ctokens)) finally: frandom.close() except IOError: @@ -300,9 +319,9 @@ def initialize_urandom(): your system does not provide a cryptographically secure entropy source. This is not specific to web2py; consider deploying on a different operating system.""") if PY2: - packed = ''.join(chr(x) for x in ctokens) # python 2 + packed = ''.join(chr(x) for x in ctokens) else: - packed = bytes([]).join(bytes([x]) for x in ctokens) # python 3 + packed = bytes([]).join(bytes([x]) for x in ctokens) unpacked_ctokens = _struct_2_long_long.unpack(packed) return unpacked_ctokens, have_urandom UNPACKED_CTOKENS, HAVE_URANDOM = initialize_urandom() @@ -392,7 +411,7 @@ def is_loopback_ip_address(ip=None, addrinfo=None): Determines whether the address appears to be a loopback address. This assumes that the IP is valid. """ - if addrinfo: # see socket.getaddrinfo() for layout of addrinfo tuple + if addrinfo: # see socket.getaddrinfo() for layout of addrinfo tuple if addrinfo[0] == socket.AF_INET or addrinfo[0] == socket.AF_INET6: ip = addrinfo[4] if not isinstance(ip, basestring): @@ -433,11 +452,10 @@ def local_html_escape(data, quote=False): import html if isinstance(data, str): return html.escape(data, quote=quote) - data = data.replace(b"&", b"&") # Must be done first! + data = data.replace(b"&", b"&") # Must be done first! data = data.replace(b"<", b"<") data = data.replace(b">", b">") if quote: data = data.replace(b'"', b""") data = data.replace(b'\'', b"'") return data - diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 904545b4..00000000 --- a/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -pycrypto From a1c1d1357f029cc82048b22f2a73fd7607b5e501 Mon Sep 17 00:00:00 2001 From: niphlod Date: Tue, 4 Oct 2016 00:30:11 +0200 Subject: [PATCH 47/49] remove __pycache__ from the list of apps in case someone wonders how many core devs are actively using the admin app...here's the evidence ^_^' --- applications/admin/controllers/default.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/applications/admin/controllers/default.py b/applications/admin/controllers/default.py index b7831e58..e9560edf 100644 --- a/applications/admin/controllers/default.py +++ b/applications/admin/controllers/default.py @@ -310,12 +310,13 @@ def site(): regex = re.compile('^\w+$') if is_manager(): - apps = [f for f in os.listdir(apath(r=request)) if regex.match(f)] + apps = [a for a in os.listdir(apath(r=request)) if regex.match(f) and + a != '__pycache__'] else: - apps = [f.name for f in db(db.app.owner == auth.user_id).select()] + apps = [a.name for a in db(db.app.owner == auth.user_id).select()] if FILTER_APPS: - apps = [f for f in apps if f in FILTER_APPS] + apps = [a for a in apps if a in FILTER_APPS] apps = sorted(apps, key=lambda a: a.upper()) myplatform = platform.python_version() From b9c1b4d62bdb5b8ece74bb10599a076cfb3380dc Mon Sep 17 00:00:00 2001 From: niphlod Date: Tue, 4 Oct 2016 00:40:29 +0200 Subject: [PATCH 48/49] fixes #1485, thanks @abastardi once again --- gluon/shell.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/gluon/shell.py b/gluon/shell.py index 95359c3a..9d93f1a6 100644 --- a/gluon/shell.py +++ b/gluon/shell.py @@ -15,6 +15,7 @@ from __future__ import print_function import os import sys import code +import copy import logging import types import re @@ -167,6 +168,8 @@ def env( sys.stderr.write(e.traceback + '\n') sys.exit(1) + response._view_environment = copy.copy(environment) + environment['__name__'] = '__main__' return environment From 27ce91474d24389dc72062214244e7100f154f9d Mon Sep 17 00:00:00 2001 From: niphlod Date: Fri, 7 Oct 2016 13:10:44 +0200 Subject: [PATCH 49/49] fix issue with regex --- applications/admin/controllers/default.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/admin/controllers/default.py b/applications/admin/controllers/default.py index e9560edf..6ad8b332 100644 --- a/applications/admin/controllers/default.py +++ b/applications/admin/controllers/default.py @@ -310,7 +310,7 @@ def site(): regex = re.compile('^\w+$') if is_manager(): - apps = [a for a in os.listdir(apath(r=request)) if regex.match(f) and + apps = [a for a in os.listdir(apath(r=request)) if regex.match(a) and a != '__pycache__'] else: apps = [a.name for a in db(db.app.owner == auth.user_id).select()]