Changeset - 7d63bc813e3b
[Not reviewed]
Merge default
0 63 0
Thomas De Schampheleire - 6 years ago 2019-05-22 12:50:45
thomas.de_schampheleire@nokia.com
Merge stable
12 files changed:
0 comments (0 inline, 0 general)
.hgtags
Show inline comments
 
c097458480a5972dd75d5695b61e855fd0ab371e rhodecode-0.0.0.7.0
 
8bdec09436cb7e4a764bd2ba50b84060e30eb34f rhodecode-0.0.0.7.1
 
1a18994cdc3bdd156ee93c7c0fb8d94a88f1f640 rhodecode-0.0.0.7.2
 
a3a7c3e03b76ee264a828cb1087970bb98bbffcd rhodecode-0.0.0.7.3
 
58b46f9194c347641bfc9a26697ef413a4761971 rhodecode-0.0.0.7.4
 
710e7a75bb6b8346cee3bd0ddda67592e4790268 rhodecode-0.0.0.7.5
 
ca80f8c0056211dad33483a50b913593516d7a6c rhodecode-0.0.0.7.6
 
0cf49c29c846fefeb4e1a222e4b1850e9e3eaa62 rhodecode-0.0.0.7.7
 
702c7e565c56a49c89414e81f28571c8e5b67408 rhodecode-0.0.0.7.8
 
c12f4d19c95065f313eefcd45eac9ef507f5fa55 rhodecode-0.0.0.7.9
 
558eb7c5028f24a90b5466ed16be13b213ba1fc2 rhodecode-0.0.0.8.0
 
a9814a642e11092b243ca01721254a04633a0ffc rhodecode-0.0.0.8.1
 
ccbe729908844884aea89d00fb14a6cb92e10c06 rhodecode-0.0.0.8.2
 
ca41d544dbdfd2f81bd0304168492a26276aadb6 rhodecode-0.0.0.8.3
 
2fa16ec5822da0c6fade3dd1ed9b6c0655e5dbbf rhodecode-0.0.0.8.4
 
16ba57d8fe2317c49dbd422afd07ab497687aa02 rhodecode-0.0.0.8.5
 
53128b6b9a4ddb6ee9554cbb83a082a6d1316b42 rhodecode-0.0.1.0.0rc4
 
afd98d1f817e6a6b52172735c22160239e615a6b rhodecode-0.0.1.0.0
 
bee56f209c40a6880f2f633b02227b5ee1f8ff5a rhodecode-0.0.1.0.1
 
d85b0948e53925ebbbc49e9f7967013a04f866e9 rhodecode-0.0.1.0.2
 
d9c8dddb96af521e346f05b88d515c536eef3d17 rhodecode-0.0.1.1.0
 
344f748517814ed0408a49e392dc625f4cc37fdc rhodecode-0.0.1.1.1
 
6c01c12eafb8cc72d4c4cbd121400fad755b2862 rhodecode-0.0.1.1.2
 
4fa80e0484ef5c33feaa9c39fc66916f410ba353 rhodecode-0.0.1.1.3
 
cb77867d69d3c5931712aac486c980a42ee90745 rhodecode-0.0.1.1.5
 
cb77867d69d3c5931712aac486c980a42ee90745 rhodecode-0.0.1.1.5
 
008bdfdd95c8bd31ae6d89f76c75c1f49cbcd0bc rhodecode-0.0.1.1.5
 
c5af1d3c861fb36b156224e75c2f55a97f54657d rhodecode-0.0.1.1.6
 
7327a0d1584cf28d33e738048af1f6809d499451 rhodecode-0.0.1.1.7
 
bd102f45950f779995a1beae42b6eb099cdd27b3 rhodecode-0.0.1.1.7
 
c8974135732aa0ceb841cee6df66e29f089b4963 rhodecode-0.0.1.1.8
 
c252049af24cd98eef5f4143fa3abbff3c912e29 rhodecode-0.0.1.2.0
 
0b8fba8ab90b01f811a50e6e7384989cced21d38 rhodecode-0.0.1.2.1
 
22273bec00ba2fd860c60a9277d3d7229e288e18 rhodecode-0.0.1.2.2
 
1ff606a7858dbd8a5f70b3da5cc89524bd0d84f9 rhodecode-0.0.1.2.3
 
a7a282a902b207ce34e830d643c79b7ab52e3b35 rhodecode-0.0.1.2.4
 
b6b611e7722e754abebaae6e265cbb4c823d344d rhodecode-0.0.1.2.5
 
dbc82e3362a25d2aece42060089824c4342efd17 rhodecode-0.0.1.3.0
 
79a95f338fd0115b2cdb77118f39e17d22ff505c rhodecode-0.0.1.3.1
 
9ab21c5ddb84935bea5c743b4e147ed5a398b30c rhodecode-0.0.1.3.2
 
934906f028b582a254e0028ba25e5d20dd32b9cd rhodecode-0.0.1.3.3
 
af21362474e3ab5aa0e2fbb1c872356f2c16c4f3 rhodecode-0.0.1.3.4
 
0e2792e04bd316fe64335cbe6a476031ac60b29b rhodecode-0.0.1.3.5
 
edfff9f37916389144d3a3644d0a7d7adfd79b11 rhodecode-0.0.1.3.6
 
9ae95fdeca184f2404205645f06c6597b74ef2db rhodecode-0.0.1.4.0
 
909143a4dde53c46d4f24abb426ec870471c7de1 rhodecode-0.0.1.4.1
 
d998cc84cf726798486a438763053f0e1dc1b646 rhodecode-0.0.1.4.2
 
3f5d40b9dd99ccb009ea2211ee2d4b594c634946 rhodecode-0.0.1.4.3
 
3148c08cf86f1849917e2d50f7ab7766c1550b0a rhodecode-0.0.1.4.4
 
a5f0bc867edc88be23eb808693e5393a97d4c54a rhodecode-0.0.1.5.0
 
3259dc7caea48687eab018ee646ae6ad7e7ef377 rhodecode-0.0.1.5.1
 
efe23d6c178c11d575a0214181276a3452776e48 rhodecode-0.0.1.5.2
 
1a498b11f1540f5b94b6f6009298f5dc3eaad9e9 rhodecode-0.0.1.5.3
 
3447862ad8c9ceba85857774c526e39fde3a2281 rhodecode-0.0.1.5.4
 
c15d7b336af58df9f1bbc8f8957464e7ea618d4c rhodecode-0.0.1.6.0rc1
 
78b53ee0d247f90d51b028307ff5717851b6c265 rhodecode-0.0.1.6.0
 
351ad34d56321349ff5bd38f537bd768b8efef2e rhodecode-0.0.1.7.0
 
1f71ef689d2a3c9978cea6591a1f4e9107a5ca83 rhodecode-0.0.1.7.1
 
cc48c1541c7e2e84114bf92a0f9cd4b8b1341545 0.0
 
d17e88a1a88a29f6fac948c94498129e405a40d3 0.1
 
ad0ce803b40cb17fc3988373052943e041030b02 0.2
 
c6e32714336345403adf76abb6ebf9b8116fcdc7 0.2.1
 
14f488a5dc4ca6647bc6acf12534fd137e968aa8 0.2.2
 
9b3e9e242f5c97cc0c7657e5ac93dce7de61ca16 0.3
 
9bf8eb837e785b6856ccfac264e977ce3ebe1535 0.3.1
 
a84d40e9481fcea4dafadee86b03f0dd401527d6 0.3.2
 
64ea7ea0923618a0c117acebb816a6f0d162bfdb 0.3.3
 
cf635c823ea059cc3a1581b82d8672e46b682384 0.3.4
 
4cca4cc6a0a97f4c4763317184cd41aca4297630 0.3.5
 
082c9b8f0f17bd34740eb90c69bdc4c80d4b5b31 0.3.6
 
a18445b85d407294da0b7f1d8be3bedef5ffdea6 0.3.7
 
8db761c407685e7b08b800c947890035b0d67025 0.4.0rc1
 
60f726162fd6c515bd819feb423be73cad01d7d3 0.4.0rc2
 
19086c5de05f4984d7a90cd31624c45dd893f6bb 0.4.0
 
da65398a62fff50f3d241796cbf17acdea2092ef 0.4.1
CONTRIBUTORS
Show inline comments
 
List of contributors to Kallithea project:
 

	
 
    Andrej Shadura <andrew@shadura.me> 2012 2014-2017 2019
 
    Thomas De Schampheleire <thomas.de_schampheleire@nokia.com> 2014-2019
 
    Étienne Gilli <etienne.gilli@gmail.com> 2015-2017 2019
 
    Mads Kiilerich <mads@kiilerich.com> 2016-2019
 
    Allan Nordhøy <epost@anotheragency.no> 2017-2019
 
    ssantos <ssantos@web.de> 2018-2019
 
    Danni Randeris <danniranderis@gmail.com> 2019
 
    Edmund Wong <ewong@crazy-cat.org> 2019
 
    Manuel Jacob <me@manueljacob.de> 2019
 
    Wolfgang Scherer <wolfgang.scherer@gmx.de> 2019
 
    Dominik Ruf <dominikruf@gmail.com> 2012 2014-2018
 
    Michal Čihař <michal@cihar.com> 2014-2015 2018
 
    Branko Majic <branko@majic.rs> 2015 2018
 
    Chris Rule <crule@aegistg.com> 2018
 
    Jesús Sánchez <jsanchezfdz95@gmail.com> 2018
 
    Patrick Vane <patrick_vane@lowentry.com> 2018
 
    Pheng Heong Tan <phtan90@gmail.com> 2018
 
    ssantos <ssantos@web.de> 2018
 
    Максим Якимчук <xpinovo@gmail.com> 2018
 
    Марс Ямбар <mjambarmeta@gmail.com> 2018
 
    Mads Kiilerich <madski@unity3d.com> 2012-2017
 
    Unity Technologies 2012-2017
 
    Søren Løvborg <sorenl@unity3d.com> 2015-2017
 
    Sam Jaques <sam.jaques@me.com> 2015 2017
 
    Asterios Dimitriou <steve@pci.gr> 2016-2017
 
    Alessandro Molina <alessandro.molina@axant.it> 2017
 
    Anton Schur <tonich.sh@gmail.com> 2017
 
    Ching-Chen Mao <mao@lins.fju.edu.tw> 2017
 
    Eivind Tagseth <eivindt@gmail.com> 2017
 
    FUJIWARA Katsunori <foozy@lares.dti.ne.jp> 2017
 
    Holger Schramm <info@schramm.by> 2017
 
    Karl Goetz <karl@kgoetz.id.au> 2017
 
    Lars Kruse <devel@sumpfralle.de> 2017
 
    Marko Semet <markosemet@googlemail.com> 2017
 
    Viktar Vauchkevich <victorenator@gmail.com> 2017
 
    Takumi IINO <trot.thunder@gmail.com> 2012-2016
 
    Jan Heylen <heyleke@gmail.com> 2015-2016
 
    Robert Martinez <ntttq@inboxen.org> 2015-2016
 
    Robert Rauch <mail@robertrauch.de> 2015-2016
 
    Angel Ezquerra <angel.ezquerra@gmail.com> 2016
 
    Anton Shestakov <av6@dwimlabs.net> 2016
 
    Brandon Jones <bjones14@gmail.com> 2016
 
    Kateryna Musina <kateryna@unity3d.com> 2016
 
    Konstantin Veretennicov <kveretennicov@gmail.com> 2016
 
    Oscar Curero <oscar@naiandei.net> 2016
 
    Robert James Dennington <tinytimrob@googlemail.com> 2016
 
    timeless@gmail.com 2016
 
    YFdyh000 <yfdyh000@gmail.com> 2016
 
    Aras Pranckevičius <aras@unity3d.com> 2012-2013 2015
 
    Sean Farley <sean.michael.farley@gmail.com> 2013-2015
 
    Christian Oyarzun <oyarzun@gmail.com> 2014-2015
 
    Joseph Rivera <rivera.d.joseph@gmail.com> 2014-2015
 
    Anatoly Bubenkov <bubenkoff@gmail.com> 2015
 
    Andrew Bartlett <abartlet@catalyst.net.nz> 2015
 
    Balázs Úr <urbalazs@gmail.com> 2015
 
    Ben Finney <ben@benfinney.id.au> 2015
 
    Daniel Hobley <danielh@unity3d.com> 2015
 
    David Avigni <david.avigni@ankapi.com> 2015
 
    Denis Blanchette <dblanchette@coveo.com> 2015
 
    duanhongyi <duanhongyi@doopai.com> 2015
 
    EriCSN Chang <ericsning@gmail.com> 2015
 
    Grzegorz Krason <grzegorz.krason@gmail.com> 2015
 
    Jiří Suchan <yed@vanyli.net> 2015
 
    Kazunari Kobayashi <kobanari@nifty.com> 2015
 
    Kevin Bullock <kbullock@ringworld.org> 2015
 
    kobanari <kobanari@nifty.com> 2015
 
    Marc Abramowitz <marc@marc-abramowitz.com> 2015
 
    Marc Villetard <marc.villetard@gmail.com> 2015
 
    Matthias Zilk <matthias.zilk@gmail.com> 2015
 
    Michael Pohl <michael@mipapo.de> 2015
 
    Michael V. DePalatis <mike@depalatis.net> 2015
 
    Morten Skaaning <mortens@unity3d.com> 2015
 
    Nick High <nick@silverchip.org> 2015
 
    Niemand Jedermann <predatorix@web.de> 2015
 
    Peter Vitt <petervitt@web.de> 2015
 
    Ronny Pfannschmidt <opensource@ronnypfannschmidt.de> 2015
 
    Tuux <tuxa@galaxie.eu.org> 2015
 
    Viktar Palstsiuk <vipals@gmail.com> 2015
 
    Ante Ilic <ante@unity3d.com> 2014
 
    Bradley M. Kuhn <bkuhn@sfconservancy.org> 2014
 
    Calinou <calinou@opmbx.org> 2014
 
    Daniel Anderson <daniel@dattrix.com> 2014
 
    Henrik Stuart <hg@hstuart.dk> 2014
 
    Ingo von Borstel <kallithea@planetmaker.de> 2014
 
    Jelmer Vernooij <jelmer@samba.org> 2014
 
    Jim Hague <jim.hague@acm.org> 2014
 
    Matt Fellows <kallithea@matt-fellows.me.uk> 2014
 
    Max Roman <max@choloclos.se> 2014
 
    Na'Tosha Bard <natosha@unity3d.com> 2014
 
    Rasmus Selsmark <rasmuss@unity3d.com> 2014
 
    Tim Freund <tim@freunds.net> 2014
 
    Travis Burtrum <android@moparisthebest.com> 2014
 
    Zoltan Gyarmati <mr.zoltan.gyarmati@gmail.com> 2014
 
    Marcin Kuźmiński <marcin@python-works.com> 2010-2013
 
    xpol <xpolife@gmail.com> 2012-2013
 
    Aparkar <aparkar@icloud.com> 2013
 
    Dennis Brakhane <brakhane@googlemail.com> 2013
 
    Grzegorz Rożniecki <xaerxess@gmail.com> 2013
 
    Jonathan Sternberg <jonathansternberg@gmail.com> 2013
 
    Leonardo Carneiro <leonardo@unity3d.com> 2013
 
    Magnus Ericmats <magnus.ericmats@gmail.com> 2013
 
    Martin Vium <martinv@unity3d.com> 2013
 
    Simon Lopez <simon.lopez@slopez.org> 2013
 
    Ton Plomp <tcplomp@gmail.com> 2013
 
    Augusto Herrmann <augusto.herrmann@planejamento.gov.br> 2011-2012
 
    Dan Sheridan <djs@adelard.com> 2012
 
    Dies Koper <diesk@fast.au.fujitsu.com> 2012
 
    Erwin Kroon <e.kroon@smartmetersolutions.nl> 2012
 
    H Waldo G <gwaldo@gmail.com> 2012
 
    hppj <hppj@postmage.biz> 2012
 
    Indra Talip <indra.talip@gmail.com> 2012
 
    mikespook 2012
 
    nansenat16 <nansenat16@null.tw> 2012
 
    Philip Jameson <philip.j@hostdime.com> 2012
 
    Raoul Thill <raoul.thill@gmail.com> 2012
 
    Stefan Engel <mail@engel-stefan.de> 2012
 
    Tony Bussieres <t.bussieres@gmail.com> 2012
 
    Vincent Caron <vcaron@bearstech.com> 2012
 
    Vincent Duvert <vincent@duvert.net> 2012
 
    Vladislav Poluhin <nuklea@gmail.com> 2012
 
    Zachary Auclair <zach101@gmail.com> 2012
 
    Ankit Solanki <ankit.solanki@gmail.com> 2011
 
    Dmitri Kuznetsov 2011
 
    Jared Bunting <jared.bunting@peachjean.com> 2011
 
    Jason Harris <jason@jasonfharris.com> 2011
 
    Les Peabody <lpeabody@gmail.com> 2011
 
    Liad Shani <liadff@gmail.com> 2011
 
    Lorenzo M. Catucci <lorenzo@sancho.ccd.uniroma2.it> 2011
 
    Matt Zuba <matt.zuba@goodwillaz.org> 2011
 
    Nicolas VINOT <aeris@imirhil.fr> 2011
 
    Shawn K. O'Shea <shawn@eth0.net> 2011
 
    Thayne Harbaugh <thayne@fusionio.com> 2011
 
    Łukasz Balcerzak <lukaszbalcerzak@gmail.com> 2010
 
    Andrew Kesterson <andrew@aklabs.net>
 
    cejones
 
    David A. Sjøen <david.sjoen@westcon.no>
 
    James Rhodes <jrhodes@redpointsoftware.com.au>
 
    Jonas Oberschweiber <jonas.oberschweiber@d-velop.de>
 
    larikale
 
    RhodeCode GmbH
 
    Sebastian Kreutzberger <sebastian@rhodecode.com>
 
    Steve Romanow <slestak989@gmail.com>
 
    SteveCohen
 
    Thomas <thomas@rhodecode.com>
 
    Thomas Waldmann <tw-public@gmx.de>
development.ini
Show inline comments
 
################################################################################
 
################################################################################
 
# Kallithea - config file generated with kallithea-config                      #
 
#                                                                              #
 
# The %(here)s variable will be replaced with the parent directory of this file#
 
################################################################################
 
################################################################################
 

	
 
[DEFAULT]
 

	
 
################################################################################
 
## Email settings                                                             ##
 
##                                                                            ##
 
## Refer to the documentation ("Email settings") for more details.            ##
 
##                                                                            ##
 
## It is recommended to use a valid sender address that passes access         ##
 
## validation and spam filtering in mail servers.                             ##
 
################################################################################
 

	
 
## 'From' header for application emails. You can optionally add a name.
 
## Default:
 
#app_email_from = Kallithea
 
## Examples:
 
#app_email_from = Kallithea <kallithea-noreply@example.com>
 
#app_email_from = kallithea-noreply@example.com
 

	
 
## Subject prefix for application emails.
 
## A space between this prefix and the real subject is automatically added.
 
## Default:
 
#email_prefix =
 
## Example:
 
#email_prefix = [Kallithea]
 

	
 
## Recipients for error emails and fallback recipients of application mails.
 
## Multiple addresses can be specified, comma-separated.
 
## Only addresses are allowed, do not add any name part.
 
## Default:
 
#email_to =
 
## Examples:
 
#email_to = admin@example.com
 
#email_to = admin@example.com,another_admin@example.com
 
email_to =
 

	
 
## 'From' header for error emails. You can optionally add a name.
 
## Default: (none)
 
## Examples:
 
#error_email_from = Kallithea Errors <kallithea-noreply@example.com>
 
#error_email_from = kallithea_errors@example.com
 
error_email_from =
 

	
 
## SMTP server settings
 
## If specifying credentials, make sure to use secure connections.
 
## Default: Send unencrypted unauthenticated mails to the specified smtp_server.
 
## For "SSL", use smtp_use_ssl = true and smtp_port = 465.
 
## For "STARTTLS", use smtp_use_tls = true and smtp_port = 587.
 
smtp_server =
 
#smtp_username =
 
#smtp_password =
 
smtp_port =
 
#smtp_use_ssl = false
 
#smtp_use_tls = false
 

	
 
## Entry point for 'gearbox serve'
 
[server:main]
 
#host = 127.0.0.1
 
host = 0.0.0.0
 
port = 5000
 

	
 
## WAITRESS ##
 
use = egg:waitress#main
 
## number of worker threads
 
threads = 1
 
## MAX BODY SIZE 100GB
 
max_request_body_size = 107374182400
 
## use poll instead of select, fixes fd limits, may not work on old
 
## windows systems.
 
#asyncore_use_poll = True
 

	
 
## middleware for hosting the WSGI application under a URL prefix
 
#[filter:proxy-prefix]
 
#use = egg:PasteDeploy#prefix
 
#prefix = /<your-prefix>
 

	
 
[app:main]
 
use = egg:kallithea
 
## enable proxy prefix middleware
 
#filter-with = proxy-prefix
 

	
 
full_stack = true
 
static_files = true
 

	
 
## Internationalization (see setup documentation for details)
 
## By default, the language requested by the browser is used if available.
 
#i18n.enable = false
 
#i18n.enabled = false
 
## Fallback language, empty for English (valid values are the names of subdirectories in kallithea/i18n):
 
i18n.lang =
 

	
 
cache_dir = %(here)s/data
 
index_dir = %(here)s/data/index
 

	
 
## uncomment and set this path to use archive download cache
 
archive_cache_dir = %(here)s/tarballcache
 

	
 
## change this to unique ID for security
 
#app_instance_uuid = VERY-SECRET
 
app_instance_uuid = development-not-secret
 

	
 
## cut off limit for large diffs (size in bytes)
 
cut_off_limit = 256000
 

	
 
## force https in Kallithea, fixes https redirects, assumes it's always https
 
force_https = false
 

	
 
## use Strict-Transport-Security headers
 
use_htsts = false
 

	
 
## number of commits stats will parse on each iteration
 
commit_parse_limit = 25
 

	
 
## Path to Python executable to be used for git hooks.
 
## This value will be written inside the git hook scripts as the text
 
## after '#!' (shebang). When empty or not defined, the value of
 
## 'sys.executable' at the time of installation of the git hooks is
 
## used, which is correct in many cases but for example not when using uwsgi.
 
## If you change this setting, you should reinstall the Git hooks via
 
## Admin > Settings > Remap and Rescan.
 
# git_hook_interpreter = /srv/kallithea/venv/bin/python2
 

	
 
## path to git executable
 
git_path = git
 

	
 
## git rev filter option, --all is the default filter, if you need to
 
## hide all refs in changelog switch this to --branches --tags
 
#git_rev_filter = --branches --tags
 

	
 
## RSS feed options
 
rss_cut_off_limit = 256000
 
rss_items_per_page = 10
 
rss_include_diff = false
 

	
 
## options for showing and identifying changesets
 
show_sha_length = 12
 
show_revision_number = false
 

	
 
## Canonical URL to use when creating full URLs in UI and texts.
 
## Useful when the site is available under different names or protocols.
 
## Defaults to what is provided in the WSGI environment.
 
#canonical_url = https://kallithea.example.com/repos
 

	
 
## gist URL alias, used to create nicer urls for gist. This should be an
 
## url that does rewrites to _admin/gists/<gistid>.
 
## example: http://gist.example.com/{gistid}. Empty means use the internal
 
## Kallithea url, ie. http[s]://kallithea.example.com/_admin/gists/<gistid>
 
gist_alias_url =
 

	
 
## white list of API enabled controllers. This allows to add list of
 
## controllers to which access will be enabled by api_key. eg: to enable
 
## api access to raw_files put `FilesController:raw`, to enable access to patches
 
## add `ChangesetController:changeset_patch`. This list should be "," separated
 
## Syntax is <ControllerClass>:<function>. Check debug logs for generated names
 
## Recommended settings below are commented out:
 
api_access_controllers_whitelist =
 
#    ChangesetController:changeset_patch,
 
#    ChangesetController:changeset_raw,
 
#    FilesController:raw,
 
#    FilesController:archivefile
 

	
 
## default encoding used to convert from and to unicode
 
## can be also a comma separated list of encoding in case of mixed encodings
 
default_encoding = utf-8
 

	
 
## Set Mercurial encoding, similar to setting HGENCODING before launching Kallithea
 
hgencoding = utf-8
 

	
 
## issue tracker for Kallithea (leave blank to disable, absent for default)
 
#bugtracker = https://bitbucket.org/conservancy/kallithea/issues
 

	
 
## issue tracking mapping for commit messages, comments, PR descriptions, ...
 
## Refer to the documentation ("Integration with issue trackers") for more details.
 

	
 
## regular expression to match issue references
 
## This pattern may/should contain parenthesized groups, that can
 
## be referred to in issue_server_link or issue_sub using Python backreferences
 
## (e.g. \1, \2, ...). You can also create named groups with '(?P<groupname>)'.
 
## To require mandatory whitespace before the issue pattern, use:
 
## (?:^|(?<=\s)) before the actual pattern, and for mandatory whitespace
 
## behind the issue pattern, use (?:$|(?=\s)) after the actual pattern.
 

	
 
issue_pat = #(\d+)
 

	
 
## server url to the issue
 
## This pattern may/should contain backreferences to parenthesized groups in issue_pat.
 
## A backreference can be \1, \2, ... or \g<groupname> if you specified a named group
 
## called 'groupname' in issue_pat.
 
## The special token {repo} is replaced with the full repository name
 
## including repository groups, while {repo_name} is replaced with just
 
## the name of the repository.
 

	
 
issue_server_link = https://issues.example.com/{repo}/issue/\1
 

	
 
## substitution pattern to use as the link text
 
## If issue_sub is empty, the text matched by issue_pat is retained verbatim
 
## for the link text. Otherwise, the link text is that of issue_sub, with any
 
## backreferences to groups in issue_pat replaced.
 

	
 
issue_sub =
 

	
 
## issue_pat, issue_server_link and issue_sub can have suffixes to specify
 
## multiple patterns, to other issues server, wiki or others
 
## below an example how to create a wiki pattern
 
# wiki-some-id -> https://wiki.example.com/some-id
 

	
 
#issue_pat_wiki = wiki-(\S+)
 
#issue_server_link_wiki = https://wiki.example.com/\1
 
#issue_sub_wiki = WIKI-\1
 

	
 
## alternative return HTTP header for failed authentication. Default HTTP
 
## response is 401 HTTPUnauthorized. Currently Mercurial clients have trouble with
 
## handling that. Set this variable to 403 to return HTTPForbidden
 
auth_ret_code =
 

	
 
## locking return code. When repository is locked return this HTTP code. 2XX
 
## codes don't break the transactions while 4XX codes do
 
lock_ret_code = 423
 

	
 
## allows to change the repository location in settings page
 
allow_repo_location_change = True
 

	
 
## allows to setup custom hooks in settings page
 
allow_custom_hooks_settings = True
 

	
 
## extra extensions for indexing, space separated and without the leading '.'.
 
# index.extensions =
 
#    gemfile
 
#    lock
 

	
 
## extra filenames for indexing, space separated
 
# index.filenames =
 
#    .dockerignore
 
#    .editorconfig
 
#    INSTALL
 
#    CHANGELOG
 

	
 
####################################
 
###        CELERY CONFIG        ####
 
####################################
 

	
 
use_celery = false
 

	
 
## Example: connect to the virtual host 'rabbitmqhost' on localhost as rabbitmq:
 
broker.url = amqp://rabbitmq:qewqew@localhost:5672/rabbitmqhost
 

	
 
celery.imports = kallithea.lib.celerylib.tasks
 
celery.accept.content = pickle
 
celery.result.backend = amqp
 
celery.result.dburi = amqp://
 
celery.result.serialier = json
 

	
 
#celery.send.task.error.emails = true
 
#celery.amqp.task.result.expires = 18000
 

	
 
celeryd.concurrency = 2
 
celeryd.max.tasks.per.child = 1
 

	
 
## If true, tasks will never be sent to the queue, but executed locally instead.
 
celery.always.eager = false
 

	
 
####################################
 
###         BEAKER CACHE        ####
 
####################################
 

	
 
beaker.cache.data_dir = %(here)s/data/cache/data
 
beaker.cache.lock_dir = %(here)s/data/cache/lock
 

	
 
beaker.cache.regions = short_term,long_term,sql_cache_short
 

	
 
beaker.cache.short_term.type = memory
 
beaker.cache.short_term.expire = 60
 
beaker.cache.short_term.key_length = 256
 

	
 
beaker.cache.long_term.type = memory
 
beaker.cache.long_term.expire = 36000
 
beaker.cache.long_term.key_length = 256
 

	
 
beaker.cache.sql_cache_short.type = memory
 
beaker.cache.sql_cache_short.expire = 10
 
beaker.cache.sql_cache_short.key_length = 256
 

	
 
####################################
 
###       BEAKER SESSION        ####
 
####################################
 

	
 
## Name of session cookie. Should be unique for a given host and path, even when running
 
## on different ports. Otherwise, cookie sessions will be shared and messed up.
 
beaker.session.key = kallithea
 
## Sessions should always only be accessible by the browser, not directly by JavaScript.
 
beaker.session.httponly = true
 
## Session lifetime. 2592000 seconds is 30 days.
 
beaker.session.timeout = 2592000
 

	
 
## Server secret used with HMAC to ensure integrity of cookies.
 
#beaker.session.secret = VERY-SECRET
 
beaker.session.secret = development-not-secret
 
## Further, encrypt the data with AES.
 
#beaker.session.encrypt_key = <key_for_encryption>
 
#beaker.session.validate_key = <validation_key>
 

	
 
## Type of storage used for the session, current types are
 
## dbm, file, memcached, database, and memory.
 

	
 
## File system storage of session data. (default)
 
#beaker.session.type = file
 

	
 
## Cookie only, store all session data inside the cookie. Requires secure secrets.
 
#beaker.session.type = cookie
 

	
 
## Database storage of session data.
 
#beaker.session.type = ext:database
 
#beaker.session.sa.url = postgresql://postgres:qwe@localhost/kallithea
 
#beaker.session.table_name = db_session
docs/overview.rst
Show inline comments
 
.. _overview:
 

	
 
=====================
 
Installation overview
 
=====================
 

	
 
Some overview and some details that can help understanding the options when
 
installing Kallithea.
 

	
 

	
 
Python environment
 
------------------
 

	
 
**Kallithea** is written entirely in Python_ and requires Python version
 
2.6 or higher. Python 3.x is currently not supported.
 

	
 
Given a Python installation, there are different ways of providing the
 
environment for running Python applications. Each of them pretty much
 
corresponds to a ``site-packages`` directory somewhere where packages can be
 
installed.
 

	
 
Kallithea itself can be run from source or be installed, but even when running
 
from source, there are some dependencies that must be installed in the Python
 
environment used for running Kallithea.
 

	
 
- Packages *could* be installed in Python's ``site-packages`` directory ... but
 
  that would require running pip_ as root and it would be hard to uninstall or
 
  upgrade and is probably not a good idea unless using a package manager.
 

	
 
- Packages could also be installed in ``~/.local`` ... but that is probably
 
  only a good idea if using a dedicated user per application or instance.
 

	
 
- Finally, it can be installed in a virtualenv_. That is a very lightweight
 
  "container" where each Kallithea instance can get its own dedicated and
 
  self-contained virtual environment.
 

	
 
We recommend using virtualenv for installing Kallithea.
 

	
 

	
 
Locale environment
 
------------------
 

	
 
In order to ensure a correct functioning of Kallithea with respect to non-ASCII
 
characters in user names, file paths, commit messages, etc., it is very
 
important that Kallithea is run with a correct `locale` configuration.
 

	
 
On Unix, environment variables like ``LANG`` or ``LC_ALL`` can specify a language (like
 
``en_US``) and encoding (like ``UTF-8``) to use for code points outside the ASCII
 
range. The flexibility of supporting multiple encodings of Unicode has the flip
 
side of having to specify which encoding to use - especially for Mercurial.
 

	
 
It depends on the OS distribution and system configuration which locales are
 
available. For example, some Docker containers based on Debian default to only
 
supporting the ``C`` language, while other Linux environments have ``en_US`` but not
 
``C``. The ``locale -a`` command will show which values are available on the
 
current system. Regardless of the actual language, you should normally choose a
 
locale that has the ``UTF-8`` encoding (note that spellings ``utf8``, ``utf-8``,
 
``UTF8``, ``UTF-8`` are all referring to the same thing)
 

	
 
For technical reasons, the locale configuration **must** be provided in the
 
environment in which Kallithea runs - it cannot be specified in the ``.ini`` file.
 
How to practically do this depends on the web server that is used and the way it
 
is started. For example, gearbox is often started by a normal user, either
 
manually or via a script. In this case, the required locale environment
 
variables can be provided directly in that user's environment or in the script.
 
However, web servers like Apache are often started at boot via an init script or
 
service file. Modifying the environment for this case would thus require
 
root/administrator privileges. Moreover, that environment would dictate the
 
settings for all web services running under that web server, Kallithea being
 
just one of them. Specifically in the case of Apache with ``mod_wsgi``, the
 
locale can be set for a specific service in its ``WSGIDaemonProcess`` directive,
 
using the ``lang`` parameter.
 

	
 

	
 
Installation methods
 
--------------------
 

	
 
Kallithea must be installed on a server. Kallithea is installed in a Python
 
environment so it can use packages that are installed there and make itself
 
available for other packages.
 

	
 
Two different cases will pretty much cover the options for how it can be
 
installed.
 

	
 
- The Kallithea source repository can be cloned and used -- it is kept stable and
 
  can be used in production. The Kallithea maintainers use the development
 
  branch in production. The advantage of installation from source and regularly
 
  updating it is that you take advantage of the most recent improvements. Using
 
  it directly from a DVCS also means that it is easy to track local customizations.
 

	
 
  Running ``pip install -e .`` in the source will use pip to install the
 
  necessary dependencies in the Python environment and create a
 
  ``.../site-packages/Kallithea.egg-link`` file there that points at the Kallithea
 
  source.
 

	
 
- Kallithea can also be installed from ready-made packages using a package manager.
 
  The official released versions are available on PyPI_ and can be downloaded and
 
  installed with all dependencies using ``pip install kallithea``.
 

	
 
  With this method, Kallithea is installed in the Python environment as any
 
  other package, usually as a ``.../site-packages/Kallithea-X-py2.7.egg/``
 
  directory with Python files and everything else that is needed.
 

	
 
  (``pip install kallithea`` from a source tree will do pretty much the same
 
  but build the Kallithea package itself locally instead of downloading it.)
 

	
 
.. note::
 
   Kallithea includes front-end code that needs to be processed first.
 
   The tool npm_ is used to download external dependencies and orchestrate the
 
   processing. The ``npm`` binary must thus be available.
 

	
 

	
 
Web server
 
----------
 

	
 
Kallithea is (primarily) a WSGI_ application that must be run from a web
 
server that serves WSGI applications over HTTP.
 

	
 
Kallithea itself is not serving HTTP (or HTTPS); that is the web server's
 
responsibility. Kallithea does however need to know its own user facing URL
 
(protocol, address, port and path) for each HTTP request. Kallithea will
 
usually use its own HTML/cookie based authentication but can also be configured
 
to use web server authentication.
 

	
 
There are several web server options:
 

	
 
- Kallithea uses the Gearbox_ tool as command line interface. Gearbox provides
 
  ``gearbox serve`` as a convenient way to launch a Python WSGI / web server
 
  from the command line. That is perfect for development and evaluation.
 
  Actual use in production might have different requirements and need extra
 
  work to make it manageable as a scalable system service.
 

	
 
  Gearbox comes with its own built-in web server but Kallithea defaults to use
 
  Waitress_. Gunicorn_ is also an option. These web servers have different
 
  limited feature sets.
 

	
 
  The web server used by ``gearbox`` is configured in the ``.ini`` file passed
 
  to it. The entry point for the WSGI application is configured
 
  in ``setup.py`` as ``kallithea.config.middleware:make_app``.
 

	
 
- `Apache httpd`_ can serve WSGI applications directly using mod_wsgi_ and a
 
  simple Python file with the necessary configuration. This is a good option if
 
  Apache is an option.
 

	
 
- uWSGI_ is also a full web server with built-in WSGI module.
 

	
 
- IIS_ can also server WSGI applications directly using isapi-wsgi_.
 

	
 
- A `reverse HTTP proxy <https://en.wikipedia.org/wiki/Reverse_proxy>`_
 
  can be put in front of another web server which has WSGI support.
 
  Such a layered setup can be complex but might in some cases be the right
 
  option, for example to standardize on one internet-facing web server, to add
 
  encryption or special authentication or for other security reasons, to
 
  provide caching of static files, or to provide load balancing or fail-over.
 
  Nginx_, Varnish_ and HAProxy_ are often used for this purpose, often in front
 
  of a ``gearbox serve`` that somehow is wrapped as a service.
 

	
 
The best option depends on what you are familiar with and the requirements for
 
performance and stability. Also, keep in mind that Kallithea mainly is serving
 
dynamically generated pages from a relatively slow Python process. Kallithea is
 
also often used inside organizations with a limited amount of users and thus no
 
continuous hammering from the internet.
 

	
 

	
 
.. _Python: http://www.python.org/
 
.. _Gunicorn: http://gunicorn.org/
 
.. _Waitress: http://waitress.readthedocs.org/en/latest/
 
.. _virtualenv: http://pypi.python.org/pypi/virtualenv
 
.. _Gearbox: http://turbogears.readthedocs.io/en/latest/turbogears/gearbox.html
 
.. _PyPI: https://pypi.python.org/pypi
 
.. _Apache httpd: http://httpd.apache.org/
 
.. _mod_wsgi: https://code.google.com/p/modwsgi/
 
.. _isapi-wsgi: https://github.com/hexdump42/isapi-wsgi
 
.. _uWSGI: https://uwsgi-docs.readthedocs.org/en/latest/
 
.. _nginx: http://nginx.org/en/
 
.. _iis: http://en.wikipedia.org/wiki/Internet_Information_Services
 
.. _pip: http://en.wikipedia.org/wiki/Pip_%28package_manager%29
 
.. _WSGI: http://en.wikipedia.org/wiki/Web_Server_Gateway_Interface
 
.. _HAProxy: http://www.haproxy.org/
 
.. _Varnish: https://www.varnish-cache.org/
 
.. _npm: https://www.npmjs.com/
docs/setup.rst
Show inline comments
 
@@ -310,278 +310,283 @@ HTTPS support
 

	
 
Kallithea will by default generate URLs based on the WSGI environment.
 

	
 
Alternatively, you can use some special configuration settings to control
 
directly which scheme/protocol Kallithea will use when generating URLs:
 

	
 
- With ``https_fixup = true``, the scheme will be taken from the
 
  ``X-Url-Scheme``, ``X-Forwarded-Scheme`` or ``X-Forwarded-Proto`` HTTP header
 
  (default ``http``).
 
- With ``force_https = true`` the default will be ``https``.
 
- With ``use_htsts = true``, Kallithea will set ``Strict-Transport-Security`` when using https.
 

	
 
.. _nginx_virtual_host:
 

	
 

	
 
Nginx virtual host example
 
--------------------------
 

	
 
Sample config for Nginx using proxy:
 

	
 
.. code-block:: nginx
 

	
 
    upstream kallithea {
 
        server 127.0.0.1:5000;
 
        # add more instances for load balancing
 
        #server 127.0.0.1:5001;
 
        #server 127.0.0.1:5002;
 
    }
 

	
 
    ## gist alias
 
    server {
 
       listen          443;
 
       server_name     gist.example.com;
 
       access_log      /var/log/nginx/gist.access.log;
 
       error_log       /var/log/nginx/gist.error.log;
 

	
 
       ssl on;
 
       ssl_certificate     gist.your.kallithea.server.crt;
 
       ssl_certificate_key gist.your.kallithea.server.key;
 

	
 
       ssl_session_timeout 5m;
 

	
 
       ssl_protocols SSLv3 TLSv1;
 
       ssl_ciphers DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:EDH-RSA-DES-CBC3-SHA:AES256-SHA:DES-CBC3-SHA:AES128-SHA:RC4-SHA:RC4-MD5;
 
       ssl_prefer_server_ciphers on;
 

	
 
       rewrite ^/(.+)$ https://kallithea.example.com/_admin/gists/$1;
 
       rewrite (.*)    https://kallithea.example.com/_admin/gists;
 
    }
 

	
 
    server {
 
       listen          443;
 
       server_name     kallithea.example.com
 
       access_log      /var/log/nginx/kallithea.access.log;
 
       error_log       /var/log/nginx/kallithea.error.log;
 

	
 
       ssl on;
 
       ssl_certificate     your.kallithea.server.crt;
 
       ssl_certificate_key your.kallithea.server.key;
 

	
 
       ssl_session_timeout 5m;
 

	
 
       ssl_protocols SSLv3 TLSv1;
 
       ssl_ciphers DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:EDH-RSA-DES-CBC3-SHA:AES256-SHA:DES-CBC3-SHA:AES128-SHA:RC4-SHA:RC4-MD5;
 
       ssl_prefer_server_ciphers on;
 

	
 
       ## uncomment root directive if you want to serve static files by nginx
 
       ## requires static_files = false in .ini file
 
       #root /srv/kallithea/kallithea/kallithea/public;
 
       include         /etc/nginx/proxy.conf;
 
       location / {
 
            try_files $uri @kallithea;
 
       }
 

	
 
       location @kallithea {
 
            proxy_pass      http://127.0.0.1:5000;
 
       }
 

	
 
    }
 

	
 
Here's the proxy.conf. It's tuned so it will not timeout on long
 
pushes or large pushes::
 

	
 
    proxy_redirect              off;
 
    proxy_set_header            Host $host;
 
    ## needed for container auth
 
    #proxy_set_header            REMOTE_USER $remote_user;
 
    #proxy_set_header            X-Forwarded-User $remote_user;
 
    proxy_set_header            X-Url-Scheme $scheme;
 
    proxy_set_header            X-Host $http_host;
 
    proxy_set_header            X-Real-IP $remote_addr;
 
    proxy_set_header            X-Forwarded-For $proxy_add_x_forwarded_for;
 
    proxy_set_header            Proxy-host $proxy_host;
 
    proxy_buffering             off;
 
    proxy_connect_timeout       7200;
 
    proxy_send_timeout          7200;
 
    proxy_read_timeout          7200;
 
    proxy_buffers               8 32k;
 
    client_max_body_size        1024m;
 
    client_body_buffer_size     128k;
 
    large_client_header_buffers 8 64k;
 

	
 
.. _apache_virtual_host_reverse_proxy:
 

	
 

	
 
Apache virtual host reverse proxy example
 
-----------------------------------------
 

	
 
Here is a sample configuration file for Apache using proxy:
 

	
 
.. code-block:: apache
 

	
 
    <VirtualHost *:80>
 
            ServerName kallithea.example.com
 

	
 
            <Proxy *>
 
              # For Apache 2.4 and later:
 
              Require all granted
 

	
 
              # For Apache 2.2 and earlier, instead use:
 
              # Order allow,deny
 
              # Allow from all
 
            </Proxy>
 

	
 
            #important !
 
            #Directive to properly generate url (clone url) for Kallithea
 
            ProxyPreserveHost On
 

	
 
            #kallithea instance
 
            ProxyPass / http://127.0.0.1:5000/
 
            ProxyPassReverse / http://127.0.0.1:5000/
 

	
 
            #to enable https use line below
 
            #SetEnvIf X-Url-Scheme https HTTPS=1
 
    </VirtualHost>
 

	
 
Additional tutorial
 
http://pylonsbook.com/en/1.1/deployment.html#using-apache-to-proxy-requests-to-pylons
 

	
 
.. _apache_subdirectory:
 

	
 

	
 
Apache as subdirectory
 
----------------------
 

	
 
Apache subdirectory part:
 

	
 
.. code-block:: apache
 

	
 
    <Location /PREFIX >
 
      ProxyPass http://127.0.0.1:5000/PREFIX
 
      ProxyPassReverse http://127.0.0.1:5000/PREFIX
 
      SetEnvIf X-Url-Scheme https HTTPS=1
 
    </Location>
 

	
 
Besides the regular apache setup you will need to add the following line
 
into ``[app:main]`` section of your .ini file::
 

	
 
    filter-with = proxy-prefix
 

	
 
Add the following at the end of the .ini file::
 

	
 
    [filter:proxy-prefix]
 
    use = egg:PasteDeploy#prefix
 
    prefix = /PREFIX
 

	
 
then change ``PREFIX`` into your chosen prefix
 

	
 
.. _apache_mod_wsgi:
 

	
 

	
 
Apache with mod_wsgi
 
--------------------
 

	
 
Alternatively, Kallithea can be set up with Apache under mod_wsgi. For
 
that, you'll need to:
 

	
 
- Install mod_wsgi. If using a Debian-based distro, you can install
 
  the package libapache2-mod-wsgi::
 

	
 
    aptitude install libapache2-mod-wsgi
 

	
 
- Enable mod_wsgi::
 

	
 
    a2enmod wsgi
 

	
 
- Add global Apache configuration to tell mod_wsgi that Python only will be
 
  used in the WSGI processes and shouldn't be initialized in the Apache
 
  processes::
 

	
 
    WSGIRestrictEmbedded On
 

	
 
- Create a wsgi dispatch script, like the one below. Make sure you
 
- Create a WSGI dispatch script, like the one below. Make sure you
 
  check that the paths correctly point to where you installed Kallithea
 
  and its Python Virtual Environment.
 
- Enable the ``WSGIScriptAlias`` directive for the WSGI dispatch script,
 
  as in the following example. Once again, check the paths are
 
  correctly specified.
 

	
 
Here is a sample excerpt from an Apache Virtual Host configuration file:
 

	
 
.. code-block:: apache
 

	
 
    WSGIDaemonProcess kallithea processes=5 threads=1 maximum-requests=100 \
 
        python-home=/srv/kallithea/venv
 
    WSGIProcessGroup kallithea
 
    WSGIScriptAlias / /srv/kallithea/dispatch.wsgi
 
    WSGIPassAuthorization On
 

	
 
Or if using a dispatcher WSGI script with proper virtualenv activation:
 

	
 
.. code-block:: apache
 

	
 
    WSGIDaemonProcess kallithea processes=5 threads=1 maximum-requests=100
 
    WSGIProcessGroup kallithea
 
    WSGIScriptAlias / /srv/kallithea/dispatch.wsgi
 
    WSGIPassAuthorization On
 

	
 
Apache will by default run as a special Apache user, on Linux systems
 
usually ``www-data`` or ``apache``. If you need to have the repositories
 
directory owned by a different user, use the user and group options to
 
WSGIDaemonProcess to set the name of the user and group.
 

	
 
Example WSGI dispatch script:
 

	
 
.. code-block:: python
 

	
 
    import os
 
    os.environ['PYTHON_EGG_CACHE'] = '/srv/kallithea/.egg-cache'
 

	
 
    # sometimes it's needed to set the current dir
 
    os.chdir('/srv/kallithea/')
 

	
 
    import site
 
    site.addsitedir("/srv/kallithea/venv/lib/python2.7/site-packages")
 

	
 
    ini = '/srv/kallithea/my.ini'
 
    from logging.config import fileConfig
 
    fileConfig(ini)
 
    from paste.deploy import loadapp
 
    application = loadapp('config:' + ini)
 

	
 
Or using proper virtualenv activation:
 

	
 
.. code-block:: python
 

	
 
    activate_this = '/srv/kallithea/venv/bin/activate_this.py'
 
    execfile(activate_this, dict(__file__=activate_this))
 

	
 
    import os
 
    os.environ['HOME'] = '/srv/kallithea'
 

	
 
    ini = '/srv/kallithea/kallithea.ini'
 
    from logging.config import fileConfig
 
    fileConfig(ini)
 
    from paste.deploy import loadapp
 
    application = loadapp('config:' + ini)
 

	
 
- Add the necessary ``WSGI*`` directives to the Apache Virtual Host configuration
 
  file, like in the example below. Notice that the WSGI dispatch script created
 
  above is referred to with the ``WSGIScriptAlias`` directive.
 
  The default locale settings Apache provides for web services are often not
 
  adequate, with `C` as the default language and `ASCII` as the encoding.
 
  Instead, use the ``lang`` parameter of ``WSGIDaemonProcess`` to specify a
 
  suitable locale. See also the :ref:`overview` section and the
 
  `WSGIDaemonProcess documentation`_.
 

	
 
  Apache will by default run as a special Apache user, on Linux systems
 
  usually ``www-data`` or ``apache``. If you need to have the repositories
 
  directory owned by a different user, use the user and group options to
 
  WSGIDaemonProcess to set the name of the user and group.
 

	
 
  Once again, check that all paths are correctly specified.
 

	
 
  .. code-block:: apache
 

	
 
      WSGIDaemonProcess kallithea processes=5 threads=1 maximum-requests=100 \
 
          python-home=/srv/kallithea/venv lang=C.UTF-8
 
      WSGIProcessGroup kallithea
 
      WSGIScriptAlias / /srv/kallithea/dispatch.wsgi
 
      WSGIPassAuthorization On
 

	
 
  Or if using a dispatcher WSGI script with proper virtualenv activation:
 

	
 
  .. code-block:: apache
 

	
 
      WSGIDaemonProcess kallithea processes=5 threads=1 maximum-requests=100 lang=en_US.utf8
 
      WSGIProcessGroup kallithea
 
      WSGIScriptAlias / /srv/kallithea/dispatch.wsgi
 
      WSGIPassAuthorization On
 

	
 

	
 
Other configuration files
 
-------------------------
 

	
 
A number of `example init.d scripts`__ can be found in
 
the ``init.d`` directory of the Kallithea source.
 

	
 
.. __: https://kallithea-scm.org/repos/kallithea/files/tip/init.d/ .
 

	
 

	
 
.. _virtualenv: http://pypi.python.org/pypi/virtualenv
 
.. _python: http://www.python.org/
 
.. _Python regular expression documentation: https://docs.python.org/2/library/re.html
 
.. _Mercurial: https://www.mercurial-scm.org/
 
.. _Celery: http://celeryproject.org/
 
.. _Celery documentation: http://docs.celeryproject.org/en/latest/getting-started/index.html
 
.. _RabbitMQ: http://www.rabbitmq.com/
 
.. _Redis: http://redis.io/
 
.. _mercurial-server: http://www.lshift.net/mercurial-server.html
 
.. _PublishingRepositories: https://www.mercurial-scm.org/wiki/PublishingRepositories
 
.. _WSGIDaemonProcess documentation: https://modwsgi.readthedocs.io/en/develop/configuration-directives/WSGIDaemonProcess.html
kallithea/bin/kallithea_cli_config.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
# This program is free software: you can redistribute it and/or modify
 
# it under the terms of the GNU General Public License as published by
 
# the Free Software Foundation, either version 3 of the License, or
 
# (at your option) any later version.
 
#
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 

	
 
import click
 
import kallithea.bin.kallithea_cli_base as cli_base
 

	
 
import os
 
import sys
 
import uuid
 
from collections import defaultdict
 

	
 
import mako.exceptions
 

	
 
from kallithea.lib import inifile
 

	
 
def show_defaults(ctx, param, value):
 
    # Following construct is taken from the Click documentation:
 
    # https://click.palletsprojects.com/en/7.x/options/#callbacks-and-eager-options
 
    # "The resilient_parsing flag is applied to the context if Click wants to
 
    # parse the command line without any destructive behavior that would change
 
    # the execution flow. In this case, because we would exit the program, we
 
    # instead do nothing."
 
    if not value or ctx.resilient_parsing:
 
        return
 

	
 
    for key, value in inifile.default_variables.items():
 
        click.echo('%s=%s' % (key, value))
 

	
 
    ctx.exit()
 

	
 
@cli_base.register_command()
 
@click.option('--show-defaults', callback=show_defaults,
 
              is_flag=True, expose_value=False, is_eager=True,
 
              help='Show the default values that can be overridden')
 
@click.argument('config_file', type=click.Path(dir_okay=False, writable=True), required=True)
 
@click.argument('key_value_pairs', nargs=-1)
 
def config_create(config_file, key_value_pairs):
 
    """Create a new configuration file.
 

	
 
    This command creates a default configuration file, possibly adding/updating
 
    settings you specify.
 

	
 
    The primary high level configuration keys and their default values are
 
    shown with --show-defaults . Custom values for these keys can be specified
 
    on the command line as key=value arguments.
 

	
 
    Additional key=value arguments will be patched/inserted in the [app:main]
 
    section ... until another section name specifies where any following values
 
    should go.
 
    """
 

	
 
    mako_variable_values = {}
 
    mako_variable_values = {
 
        'git_hook_interpreter': sys.executable,
 
    }
 
    ini_settings = defaultdict(dict)
 

	
 
    section_name = None
 
    for parameter in key_value_pairs:
 
        parts = parameter.split('=', 1)
 
        if len(parts) == 1 and parameter.startswith('[') and parameter.endswith(']'):
 
            section_name = parameter
 
        elif len(parts) == 2:
 
            key, value = parts
 
            if section_name is None and key in inifile.default_variables:
 
                mako_variable_values[key] = value
 
            else:
 
                if section_name is None:
 
                    section_name = '[app:main]'
 
                ini_settings[section_name][key] = value
 
        else:
 
            raise ValueError("Invalid name=value parameter %r" % parameter)
 

	
 
    # use default that cannot be replaced
 
    mako_variable_values.update({
 
        'uuid': lambda: uuid.uuid4().hex,
 
    })
 
    try:
 
        config_file_abs = os.path.abspath(config_file)
 
        inifile.create(config_file_abs, mako_variable_values, ini_settings)
 
        click.echo('Wrote new config file in %s' % config_file_abs)
 
        click.echo("Don't forget to build the front-end using 'kallithea-cli front-end-build'.")
 

	
 
    except Exception:
 
        click.echo(mako.exceptions.text_error_template().render())
kallithea/controllers/admin/repos.py
Show inline comments
 
@@ -12,388 +12,388 @@
 
# You should have received a copy of the GNU General Public License
 
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
"""
 
kallithea.controllers.admin.repos
 
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 

	
 
Repositories controller for Kallithea
 

	
 
This file was forked by the Kallithea project in July 2014.
 
Original author and date, and relevant copyright and licensing information is below:
 
:created_on: Apr 7, 2010
 
:author: marcink
 
:copyright: (c) 2013 RhodeCode GmbH, and others.
 
:license: GPLv3, see LICENSE.md for more details.
 
"""
 

	
 
import logging
 
import traceback
 
import formencode
 
from formencode import htmlfill
 
from tg import request, tmpl_context as c
 
from tg.i18n import ugettext as _
 
from sqlalchemy.sql.expression import func
 
from webob.exc import HTTPFound, HTTPInternalServerError, HTTPForbidden, HTTPNotFound
 

	
 
from kallithea.config.routing import url
 
from kallithea.lib import helpers as h
 
from kallithea.lib.auth import LoginRequired, \
 
    HasRepoPermissionLevelDecorator, NotAnonymous, HasPermissionAny
 
from kallithea.lib.base import BaseRepoController, render, jsonify
 
from kallithea.lib.utils import action_logger
 
from kallithea.lib.vcs import RepositoryError
 
from kallithea.model.meta import Session
 
from kallithea.model.db import User, Repository, UserFollowing, RepoGroup, \
 
    Setting, RepositoryField
 
from kallithea.model.forms import RepoForm, RepoFieldForm, RepoPermsForm
 
from kallithea.model.scm import ScmModel, AvailableRepoGroupChoices, RepoList
 
from kallithea.model.repo import RepoModel
 
from kallithea.lib.exceptions import AttachedForksError
 
from kallithea.lib.utils2 import safe_int
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
class ReposController(BaseRepoController):
 
    """
 
    REST Controller styled on the Atom Publishing Protocol"""
 
    # To properly map this controller, ensure your config/routing.py
 
    # file has a resource setup:
 
    #     map.resource('repo', 'repos')
 

	
 
    @LoginRequired(allow_default_user=True)
 
    def _before(self, *args, **kwargs):
 
        super(ReposController, self)._before(*args, **kwargs)
 

	
 
    def _load_repo(self):
 
        repo_obj = c.db_repo
 

	
 
        if repo_obj is None:
 
            h.not_mapped_error(c.repo_name)
 
            raise HTTPFound(location=url('repos'))
 

	
 
        return repo_obj
 

	
 
    def __load_defaults(self, repo=None):
 
        top_perms = ['hg.create.repository']
 
        if HasPermissionAny('hg.create.write_on_repogroup.true')():
 
            repo_group_perm_level = 'write'
 
        else:
 
            repo_group_perm_level = 'admin'
 
        extras = [] if repo is None else [repo.group]
 

	
 
        c.repo_groups = AvailableRepoGroupChoices(top_perms, repo_group_perm_level, extras)
 

	
 
        c.landing_revs_choices, c.landing_revs = ScmModel().get_repo_landing_revs(repo)
 

	
 
    def __load_data(self):
 
        """
 
        Load defaults settings for edit, and update
 
        """
 
        c.repo_info = self._load_repo()
 
        self.__load_defaults(c.repo_info)
 

	
 
        defaults = RepoModel()._get_defaults(c.repo_name)
 
        defaults['clone_uri'] = c.repo_info.clone_uri_hidden # don't show password
 

	
 
        return defaults
 

	
 
    def index(self, format='html'):
 
        _list = Repository.query(sorted=True).all()
 

	
 
        c.repos_list = RepoList(_list, perm_level='admin')
 
        # the repo list will be filtered to only show repos where the user has read permissions
 
        repos_data = RepoModel().get_repos_as_dict(c.repos_list, admin=True)
 
        # data used to render the grid
 
        c.data = repos_data
 

	
 
        return render('admin/repos/repos.html')
 

	
 
    @NotAnonymous()
 
    def create(self):
 
        self.__load_defaults()
 
        form_result = {}
 
        try:
 
            # CanWriteGroup validators checks permissions of this POST
 
            form_result = RepoForm(repo_groups=c.repo_groups,
 
                                   landing_revs=c.landing_revs_choices)() \
 
                            .to_python(dict(request.POST))
 

	
 
            # create is done sometimes async on celery, db transaction
 
            # management is handled there.
 
            task = RepoModel().create(form_result, request.authuser.user_id)
 
            task_id = task.task_id
 
        except formencode.Invalid as errors:
 
            log.info(errors)
 
            return htmlfill.render(
 
                render('admin/repos/repo_add.html'),
 
                defaults=errors.value,
 
                errors=errors.error_dict or {},
 
                prefix_error=False,
 
                force_defaults=False,
 
                encoding="UTF-8")
 

	
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            msg = (_('Error creating repository %s')
 
                   % form_result.get('repo_name'))
 
            h.flash(msg, category='error')
 
            raise HTTPFound(location=url('home'))
 

	
 
        raise HTTPFound(location=h.url('repo_creating_home',
 
                              repo_name=form_result['repo_name_full'],
 
                              task_id=task_id))
 

	
 
    @NotAnonymous()
 
    def create_repository(self):
 
        self.__load_defaults()
 
        if not c.repo_groups:
 
            raise HTTPForbidden
 
        parent_group = request.GET.get('parent_group')
 

	
 
        ## apply the defaults from defaults page
 
        defaults = Setting.get_default_repo_settings(strip_prefix=True)
 
        if parent_group:
 
            prg = RepoGroup.get(parent_group)
 
            if prg is None or not any(rgc[0] == prg.group_id
 
                                      for rgc in c.repo_groups):
 
                raise HTTPForbidden
 
            defaults.update({'repo_group': parent_group})
 

	
 
        return htmlfill.render(
 
            render('admin/repos/repo_add.html'),
 
            defaults=defaults,
 
            errors={},
 
            prefix_error=False,
 
            encoding="UTF-8",
 
            force_defaults=False)
 

	
 
    @LoginRequired()
 
    def repo_creating(self, repo_name):
 
        c.repo = repo_name
 
        c.task_id = request.GET.get('task_id')
 
        if not c.repo:
 
            raise HTTPNotFound()
 
        return render('admin/repos/repo_creating.html')
 

	
 
    @LoginRequired()
 
    @jsonify
 
    def repo_check(self, repo_name):
 
        c.repo = repo_name
 
        task_id = request.GET.get('task_id')
 

	
 
        if task_id and task_id not in ['None']:
 
            from kallithea import CELERY_ON
 
            from kallithea.lib import celerypylons
 
            if CELERY_ON:
 
                task = celerypylons.result.AsyncResult(task_id)
 
                if task.failed():
 
                    raise HTTPInternalServerError(task.traceback)
 

	
 
        repo = Repository.get_by_repo_name(repo_name)
 
        if repo and repo.repo_state == Repository.STATE_CREATED:
 
            if repo.clone_uri:
 
                h.flash(_('Created repository %s from %s')
 
                        % (repo.repo_name, repo.clone_uri_hidden), category='success')
 
            else:
 
                repo_url = h.link_to(repo.repo_name,
 
                                     h.url('summary_home',
 
                                           repo_name=repo.repo_name))
 
                fork = repo.fork
 
                if fork is not None:
 
                    fork_name = fork.repo_name
 
                    h.flash(h.literal(_('Forked repository %s as %s')
 
                            % (fork_name, repo_url)), category='success')
 
                    h.flash(h.HTML(_('Forked repository %s as %s'))
 
                            % (fork_name, repo_url), category='success')
 
                else:
 
                    h.flash(h.literal(_('Created repository %s') % repo_url),
 
                    h.flash(h.HTML(_('Created repository %s')) % repo_url,
 
                            category='success')
 
            return {'result': True}
 
        return {'result': False}
 

	
 
    @HasRepoPermissionLevelDecorator('admin')
 
    def update(self, repo_name):
 
        c.repo_info = self._load_repo()
 
        self.__load_defaults(c.repo_info)
 
        c.active = 'settings'
 
        c.repo_fields = RepositoryField.query() \
 
            .filter(RepositoryField.repository == c.repo_info).all()
 

	
 
        repo_model = RepoModel()
 
        changed_name = repo_name
 
        repo = Repository.get_by_repo_name(repo_name)
 
        old_data = {
 
            'repo_name': repo_name,
 
            'repo_group': repo.group.get_dict() if repo.group else {},
 
            'repo_type': repo.repo_type,
 
        }
 
        _form = RepoForm(edit=True, old_data=old_data,
 
                         repo_groups=c.repo_groups,
 
                         landing_revs=c.landing_revs_choices)()
 

	
 
        try:
 
            form_result = _form.to_python(dict(request.POST))
 
            repo = repo_model.update(repo_name, **form_result)
 
            ScmModel().mark_for_invalidation(repo_name)
 
            h.flash(_('Repository %s updated successfully') % repo_name,
 
                    category='success')
 
            changed_name = repo.repo_name
 
            action_logger(request.authuser, 'admin_updated_repo',
 
                changed_name, request.ip_addr)
 
            Session().commit()
 
        except formencode.Invalid as errors:
 
            log.info(errors)
 
            defaults = self.__load_data()
 
            defaults.update(errors.value)
 
            return htmlfill.render(
 
                render('admin/repos/repo_edit.html'),
 
                defaults=defaults,
 
                errors=errors.error_dict or {},
 
                prefix_error=False,
 
                encoding="UTF-8",
 
                force_defaults=False)
 

	
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            h.flash(_('Error occurred during update of repository %s')
 
                    % repo_name, category='error')
 
        raise HTTPFound(location=url('edit_repo', repo_name=changed_name))
 

	
 
    @HasRepoPermissionLevelDecorator('admin')
 
    def delete(self, repo_name):
 
        repo_model = RepoModel()
 
        repo = repo_model.get_by_repo_name(repo_name)
 
        if not repo:
 
            h.not_mapped_error(repo_name)
 
            raise HTTPFound(location=url('repos'))
 
        try:
 
            _forks = repo.forks.count()
 
            handle_forks = None
 
            if _forks and request.POST.get('forks'):
 
                do = request.POST['forks']
 
                if do == 'detach_forks':
 
                    handle_forks = 'detach'
 
                    h.flash(_('Detached %s forks') % _forks, category='success')
 
                elif do == 'delete_forks':
 
                    handle_forks = 'delete'
 
                    h.flash(_('Deleted %s forks') % _forks, category='success')
 
            repo_model.delete(repo, forks=handle_forks)
 
            action_logger(request.authuser, 'admin_deleted_repo',
 
                repo_name, request.ip_addr)
 
            ScmModel().mark_for_invalidation(repo_name)
 
            h.flash(_('Deleted repository %s') % repo_name, category='success')
 
            Session().commit()
 
        except AttachedForksError:
 
            h.flash(_('Cannot delete repository %s which still has forks')
 
                        % repo_name, category='warning')
 

	
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            h.flash(_('An error occurred during deletion of %s') % repo_name,
 
                    category='error')
 

	
 
        if repo.group:
 
            raise HTTPFound(location=url('repos_group_home', group_name=repo.group.group_name))
 
        raise HTTPFound(location=url('repos'))
 

	
 
    @HasRepoPermissionLevelDecorator('admin')
 
    def edit(self, repo_name):
 
        defaults = self.__load_data()
 
        c.repo_fields = RepositoryField.query() \
 
            .filter(RepositoryField.repository == c.repo_info).all()
 
        c.active = 'settings'
 
        return htmlfill.render(
 
            render('admin/repos/repo_edit.html'),
 
            defaults=defaults,
 
            encoding="UTF-8",
 
            force_defaults=False)
 

	
 
    @HasRepoPermissionLevelDecorator('admin')
 
    def edit_permissions(self, repo_name):
 
        c.repo_info = self._load_repo()
 
        c.active = 'permissions'
 
        defaults = RepoModel()._get_defaults(repo_name)
 

	
 
        return htmlfill.render(
 
            render('admin/repos/repo_edit.html'),
 
            defaults=defaults,
 
            encoding="UTF-8",
 
            force_defaults=False)
 

	
 
    @HasRepoPermissionLevelDecorator('admin')
 
    def edit_permissions_update(self, repo_name):
 
        form = RepoPermsForm()().to_python(request.POST)
 
        RepoModel()._update_permissions(repo_name, form['perms_new'],
 
                                        form['perms_updates'])
 
        # TODO: implement this
 
        #action_logger(request.authuser, 'admin_changed_repo_permissions',
 
        #              repo_name, request.ip_addr)
 
        Session().commit()
 
        h.flash(_('Repository permissions updated'), category='success')
 
        raise HTTPFound(location=url('edit_repo_perms', repo_name=repo_name))
 

	
 
    @HasRepoPermissionLevelDecorator('admin')
 
    def edit_permissions_revoke(self, repo_name):
 
        try:
 
            obj_type = request.POST.get('obj_type')
 
            obj_id = None
 
            if obj_type == 'user':
 
                obj_id = safe_int(request.POST.get('user_id'))
 
            elif obj_type == 'user_group':
 
                obj_id = safe_int(request.POST.get('user_group_id'))
 
            else: assert False
 

	
 
            if obj_type == 'user':
 
                RepoModel().revoke_user_permission(repo=repo_name, user=obj_id)
 
            elif obj_type == 'user_group':
 
                RepoModel().revoke_user_group_permission(
 
                    repo=repo_name, group_name=obj_id
 
                )
 
            else: assert False
 
            # TODO: implement this
 
            #action_logger(request.authuser, 'admin_revoked_repo_permissions',
 
            #              repo_name, request.ip_addr)
 
            Session().commit()
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            h.flash(_('An error occurred during revoking of permission'),
 
                    category='error')
 
            raise HTTPInternalServerError()
 
        return []
 

	
 
    @HasRepoPermissionLevelDecorator('admin')
 
    def edit_fields(self, repo_name):
 
        c.repo_info = self._load_repo()
 
        c.repo_fields = RepositoryField.query() \
 
            .filter(RepositoryField.repository == c.repo_info).all()
 
        c.active = 'fields'
 
        if request.POST:
 

	
 
            raise HTTPFound(location=url('repo_edit_fields'))
 
        return render('admin/repos/repo_edit.html')
 

	
 
    @HasRepoPermissionLevelDecorator('admin')
 
    def create_repo_field(self, repo_name):
 
        try:
 
            form_result = RepoFieldForm()().to_python(dict(request.POST))
 
            new_field = RepositoryField()
 
            new_field.repository = Repository.get_by_repo_name(repo_name)
 
            new_field.field_key = form_result['new_field_key']
 
            new_field.field_type = form_result['new_field_type']  # python type
 
            new_field.field_value = form_result['new_field_value']  # set initial blank value
 
            new_field.field_desc = form_result['new_field_desc']
 
            new_field.field_label = form_result['new_field_label']
 
            Session().add(new_field)
 
            Session().commit()
 
        except formencode.Invalid as e:
 
            h.flash(_('Field validation error: %s') % e.msg, category='error')
 
        except Exception as e:
 
            log.error(traceback.format_exc())
 
            h.flash(_('An error occurred during creation of field: %r') % e, category='error')
 
        raise HTTPFound(location=url('edit_repo_fields', repo_name=repo_name))
 

	
 
    @HasRepoPermissionLevelDecorator('admin')
 
    def delete_repo_field(self, repo_name, field_id):
 
        field = RepositoryField.get_or_404(field_id)
 
        try:
 
            Session().delete(field)
 
            Session().commit()
 
        except Exception as e:
kallithea/controllers/admin/settings.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
# This program is free software: you can redistribute it and/or modify
 
# it under the terms of the GNU General Public License as published by
 
# the Free Software Foundation, either version 3 of the License, or
 
# (at your option) any later version.
 
#
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
"""
 
kallithea.controllers.admin.settings
 
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 

	
 
settings controller for Kallithea admin
 

	
 
This file was forked by the Kallithea project in July 2014.
 
Original author and date, and relevant copyright and licensing information is below:
 
:created_on: Jul 14, 2010
 
:author: marcink
 
:copyright: (c) 2013 RhodeCode GmbH, and others.
 
:license: GPLv3, see LICENSE.md for more details.
 
"""
 

	
 
import logging
 
import traceback
 
import formencode
 

	
 
from formencode import htmlfill
 
from tg import request, tmpl_context as c, config
 
from tg.i18n import ugettext as _
 
from webob.exc import HTTPFound
 

	
 
from kallithea.config.routing import url
 
from kallithea.lib import helpers as h
 
from kallithea.lib.auth import LoginRequired, HasPermissionAnyDecorator
 
from kallithea.lib.base import BaseController, render
 
from kallithea.lib.celerylib import tasks
 
from kallithea.lib.exceptions import HgsubversionImportError
 
from kallithea.lib.utils import repo2db_mapper, set_app_settings
 
from kallithea.lib.vcs import VCSError
 
from kallithea.model.db import Ui, Repository, Setting
 
from kallithea.model.forms import ApplicationSettingsForm, \
 
    ApplicationUiSettingsForm, ApplicationVisualisationForm
 
from kallithea.model.scm import ScmModel
 
from kallithea.model.notification import EmailNotificationModel
 
from kallithea.model.meta import Session
 
from kallithea.lib.utils2 import str2bool, safe_unicode
 
log = logging.getLogger(__name__)
 

	
 

	
 
class SettingsController(BaseController):
 
    """REST Controller styled on the Atom Publishing Protocol"""
 
    # To properly map this controller, ensure your config/routing.py
 
    # file has a resource setup:
 
    #     map.resource('setting', 'settings', controller='admin/settings',
 
    #         path_prefix='/admin', name_prefix='admin_')
 

	
 
    @LoginRequired(allow_default_user=True)
 
    def _before(self, *args, **kwargs):
 
        super(SettingsController, self)._before(*args, **kwargs)
 

	
 
    def _get_hg_ui_settings(self):
 
        ret = Ui.query().all()
 

	
 
        settings = {}
 
        for each in ret:
 
            k = each.ui_section + '_' + each.ui_key
 
            v = each.ui_value
 
            if k == 'paths_/':
 
                k = 'paths_root_path'
 

	
 
            k = k.replace('.', '_')
 

	
 
            if each.ui_section in ['hooks', 'extensions']:
 
                v = each.ui_active
 

	
 
            settings[k] = v
 
        return settings
 

	
 
    @HasPermissionAnyDecorator('hg.admin')
 
    def settings_vcs(self):
 
        c.active = 'vcs'
 
        if request.POST:
 
            application_form = ApplicationUiSettingsForm()()
 
            try:
 
                form_result = application_form.to_python(dict(request.POST))
 
            except formencode.Invalid as errors:
 
                return htmlfill.render(
 
                     render('admin/settings/settings.html'),
 
                     defaults=errors.value,
 
                     errors=errors.error_dict or {},
 
                     prefix_error=False,
 
                     encoding="UTF-8",
 
                     force_defaults=False)
 

	
 
            try:
 
                if c.visual.allow_repo_location_change:
 
                    sett = Ui.get_by_key('paths', '/')
 
                    sett.ui_value = form_result['paths_root_path']
 

	
 
                # HOOKS
 
                sett = Ui.get_by_key('hooks', Ui.HOOK_UPDATE)
 
                sett.ui_active = form_result['hooks_changegroup_update']
 

	
 
                sett = Ui.get_by_key('hooks', Ui.HOOK_REPO_SIZE)
 
                sett.ui_active = form_result['hooks_changegroup_repo_size']
 

	
 
                sett = Ui.get_by_key('hooks', Ui.HOOK_PUSH_LOG)
 
                sett.ui_active = form_result['hooks_changegroup_push_logger']
 

	
 
                sett = Ui.get_by_key('hooks', Ui.HOOK_PULL_LOG)
 
                sett.ui_active = form_result['hooks_outgoing_pull_logger']
 

	
 
                ## EXTENSIONS
 
                sett = Ui.get_or_create('extensions', 'largefiles')
 
                sett.ui_active = form_result['extensions_largefiles']
 

	
 
                sett = Ui.get_or_create('extensions', 'hgsubversion')
 
                sett.ui_active = form_result['extensions_hgsubversion']
 
                if sett.ui_active:
 
                    try:
 
                        import hgsubversion  # pragma: no cover
 
                    except ImportError:
 
                        raise HgsubversionImportError
 

	
 
#                sett = Ui.get_or_create('extensions', 'hggit')
 
#                sett.ui_active = form_result['extensions_hggit']
 

	
 
                Session().commit()
 

	
 
                h.flash(_('Updated VCS settings'), category='success')
 

	
 
            except HgsubversionImportError:
 
                log.error(traceback.format_exc())
 
                h.flash(_('Unable to activate hgsubversion support. '
 
                          'The "hgsubversion" library is missing'),
 
                        category='error')
 

	
 
            except Exception:
 
                log.error(traceback.format_exc())
 
                h.flash(_('Error occurred while updating '
 
                          'application settings'), category='error')
 

	
 
        defaults = Setting.get_app_settings()
 
        defaults.update(self._get_hg_ui_settings())
 

	
 
        return htmlfill.render(
 
            render('admin/settings/settings.html'),
 
            defaults=defaults,
 
            encoding="UTF-8",
 
            force_defaults=False)
 

	
 
    @HasPermissionAnyDecorator('hg.admin')
 
    def settings_mapping(self):
 
        c.active = 'mapping'
 
        if request.POST:
 
            rm_obsolete = request.POST.get('destroy', False)
 
            install_git_hooks = request.POST.get('hooks', False)
 
            overwrite_git_hooks = request.POST.get('hooks_overwrite', False)
 
            invalidate_cache = request.POST.get('invalidate', False)
 
            log.debug('rescanning repo location with destroy obsolete=%s, '
 
                      'install git hooks=%s and '
 
                      'overwrite git hooks=%s' % (rm_obsolete, install_git_hooks, overwrite_git_hooks))
 

	
 
            filesystem_repos = ScmModel().repo_scan()
 
            added, removed = repo2db_mapper(filesystem_repos, rm_obsolete,
 
                                            install_git_hooks=install_git_hooks,
 
                                            user=request.authuser.username,
 
                                            overwrite_git_hooks=overwrite_git_hooks)
 
            h.flash(h.literal(_('Repositories successfully rescanned. Added: %s. Removed: %s.') %
 
                (', '.join(h.link_to(safe_unicode(repo_name), h.url('summary_home', repo_name=repo_name))
 
                 for repo_name in added) or '-',
 
                 ', '.join(h.escape(safe_unicode(repo_name)) for repo_name in removed) or '-')),
 
                category='success')
 
            added_msg = h.HTML(', ').join(
 
                h.link_to(safe_unicode(repo_name), h.url('summary_home', repo_name=repo_name)) for repo_name in added
 
            ) or '-'
 
            removed_msg = h.HTML(', ').join(
 
                safe_unicode(repo_name) for repo_name in removed
 
            ) or '-'
 
            h.flash(h.HTML(_('Repositories successfully rescanned. Added: %s. Removed: %s.')) %
 
                    (added_msg, removed_msg), category='success')
 

	
 
            if invalidate_cache:
 
                log.debug('invalidating all repositories cache')
 
                i = 0
 
                for repo in Repository.query():
 
                    try:
 
                        ScmModel().mark_for_invalidation(repo.repo_name)
 
                        i += 1
 
                    except VCSError as e:
 
                        log.warning('VCS error invalidating %s: %s', repo.repo_name, e)
 
                h.flash(_('Invalidated %s repositories') % i, category='success')
 

	
 
            raise HTTPFound(location=url('admin_settings_mapping'))
 

	
 
        defaults = Setting.get_app_settings()
 
        defaults.update(self._get_hg_ui_settings())
 

	
 
        return htmlfill.render(
 
            render('admin/settings/settings.html'),
 
            defaults=defaults,
 
            encoding="UTF-8",
 
            force_defaults=False)
 

	
 
    @HasPermissionAnyDecorator('hg.admin')
 
    def settings_global(self):
 
        c.active = 'global'
 
        if request.POST:
 
            application_form = ApplicationSettingsForm()()
 
            try:
 
                form_result = application_form.to_python(dict(request.POST))
 
            except formencode.Invalid as errors:
 
                return htmlfill.render(
 
                    render('admin/settings/settings.html'),
 
                    defaults=errors.value,
 
                    errors=errors.error_dict or {},
 
                    prefix_error=False,
 
                    encoding="UTF-8",
 
                    force_defaults=False)
 

	
 
            try:
 
                for setting in (
 
                    'title',
 
                    'realm',
 
                    'ga_code',
 
                    'captcha_public_key',
 
                    'captcha_private_key',
 
                ):
 
                    Setting.create_or_update(setting, form_result[setting])
 

	
 
                Session().commit()
 
                set_app_settings(config)
 
                h.flash(_('Updated application settings'), category='success')
 

	
 
            except Exception:
 
                log.error(traceback.format_exc())
 
                h.flash(_('Error occurred while updating '
 
                          'application settings'),
 
                          category='error')
 

	
 
            raise HTTPFound(location=url('admin_settings_global'))
 

	
 
        defaults = Setting.get_app_settings()
 
        defaults.update(self._get_hg_ui_settings())
 

	
 
        return htmlfill.render(
 
            render('admin/settings/settings.html'),
 
            defaults=defaults,
 
            encoding="UTF-8",
 
            force_defaults=False)
 

	
 
    @HasPermissionAnyDecorator('hg.admin')
 
    def settings_visual(self):
 
        c.active = 'visual'
 
        if request.POST:
 
            application_form = ApplicationVisualisationForm()()
 
            try:
 
                form_result = application_form.to_python(dict(request.POST))
 
            except formencode.Invalid as errors:
 
                return htmlfill.render(
 
                    render('admin/settings/settings.html'),
 
                    defaults=errors.value,
 
                    errors=errors.error_dict or {},
 
                    prefix_error=False,
 
                    encoding="UTF-8",
 
                    force_defaults=False)
 

	
 
            try:
 
                settings = [
 
                    ('show_public_icon', 'show_public_icon', 'bool'),
 
                    ('show_private_icon', 'show_private_icon', 'bool'),
 
                    ('stylify_metalabels', 'stylify_metalabels', 'bool'),
 
                    ('repository_fields', 'repository_fields', 'bool'),
 
                    ('dashboard_items', 'dashboard_items', 'int'),
 
                    ('admin_grid_items', 'admin_grid_items', 'int'),
 
                    ('show_version', 'show_version', 'bool'),
 
                    ('use_gravatar', 'use_gravatar', 'bool'),
 
                    ('gravatar_url', 'gravatar_url', 'unicode'),
 
                    ('clone_uri_tmpl', 'clone_uri_tmpl', 'unicode'),
 
                ]
 
                for setting, form_key, type_ in settings:
 
                    Setting.create_or_update(setting, form_result[form_key], type_)
 

	
 
                Session().commit()
 
                set_app_settings(config)
 
                h.flash(_('Updated visualisation settings'),
 
                        category='success')
 

	
 
            except Exception:
 
                log.error(traceback.format_exc())
 
                h.flash(_('Error occurred during updating '
 
                          'visualisation settings'),
 
                        category='error')
 

	
 
            raise HTTPFound(location=url('admin_settings_visual'))
 

	
 
        defaults = Setting.get_app_settings()
 
        defaults.update(self._get_hg_ui_settings())
 

	
 
        return htmlfill.render(
 
            render('admin/settings/settings.html'),
 
            defaults=defaults,
 
            encoding="UTF-8",
 
            force_defaults=False)
 

	
 
    @HasPermissionAnyDecorator('hg.admin')
 
    def settings_email(self):
 
        c.active = 'email'
 
        if request.POST:
 
            test_email = request.POST.get('test_email')
 
            test_email_subj = 'Kallithea test email'
 
            test_body = ('Kallithea Email test, '
 
                               'Kallithea version: %s' % c.kallithea_version)
 
            if not test_email:
 
                h.flash(_('Please enter email address'), category='error')
 
                raise HTTPFound(location=url('admin_settings_email'))
 

	
 
            test_email_txt_body = EmailNotificationModel() \
 
                .get_email_tmpl(EmailNotificationModel.TYPE_DEFAULT,
 
                                'txt', body=test_body)
 
            test_email_html_body = EmailNotificationModel() \
 
                .get_email_tmpl(EmailNotificationModel.TYPE_DEFAULT,
 
                                'html', body=test_body)
 

	
 
            recipients = [test_email] if test_email else None
 

	
 
            tasks.send_email(recipients, test_email_subj,
 
                             test_email_txt_body, test_email_html_body)
 

	
 
            h.flash(_('Send email task created'), category='success')
 
            raise HTTPFound(location=url('admin_settings_email'))
 

	
 
        defaults = Setting.get_app_settings()
 
        defaults.update(self._get_hg_ui_settings())
 

	
 
        import kallithea
 
        c.ini = kallithea.CONFIG
 

	
 
        return htmlfill.render(
 
            render('admin/settings/settings.html'),
 
            defaults=defaults,
 
            encoding="UTF-8",
 
            force_defaults=False)
 

	
 
    @HasPermissionAnyDecorator('hg.admin')
 
    def settings_hooks(self):
 
        c.active = 'hooks'
 
        if request.POST:
 
            if c.visual.allow_custom_hooks_settings:
 
                ui_key = request.POST.get('new_hook_ui_key')
 
                ui_value = request.POST.get('new_hook_ui_value')
 

	
 
                hook_id = request.POST.get('hook_id')
 

	
 
                try:
 
                    ui_key = ui_key and ui_key.strip()
 
                    if ui_key in (x.ui_key for x in Ui.get_custom_hooks()):
 
                        h.flash(_('Hook already exists'), category='error')
 
                    elif ui_key in (x.ui_key for x in Ui.get_builtin_hooks()):
 
                        h.flash(_('Builtin hooks are read-only. Please use another hook name.'), category='error')
 
                    elif ui_value and ui_key:
 
                        Ui.create_or_update_hook(ui_key, ui_value)
 
                        h.flash(_('Added new hook'), category='success')
 
                    elif hook_id:
 
                        Ui.delete(hook_id)
 
                        Session().commit()
 

	
 
                    # check for edits
 
                    update = False
 
                    _d = request.POST.dict_of_lists()
 
                    for k, v, ov in zip(_d.get('hook_ui_key', []),
 
                                        _d.get('hook_ui_value_new', []),
 
                                        _d.get('hook_ui_value', [])):
kallithea/controllers/admin/user_groups.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
# This program is free software: you can redistribute it and/or modify
 
# it under the terms of the GNU General Public License as published by
 
# the Free Software Foundation, either version 3 of the License, or
 
# (at your option) any later version.
 
#
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
"""
 
kallithea.controllers.admin.user_groups
 
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 

	
 
User Groups crud controller
 

	
 
This file was forked by the Kallithea project in July 2014.
 
Original author and date, and relevant copyright and licensing information is below:
 
:created_on: Jan 25, 2011
 
:author: marcink
 
:copyright: (c) 2013 RhodeCode GmbH, and others.
 
:license: GPLv3, see LICENSE.md for more details.
 
"""
 

	
 
import logging
 
import traceback
 
import formencode
 

	
 
from formencode import htmlfill
 
from tg import request, tmpl_context as c, config, app_globals
 
from tg.i18n import ugettext as _
 
from webob.exc import HTTPFound
 

	
 
from sqlalchemy.orm import joinedload
 
from sqlalchemy.sql.expression import func
 
from webob.exc import HTTPInternalServerError
 

	
 
import kallithea
 
from kallithea.config.routing import url
 
from kallithea.lib import helpers as h
 
from kallithea.lib.exceptions import UserGroupsAssignedException, \
 
    RepoGroupAssignmentError
 
from kallithea.lib.utils2 import safe_unicode, safe_int
 
from kallithea.lib.auth import LoginRequired, \
 
    HasUserGroupPermissionLevelDecorator, HasPermissionAnyDecorator
 
from kallithea.lib.base import BaseController, render
 
from kallithea.model.scm import UserGroupList
 
from kallithea.model.user_group import UserGroupModel
 
from kallithea.model.repo import RepoModel
 
from kallithea.model.db import User, UserGroup, UserGroupToPerm, \
 
    UserGroupRepoToPerm, UserGroupRepoGroupToPerm
 
from kallithea.model.forms import UserGroupForm, UserGroupPermsForm, \
 
    CustomDefaultPermissionsForm
 
from kallithea.model.meta import Session
 
from kallithea.lib.utils import action_logger
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
class UserGroupsController(BaseController):
 
    """REST Controller styled on the Atom Publishing Protocol"""
 

	
 
    @LoginRequired(allow_default_user=True)
 
    def _before(self, *args, **kwargs):
 
        super(UserGroupsController, self)._before(*args, **kwargs)
 
        c.available_permissions = config['available_permissions']
 

	
 
    def __load_data(self, user_group_id):
 
        c.group_members_obj = sorted((x.user for x in c.user_group.members),
 
                                     key=lambda u: u.username.lower())
 

	
 
        c.group_members = [(x.user_id, x.username) for x in c.group_members_obj]
 
        c.available_members = sorted(((x.user_id, x.username) for x in
 
                                      User.query().all()),
 
                                     key=lambda u: u[1].lower())
 

	
 
    def __load_defaults(self, user_group_id):
 
        """
 
        Load defaults settings for edit, and update
 

	
 
        :param user_group_id:
 
        """
 
        user_group = UserGroup.get_or_404(user_group_id)
 
        data = user_group.get_dict()
 
        return data
 

	
 
    def index(self, format='html'):
 
        _list = UserGroup.query() \
 
                        .order_by(func.lower(UserGroup.users_group_name)) \
 
                        .all()
 
        group_iter = UserGroupList(_list, perm_level='admin')
 
        user_groups_data = []
 
        total_records = len(group_iter)
 
        _tmpl_lookup = app_globals.mako_lookup
 
        template = _tmpl_lookup.get_template('data_table/_dt_elements.html')
 

	
 
        user_group_name = lambda user_group_id, user_group_name: (
 
            template.get_def("user_group_name")
 
            .render(user_group_id, user_group_name, _=_, h=h, c=c)
 
        )
 
        user_group_actions = lambda user_group_id, user_group_name: (
 
            template.get_def("user_group_actions")
 
            .render(user_group_id, user_group_name, _=_, h=h, c=c)
 
        )
 
        for user_gr in group_iter:
 

	
 
            user_groups_data.append({
 
                "raw_name": user_gr.users_group_name,
 
                "group_name": user_group_name(user_gr.users_group_id,
 
                                              user_gr.users_group_name),
 
                "desc": h.escape(user_gr.user_group_description),
 
                "members": len(user_gr.members),
 
                "active": h.boolicon(user_gr.users_group_active),
 
                "owner": h.person(user_gr.owner.username),
 
                "action": user_group_actions(user_gr.users_group_id, user_gr.users_group_name)
 
            })
 

	
 
        c.data = {
 
            "sort": None,
 
            "dir": "asc",
 
            "records": user_groups_data
 
        }
 

	
 
        return render('admin/user_groups/user_groups.html')
 

	
 
    @HasPermissionAnyDecorator('hg.admin', 'hg.usergroup.create.true')
 
    def create(self):
 
        users_group_form = UserGroupForm()()
 
        try:
 
            form_result = users_group_form.to_python(dict(request.POST))
 
            ug = UserGroupModel().create(name=form_result['users_group_name'],
 
                                         description=form_result['user_group_description'],
 
                                         owner=request.authuser.user_id,
 
                                         active=form_result['users_group_active'])
 

	
 
            gr = form_result['users_group_name']
 
            action_logger(request.authuser,
 
                          'admin_created_users_group:%s' % gr,
 
                          None, request.ip_addr)
 
            h.flash(h.literal(_('Created user group %s') % h.link_to(h.escape(gr), url('edit_users_group', id=ug.users_group_id))),
 
            h.flash(h.HTML(_('Created user group %s')) % h.link_to(gr, url('edit_users_group', id=ug.users_group_id)),
 
                category='success')
 
            Session().commit()
 
        except formencode.Invalid as errors:
 
            return htmlfill.render(
 
                render('admin/user_groups/user_group_add.html'),
 
                defaults=errors.value,
 
                errors=errors.error_dict or {},
 
                prefix_error=False,
 
                encoding="UTF-8",
 
                force_defaults=False)
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            h.flash(_('Error occurred during creation of user group %s')
 
                    % request.POST.get('users_group_name'), category='error')
 

	
 
        raise HTTPFound(location=url('users_groups'))
 

	
 
    @HasPermissionAnyDecorator('hg.admin', 'hg.usergroup.create.true')
 
    def new(self, format='html'):
 
        return render('admin/user_groups/user_group_add.html')
 

	
 
    @HasUserGroupPermissionLevelDecorator('admin')
 
    def update(self, id):
 
        c.user_group = UserGroup.get_or_404(id)
 
        c.active = 'settings'
 
        self.__load_data(id)
 

	
 
        available_members = [safe_unicode(x[0]) for x in c.available_members]
 

	
 
        users_group_form = UserGroupForm(edit=True,
 
                                         old_data=c.user_group.get_dict(),
 
                                         available_members=available_members)()
 

	
 
        try:
 
            form_result = users_group_form.to_python(request.POST)
 
            UserGroupModel().update(c.user_group, form_result)
 
            gr = form_result['users_group_name']
 
            action_logger(request.authuser,
 
                          'admin_updated_users_group:%s' % gr,
 
                          None, request.ip_addr)
 
            h.flash(_('Updated user group %s') % gr, category='success')
 
            Session().commit()
 
        except formencode.Invalid as errors:
 
            ug_model = UserGroupModel()
 
            defaults = errors.value
 
            e = errors.error_dict or {}
 
            defaults.update({
 
                'create_repo_perm': ug_model.has_perm(id,
 
                                                      'hg.create.repository'),
 
                'fork_repo_perm': ug_model.has_perm(id,
 
                                                    'hg.fork.repository'),
 
            })
 

	
 
            return htmlfill.render(
 
                render('admin/user_groups/user_group_edit.html'),
 
                defaults=defaults,
 
                errors=e,
 
                prefix_error=False,
 
                encoding="UTF-8",
 
                force_defaults=False)
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            h.flash(_('Error occurred during update of user group %s')
 
                    % request.POST.get('users_group_name'), category='error')
 

	
 
        raise HTTPFound(location=url('edit_users_group', id=id))
 

	
 
    @HasUserGroupPermissionLevelDecorator('admin')
 
    def delete(self, id):
 
        usr_gr = UserGroup.get_or_404(id)
 
        try:
 
            UserGroupModel().delete(usr_gr)
 
            Session().commit()
 
            h.flash(_('Successfully deleted user group'), category='success')
 
        except UserGroupsAssignedException as e:
 
            h.flash(e, category='error')
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            h.flash(_('An error occurred during deletion of user group'),
 
                    category='error')
 
        raise HTTPFound(location=url('users_groups'))
 

	
 
    @HasUserGroupPermissionLevelDecorator('admin')
 
    def edit(self, id, format='html'):
 
        c.user_group = UserGroup.get_or_404(id)
 
        c.active = 'settings'
 
        self.__load_data(id)
 

	
 
        defaults = self.__load_defaults(id)
 

	
 
        return htmlfill.render(
 
            render('admin/user_groups/user_group_edit.html'),
 
            defaults=defaults,
 
            encoding="UTF-8",
 
            force_defaults=False
 
        )
 

	
 
    @HasUserGroupPermissionLevelDecorator('admin')
 
    def edit_perms(self, id):
 
        c.user_group = UserGroup.get_or_404(id)
 
        c.active = 'perms'
 

	
 
        defaults = {}
 
        # fill user group users
 
        for p in c.user_group.user_user_group_to_perm:
 
            defaults.update({'u_perm_%s' % p.user.username:
 
                             p.permission.permission_name})
 

	
 
        for p in c.user_group.user_group_user_group_to_perm:
 
            defaults.update({'g_perm_%s' % p.user_group.users_group_name:
 
                             p.permission.permission_name})
 

	
 
        return htmlfill.render(
 
            render('admin/user_groups/user_group_edit.html'),
 
            defaults=defaults,
 
            encoding="UTF-8",
 
            force_defaults=False
 
        )
 

	
 
    @HasUserGroupPermissionLevelDecorator('admin')
 
    def update_perms(self, id):
 
        """
 
        grant permission for given usergroup
 

	
 
        :param id:
 
        """
 
        user_group = UserGroup.get_or_404(id)
 
        form = UserGroupPermsForm()().to_python(request.POST)
 

	
 
        # set the permissions !
 
        try:
 
            UserGroupModel()._update_permissions(user_group, form['perms_new'],
 
                                                 form['perms_updates'])
 
        except RepoGroupAssignmentError:
 
            h.flash(_('Target group cannot be the same'), category='error')
 
            raise HTTPFound(location=url('edit_user_group_perms', id=id))
 
        # TODO: implement this
 
        #action_logger(request.authuser, 'admin_changed_repo_permissions',
 
        #              repo_name, request.ip_addr)
 
        Session().commit()
 
        h.flash(_('User group permissions updated'), category='success')
 
        raise HTTPFound(location=url('edit_user_group_perms', id=id))
 

	
 
    @HasUserGroupPermissionLevelDecorator('admin')
 
    def delete_perms(self, id):
 
        try:
 
            obj_type = request.POST.get('obj_type')
 
            obj_id = None
 
            if obj_type == 'user':
 
                obj_id = safe_int(request.POST.get('user_id'))
 
            elif obj_type == 'user_group':
 
                obj_id = safe_int(request.POST.get('user_group_id'))
 

	
 
            if not request.authuser.is_admin:
 
                if obj_type == 'user' and request.authuser.user_id == obj_id:
 
                    msg = _('Cannot revoke permission for yourself as admin')
 
                    h.flash(msg, category='warning')
 
                    raise Exception('revoke admin permission on self')
 
            if obj_type == 'user':
 
                UserGroupModel().revoke_user_permission(user_group=id,
 
                                                        user=obj_id)
 
            elif obj_type == 'user_group':
 
                UserGroupModel().revoke_user_group_permission(target_user_group=id,
 
                                                              user_group=obj_id)
 
            Session().commit()
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            h.flash(_('An error occurred during revoking of permission'),
 
                    category='error')
 
            raise HTTPInternalServerError()
 

	
 
    @HasUserGroupPermissionLevelDecorator('admin')
 
    def edit_default_perms(self, id):
 
        c.user_group = UserGroup.get_or_404(id)
 
        c.active = 'default_perms'
 

	
 
        permissions = {
 
            'repositories': {},
 
            'repositories_groups': {}
 
        }
 
        ugroup_repo_perms = UserGroupRepoToPerm.query() \
 
            .options(joinedload(UserGroupRepoToPerm.permission)) \
 
            .options(joinedload(UserGroupRepoToPerm.repository)) \
 
            .filter(UserGroupRepoToPerm.users_group_id == id) \
 
            .all()
 

	
 
        for gr in ugroup_repo_perms:
 
            permissions['repositories'][gr.repository.repo_name]  \
 
                = gr.permission.permission_name
 

	
 
        ugroup_group_perms = UserGroupRepoGroupToPerm.query() \
 
            .options(joinedload(UserGroupRepoGroupToPerm.permission)) \
kallithea/controllers/files.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
# This program is free software: you can redistribute it and/or modify
 
# it under the terms of the GNU General Public License as published by
 
# the Free Software Foundation, either version 3 of the License, or
 
# (at your option) any later version.
 
#
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
"""
 
kallithea.controllers.files
 
~~~~~~~~~~~~~~~~~~~~~~~~~~~
 

	
 
Files controller for Kallithea
 

	
 
This file was forked by the Kallithea project in July 2014.
 
Original author and date, and relevant copyright and licensing information is below:
 
:created_on: Apr 21, 2010
 
:author: marcink
 
:copyright: (c) 2013 RhodeCode GmbH, and others.
 
:license: GPLv3, see LICENSE.md for more details.
 
"""
 

	
 
import os
 
import posixpath
 
import logging
 
import traceback
 
import tempfile
 
import shutil
 

	
 
from tg import request, response, tmpl_context as c
 
from tg.i18n import ugettext as _
 
from webob.exc import HTTPFound
 

	
 
from kallithea.config.routing import url
 
from kallithea.lib.utils import action_logger
 
from kallithea.lib import diffs
 
from kallithea.lib import helpers as h
 

	
 
from kallithea.lib.compat import OrderedDict
 
from kallithea.lib.utils2 import convert_line_endings, detect_mode, safe_str, \
 
    str2bool, safe_int
 
from kallithea.lib.auth import LoginRequired, HasRepoPermissionLevelDecorator
 
from kallithea.lib.base import BaseRepoController, render, jsonify
 
from kallithea.lib.vcs.backends.base import EmptyChangeset
 
from kallithea.lib.vcs.conf import settings
 
from kallithea.lib.vcs.exceptions import RepositoryError, \
 
    ChangesetDoesNotExistError, EmptyRepositoryError, \
 
    ImproperArchiveTypeError, VCSError, NodeAlreadyExistsError, \
 
    NodeDoesNotExistError, ChangesetError, NodeError
 
from kallithea.lib.vcs.nodes import FileNode
 

	
 
from kallithea.model.repo import RepoModel
 
from kallithea.model.scm import ScmModel
 
from kallithea.model.db import Repository
 

	
 
from kallithea.controllers.changeset import anchor_url, _ignorews_url, \
 
    _context_url, get_line_ctx, get_ignore_ws
 
from webob.exc import HTTPNotFound
 
from kallithea.lib.exceptions import NonRelativePathError
 

	
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
class FilesController(BaseRepoController):
 

	
 
    def _before(self, *args, **kwargs):
 
        super(FilesController, self)._before(*args, **kwargs)
 

	
 
    def __get_cs(self, rev, silent_empty=False):
 
        """
 
        Safe way to get changeset if error occur it redirects to tip with
 
        proper message
 

	
 
        :param rev: revision to fetch
 
        :silent_empty: return None if repository is empty
 
        """
 

	
 
        try:
 
            return c.db_repo_scm_instance.get_changeset(rev)
 
        except EmptyRepositoryError as e:
 
            if silent_empty:
 
                return None
 
            url_ = url('files_add_home',
 
                       repo_name=c.repo_name,
 
                       revision=0, f_path='', anchor='edit')
 
            add_new = h.link_to(_('Click here to add new file'), url_, class_="alert-link")
 
            h.flash(h.literal(_('There are no files yet. %s') % add_new),
 
                    category='warning')
 
            h.flash(_('There are no files yet.') + ' ' + add_new, category='warning')
 
            raise HTTPNotFound()
 
        except (ChangesetDoesNotExistError, LookupError):
 
            msg = _('Such revision does not exist for this repository')
 
            h.flash(msg, category='error')
 
            raise HTTPNotFound()
 
        except RepositoryError as e:
 
            h.flash(safe_str(e), category='error')
 
            raise HTTPNotFound()
 

	
 
    def __get_filenode(self, cs, path):
 
        """
 
        Returns file_node or raise HTTP error.
 

	
 
        :param cs: given changeset
 
        :param path: path to lookup
 
        """
 

	
 
        try:
 
            file_node = cs.get_node(path)
 
            if file_node.is_dir():
 
                raise RepositoryError('given path is a directory')
 
        except ChangesetDoesNotExistError:
 
            msg = _('Such revision does not exist for this repository')
 
            h.flash(msg, category='error')
 
            raise HTTPNotFound()
 
        except RepositoryError as e:
 
            h.flash(safe_str(e), category='error')
 
            raise HTTPNotFound()
 

	
 
        return file_node
 

	
 
    @LoginRequired(allow_default_user=True)
 
    @HasRepoPermissionLevelDecorator('read')
 
    def index(self, repo_name, revision, f_path, annotate=False):
 
        # redirect to given revision from form if given
 
        post_revision = request.POST.get('at_rev', None)
 
        if post_revision:
 
            cs = self.__get_cs(post_revision) # FIXME - unused!
 

	
 
        c.revision = revision
 
        c.changeset = self.__get_cs(revision)
 
        c.branch = request.GET.get('branch', None)
 
        c.f_path = f_path
 
        c.annotate = annotate
 
        cur_rev = c.changeset.revision
 
        # used in files_source.html:
 
        c.cut_off_limit = self.cut_off_limit
 
        c.fulldiff = request.GET.get('fulldiff')
 

	
 
        # prev link
 
        try:
 
            prev_rev = c.db_repo_scm_instance.get_changeset(cur_rev).prev(c.branch)
 
            c.url_prev = url('files_home', repo_name=c.repo_name,
 
                         revision=prev_rev.raw_id, f_path=f_path)
 
            if c.branch:
 
                c.url_prev += '?branch=%s' % c.branch
 
        except (ChangesetDoesNotExistError, VCSError):
 
            c.url_prev = '#'
 

	
 
        # next link
 
        try:
 
            next_rev = c.db_repo_scm_instance.get_changeset(cur_rev).next(c.branch)
 
            c.url_next = url('files_home', repo_name=c.repo_name,
 
                     revision=next_rev.raw_id, f_path=f_path)
 
            if c.branch:
 
                c.url_next += '?branch=%s' % c.branch
 
        except (ChangesetDoesNotExistError, VCSError):
 
            c.url_next = '#'
 

	
 
        # files or dirs
 
        try:
 
            c.file = c.changeset.get_node(f_path)
 

	
 
            if c.file.is_submodule():
 
                raise HTTPFound(location=c.file.url)
 
            elif c.file.is_file():
 
                c.load_full_history = False
 
                # determine if we're on branch head
 
                _branches = c.db_repo_scm_instance.branches
 
                c.on_branch_head = revision in _branches.keys() + _branches.values()
 
                _hist = []
 
                c.file_history = []
 
                if c.load_full_history:
 
                    c.file_history, _hist = self._get_node_history(c.changeset, f_path)
 

	
 
                c.authors = []
 
                for a in set([x.author for x in _hist]):
 
                    c.authors.append((h.email(a), h.person(a)))
 
            else:
 
                c.authors = c.file_history = []
 
        except RepositoryError as e:
 
            h.flash(safe_str(e), category='error')
 
            raise HTTPNotFound()
 

	
 
        if request.environ.get('HTTP_X_PARTIAL_XHR'):
 
            return render('files/files_ypjax.html')
 

	
 
        # TODO: tags and bookmarks?
 
        c.revision_options = [(c.changeset.raw_id,
 
                              _('%s at %s') % (b, h.short_id(c.changeset.raw_id))) for b in c.changeset.branches] + \
 
            [(n, b) for b, n in c.db_repo_scm_instance.branches.items()]
 
        if c.db_repo_scm_instance.closed_branches:
 
            prefix = _('(closed)') + ' '
 
            c.revision_options += [('-', '-')] + \
 
                [(n, prefix + b) for b, n in c.db_repo_scm_instance.closed_branches.items()]
 

	
 
        return render('files/files.html')
 

	
 
    @LoginRequired(allow_default_user=True)
 
    @HasRepoPermissionLevelDecorator('read')
 
    @jsonify
 
    def history(self, repo_name, revision, f_path):
 
        changeset = self.__get_cs(revision)
 
        _file = changeset.get_node(f_path)
 
        if _file.is_file():
 
            file_history, _hist = self._get_node_history(changeset, f_path)
 

	
 
            res = []
 
            for obj in file_history:
 
                res.append({
 
                    'text': obj[1],
 
                    'children': [{'id': o[0], 'text': o[1]} for o in obj[0]]
 
                })
 

	
 
            data = {
 
                'more': False,
 
                'results': res
 
            }
 
            return data
 

	
 
    @LoginRequired(allow_default_user=True)
 
    @HasRepoPermissionLevelDecorator('read')
 
    def authors(self, repo_name, revision, f_path):
 
        changeset = self.__get_cs(revision)
 
        _file = changeset.get_node(f_path)
 
        if _file.is_file():
 
            file_history, _hist = self._get_node_history(changeset, f_path)
 
            c.authors = []
 
            for a in set([x.author for x in _hist]):
 
                c.authors.append((h.email(a), h.person(a)))
 
            return render('files/files_history_box.html')
 

	
 
    @LoginRequired(allow_default_user=True)
 
    @HasRepoPermissionLevelDecorator('read')
 
    def rawfile(self, repo_name, revision, f_path):
 
        cs = self.__get_cs(revision)
 
        file_node = self.__get_filenode(cs, f_path)
 

	
 
        response.content_disposition = 'attachment; filename=%s' % \
 
            safe_str(f_path.split(Repository.url_sep())[-1])
 

	
 
        response.content_type = file_node.mimetype
 
        return file_node.content
 

	
 
    @LoginRequired(allow_default_user=True)
 
    @HasRepoPermissionLevelDecorator('read')
 
    def raw(self, repo_name, revision, f_path):
 
        cs = self.__get_cs(revision)
 
        file_node = self.__get_filenode(cs, f_path)
 

	
 
        raw_mimetype_mapping = {
 
            # map original mimetype to a mimetype used for "show as raw"
 
            # you can also provide a content-disposition to override the
 
            # default "attachment" disposition.
 
            # orig_type: (new_type, new_dispo)
 

	
 
            # show images inline:
 
            'image/x-icon': ('image/x-icon', 'inline'),
 
            'image/png': ('image/png', 'inline'),
 
            'image/gif': ('image/gif', 'inline'),
 
            'image/jpeg': ('image/jpeg', 'inline'),
 
            'image/svg+xml': ('image/svg+xml', 'inline'),
 
        }
 

	
 
        mimetype = file_node.mimetype
 
        try:
 
            mimetype, dispo = raw_mimetype_mapping[mimetype]
 
        except KeyError:
 
            # we don't know anything special about this, handle it safely
 
            if file_node.is_binary:
 
                # do same as download raw for binary files
 
                mimetype, dispo = 'application/octet-stream', 'attachment'
 
            else:
 
                # do not just use the original mimetype, but force text/plain,
 
                # otherwise it would serve text/html and that might be unsafe.
 
                # Note: underlying vcs library fakes text/plain mimetype if the
 
                # mimetype can not be determined and it thinks it is not
 
                # binary.This might lead to erroneous text display in some
 
                # cases, but helps in other cases, like with text files
 
                # without extension.
 
                mimetype, dispo = 'text/plain', 'inline'
 

	
kallithea/front-end/style.less
Show inline comments
 
@@ -733,226 +733,227 @@ div.comment-prev-next-links div.next-com
 
    }
 
    .form {
 
      .form-horizontal;
 
    }
 
    .form-group {
 
      .clearfix;
 
      > label {
 
        .make-xs-column(3);
 
        overflow: hidden;
 
        text-overflow: ellipsis;
 
        input {
 
          width: 100%;
 
        }
 
      }
 
      > div {
 
        .make-xs-column(9);
 
      }
 
      .buttons {
 
        .make-xs-column-offset(3);
 
      }
 
    }
 
  }
 
}
 

	
 
/* use columns and form-horizontal for summary page */
 
#summary {
 
  max-width: @container-md;
 
  .form-horizontal;
 
  .make-sm-column(10);
 
  padding-left: 0;
 
  .form-group > label {
 
    .make-sm-column(2);
 
  }
 
  .form-group > div {
 
    .make-sm-column(10);
 
  }
 
}
 
#summary-menu-stats {
 
  .make-sm-column(2);
 
  padding-right: 0;
 
}
 

	
 
/* use columns and form-horizontal for pull request page */
 
.pr-box {
 
  .make-sm-column(9);
 
  padding-left: 0;
 
  max-width: @container-md;
 
  #pr-summary {
 
    .form-horizontal;
 
    .form-group > label {
 
      .make-sm-column(3);
 
    }
 
    .form-group > div {
 
      .make-sm-column(9);
 
    }
 
    .form-group > .buttons {
 
      .make-sm-column-offset(3);
 
      .make-sm-column(9);
 
    }
 
  }
 
}
 
.pr-reviewers-box {
 
  .make-sm-column(3);
 
  padding-right: 0;
 
}
 

	
 
/* repo table icons */
 
#repos_list_wrap_wrapper {
 
  /* make icon-folder and repotag the same width */
 
  .icon-folder:before {
 
    margin: 0; // default margin would otherwise add to the total width
 
    width: 24px;
 
    text-align: left;
 
  }
 
  .label-repo {
 
    display: inline-block;
 
    width: 24px;
 
  }
 
}
 

	
 
/* changelog table columns */
 
.table#changesets {
 
  table-layout: fixed;
 
  td {
 
    overflow: hidden;
 
    text-overflow: ellipsis;
 
    white-space: nowrap;
 
    vertical-align: baseline;
 
    &:last-child {
 
      padding-right: 0;
 
    }
 
  }
 
  .checkbox-column {
 
    width: 20px;
 
    padding: 0;
 
    /* the optional second checkbox will be inline-block but should wrap to a new line */
 
    white-space: normal;
 
    > input[type=checkbox] {
 
      margin-top: inherit;
 
      vertical-align: text-bottom;
 
    }
 
  }
 
  .changeset-logical-index {
 
    color: @gray-light;
 
    font-style: italic;
 
    font-size: 85%;
 
    text-align: right;
 
    overflow: visible;
 
  }
 
  .changeset-logical-index,
 
  .expand_commit,
 
  .status {
 
    width: 28px;
 
  }
 
  .author {
 
    width: 200px;
 
    @media (max-width: @screen-sm-max) {
 
      width: 120px;
 
    }
 
    @media (max-width: @screen-xs-max) {
 
      width: 20px;
 
      /* keep gravatar but hide name on tiny screens to give important columns more room */
 
      span {
 
        .hidden;
 
      }
 
    }
 
    > .icon-user::before {
 
      margin: 0;
 
    }
 
  }
 
  .hash {
 
    .small;
 
    width: 110px;
 
    @media (max-width: @screen-xs-max) {
 
      width: 48px;
 
    }
 
  }
 
  .date {
 
    .small;
 
    width: 100px;
 
  }
 
  /* hide on small screens to give important columns more room */
 
  .status,
 
  .expand_commit,
 
  .comments,
 
  .extra-container {
 
    .hidden-xs;
 
  }
 
  .mid > .log-container {
 
    position: relative;
 
    overflow: hidden;
 
    > .extra-container {
 
      position: absolute;
 
      top: 0;
 
      right: 0;
 
      background: white;
 
      box-shadow: -10px 0px 10px 0px white;
 
    }
 
  }
 
}
 

	
 
/* undo Bootstrap chrome/webkit blue outline on focus in navbar */
 
.navbar-inverse .navbar-nav > li > a:focus {
 
  outline: 0;
 
}
 

	
 
/* use same badge coloring in navbar inverse as in panel-heading */
 
.navbar-inverse {
 
  .badge {
 
    color: @navbar-inverse-bg;
 
    background-color: @navbar-inverse-color;
 
  }
 
}
 

	
 
/* pygments style */
 
div.search-code-body pre .match {
 
  background-color: @highlight-color;
 
}
 
div.search-code-body pre .break {
 
  background-color: @highlight-line-color;
 
  width: 100%;
 
  color: #747474;
 
  display: block;
 
}
 
div.annotatediv {
 
  margin-left: 2px;
 
  margin-right: 4px;
 
}
 
.code-highlight {
 
  border-left: 1px solid #ccc;
 
}
 
.code-highlight pre,
 
.annotatediv pre,
 
.linenodiv pre {
 
  padding: 5px 2px 0px 5px;
 
  margin: 0;
 
}
 
.code-highlight pre div:target {
 
  background-color: #FFFFBE !important;
 
}
 
.linenos a { text-decoration: none; }
 

	
 
/* Stylesheets for the context bar */
 
#quick_login > .pull-right .list-group-item {
 
  background-color: @kallithea-theme-main-color;
 
  border: 0;
 
}
 
#content #context-pages .follow .show-following,
 
#content #context-pages .following .show-follow {
 
  display: none;
 
}
 

	
 
nav.navbar #quick > li > a,
 
#context-pages > ul > li > a {
 
  height: @navbar-height;
 
}
 

	
 
/* align with panel-heading */
 
nav.navbar#context-bar > .container-fluid {
 
  padding-left: 15px;
 
}
 

	
 
/* at.js */
 
.atwho-view strong {
 
  /* the blue color doesn't look good, use normal color */
 
  color: inherit;
 
}
kallithea/i18n/be/LC_MESSAGES/kallithea.po
Show inline comments
 
# Belarusian translations for Kallithea.
 
# Copyright (C) 2016 Various authors, licensing as GPLv3
 
# This file is distributed under the same license as the Kallithea project.
 
# Automatically generated, 2016.
 
# #, fuzzy
 
msgid ""
 
msgstr ""
 
"Project-Id-Version: Kallithea 0.3\n"
 
"Report-Msgid-Bugs-To: translations@kallithea-scm.org\n"
 
"POT-Creation-Date: 2019-03-26 22:07+0100\n"
 
"POT-Creation-Date: 2019-05-04 21:13+0200\n"
 
"PO-Revision-Date: 2017-08-20 10:44+0000\n"
 
"Last-Translator: Viktar Vauchkevich <victorenator@gmail.com>\n"
 
"Language-Team: Belarusian <https://hosted.weblate.org/projects/kallithea/"
 
"kallithea/be/>\n"
 
"Language: be\n"
 
"MIME-Version: 1.0\n"
 
"Content-Type: text/plain; charset=UTF-8\n"
 
"Content-Transfer-Encoding: 8bit\n"
 
"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
 
"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
 
"X-Generator: Weblate 2.17-dev\n"
 

	
 
#: kallithea/controllers/changelog.py:67
 
#: kallithea/controllers/pullrequests.py:252 kallithea/lib/base.py:605
 
msgid "There are no changesets yet"
 
msgstr "Яшчэ не было змен"
 

	
 
#: kallithea/controllers/admin/permissions.py:62
 
#: kallithea/controllers/admin/permissions.py:66
 
#: kallithea/controllers/admin/permissions.py:70
 
#: kallithea/controllers/changelog.py:136
 
#: kallithea/templates/admin/repo_groups/repo_group_edit_perms.html:7
 
#: kallithea/templates/admin/repo_groups/repo_group_edit_perms.html:88
 
#: kallithea/templates/admin/repos/repo_edit_permissions.html:7
 
#: kallithea/templates/admin/user_groups/user_group_edit_perms.html:7
 
#: kallithea/templates/base/perms_summary.html:14
 
msgid "None"
 
msgstr "Нічога"
 

	
 
#: kallithea/controllers/changelog.py:139 kallithea/controllers/files.py:197
 
#: kallithea/controllers/changelog.py:139 kallithea/controllers/files.py:196
 
msgid "(closed)"
 
msgstr "(зачынена)"
 

	
 
#: kallithea/controllers/changeset.py:83
 
msgid "Show whitespace"
 
msgstr "Паказваць прабелы"
 

	
 
#: kallithea/controllers/changeset.py:90
 
#: kallithea/controllers/changeset.py:97
 
#: kallithea/templates/files/diff_2way.html:55
 
msgid "Ignore whitespace"
 
msgstr "Ігнараваць прабелы"
 

	
 
#: kallithea/controllers/changeset.py:163
 
#, python-format
 
msgid "Increase diff context to %(num)s lines"
 
msgstr "Павялічыць кантэкст да %(num)s радкоў"
 

	
 
#: kallithea/controllers/changeset.py:203
 
#, fuzzy
 
#| msgid "No permission to change pull request status"
 
msgid "No permission to change status"
 
msgstr "Няма правоў змяняць статус pull-запыту"
 

	
 
#: kallithea/controllers/changeset.py:214
 
#, python-format
 
msgid "Successfully deleted pull request %s"
 
msgstr "Pull-запыт %s паспяхова выдалены"
 

	
 
#: kallithea/controllers/changeset.py:321 kallithea/controllers/files.py:97
 
#: kallithea/controllers/files.py:117 kallithea/controllers/files.py:727
 
#: kallithea/controllers/changeset.py:321 kallithea/controllers/files.py:96
 
#: kallithea/controllers/files.py:116 kallithea/controllers/files.py:726
 
msgid "Such revision does not exist for this repository"
 
msgstr "Няма такой рэвізіі ў гэтым рэпазітары"
 

	
 
#: kallithea/controllers/compare.py:66
 
#, python-format
 
msgid "Could not find other repository %s"
 
msgstr "Не атрымалася знайсці іншы рэпазітар %s"
 

	
 
#: kallithea/controllers/compare.py:72
 
msgid "Cannot compare repositories of different types"
 
msgstr "Немагчыма параўноўваць рэпазітары розных тыпаў"
 

	
 
#: kallithea/controllers/compare.py:244
 
msgid "Cannot show empty diff"
 
msgstr ""
 

	
 
#: kallithea/controllers/compare.py:246
 
msgid "No ancestor found for merge diff"
 
msgstr ""
 

	
 
#: kallithea/controllers/compare.py:250
 
msgid "Multiple merge ancestors found for merge compare"
 
msgstr ""
 

	
 
#: kallithea/controllers/compare.py:266
 
msgid "Cannot compare repositories without using common ancestor"
 
msgstr "Немагчыма параўноўваць рэпазітары без агульнага продка"
 

	
 
#: kallithea/controllers/error.py:70
 
msgid "No response"
 
msgstr "Няма адказу"
 

	
 
#: kallithea/controllers/error.py:71
 
msgid "Unknown error"
 
msgstr "Невядомая памылка"
 

	
 
#: kallithea/controllers/error.py:84
 
msgid ""
 
"The request could not be understood by the server due to malformed syntax."
 
msgstr "Запыт не распазнаны серверам з-за няправільнага сінтаксісу."
 

	
 
#: kallithea/controllers/error.py:87
 
msgid "Unauthorized access to resource"
 
msgstr "Несанкцыянаваны доступ да рэсурсу"
 

	
 
#: kallithea/controllers/error.py:89
 
msgid "You don't have permission to view this page"
 
msgstr "У вас няма правоў для прагляду гэтай старонкі"
 

	
 
#: kallithea/controllers/error.py:91
 
msgid "The resource could not be found"
 
msgstr "Рэсурс не знойдзены"
 

	
 
#: kallithea/controllers/error.py:93
 
msgid ""
 
"The server encountered an unexpected condition which prevented it from "
 
"fulfilling the request."
 
msgstr ""
 
"Сервер не можа выканаць запыт з-за нечаканых умоваў, якія ўзніклі падчас "
 
"яго спрацавання."
 

	
 
#: kallithea/controllers/feed.py:63
 
#, python-format
 
msgid "%s committed on %s"
 
msgstr "%s выканаў каміт у %s"
 

	
 
#: kallithea/controllers/feed.py:88
 
#: kallithea/templates/changeset/changeset.html:154
 
#: kallithea/templates/changeset/changeset.html:173
 
#: kallithea/templates/compare/compare_diff.html:81
 
#: kallithea/templates/compare/compare_diff.html:95
 
#: kallithea/templates/pullrequests/pullrequest_show.html:309
 
#: kallithea/templates/pullrequests/pullrequest_show.html:333
 
msgid "Changeset was too big and was cut off..."
 
msgstr "Змены апынуліся занадта вялікімі і былі скарочаныя..."
 

	
 
#: kallithea/controllers/feed.py:111 kallithea/controllers/feed.py:143
 
#, python-format
 
msgid "%s %s feed"
 
msgstr "Стужка навін %s %s"
 

	
 
#: kallithea/controllers/feed.py:113 kallithea/controllers/feed.py:145
 
#, python-format
 
msgid "Changes on %s repository"
 
msgstr "Змены ў рэпазітары %s"
 

	
 
#: kallithea/controllers/files.py:92
 
msgid "Click here to add new file"
 
msgstr "Націсніце каб дадаць новы файл"
 

	
 
#: kallithea/controllers/files.py:93
 
#, python-format
 
msgid "There are no files yet. %s"
 
#, fuzzy
 
#| msgid "There are no files yet. %s"
 
msgid "There are no files yet."
 
msgstr "Няма файлаў. %s"
 

	
 
#: kallithea/controllers/files.py:194
 
#: kallithea/controllers/files.py:193
 
#, python-format
 
msgid "%s at %s"
 
msgstr "%s (%s)"
 

	
 
#: kallithea/controllers/files.py:300 kallithea/controllers/files.py:360
 
#: kallithea/controllers/files.py:427
 
#: kallithea/controllers/files.py:299 kallithea/controllers/files.py:359
 
#: kallithea/controllers/files.py:426
 
#, python-format
 
msgid "This repository has been locked by %s on %s"
 
msgstr "Рэпазітар заблакаваў %s у %s"
 

	
 
#: kallithea/controllers/files.py:312
 
#: kallithea/controllers/files.py:311
 
msgid "You can only delete files with revision being a valid branch"
 
msgstr "Вы можаце выдаляць файлы толькі ў рэвізіі, злучанай з існай галінай"
 

	
 
#: kallithea/controllers/files.py:323
 
#: kallithea/controllers/files.py:322
 
#, python-format
 
msgid "Deleted file %s via Kallithea"
 
msgstr "Файл %s выдалены з дапамогай Kallithea"
 

	
 
#: kallithea/controllers/files.py:345
 
#: kallithea/controllers/files.py:344
 
#, python-format
 
msgid "Successfully deleted file %s"
 
msgstr "Файл %s выдалены"
 

	
 
#: kallithea/controllers/files.py:349 kallithea/controllers/files.py:415
 
#: kallithea/controllers/files.py:496
 
#: kallithea/controllers/files.py:348 kallithea/controllers/files.py:414
 
#: kallithea/controllers/files.py:495
 
msgid "Error occurred during commit"
 
msgstr "Падчас каміта адбылася памылка"
 

	
 
#: kallithea/controllers/files.py:372
 
#: kallithea/controllers/files.py:371
 
msgid "You can only edit files with revision being a valid branch"
 
msgstr ""
 
"Вы можаце рэдагаваць файлы толькі ў рэвізіі, злучанай з існай галінай"
 

	
 
#: kallithea/controllers/files.py:386
 
#: kallithea/controllers/files.py:385
 
#, python-format
 
msgid "Edited file %s via Kallithea"
 
msgstr "Файл %s адрэдагаваны з дапамогай Kallithea"
 

	
 
#: kallithea/controllers/files.py:402
 
#: kallithea/controllers/files.py:401
 
msgid "No changes"
 
msgstr "Без змен"
 

	
 
#: kallithea/controllers/files.py:411 kallithea/controllers/files.py:485
 
#: kallithea/controllers/files.py:410 kallithea/controllers/files.py:484
 
#, python-format
 
msgid "Successfully committed to %s"
 
msgstr "Змены захаваныя ў %s"
 

	
 
#: kallithea/controllers/files.py:438
 
#: kallithea/controllers/files.py:437
 
msgid "Added file via Kallithea"
 
msgstr "Файл дададзены з дапамогай Kallithea"
 

	
 
#: kallithea/controllers/files.py:459
 
#: kallithea/controllers/files.py:458
 
msgid "No content"
 
msgstr "Пуста"
 

	
 
#: kallithea/controllers/files.py:463
 
#: kallithea/controllers/files.py:462
 
msgid "No filename"
 
msgstr "Безназоўны"
 

	
 
#: kallithea/controllers/files.py:488
 
#: kallithea/controllers/files.py:487
 
msgid "Location must be relative path and must not contain .. in path"
 
msgstr ""
 
"Размяшчэнне павінна быць адносным шляхам, і не можа ўтрымліваць \"..\" у "
 
"шляхі"
 

	
 
#: kallithea/controllers/files.py:520
 
#: kallithea/controllers/files.py:519
 
msgid "Downloads disabled"
 
msgstr "Магчымасць спампоўваць адключаная"
 

	
 
#: kallithea/controllers/files.py:531
 
#: kallithea/controllers/files.py:530
 
#, python-format
 
msgid "Unknown revision %s"
 
msgstr "Невядомая рэвізія %s"
 

	
 
#: kallithea/controllers/files.py:533
 
#: kallithea/controllers/files.py:532
 
msgid "Empty repository"
 
msgstr "Пусты рэпазітар"
 

	
 
#: kallithea/controllers/files.py:535
 
#: kallithea/controllers/files.py:534
 
msgid "Unknown archive type"
 
msgstr "Невядомы тып архіва"
 

	
 
#: kallithea/controllers/files.py:756
 
#: kallithea/controllers/files.py:755
 
#: kallithea/templates/changeset/changeset_range.html:9
 
#: kallithea/templates/email_templates/pull_request.html:64
 
#: kallithea/templates/pullrequests/pullrequest.html:84
 
msgid "Changesets"
 
msgstr "Набор змен"
 

	
 
#: kallithea/controllers/files.py:757
 
#: kallithea/controllers/files.py:756
 
#: kallithea/controllers/pullrequests.py:184 kallithea/model/scm.py:706
 
msgid "Branches"
 
msgstr "Галіны"
 

	
 
#: kallithea/controllers/files.py:758
 
#: kallithea/controllers/files.py:757
 
#: kallithea/controllers/pullrequests.py:185 kallithea/model/scm.py:717
 
msgid "Tags"
 
msgstr "Тэгі"
 

	
 
#: kallithea/controllers/forks.py:174
 
#, python-format
 
msgid "An error occurred during repository forking %s"
 
msgstr "Памылка падчас стварэння форка рэпазітара %s"
 

	
 
#: kallithea/controllers/home.py:78
 
msgid "Groups"
 
msgstr "Групы"
 

	
 
#: kallithea/controllers/home.py:88
 
#: kallithea/templates/admin/repo_groups/repo_group_edit_perms.html:90
 
#: kallithea/templates/admin/repos/repo_add.html:12
 
#: kallithea/templates/admin/repos/repo_add.html:16
 
#: kallithea/templates/admin/repos/repos.html:9
 
#: kallithea/templates/admin/users/user_edit_advanced.html:6
 
#: kallithea/templates/base/base.html:56
 
#: kallithea/templates/base/base.html:73
 
#: kallithea/templates/base/base.html:444 kallithea/templates/index.html:5
 
msgid "Repositories"
 
msgstr "Рэпазітары"
 

	
 
#: kallithea/controllers/home.py:121
 
#: kallithea/templates/files/files_add.html:32
 
#: kallithea/templates/files/files_delete.html:23
 
#: kallithea/templates/files/files_edit.html:32
 
msgid "Branch"
 
msgstr "Галіна"
 

	
 
#: kallithea/controllers/home.py:127
 
msgid "Closed Branches"
 
msgstr "Зачыненыя галіны"
 

	
 
#: kallithea/controllers/home.py:133
 
msgid "Tag"
 
msgstr "Тэгі"
 

	
 
#: kallithea/controllers/home.py:139
 
msgid "Bookmark"
 
msgstr "Закладкі"
 

	
 
#: kallithea/controllers/journal.py:113 kallithea/controllers/journal.py:155
 
#: kallithea/templates/journal/public_journal.html:4
 
#: kallithea/templates/journal/public_journal.html:18
 
msgid "Public Journal"
 
msgstr "Публічны журнал"
 

	
 
#: kallithea/controllers/journal.py:117 kallithea/controllers/journal.py:159
 
#: kallithea/templates/base/base.html:297
 
#: kallithea/templates/journal/journal.html:5
 
#: kallithea/templates/journal/journal.html:13
 
msgid "Journal"
 
msgstr "Журнал"
 

	
 
#: kallithea/controllers/login.py:139 kallithea/controllers/login.py:184
 
msgid "Bad captcha"
 
msgstr "Няслушная капча"
 

	
 
#: kallithea/controllers/login.py:145
 
#, python-format
 
msgid "You have successfully registered with %s"
 
msgstr "Рэгістрацыя ў %s прайшла паспяхова"
 

	
 
#: kallithea/controllers/login.py:189
 
msgid "A password reset confirmation code has been sent"
 
msgstr "Код для скідання пароля адпраўлены"
 

	
 
#: kallithea/controllers/login.py:238
 
msgid "Invalid password reset token"
 
msgstr "Няслушны код скідання пароля"
 

	
 
#: kallithea/controllers/admin/my_account.py:155
 
#: kallithea/controllers/login.py:243
 
msgid "Successfully updated password"
 
msgstr "Пароль абноўлены"
 

	
 
#: kallithea/controllers/pullrequests.py:71
 
#, python-format
 
msgid "Invalid reviewer \"%s\" specified"
 
msgstr "Няслушны рэцэнзент \"%s\""
 

	
 
#: kallithea/controllers/pullrequests.py:133
 
#, python-format
 
msgid "%s (closed)"
 
msgstr "%s (зачынена)"
 

	
 
#: kallithea/controllers/pullrequests.py:160
 
#: kallithea/templates/changeset/changeset.html:12
 
msgid "Changeset"
 
msgstr "Змены"
 

	
 
#: kallithea/controllers/pullrequests.py:181
 
msgid "Special"
 
msgstr "Адмысловы"
 

	
 
#: kallithea/controllers/pullrequests.py:182
 
msgid "Peer branches"
 
msgstr "Галіны ўдзельніка"
 

	
 
#: kallithea/controllers/pullrequests.py:183 kallithea/model/scm.py:712
 
msgid "Bookmarks"
 
msgstr "Закладкі"
 

	
 
#: kallithea/controllers/pullrequests.py:320
 
#, python-format
 
msgid "Error creating pull request: %s"
 
msgstr "Памылка пры стварэнні pull-запыту: %s"
 

	
 
#: kallithea/controllers/pullrequests.py:347
 
#: kallithea/controllers/pullrequests.py:370
 
msgid "Error occurred while creating pull request"
 
msgstr "Адбылася памылка пры стварэнні pull-запыту"
 

	
 
#: kallithea/controllers/pullrequests.py:352
 
msgid "Successfully opened new pull request"
 
msgstr "Pull-запыт створаны паспяхова"
 

	
 
#: kallithea/controllers/pullrequests.py:375
 
#, fuzzy
 
#| msgid "Pull request update created"
 
msgid "New pull request iteration created"
 
msgstr "Абнаўленне для pull-запыту створана"
 

	
 
#: kallithea/controllers/pullrequests.py:403
 
#, python-format
 
msgid "Meanwhile, the following reviewers have been added: %s"
 
msgstr ""
 

	
 
#: kallithea/controllers/pullrequests.py:407
 
#, python-format
 
msgid "Meanwhile, the following reviewers have been removed: %s"
 
msgstr ""
 

	
 
#: kallithea/controllers/pullrequests.py:423
 
#: kallithea/model/pull_request.py:234
 
msgid "No description"
 
msgstr "Няма апісання"
 

	
 
#: kallithea/controllers/pullrequests.py:432
 
msgid "Pull request updated"
 
msgstr "Pull-запыт абноўлены"
 

	
 
#: kallithea/controllers/pullrequests.py:445
 
msgid "Successfully deleted pull request"
 
msgstr "Pull-запыт паспяхова выдалены"
 

	
 
#: kallithea/controllers/pullrequests.py:481
 
#, fuzzy, python-format
 
#| msgid "Changeset for %s %s not found in %s"
 
msgid "Revision %s not found in %s"
 
msgstr "Набор змен для %s %s не знойдзены ў %s"
 

	
 
#: kallithea/controllers/pullrequests.py:508
 
#, fuzzy, python-format
 
#| msgid "No changesets found for updating this pull request."
 
msgid "Error: changesets not found when displaying pull request from %s."
 
msgstr "Няма змен для абнаўлення гэтага pull-запыту."
 

	
 
#: kallithea/controllers/pullrequests.py:522
 
#, python-format
 
msgid "This pull request has already been merged to %s."
 
msgstr "Гэты pull-запыт ужо прыняты на галіну %s."
 

	
 
#: kallithea/controllers/pullrequests.py:524
 
msgid "This pull request has been closed and can not be updated."
 
msgstr "Гэты pull-запыт быў зачынены і не можа быць абноўлены."
 

	
 
#: kallithea/controllers/pullrequests.py:543
 
#, fuzzy, python-format
 
#| msgid "The following changes are available on %s:"
 
msgid "The following additional changes are available on %s:"
 
msgstr "Гэтыя змены даступныя на %s:"
 

	
 
#: kallithea/controllers/pullrequests.py:545
 
#: kallithea/controllers/pullrequests.py:549
 
#, fuzzy
 
#| msgid "No changesets found for updating this pull request."
 
msgid "No additional changesets found for iterating on this pull request."
 
msgstr "Няма змен для абнаўлення гэтага pull-запыту."
 

	
 
#: kallithea/controllers/pullrequests.py:557
 
#, python-format
 
msgid "Note: Branch %s has another head: %s."
 
msgstr "Увага: Галіна %s мае яшчэ адну верхавіну: %s."
 

	
 
#: kallithea/controllers/pullrequests.py:564
 
#, fuzzy
 
#| msgid "Git pull requests don't support updates yet."
 
msgid "Git pull requests don't support iterating yet."
 
@@ -732,441 +733,441 @@ msgstr "Створаная новая група рэпазітароў %s"
 
#, python-format
 
msgid "Updated repository group %s"
 
msgstr "Група рэпазітароў %s абноўленая"
 

	
 
#: kallithea/controllers/admin/repo_groups.py:242
 
#, python-format
 
msgid "Error occurred during update of repository group %s"
 
msgstr "Адбылася памылка пры абнаўленні групы рэпазітароў %s"
 

	
 
#: kallithea/controllers/admin/repo_groups.py:252
 
#, python-format
 
msgid "This group contains %s repositories and cannot be deleted"
 
msgstr "Група ўтрымлівае %s рэпазітароў і не можа быць выдаленая"
 

	
 
#: kallithea/controllers/admin/repo_groups.py:259
 
#, python-format
 
msgid "This group contains %s subgroups and cannot be deleted"
 
msgstr "Група ўтрымлівае ў сабе %s падгруп і не можа быць выдаленая"
 

	
 
#: kallithea/controllers/admin/repo_groups.py:265
 
#, python-format
 
msgid "Removed repository group %s"
 
msgstr "Група рэпазітароў %s выдаленая"
 

	
 
#: kallithea/controllers/admin/repo_groups.py:270
 
#, python-format
 
msgid "Error occurred during deletion of repository group %s"
 
msgstr "Памылка пры выдаленні групы рэпазітароў %s"
 

	
 
#: kallithea/controllers/admin/repo_groups.py:354
 
#: kallithea/controllers/admin/repo_groups.py:384
 
#: kallithea/controllers/admin/user_groups.py:299
 
msgid "Cannot revoke permission for yourself as admin"
 
msgstr "Адміністратар не можа адклікаць свае прывелеі"
 

	
 
#: kallithea/controllers/admin/repo_groups.py:369
 
msgid "Repository group permissions updated"
 
msgstr "Прывілеі групы рэпазітароў абноўленыя"
 

	
 
#: kallithea/controllers/admin/repo_groups.py:401
 
#: kallithea/controllers/admin/repos.py:357
 
#: kallithea/controllers/admin/user_groups.py:311
 
msgid "An error occurred during revoking of permission"
 
msgstr "Памылка пры водгуку прывелея"
 

	
 
#: kallithea/controllers/admin/repos.py:137
 
#, python-format
 
msgid "Error creating repository %s"
 
msgstr "Памылка пры стварэнні рэпазітара %s"
 

	
 
#: kallithea/controllers/admin/repos.py:195
 
#, python-format
 
msgid "Created repository %s from %s"
 
msgstr "Рэпазітар %s створаны з %s"
 

	
 
#: kallithea/controllers/admin/repos.py:204
 
#, python-format
 
msgid "Forked repository %s as %s"
 
msgstr "Зроблены форк рэпазітара %s на %s"
 

	
 
#: kallithea/controllers/admin/repos.py:207
 
#, python-format
 
msgid "Created repository %s"
 
msgstr "Рэпазітар %s створаны"
 

	
 
#: kallithea/controllers/admin/repos.py:236
 
#, python-format
 
msgid "Repository %s updated successfully"
 
msgstr "Рэпазітар %s паспяхова абноўлены"
 

	
 
#: kallithea/controllers/admin/repos.py:256
 
#, python-format
 
msgid "Error occurred during update of repository %s"
 
msgstr "Памылка падчас абнаўлення рэпазітара %s"
 

	
 
#: kallithea/controllers/admin/repos.py:274
 
#, python-format
 
msgid "Detached %s forks"
 
msgstr "Форкі %s адлучаныя"
 

	
 
#: kallithea/controllers/admin/repos.py:277
 
#, python-format
 
msgid "Deleted %s forks"
 
msgstr "Выдаленыя форки рэпазітара %s"
 

	
 
#: kallithea/controllers/admin/repos.py:282
 
#, python-format
 
msgid "Deleted repository %s"
 
msgstr "Рэпазітар %s выдалены"
 

	
 
#: kallithea/controllers/admin/repos.py:285
 
#, python-format
 
msgid "Cannot delete repository %s which still has forks"
 
msgstr "Немагчыма выдаліць %s, ён усё яшчэ мае форкі"
 

	
 
#: kallithea/controllers/admin/repos.py:290
 
#, python-format
 
msgid "An error occurred during deletion of %s"
 
msgstr "Памылка падчас выдалення %s"
 

	
 
#: kallithea/controllers/admin/repos.py:330
 
msgid "Repository permissions updated"
 
msgstr "Прывілеі рэпазітара абноўленыя"
 

	
 
#: kallithea/controllers/admin/repos.py:387
 
#, python-format
 
msgid "Field validation error: %s"
 
msgstr ""
 

	
 
#: kallithea/controllers/admin/repos.py:390
 
#, fuzzy, python-format
 
#| msgid "An error occurred during creation of field"
 
msgid "An error occurred during creation of field: %r"
 
msgstr "Памылка пры стварэнні поля"
 

	
 
#: kallithea/controllers/admin/repos.py:401
 
msgid "An error occurred during removal of field"
 
msgstr "Памылка пры выдаленні поля"
 

	
 
#: kallithea/controllers/admin/repos.py:415
 
msgid "-- Not a fork --"
 
msgstr "-- Не форк --"
 

	
 
#: kallithea/controllers/admin/repos.py:446
 
msgid "Updated repository visibility in public journal"
 
msgstr "Бачнасць рэпазітара ў публічным часопісе абноўлена"
 

	
 
#: kallithea/controllers/admin/repos.py:450
 
msgid "An error occurred during setting this repository in public journal"
 
msgstr "Памылка пры даданні рэпазітара ў агульнадаступны часопіс"
 

	
 
#: kallithea/controllers/admin/repos.py:466
 
msgid "Nothing"
 
msgstr "Нічога"
 

	
 
#: kallithea/controllers/admin/repos.py:468
 
#, python-format
 
msgid "Marked repository %s as fork of %s"
 
msgstr "Рэпазітар %s адзначаны як форк %s"
 

	
 
#: kallithea/controllers/admin/repos.py:475
 
msgid "An error occurred during this operation"
 
msgstr "Памылка пры выкананні аперацыі"
 

	
 
#: kallithea/controllers/admin/repos.py:491
 
#: kallithea/controllers/admin/repos.py:512
 
msgid "Repository has been locked"
 
msgstr "Рэпазітар заблакаваны"
 

	
 
#: kallithea/controllers/admin/repos.py:494
 
#: kallithea/controllers/admin/repos.py:509
 
msgid "Repository has been unlocked"
 
msgstr "Рэпазітар разблакаваны"
 

	
 
#: kallithea/controllers/admin/repos.py:497
 
#: kallithea/controllers/admin/repos.py:516
 
msgid "An error occurred during unlocking"
 
msgstr "Памылка падчас разблакавання"
 

	
 
#: kallithea/controllers/admin/repos.py:528
 
msgid "Cache invalidation successful"
 
msgstr "Кэш скінуты"
 

	
 
#: kallithea/controllers/admin/repos.py:532
 
msgid "An error occurred during cache invalidation"
 
msgstr "Памылка пры скіданні кэша"
 

	
 
#: kallithea/controllers/admin/repos.py:545
 
msgid "Pulled from remote location"
 
msgstr "Занесеныя змены з аддаленага рэпазітара"
 

	
 
#: kallithea/controllers/admin/repos.py:548
 
msgid "An error occurred during pull from remote location"
 
msgstr "Памылка пры занясенні змен з аддаленага рэпазітара"
 

	
 
#: kallithea/controllers/admin/repos.py:579
 
msgid "An error occurred during deletion of repository stats"
 
msgstr "Адбылася памылка пры выдаленні статыстыкі рэпазітара"
 

	
 
#: kallithea/controllers/admin/settings.py:135
 
msgid "Updated VCS settings"
 
msgstr "Абноўлены налады VCS"
 

	
 
#: kallithea/controllers/admin/settings.py:139 kallithea/lib/utils.py:231
 
msgid ""
 
"Unable to activate hgsubversion support. The \"hgsubversion\" library is "
 
"missing"
 
msgstr ""
 
"Немагчыма ўключыць падтрымку hgsubversion. Бібліятэка hgsubversion "
 
"адсутнічае"
 

	
 
#: kallithea/controllers/admin/settings.py:145
 
#: kallithea/controllers/admin/settings.py:234
 
#: kallithea/controllers/admin/settings.py:237
 
msgid "Error occurred while updating application settings"
 
msgstr "Памылка пры абнаўленні наладаў праграмы"
 

	
 
#: kallithea/controllers/admin/settings.py:174
 
#: kallithea/controllers/admin/settings.py:180
 
#, python-format
 
msgid "Repositories successfully rescanned. Added: %s. Removed: %s."
 
msgstr "Рэпазітары паспяхова перасканаваныя, дададзена: %s, выдалена: %s."
 

	
 
#: kallithea/controllers/admin/settings.py:189
 
#: kallithea/controllers/admin/settings.py:192
 
#, python-format
 
msgid "Invalidated %s repositories"
 
msgstr "Скінуць кэш для %s рэпазітароў"
 

	
 
#: kallithea/controllers/admin/settings.py:230
 
#: kallithea/controllers/admin/settings.py:233
 
msgid "Updated application settings"
 
msgstr "Абноўленыя налады праграмы"
 

	
 
#: kallithea/controllers/admin/settings.py:283
 
#: kallithea/controllers/admin/settings.py:286
 
msgid "Updated visualisation settings"
 
msgstr "Налады візуалізацыі абноўленыя"
 

	
 
#: kallithea/controllers/admin/settings.py:288
 
#: kallithea/controllers/admin/settings.py:291
 
msgid "Error occurred during updating visualisation settings"
 
msgstr "Адбылася памылка пры абнаўленні наладаў візуалізацыі"
 

	
 
#: kallithea/controllers/admin/settings.py:312
 
#: kallithea/controllers/admin/settings.py:315
 
msgid "Please enter email address"
 
msgstr "Калі ласка, увядзіце e-mail-адрас"
 

	
 
#: kallithea/controllers/admin/settings.py:327
 
#: kallithea/controllers/admin/settings.py:330
 
msgid "Send email task created"
 
msgstr "Задача адпраўкі e-mail створаная"
 

	
 
#: kallithea/controllers/admin/settings.py:355
 
#: kallithea/controllers/admin/settings.py:358
 
#, fuzzy
 
#| msgid "No data ready yet"
 
msgid "Hook already exists"
 
msgstr "Няма дадзеных"
 

	
 
#: kallithea/controllers/admin/settings.py:357
 
#: kallithea/controllers/admin/settings.py:360
 
msgid "Builtin hooks are read-only. Please use another hook name."
 
msgstr ""
 

	
 
#: kallithea/controllers/admin/settings.py:360
 
#: kallithea/controllers/admin/settings.py:363
 
msgid "Added new hook"
 
msgstr "Дададзены новы хук"
 

	
 
#: kallithea/controllers/admin/settings.py:376
 
#: kallithea/controllers/admin/settings.py:379
 
msgid "Updated hooks"
 
msgstr "Абноўленыя хукі"
 

	
 
#: kallithea/controllers/admin/settings.py:380
 
#: kallithea/controllers/admin/settings.py:383
 
msgid "Error occurred during hook creation"
 
msgstr "Памылка пры стварэнні хука"
 

	
 
#: kallithea/controllers/admin/settings.py:404
 
#: kallithea/controllers/admin/settings.py:407
 
msgid "Whoosh reindex task scheduled"
 
msgstr "Запланаванае пераіндэксаванне базы Whoosh"
 

	
 
#: kallithea/controllers/admin/user_groups.py:143
 
#, python-format
 
msgid "Created user group %s"
 
msgstr "Створана група карыстальнікаў %s"
 

	
 
#: kallithea/controllers/admin/user_groups.py:156
 
#, python-format
 
msgid "Error occurred during creation of user group %s"
 
msgstr "Памылка пры стварэнні групы карыстальнікаў %s"
 

	
 
#: kallithea/controllers/admin/user_groups.py:184
 
#, python-format
 
msgid "Updated user group %s"
 
msgstr "Група карыстальнікаў %s абноўленая"
 

	
 
#: kallithea/controllers/admin/user_groups.py:206
 
#, python-format
 
msgid "Error occurred during update of user group %s"
 
msgstr "Памылка пры абнаўленні групы карыстальнікаў %s"
 

	
 
#: kallithea/controllers/admin/user_groups.py:217
 
msgid "Successfully deleted user group"
 
msgstr "Група карыстальнікаў паспяхова выдаленая"
 

	
 
#: kallithea/controllers/admin/user_groups.py:222
 
msgid "An error occurred during deletion of user group"
 
msgstr "Памылка пры выдаленні групы карыстальнікаў"
 

	
 
#: kallithea/controllers/admin/user_groups.py:278
 
msgid "Target group cannot be the same"
 
msgstr "Мэтавая група не можа быць той жа самай"
 

	
 
#: kallithea/controllers/admin/user_groups.py:284
 
msgid "User group permissions updated"
 
msgstr "Прывілеі групы карыстальнікаў абноўленыя"
 

	
 
#: kallithea/controllers/admin/user_groups.py:395
 
#: kallithea/controllers/admin/users.py:340
 
msgid "Updated permissions"
 
msgstr "Абноўленыя прывілеі"
 

	
 
#: kallithea/controllers/admin/user_groups.py:399
 
#: kallithea/controllers/admin/users.py:344
 
msgid "An error occurred during permissions saving"
 
msgstr "Памылка пры захаванні прывілеяў"
 

	
 
#: kallithea/controllers/admin/users.py:123
 
#, python-format
 
msgid "Created user %s"
 
msgstr "Карыстальнік %s створаны"
 

	
 
#: kallithea/controllers/admin/users.py:138
 
#, python-format
 
msgid "Error occurred during creation of user %s"
 
msgstr "Памылка пры стварэнні карыстальніка %s"
 

	
 
#: kallithea/controllers/admin/users.py:162
 
msgid "User updated successfully"
 
msgstr "Карыстальнік паспяхова абноўлены"
 

	
 
#: kallithea/controllers/admin/users.py:190
 
msgid "Successfully deleted user"
 
msgstr "Карыстальнік паспяхова выдалены"
 

	
 
#: kallithea/controllers/admin/users.py:195
 
msgid "An error occurred during deletion of user"
 
msgstr "Памылка пры выдаленні карыстальніка"
 

	
 
#: kallithea/controllers/admin/users.py:203
 
msgid "The default user cannot be edited"
 
msgstr ""
 

	
 
#: kallithea/controllers/admin/users.py:412
 
#, python-format
 
msgid "Added IP address %s to user whitelist"
 
msgstr "Дададзены IP %s у белы спіс карыстальніка"
 

	
 
#: kallithea/controllers/admin/users.py:418
 
msgid "An error occurred while adding IP address"
 
msgstr "Адбылася памылка пры захаванні IP"
 

	
 
#: kallithea/controllers/admin/users.py:430
 
msgid "Removed IP address from user whitelist"
 
msgstr "Выдалены IP %s з белага спісу карыстальніка"
 

	
 
#: kallithea/lib/auth.py:824
 
msgid "You need to be a registered user to perform this action"
 
msgstr ""
 
"Вы павінны быць зарэгістраваным карыстальнікам, каб выканаць гэта дзеянне"
 

	
 
#: kallithea/lib/auth.py:852
 
msgid "You need to be signed in to view this page"
 
msgstr "Старонка даступная толькі аўтарызаваным карыстальнікам"
 

	
 
#: kallithea/lib/base.py:444
 
msgid "Invalid API key"
 
msgstr "Няслушны API-ключ"
 

	
 
#: kallithea/lib/base.py:495
 
msgid ""
 
"CSRF token leak has been detected - all form tokens have been expired"
 
msgstr ""
 

	
 
#: kallithea/lib/base.py:583
 
msgid "Repository not found in the filesystem"
 
msgstr "Рэпазітар не знойдзены на файлавай сістэме"
 

	
 
#: kallithea/lib/base.py:608
 
#, python-format
 
msgid "Changeset for %s %s not found in %s"
 
msgstr "Набор змен для %s %s не знойдзены ў %s"
 

	
 
#: kallithea/lib/diffs.py:193
 
msgid "Binary file"
 
msgstr "Двайковы файл"
 

	
 
#: kallithea/lib/diffs.py:213
 
msgid ""
 
"Changeset was too big and was cut off, use diff menu to display this diff"
 
msgstr ""
 
"Набор змены апынуўся занадта вялікімі і быў падрэзаны, выкарыстоўвайце "
 
"меню параўнання для паказу выніку параўнання"
 

	
 
#: kallithea/lib/diffs.py:223
 
msgid "No changes detected"
 
msgstr "Змен не выяўлена"
 

	
 
#: kallithea/lib/helpers.py:612
 
#, python-format
 
msgid "Deleted branch: %s"
 
msgstr "Выдаленая галіна: %s"
 

	
 
#: kallithea/lib/helpers.py:614
 
#, python-format
 
msgid "Created tag: %s"
 
msgstr "Створаны тэг: %s"
 

	
 
#: kallithea/lib/helpers.py:625
 
#, python-format
 
msgid "Changeset %s not found"
 
msgstr "Набор змен %s не знойдзены"
 

	
 
#: kallithea/lib/helpers.py:674
 
#, python-format
 
msgid "Show all combined changesets %s->%s"
 
msgstr "Паказаць адрозненні разам %s->%s"
 

	
 
#: kallithea/lib/helpers.py:680
 
msgid "Compare view"
 
msgstr "Параўнанне"
 

	
 
#: kallithea/lib/helpers.py:699
 
msgid "and"
 
msgstr "і"
 

	
 
#: kallithea/lib/helpers.py:700
 
#, python-format
 
msgid "%s more"
 
msgstr "на %s больш"
 

	
 
#: kallithea/lib/helpers.py:701
 
#: kallithea/templates/changelog/changelog.html:43
 
msgid "revisions"
 
msgstr "версіі"
 

	
 
#: kallithea/lib/helpers.py:725
 
#, python-format
 
msgid "Fork name %s"
 
msgstr "Імя форка %s"
 

	
 
#: kallithea/lib/helpers.py:746
 
#, python-format
 
msgid "Pull request %s"
 
msgstr "Pull-запыт %s"
 

	
 
#: kallithea/lib/helpers.py:756
 
msgid "[deleted] repository"
 
msgstr "[выдалены] рэпазітар"
 

	
 
#: kallithea/lib/helpers.py:758 kallithea/lib/helpers.py:770
 
msgid "[created] repository"
 
msgstr "[створаны] рэпазітар"
 

	
 
#: kallithea/lib/helpers.py:760
 
msgid "[created] repository as fork"
 
msgstr "[створаны] рэпазітар як форк"
 

	
 
#: kallithea/lib/helpers.py:762 kallithea/lib/helpers.py:772
 
msgid "[forked] repository"
 
@@ -2064,770 +2065,774 @@ msgstr "Імя"
 
#: kallithea/templates/admin/users/user_add.html:55
 
#: kallithea/templates/admin/users/user_edit_profile.html:67
 
#: kallithea/templates/admin/users/users.html:39
 
#: kallithea/templates/register.html:59
 
msgid "Last Name"
 
msgstr "Прозвішча"
 

	
 
#: kallithea/templates/admin/my_account/my_account_profile.html:39
 
#: kallithea/templates/admin/settings/settings.html:31
 
#: kallithea/templates/admin/users/user_add.html:62
 
#: kallithea/templates/admin/users/user_edit_profile.html:25
 
#: kallithea/templates/email_templates/registration.html:33
 
#: kallithea/templates/register.html:66
 
msgid "Email"
 
msgstr "E-mail"
 

	
 
#: kallithea/templates/register.html:85
 
msgid "Registered accounts are ready to use and need no further action."
 
msgstr ""
 

	
 
#: kallithea/templates/register.html:87
 
msgid "Please wait for an administrator to activate your account."
 
msgstr ""
 
"Калі ласка, пачакайце, пакуль адміністратар пацвердзіць Вашу рэгістрацыю."
 

	
 
#: kallithea/templates/admin/admin.html:5
 
#: kallithea/templates/admin/admin.html:13
 
#: kallithea/templates/base/base.html:55
 
msgid "Admin Journal"
 
msgstr "Журнал адміністратара"
 

	
 
#: kallithea/templates/admin/admin.html:10
 
#: kallithea/templates/journal/journal.html:10
 
msgid "journal filter..."
 
msgstr "Фільтр журнала..."
 

	
 
#: kallithea/templates/admin/admin.html:12
 
#: kallithea/templates/journal/journal.html:12
 
msgid "Filter"
 
msgstr "Адфільтраваць"
 

	
 
#: kallithea/templates/admin/admin.html:13
 
#: kallithea/templates/journal/journal.html:13
 
#, python-format
 
msgid "%s Entry"
 
msgid_plural "%s Entries"
 
msgstr[0] "%s запіс"
 
msgstr[1] "%s запісаў"
 
msgstr[2] "%s запісы"
 

	
 
#: kallithea/templates/admin/admin_log.html:6
 
#: kallithea/templates/admin/my_account/my_account_repos.html:16
 
#: kallithea/templates/admin/repo_groups/repo_groups.html:43
 
#: kallithea/templates/admin/repos/repo_edit_fields.html:9
 
#: kallithea/templates/admin/repos/repos.html:44
 
#: kallithea/templates/admin/user_groups/user_groups.html:43
 
#: kallithea/templates/admin/users/users.html:45
 
msgid "Action"
 
msgstr "Дзеянне"
 

	
 
#: kallithea/templates/admin/admin_log.html:8
 
msgid "Date"
 
msgstr "Дата"
 

	
 
#: kallithea/templates/admin/admin_log.html:9
 
msgid "From IP"
 
msgstr "З IP"
 

	
 
#: kallithea/templates/admin/admin_log.html:61
 
msgid "No actions yet"
 
msgstr "Няма інфармацыі"
 

	
 
#: kallithea/templates/admin/auth/auth_settings.html:5
 
msgid "Authentication Settings"
 
msgstr "Налады аўтэнтыфікацыі"
 

	
 
#: kallithea/templates/admin/auth/auth_settings.html:11
 
#: kallithea/templates/base/base.html:61
 
msgid "Authentication"
 
msgstr "Аўтэнтыфікацыя"
 

	
 
#: kallithea/templates/admin/auth/auth_settings.html:27
 
msgid "Authentication Plugins"
 
msgstr "Плагіны аўтэнтыфікацыі"
 

	
 
#: kallithea/templates/admin/auth/auth_settings.html:29
 
msgid "Enabled Plugins"
 
msgstr "Уключаныя плагіны"
 

	
 
#: kallithea/templates/admin/auth/auth_settings.html:32
 
msgid ""
 
"Comma-separated list of plugins; Kallithea will try user authentication "
 
"in plugin order"
 
msgstr ""
 
"Спіс плагінаў, падзеленых коскамі. Kallithea будзе спрабаваць "
 
"аўтэнтыфікаваць карыстальніка ў парадку ўказання плагінаў"
 

	
 
#: kallithea/templates/admin/auth/auth_settings.html:36
 
msgid "Available built-in plugins"
 
msgstr "Даступныя ўбудаваныя плагіны"
 

	
 
#: kallithea/templates/admin/auth/auth_settings.html:53
 
msgid "Plugin"
 
msgstr "Плагін"
 

	
 
#: kallithea/templates/admin/auth/auth_settings.html:101
 
#: kallithea/templates/admin/defaults/defaults.html:67
 
#: kallithea/templates/admin/my_account/my_account_password.html:30
 
#: kallithea/templates/admin/my_account/my_account_profile.html:47
 
#: kallithea/templates/admin/permissions/permissions_globals.html:95
 
#: kallithea/templates/admin/repo_groups/repo_group_add.html:58
 
#: kallithea/templates/admin/repo_groups/repo_group_edit_perms.html:98
 
#: kallithea/templates/admin/repo_groups/repo_group_edit_settings.html:35
 
#: kallithea/templates/admin/repos/repo_edit_permissions.html:84
 
#: kallithea/templates/admin/repos/repo_edit_settings.html:101
 
#: kallithea/templates/admin/settings/settings_hooks.html:46
 
#: kallithea/templates/admin/user_groups/user_group_add.html:48
 
#: kallithea/templates/admin/user_groups/user_group_edit_perms.html:88
 
#: kallithea/templates/admin/user_groups/user_group_edit_settings.html:46
 
#: kallithea/templates/admin/users/user_add.html:80
 
#: kallithea/templates/admin/users/user_edit_profile.html:89
 
#: kallithea/templates/base/default_perms_box.html:56
 
msgid "Save"
 
msgstr "Захаваць"
 

	
 
#: kallithea/templates/admin/defaults/defaults.html:5
 
#: kallithea/templates/admin/defaults/defaults.html:11
 
#: kallithea/templates/base/base.html:62
 
msgid "Repository Defaults"
 
msgstr "Значэнні па змоўчанні"
 

	
 
#: kallithea/templates/admin/defaults/defaults.html:27
 
#: kallithea/templates/admin/repos/repo_add_base.html:42
 
#: kallithea/templates/admin/repos/repo_edit_fields.html:8
 
msgid "Type"
 
msgstr "Тып"
 

	
 
#: kallithea/templates/admin/defaults/defaults.html:34
 
#: kallithea/templates/admin/repos/repo_add_base.html:56
 
#: kallithea/templates/admin/repos/repo_edit_settings.html:57
 
#: kallithea/templates/data_table/_dt_elements.html:21
 
msgid "Private repository"
 
msgstr "Прыватны рэпазітар"
 

	
 
#: kallithea/templates/admin/defaults/defaults.html:37
 
#: kallithea/templates/admin/repos/repo_add_base.html:59
 
#: kallithea/templates/admin/repos/repo_edit_settings.html:60
 
#: kallithea/templates/forks/fork.html:61
 
msgid ""
 
"Private repositories are only visible to people explicitly added as "
 
"collaborators."
 
msgstr "Прыватныя рэпазітары бачныя толькі іх удзельнікам."
 

	
 
#: kallithea/templates/admin/defaults/defaults.html:42
 
#: kallithea/templates/admin/repos/repo_edit_settings.html:64
 
msgid "Enable statistics"
 
msgstr "Уключыць статыстыку"
 

	
 
#: kallithea/templates/admin/defaults/defaults.html:45
 
#: kallithea/templates/admin/repos/repo_edit_settings.html:67
 
msgid "Enable statistics window on summary page."
 
msgstr "Уключыць акно статыстыкі на старонцы «Агульныя звесткі»."
 

	
 
#: kallithea/templates/admin/defaults/defaults.html:50
 
#: kallithea/templates/admin/repos/repo_edit_settings.html:71
 
msgid "Enable downloads"
 
msgstr "Уключыць спампоўку"
 

	
 
#: kallithea/templates/admin/defaults/defaults.html:53
 
#: kallithea/templates/admin/repos/repo_edit_settings.html:74
 
msgid "Enable download menu on summary page."
 
msgstr "Уключыць меню спампоўкі на старонцы «Агульныя звесткі»."
 

	
 
#: kallithea/templates/admin/defaults/defaults.html:58
 
#: kallithea/templates/admin/repo_groups/repo_group_edit_settings.html:26
 
#: kallithea/templates/admin/repos/repo_edit_settings.html:78
 
msgid "Enable locking"
 
msgstr "Уключыць блакаванне"
 

	
 
#: kallithea/templates/admin/defaults/defaults.html:61
 
#: kallithea/templates/admin/repos/repo_edit_settings.html:81
 
msgid "Enable lock-by-pulling on repository."
 
msgstr "Уключыць аўтаблакаванне для рэпазітара."
 

	
 
#: kallithea/templates/admin/gists/edit.html:5
 
#: kallithea/templates/admin/gists/edit.html:18
 
msgid "Edit Gist"
 
msgstr "Правіць gist-запіс"
 

	
 
#: kallithea/templates/admin/gists/edit.html:35
 
#, python-format
 
msgid ""
 
"Gist was update since you started editing. Copy your changes and click "
 
"Gist was updated since you started editing. Copy your changes and click "
 
"%(here)s to reload new version."
 
msgstr ""
 

	
 
#: kallithea/templates/admin/gists/edit.html:36
 
msgid "here"
 
msgstr ""
 

	
 
#: kallithea/templates/admin/gists/edit.html:51
 
#: kallithea/templates/admin/gists/new.html:35
 
msgid "Gist description ..."
 
msgstr "Апісанне..."
 

	
 
#: kallithea/templates/admin/gists/edit.html:54
 
#: kallithea/templates/admin/gists/new.html:38
 
msgid "Gist lifetime"
 
msgstr ""
 

	
 
#: kallithea/templates/admin/gists/edit.html:59
 
#: kallithea/templates/admin/gists/edit.html:61
 
#: kallithea/templates/admin/gists/index.html:54
 
#: kallithea/templates/admin/gists/index.html:56
 
#: kallithea/templates/admin/gists/show.html:45
 
#: kallithea/templates/admin/gists/show.html:47
 
#: kallithea/templates/admin/my_account/my_account_api_keys.html:7
 
#: kallithea/templates/admin/my_account/my_account_api_keys.html:26
 
#: kallithea/templates/admin/my_account/my_account_api_keys.html:31
 
#: kallithea/templates/admin/users/user_edit_api_keys.html:7
 
#: kallithea/templates/admin/users/user_edit_api_keys.html:26
 
#: kallithea/templates/admin/users/user_edit_api_keys.html:31
 
msgid "Expires"
 
msgstr "Мінае"
 

	
 
#: kallithea/templates/admin/gists/edit.html:59
 
#: kallithea/templates/admin/gists/index.html:54
 
#: kallithea/templates/admin/gists/show.html:45
 
#: kallithea/templates/admin/my_account/my_account_api_keys.html:7
 
#: kallithea/templates/admin/my_account/my_account_api_keys.html:26
 
#: kallithea/templates/admin/users/user_edit_api_keys.html:7
 
#: kallithea/templates/admin/users/user_edit_api_keys.html:26
 
msgid "Never"
 
msgstr "Ніколі"
 

	
 
#: kallithea/templates/admin/gists/edit.html:145
 
msgid "Update Gist"
 
msgstr "Абнавіць"
 

	
 
#: kallithea/templates/admin/gists/edit.html:146
 
#: kallithea/templates/base/root.html:27
 
#: kallithea/templates/changeset/changeset_file_comment.html:130
 
msgid "Cancel"
 
msgstr "Адмена"
 

	
 
#: kallithea/templates/admin/gists/index.html:6
 
#: kallithea/templates/admin/gists/index.html:16
 
#, python-format
 
msgid "Private Gists for User %s"
 
msgstr "Прыватны gist-запіс для карыстальніка %s"
 

	
 
#: kallithea/templates/admin/gists/index.html:8
 
#: kallithea/templates/admin/gists/index.html:18
 
#, python-format
 
msgid "Public Gists for User %s"
 
msgstr "Публічны gist-запіс для карыстальніка %s"
 

	
 
#: kallithea/templates/admin/gists/index.html:10
 
#: kallithea/templates/admin/gists/index.html:20
 
msgid "Public Gists"
 
msgstr "Публічныя gist-запісы"
 

	
 
#: kallithea/templates/admin/gists/index.html:37
 
#: kallithea/templates/admin/gists/show.html:25
 
#: kallithea/templates/base/base.html:312
 
msgid "Create New Gist"
 
msgstr "Стварыць новы gist-запіс"
 

	
 
#: kallithea/templates/admin/gists/index.html:51
 
#: kallithea/templates/data_table/_dt_elements.html:78
 
msgid "Created"
 
msgstr "Створаны"
 

	
 
#: kallithea/templates/admin/gists/index.html:66
 
msgid "There are no gists yet"
 
msgstr "Gist-запісы адсутнічаюць"
 

	
 
#: kallithea/templates/admin/gists/new.html:5
 
#: kallithea/templates/admin/gists/new.html:18
 
msgid "New Gist"
 
msgstr "Новы gist-запіс"
 

	
 
#: kallithea/templates/admin/gists/new.html:45
 
msgid "Name this gist ..."
 
msgstr ""
 

	
 
#: kallithea/templates/admin/gists/new.html:53
 
msgid "Create Private Gist"
 
msgstr ""
 

	
 
#: kallithea/templates/admin/gists/new.html:54
 
msgid "Create Public Gist"
 
msgstr ""
 

	
 
#: kallithea/templates/admin/gists/new.html:55
 
#: kallithea/templates/admin/my_account/my_account_api_keys.html:14
 
#: kallithea/templates/admin/my_account/my_account_api_keys.html:73
 
#: kallithea/templates/admin/my_account/my_account_emails.html:47
 
#: kallithea/templates/admin/my_account/my_account_password.html:31
 
#: kallithea/templates/admin/my_account/my_account_profile.html:48
 
#: kallithea/templates/admin/permissions/permissions_globals.html:96
 
#: kallithea/templates/admin/permissions/permissions_ips.html:34
 
#: kallithea/templates/admin/repo_groups/repo_group_edit_perms.html:99
 
#: kallithea/templates/admin/repo_groups/repo_group_edit_settings.html:36
 
#: kallithea/templates/admin/repos/repo_edit_fields.html:54
 
#: kallithea/templates/admin/repos/repo_edit_permissions.html:85
 
#: kallithea/templates/admin/repos/repo_edit_settings.html:102
 
#: kallithea/templates/admin/settings/settings_global.html:50
 
#: kallithea/templates/admin/settings/settings_vcs.html:78
 
#: kallithea/templates/admin/settings/settings_visual.html:116
 
#: kallithea/templates/admin/user_groups/user_group_edit_perms.html:89
 
#: kallithea/templates/admin/users/user_edit_api_keys.html:14
 
#: kallithea/templates/admin/users/user_edit_api_keys.html:73
 
#: kallithea/templates/admin/users/user_edit_emails.html:47
 
#: kallithea/templates/admin/users/user_edit_ips.html:45
 
#: kallithea/templates/admin/users/user_edit_profile.html:90
 
#: kallithea/templates/base/default_perms_box.html:57
 
#: kallithea/templates/files/files_add.html:69
 
#: kallithea/templates/files/files_delete.html:41
 
#: kallithea/templates/files/files_edit.html:72
 
#: kallithea/templates/pullrequests/pullrequest.html:78
 
msgid "Reset"
 
msgstr "Скінуць"
 

	
 
#: kallithea/templates/admin/gists/show.html:5
 
#: kallithea/templates/admin/gists/show.html:9
 
msgid "Gist"
 
msgstr ""
 

	
 
#: kallithea/templates/admin/gists/show.html:10
 
msgid "URL"
 
msgstr "URL"
 

	
 
#: kallithea/templates/admin/gists/show.html:35
 
msgid "Public Gist"
 
msgstr ""
 

	
 
#: kallithea/templates/admin/gists/show.html:37
 
msgid "Private Gist"
 
msgstr ""
 

	
 
#: kallithea/templates/admin/gists/show.html:54
 
#: kallithea/templates/admin/my_account/my_account_emails.html:23
 
#: kallithea/templates/admin/permissions/permissions_ips.html:11
 
#: kallithea/templates/admin/repos/repo_edit_advanced.html:68
 
#: kallithea/templates/admin/repos/repo_edit_fields.html:19
 
#: kallithea/templates/admin/settings/settings_hooks.html:30
 
#: kallithea/templates/admin/users/user_edit_emails.html:23
 
#: kallithea/templates/admin/users/user_edit_ips.html:21
 
#: kallithea/templates/changeset/changeset_file_comment.html:30
 
#: kallithea/templates/changeset/changeset_file_comment.html:121
 
#: kallithea/templates/data_table/_dt_elements.html:69
 
#: kallithea/templates/data_table/_dt_elements.html:89
 
#: kallithea/templates/data_table/_dt_elements.html:91
 
#: kallithea/templates/data_table/_dt_elements.html:101
 
#: kallithea/templates/data_table/_dt_elements.html:103
 
#: kallithea/templates/data_table/_dt_elements.html:120
 
#: kallithea/templates/data_table/_dt_elements.html:122
 
#: kallithea/templates/files/files_source.html:35
 
#: kallithea/templates/files/files_source.html:38
 
#: kallithea/templates/files/files_source.html:41
 
#: kallithea/templates/pullrequests/pullrequest_data.html:20
 
msgid "Delete"
 
msgstr "Выдаліць"
 

	
 
#: kallithea/templates/admin/gists/show.html:54
 
msgid "Confirm to delete this Gist"
 
msgstr "Пацвердзіце выдаленне гэтага gist-запісу"
 

	
 
#: kallithea/templates/admin/gists/show.html:61
 
#: kallithea/templates/base/perms_summary.html:44
 
#: kallithea/templates/base/perms_summary.html:81
 
#: kallithea/templates/base/perms_summary.html:83
 
#: kallithea/templates/data_table/_dt_elements.html:63
 
#: kallithea/templates/data_table/_dt_elements.html:64
 
#: kallithea/templates/data_table/_dt_elements.html:85
 
#: kallithea/templates/data_table/_dt_elements.html:86
 
#: kallithea/templates/data_table/_dt_elements.html:97
 
#: kallithea/templates/data_table/_dt_elements.html:98
 
#: kallithea/templates/data_table/_dt_elements.html:116
 
#: kallithea/templates/data_table/_dt_elements.html:117
 
#: kallithea/templates/files/diff_2way.html:56
 
#: kallithea/templates/files/files_source.html:37
 
#: kallithea/templates/files/files_source.html:40
 
#: kallithea/templates/pullrequests/pullrequest_show.html:41
 
msgid "Edit"
 
msgstr "Рэдагаваць"
 

	
 
#: kallithea/templates/admin/gists/show.html:63
 
#: kallithea/templates/files/files_edit.html:52
 
#: kallithea/templates/files/files_source.html:30
 
msgid "Show as Raw"
 
msgstr "Паказаць толькі тэкст"
 

	
 
#: kallithea/templates/admin/gists/show.html:69
 
msgid "created"
 
msgstr "створана"
 

	
 
#: kallithea/templates/admin/gists/show.html:82
 
msgid "Show as raw"
 
msgstr "Паказаць толькі тэкст"
 

	
 
#: kallithea/templates/admin/my_account/my_account.html:5
 
#: kallithea/templates/admin/my_account/my_account.html:9
 
#: kallithea/templates/base/base.html:397
 
msgid "My Account"
 
msgstr "Мой Акаўнт"
 

	
 
#: kallithea/templates/admin/my_account/my_account.html:25
 
#: kallithea/templates/admin/users/user_edit.html:29
 
msgid "Profile"
 
msgstr "Профіль"
 

	
 
#: kallithea/templates/admin/my_account/my_account.html:26
 
msgid "Email Addresses"
 
msgstr "E-mail адрэсы"
 

	
 
#: kallithea/templates/admin/my_account/my_account.html:28
 
#: kallithea/templates/admin/users/user_edit.html:31
 
msgid "API Keys"
 
msgstr "API-ключы"
 

	
 
#: kallithea/templates/admin/my_account/my_account.html:29
 
msgid "Owned Repositories"
 
msgstr "Мае рэпазітары"
 

	
 
#: kallithea/templates/admin/my_account/my_account.html:30
 
#: kallithea/templates/journal/journal.html:33
 
#, fuzzy
 
msgid "Watched Repositories"
 
msgstr "Стварыць рэпазітары"
 

	
 
#: kallithea/templates/admin/my_account/my_account.html:31
 
#: kallithea/templates/admin/permissions/permissions.html:30
 
#: kallithea/templates/admin/user_groups/user_group_edit.html:32
 
#: kallithea/templates/admin/users/user_edit.html:34
 
msgid "Show Permissions"
 
msgstr "Паказаць прывілеі"
 

	
 
#: kallithea/templates/admin/my_account/my_account_api_keys.html:5
 
#: kallithea/templates/admin/users/user_edit_api_keys.html:5
 
msgid "Built-in"
 
msgstr "Убудаваны"
 

	
 
#: kallithea/templates/admin/my_account/my_account_api_keys.html:13
 
#: kallithea/templates/admin/users/user_edit_api_keys.html:13
 
#, python-format
 
msgid "Confirm to reset this API key: %s"
 
msgstr "Пацвердзіць скіданне гэтага API-ключа: %s"
 

	
 
#: kallithea/templates/admin/my_account/my_account_api_keys.html:29
 
#: kallithea/templates/admin/users/user_edit_api_keys.html:29
 
msgid "Expired"
 
msgstr "Ануляваны"
 

	
 
#: kallithea/templates/admin/my_account/my_account_api_keys.html:39
 
#: kallithea/templates/admin/users/user_edit_api_keys.html:39
 
#, python-format
 
msgid "Confirm to remove this API key: %s"
 
msgstr "Пацвердзіце выдаленне гэтага API-ключа: %s"
 

	
 
#: kallithea/templates/admin/my_account/my_account_api_keys.html:41
 
#: kallithea/templates/admin/users/user_edit_api_keys.html:41
 
msgid "Remove"
 
msgstr "Выдаліць"
 

	
 
#: kallithea/templates/admin/my_account/my_account_api_keys.html:48
 
#: kallithea/templates/admin/users/user_edit_api_keys.html:48
 
msgid "No additional API keys specified"
 
msgstr "Дадатковыя API-ключы не пазначаныя"
 

	
 
#: kallithea/templates/admin/my_account/my_account_api_keys.html:56
 
#: kallithea/templates/admin/users/user_edit_api_keys.html:56
 
msgid "New API key"
 
msgstr "Новы API-ключ"
 

	
 
#: kallithea/templates/admin/my_account/my_account_api_keys.html:72
 
#: kallithea/templates/admin/my_account/my_account_emails.html:46
 
#: kallithea/templates/admin/permissions/permissions_ips.html:33
 
#: kallithea/templates/admin/repos/repo_add_base.html:64
 
#: kallithea/templates/admin/repos/repo_edit_fields.html:53
 
#: kallithea/templates/admin/users/user_edit_api_keys.html:72
 
#: kallithea/templates/admin/users/user_edit_emails.html:46
 
#: kallithea/templates/admin/users/user_edit_ips.html:44
 
msgid "Add"
 
msgstr "Дадаць"
 

	
 
#: kallithea/templates/admin/my_account/my_account_api_keys.html:81
 
#, python-format
 
msgid ""
 
"\n"
 
"API keys are used to let scripts or services access %s using your\n"
 
"account, as if you had provided the script or service with your actual\n"
 
"password.\n"
 
msgstr ""
 

	
 
#: kallithea/templates/admin/my_account/my_account_api_keys.html:86
 
msgid ""
 
"\n"
 
"Like passwords, API keys should therefore never be shared with others,\n"
 
"nor passed to untrusted scripts or services. If such sharing should\n"
 
"happen anyway, reset the API key on this page to prevent further use.\n"
 
msgstr ""
 

	
 
#: kallithea/templates/admin/my_account/my_account_emails.html:9
 
#: kallithea/templates/admin/users/user_edit_emails.html:9
 
msgid "Primary"
 
msgstr "Асноўны"
 

	
 
#: kallithea/templates/admin/my_account/my_account_emails.html:24
 
#: kallithea/templates/admin/users/user_edit_emails.html:24
 
#, python-format
 
msgid "Confirm to delete this email: %s"
 
msgstr "Пацвердзіце выдаленне e-mail: %s"
 

	
 
#: kallithea/templates/admin/my_account/my_account_emails.html:30
 
#: kallithea/templates/admin/users/user_edit_emails.html:30
 
msgid "No additional emails specified."
 
msgstr "Дадатковыя адрасы e-mail не пазначаны."
 

	
 
#: kallithea/templates/admin/my_account/my_account_emails.html:39
 
#: kallithea/templates/admin/users/user_edit_emails.html:39
 
msgid "New email address"
 
msgstr "Новы e-mail"
 

	
 
#: kallithea/templates/admin/my_account/my_account_password.html:1
 
msgid "Change Your Account Password"
 
msgstr "Змена пароля"
 

	
 
#: kallithea/templates/admin/my_account/my_account_password.html:8
 
msgid "Current password"
 
msgstr "Цяперашні пароль"
 

	
 
#: kallithea/templates/admin/my_account/my_account_password.html:15
 
#: kallithea/templates/admin/users/user_edit_profile.html:46
 
msgid "New password"
 
msgstr "Новы пароль"
 

	
 
#: kallithea/templates/admin/my_account/my_account_password.html:22
 
msgid "Confirm new password"
 
msgstr "Пацвердзіце новы пароль"
 

	
 
#: kallithea/templates/admin/my_account/my_account_password.html:39
 
#, python-format
 
msgid ""
 
"This account is managed with %s and the password cannot be changed here"
 
msgstr ""
 

	
 
#: kallithea/templates/admin/my_account/my_account_perms.html:3
 
msgid "Current IP"
 
msgstr "Цяперашні IP-адрас"
 

	
 
#: kallithea/templates/admin/my_account/my_account_profile.html:4
 
#: kallithea/templates/admin/users/user_edit_profile.html:4
 
msgid "Gravatar"
 
msgstr ""
 

	
 
#: kallithea/templates/admin/my_account/my_account_profile.html:10
 
#: kallithea/templates/admin/users/user_edit_profile.html:10
 
#, fuzzy, python-format
 
#| msgid "Change your avatar at"
 
msgid "Change %s avatar at"
 
msgstr "Змяніць аватар можна праз"
 

	
 
#: kallithea/templates/admin/my_account/my_account_profile.html:12
 
#: kallithea/templates/admin/users/user_edit_profile.html:12
 
msgid "Avatars are disabled"
 
msgstr "Аватары адключаныя"
 

	
 
#: kallithea/templates/admin/my_account/my_account_repos.html:1
 
msgid "Repositories You Own"
 
msgstr "Рэпазітары, дзе Вы — уладальнік"
 

	
 
#: kallithea/templates/admin/my_account/my_account_repos.html:13
 
#: kallithea/templates/admin/my_account/my_account_watched.html:13
 
#: kallithea/templates/admin/repo_groups/repo_groups.html:39
 
#: kallithea/templates/admin/repos/repo_add_base.html:6
 
#: kallithea/templates/admin/repos/repo_edit_settings.html:4
 
#: kallithea/templates/admin/repos/repos.html:38
 
#: kallithea/templates/admin/user_groups/user_groups.html:38
 
#: kallithea/templates/base/perms_summary.html:54
 
#: kallithea/templates/files/files_browser.html:51
 
#: kallithea/templates/files/files_browser.html:54
 
msgid "Name"
 
msgstr "Імя"
 

	
 
#: kallithea/templates/admin/my_account/my_account_watched.html:1
 
msgid "Repositories You are Watching"
 
msgstr "Рэпазітары, за якімі Вы назіраеце"
 

	
 
#: kallithea/templates/admin/permissions/permissions.html:5
 
#: kallithea/templates/admin/permissions/permissions.html:11
 
#: kallithea/templates/base/base.html:60
 
msgid "Default Permissions"
 
msgstr "Стандартныя прывілеі"
 

	
 
#: kallithea/templates/admin/permissions/permissions.html:28
 
#: kallithea/templates/admin/settings/settings.html:29
 
msgid "Global"
 
msgstr "Глабальныя"
 

	
 
#: kallithea/templates/admin/permissions/permissions.html:29
 
#: kallithea/templates/admin/users/user_edit.html:32
 
msgid "IP Whitelist"
 
msgstr "Белы спіс IP"
 

	
 
#: kallithea/templates/admin/permissions/permissions_globals.html:4
 
msgid "Anonymous access"
 
msgstr "Ананімны доступ"
 

	
 
#: kallithea/templates/admin/permissions/permissions_globals.html:8
 
#, fuzzy
 
#| msgid "Anonymous access"
 
msgid "Allow anonymous access"
 
msgstr "Ананімны доступ"
 

	
 
#: kallithea/templates/admin/permissions/permissions_globals.html:10
 
#, python-format
 
msgid ""
 
"Allow access to Kallithea without needing to log in. Anonymous users use "
 
"%s user permissions."
 
msgstr ""
 

	
 
#: kallithea/templates/admin/permissions/permissions_globals.html:19
 
msgid ""
 
"All default permissions on each repository will be reset to chosen "
 
"permission, note that all custom default permission on repositories will "
 
"be lost"
 
msgstr ""
 
"Выбраныя прывілеі будуць усталяваныя па змоўчанні для кожнага рэпазітара. "
 
"Улічыце, што раней усталяваныя прывілеі па змоўчанні будуць скінутыя"
 

	
 
#: kallithea/templates/admin/permissions/permissions_globals.html:20
 
#, fuzzy
 
msgid "Apply to all existing repositories"
 
msgstr "Імпартаваць існы рэпазітар?"
 

	
 
#: kallithea/templates/admin/permissions/permissions_globals.html:23
 
msgid "Permissions for the Default user on new repositories."
 
msgstr ""
 

	
 
#: kallithea/templates/admin/permissions/permissions_globals.html:27
 
#: kallithea/templates/admin/repos/repo_add_base.html:28
 
#: kallithea/templates/admin/repos/repo_edit_settings.html:28
 
#: kallithea/templates/data_table/_dt_elements.html:134
 
#: kallithea/templates/forks/fork.html:42
 
msgid "Repository group"
 
msgstr "Група рэпазітароў"
 

	
 
#: kallithea/templates/admin/permissions/permissions_globals.html:32
 
msgid ""
 
"All default permissions on each repository group will be reset to chosen "
 
"permission, note that all custom default permission on repository groups "
 
"will be lost"
 
msgstr ""
 
"Выбраныя прывілеі будуць усталяваныя па змоўчанні для кожнай групы "
 
"рэпазітароў. Улічыце, што раней усталяваныя прывілеі па змоўчанні для "
 
"груп рэпазітароў будуць скінутыя"
 

	
 
#: kallithea/templates/admin/permissions/permissions_globals.html:33
 
#, fuzzy
 
msgid "Apply to all existing repository groups"
 
msgstr "Імпартаваць існы рэпазітар?"
 

	
 
#: kallithea/templates/admin/permissions/permissions_globals.html:36
 
msgid "Permissions for the Default user on new repository groups."
 
msgstr ""
 

	
 
#: kallithea/templates/admin/permissions/permissions_globals.html:40
 
#: kallithea/templates/data_table/_dt_elements.html:141
 
msgid "User group"
 
msgstr "Група карыстальнікаў"
 

	
 
#: kallithea/templates/admin/permissions/permissions_globals.html:45
 
msgid ""
 
"All default permissions on each user group will be reset to chosen "
 
"permission, note that all custom default permission on user groups will "
 
"be lost"
 
msgstr ""
 
"Выбраныя прывілеі будуць усталяваныя па змоўчанні для кожнай групы "
 
"карыстальнікаў. Улічыце, што раней усталяваныя прывілеі па змоўчанні для "
 
"груп карыстальнікаў будуць скінутыя"
 

	
 
#: kallithea/templates/admin/permissions/permissions_globals.html:46
 
msgid "Apply to all existing user groups"
 
msgstr ""
 

	
 
#: kallithea/templates/admin/permissions/permissions_globals.html:49
 
msgid "Permissions for the Default user on new user groups."
 
msgstr ""
 

	
 
#: kallithea/templates/admin/permissions/permissions_globals.html:53
 
#, fuzzy
 
msgid "Top level repository creation"
 
msgstr "Стварэнне рэпазітара"
 

	
 
#: kallithea/templates/admin/permissions/permissions_globals.html:56
 
msgid ""
 
"Enable this to allow non-admins to create repositories at the top level."
 
msgstr ""
 

	
 
#: kallithea/templates/admin/permissions/permissions_globals.html:57
 
msgid ""
 
"Note: This will also give all users API access to create repositories "
 
"everywhere. That might change in future versions."
 
msgstr ""
 

	
 
#: kallithea/templates/admin/permissions/permissions_globals.html:61
 
msgid "Repository creation with group write access"
 
msgstr ""
 

	
 
#: kallithea/templates/admin/permissions/permissions_globals.html:64
 
msgid ""
 
"With this, write permission to a repository group allows creating "
 
"repositories inside that group. Without this, group write permissions "
 
"mean nothing."
 
msgstr ""
 

	
 
#: kallithea/templates/admin/permissions/permissions_globals.html:68
 
msgid "User group creation"
 
msgstr "Стварэнне груп карыстальнікаў"
 

	
 
#: kallithea/templates/admin/permissions/permissions_globals.html:71
 
msgid "Enable this to allow non-admins to create user groups."
 
msgstr ""
 

	
 
#: kallithea/templates/admin/permissions/permissions_globals.html:75
 
msgid "Repository forking"
 
msgstr "Стварэнне форка рэпазітара"
 

	
 
#: kallithea/templates/admin/permissions/permissions_globals.html:78
 
msgid "Enable this to allow non-admins to fork repositories."
 
msgstr ""
 

	
 
#: kallithea/templates/admin/permissions/permissions_globals.html:82
 
msgid "Registration"
 
msgstr "Рэгістрацыя"
 

	
 
#: kallithea/templates/admin/permissions/permissions_globals.html:88
 
msgid "External auth account activation"
 
msgstr "Актывацыя іншага ўліковага запісу"
 

	
 
#: kallithea/templates/admin/permissions/permissions_ips.html:12
 
#: kallithea/templates/admin/users/user_edit_ips.html:22
 
#, python-format
 
msgid "Confirm to delete this IP address: %s"
 
msgstr "Пацвердзіце выдаленне IP %s"
 

	
 
#: kallithea/templates/admin/permissions/permissions_ips.html:18
 
#: kallithea/templates/admin/users/user_edit_ips.html:29
 
msgid "All IP addresses are allowed."
 
msgstr "Дазволены любыя IP-адрасы."
 

	
 
#: kallithea/templates/admin/permissions/permissions_ips.html:25
 
#: kallithea/templates/admin/users/user_edit_ips.html:37
 
msgid "New IP address"
 
msgstr "Новы IP-адрас"
 

	
 
#: kallithea/templates/admin/repo_groups/repo_group_add.html:11
 
#: kallithea/templates/admin/repo_groups/repo_group_edit.html:11
 
#: kallithea/templates/admin/repo_groups/repo_group_edit_perms.html:89
 
#: kallithea/templates/admin/repo_groups/repo_groups.html:9
 
#: kallithea/templates/base/base.html:57
 
#: kallithea/templates/base/base.html:76
 
msgid "Repository Groups"
 
msgstr "Групы рэпазітароў"
 

	
 
#: kallithea/templates/admin/repo_groups/repo_group_add.html:28
 
#: kallithea/templates/admin/repo_groups/repo_group_edit_settings.html:5
 
#: kallithea/templates/admin/user_groups/user_group_add.html:27
 
#: kallithea/templates/admin/user_groups/user_group_edit_settings.html:4
 
msgid "Group name"
 
msgstr "Імя групы"
 

	
 
#: kallithea/templates/admin/repo_groups/repo_group_add.html:42
 
@@ -3899,384 +3904,390 @@ msgstr "Адміністраванне карыстальнікаў"
 

	
 
#: kallithea/templates/admin/users/users.html:44
 
msgid "Auth Type"
 
msgstr ""
 

	
 
#: kallithea/templates/base/base.html:16
 
#, python-format
 
msgid "Server instance: %s"
 
msgstr "Асобнік сервера: %s"
 

	
 
#: kallithea/templates/base/base.html:28
 
msgid "Support"
 
msgstr "Падтрымка"
 

	
 
#: kallithea/templates/base/base.html:86
 
#: kallithea/templates/base/base.html:424
 
msgid "Mercurial repository"
 
msgstr "Рэпазітар Mercurial"
 

	
 
#: kallithea/templates/base/base.html:89
 
#: kallithea/templates/base/base.html:427
 
msgid "Git repository"
 
msgstr "Git рэпазітар"
 

	
 
#: kallithea/templates/base/base.html:115
 
msgid "Create Fork"
 
msgstr "Стварыць форк"
 

	
 
#: kallithea/templates/base/base.html:127
 
#: kallithea/templates/summary/summary.html:9
 
msgid "Summary"
 
msgstr "Агульныя звесткі"
 

	
 
#: kallithea/templates/base/base.html:129
 
#: kallithea/templates/base/base.html:131
 
#: kallithea/templates/changelog/changelog.html:16
 
msgid "Changelog"
 
msgstr "Гісторыя змен"
 

	
 
#: kallithea/templates/base/base.html:133
 
#: kallithea/templates/files/files.html:11
 
msgid "Files"
 
msgstr "Файлы"
 

	
 
#: kallithea/templates/base/base.html:135
 
#, python-format
 
msgid "Show Pull Requests for %s"
 
msgstr "Паказаць pull-запыты для %s"
 

	
 
#: kallithea/templates/base/base.html:135
 
msgid "Pull Requests"
 
msgstr "Pull-запыты"
 

	
 
#: kallithea/templates/base/base.html:146
 
#: kallithea/templates/base/base.html:148
 
msgid "Options"
 
msgstr "Опцыі"
 

	
 
#: kallithea/templates/base/base.html:156
 
#: kallithea/templates/forks/forks_data.html:18
 
msgid "Compare Fork"
 
msgstr "Параўнаць форк"
 

	
 
#: kallithea/templates/base/base.html:158
 
msgid "Compare"
 
msgstr "Параўнаць"
 

	
 
#: kallithea/templates/base/base.html:160
 
#: kallithea/templates/base/base.html:322
 
#: kallithea/templates/search/search.html:14
 
#: kallithea/templates/search/search.html:67
 
msgid "Search"
 
msgstr "Пошук"
 

	
 
#: kallithea/templates/base/base.html:164
 
msgid "Unlock"
 
msgstr "Разблакаваць"
 

	
 
#: kallithea/templates/base/base.html:166
 
msgid "Lock"
 
msgstr "Заблакаваць"
 

	
 
#: kallithea/templates/base/base.html:174
 
msgid "Follow"
 
msgstr "Назіраць"
 

	
 
#: kallithea/templates/base/base.html:175
 
msgid "Unfollow"
 
msgstr "Не назіраць"
 

	
 
#: kallithea/templates/base/base.html:178
 
#: kallithea/templates/forks/fork.html:9
 
msgid "Fork"
 
msgstr "Форк"
 

	
 
#: kallithea/templates/base/base.html:179
 
#: kallithea/templates/pullrequests/pullrequest.html:77
 
msgid "Create Pull Request"
 
msgstr "Стварыць pull-запыт"
 

	
 
#: kallithea/templates/base/base.html:191
 
msgid "Switch To"
 
msgstr "Пераключыцца на"
 

	
 
#: kallithea/templates/base/base.html:203
 
#: kallithea/templates/base/base.html:452
 
msgid "No matches found"
 
msgstr "Супадзенняў не знойдзена"
 

	
 
#: kallithea/templates/base/base.html:296
 
msgid "Show recent activity"
 
msgstr "Паказаць апошнюю актыўнасць"
 

	
 
#: kallithea/templates/base/base.html:302
 
#: kallithea/templates/base/base.html:303
 
msgid "Public journal"
 
msgstr "Агульнадаступны журнал"
 

	
 
#: kallithea/templates/base/base.html:308
 
msgid "Show public gists"
 
msgstr "Паказаць публічныя запісы"
 

	
 
#: kallithea/templates/base/base.html:309
 
msgid "Gists"
 
msgstr "Gist"
 

	
 
#: kallithea/templates/base/base.html:313
 
msgid "All Public Gists"
 
msgstr "Усе публічныя Gist-запісы"
 

	
 
#: kallithea/templates/base/base.html:315
 
msgid "My Public Gists"
 
msgstr "Мае публічныя Gist-запісы"
 

	
 
#: kallithea/templates/base/base.html:316
 
msgid "My Private Gists"
 
msgstr "Мае прыватныя Gist-запісы"
 

	
 
#: kallithea/templates/base/base.html:321
 
msgid "Search in repositories"
 
msgstr "Пошук па рэпазітарах"
 

	
 
#: kallithea/templates/base/base.html:344
 
#: kallithea/templates/base/base.html:345
 
#: kallithea/templates/pullrequests/pullrequest_show_my.html:6
 
#: kallithea/templates/pullrequests/pullrequest_show_my.html:10
 
msgid "My Pull Requests"
 
msgstr "Мае pull-запыты"
 

	
 
#: kallithea/templates/base/base.html:360
 
msgid "Not Logged In"
 
msgstr "Не аўтарызаваны"
 

	
 
#: kallithea/templates/base/base.html:369
 
msgid "Login to Your Account"
 
msgstr "Аўтарызавацца"
 

	
 
#: kallithea/templates/base/base.html:379
 
#, fuzzy
 
#| msgid "Forgot password ?"
 
msgid "Forgot password?"
 
msgstr "Забыліся на пароль?"
 

	
 
#: kallithea/templates/base/base.html:383
 
#, fuzzy
 
#| msgid "Don't have an account ?"
 
msgid "Don't have an account?"
 
msgstr "Няма акаўнта?"
 

	
 
#: kallithea/templates/base/base.html:400
 
msgid "Log Out"
 
msgstr "Выйсці"
 

	
 
#: kallithea/templates/base/base.html:524
 
msgid "Parent rev."
 
msgstr ""
 

	
 
#: kallithea/templates/base/base.html:533
 
msgid "Child rev."
 
msgstr ""
 

	
 
#: kallithea/templates/base/default_perms_box.html:11
 
msgid "Inherit defaults"
 
msgstr "Ужываць значэнні па змоўчанні"
 

	
 
#: kallithea/templates/base/default_perms_box.html:15
 
#, python-format
 
msgid ""
 
"Select to inherit global settings, IP whitelist and permissions from the "
 
"%s."
 
msgstr ""
 

	
 
#: kallithea/templates/base/default_perms_box.html:16
 
#, fuzzy
 
#| msgid "Default permissions"
 
msgid "default permissions"
 
msgstr "Стандартныя прывілеі"
 

	
 
#: kallithea/templates/base/default_perms_box.html:23
 
msgid "Create repositories"
 
msgstr "Стварыць рэпазітары"
 

	
 
#: kallithea/templates/base/default_perms_box.html:27
 
msgid "Select this option to allow repository creation for this user"
 
msgstr "Опцыя дазваляе карыстальніку ствараць рэпазітары"
 

	
 
#: kallithea/templates/base/default_perms_box.html:33
 
msgid "Create user groups"
 
msgstr "Ствараць групы карыстальнікаў"
 

	
 
#: kallithea/templates/base/default_perms_box.html:37
 
msgid "Select this option to allow user group creation for this user"
 
msgstr "Опцыя дазваляе карыстальніку ствараць групы карыстальнікаў"
 

	
 
#: kallithea/templates/base/default_perms_box.html:43
 
msgid "Fork repositories"
 
msgstr "Ствараць fork ад рэпазітароў"
 

	
 
#: kallithea/templates/base/default_perms_box.html:47
 
msgid "Select this option to allow repository forking for this user"
 
msgstr ""
 
"Абярыце гэту опцыю каб дазволіць дадзенаму карыстальніку ствараць форкі "
 
"рэпазітароў"
 

	
 
#: kallithea/templates/base/perms_summary.html:13
 
#: kallithea/templates/changelog/changelog.html:41
 
msgid "Show"
 
msgstr "Паказаць"
 

	
 
#: kallithea/templates/base/perms_summary.html:22
 
msgid "No permissions defined yet"
 
msgstr "Прывілеі яшчэ не прызначаныя"
 

	
 
#: kallithea/templates/base/perms_summary.html:30
 
#: kallithea/templates/base/perms_summary.html:55
 
msgid "Permission"
 
msgstr "Прывілей"
 

	
 
#: kallithea/templates/base/perms_summary.html:32
 
#: kallithea/templates/base/perms_summary.html:57
 
msgid "Edit Permission"
 
msgstr "Змяніць прывілеі"
 

	
 
#: kallithea/templates/base/perms_summary.html:92
 
msgid "No permission defined"
 
msgstr ""
 

	
 
#: kallithea/templates/base/root.html:28
 
msgid "Retry"
 
msgstr ""
 

	
 
#: kallithea/templates/base/root.html:29
 
#: kallithea/templates/changeset/changeset_file_comment.html:65
 
msgid "Submitting ..."
 
msgstr "Адпраўка..."
 

	
 
#: kallithea/templates/base/root.html:30
 
#, fuzzy
 
#| msgid "Enable downloads"
 
msgid "Unable to post"
 
msgstr "Уключыць спампоўку"
 

	
 
#: kallithea/templates/base/root.html:31
 
msgid "Add Another Comment"
 
msgstr "Дадаць яшчэ адзін каментар"
 

	
 
#: kallithea/templates/base/root.html:32
 
msgid "Stop following this repository"
 
msgstr "Адмяніць назіранне за рэпазітаром"
 

	
 
#: kallithea/templates/base/root.html:33
 
msgid "Start following this repository"
 
msgstr "Назіраць за рэпазітаром"
 

	
 
#: kallithea/templates/base/root.html:34
 
msgid "Group"
 
msgstr "Група"
 

	
 
#: kallithea/templates/base/root.html:35
 
msgid "Loading ..."
 
msgstr "Загрузка..."
 

	
 
#: kallithea/templates/base/root.html:36
 
msgid "loading ..."
 
msgstr "загрузка..."
 

	
 
#: kallithea/templates/base/root.html:37
 
msgid "Search truncated"
 
msgstr "Пошук усечаны"
 

	
 
#: kallithea/templates/base/root.html:38
 
msgid "No matching files"
 
msgstr "Няма супадзенняў"
 

	
 
#: kallithea/templates/base/root.html:39
 
msgid "Open New Pull Request from {0}"
 
msgstr "Стварыць новы pull-запыт з {0}"
 

	
 
#: kallithea/templates/base/root.html:40
 
msgid "Open New Pull Request for {0} &rarr; {1}"
 
msgstr "Стварыць новы pull-запыт для {0} &rarr; {1}"
 

	
 
#: kallithea/templates/base/root.html:41
 
msgid "Show Selected Changesets {0} &rarr; {1}"
 
msgstr "Паказаць выбраныя наборы змен: {0} &rarr; {1}"
 

	
 
#: kallithea/templates/base/root.html:42
 
msgid "Selection Link"
 
msgstr "Спасылка выбару"
 

	
 
#: kallithea/templates/base/root.html:43
 
#: kallithea/templates/changeset/diff_block.html:7
 
msgid "Collapse Diff"
 
msgstr "Згарнуць параўнанне"
 

	
 
#: kallithea/templates/base/root.html:44
 
msgid "Expand Diff"
 
msgstr "Разгарнуць параўнанне"
 

	
 
#: kallithea/templates/base/root.html:45
 
msgid "No revisions"
 
msgstr "Няма рэвізій"
 

	
 
#: kallithea/templates/base/root.html:46
 
msgid "Type name of user or member to grant permission"
 
msgstr ""
 

	
 
#: kallithea/templates/base/root.html:47
 
msgid "Failed to revoke permission"
 
msgstr "Не атрымалася адклікаць прывілеі"
 

	
 
#: kallithea/templates/base/root.html:48
 
msgid "Confirm to revoke permission for {0}: {1} ?"
 
msgstr "Пацвердзіце выдаленне прывілею для {0}: {1} ?"
 

	
 
#: kallithea/templates/base/root.html:51
 
#: kallithea/templates/compare/compare_diff.html:108
 
msgid "Select changeset"
 
msgstr "Выбраць набор змен"
 

	
 
#: kallithea/templates/base/root.html:52
 
msgid "Specify changeset"
 
msgstr "Выбраць набор змен"
 

	
 
#: kallithea/templates/base/root.html:53
 
msgid "Click to sort ascending"
 
msgstr "Па ўзрастанні"
 

	
 
#: kallithea/templates/base/root.html:54
 
msgid "Click to sort descending"
 
msgstr "Па змяншэнні"
 

	
 
#: kallithea/templates/base/root.html:55
 
msgid "No records found."
 
msgstr "Запісы не знойдзеныя."
 

	
 
#: kallithea/templates/base/root.html:56
 
msgid "Data error."
 
msgstr "Памылка дадзеных."
 

	
 
#: kallithea/templates/base/root.html:57
 
msgid "Loading..."
 
msgstr "Загрузка..."
 

	
 
#: kallithea/templates/changelog/changelog.html:8
 
#, python-format
 
msgid "%s Changelog"
 
msgstr "Логі змен %s"
 

	
 
#: kallithea/templates/changelog/changelog.html:23
 
#, python-format
 
msgid "showing %d out of %d revision"
 
msgid_plural "showing %d out of %d revisions"
 
msgstr[0] "Паказана %d з %d рэвізій"
 
msgstr[1] "Паказаны %d з %d рэвізій"
 
msgstr[2] "Паказаны %d з %d рэвізій"
 

	
 
#: kallithea/templates/changelog/changelog.html:47
 
msgid "Clear selection"
 
msgstr "Ачысціць выбар"
 

	
 
#: kallithea/templates/changelog/changelog.html:54
 
msgid "Go to tip of repository"
 
msgstr "Перайсці на верхавіну рэпазітара"
 

	
 
#: kallithea/templates/changelog/changelog.html:59
 
#: kallithea/templates/forks/forks_data.html:16
 
#, python-format
 
msgid "Compare fork with %s"
 
msgstr "Параўнаць fork з %s"
 
@@ -4729,406 +4740,406 @@ msgstr "%(user)s пакінуў каментар да набору змен %(age)s"
 
msgid "Comment on Changeset \"%s\""
 
msgstr "Каментар ад %s да набору змен %s %s"
 

	
 
#: kallithea/templates/email_templates/changeset_comment.html:20
 
#, fuzzy
 
#| msgid "Changeset flow"
 
msgid "Changeset on"
 
msgstr "Струмень змен"
 

	
 
#: kallithea/templates/email_templates/changeset_comment.html:23
 
#: kallithea/templates/email_templates/pull_request.html:22
 
#: kallithea/templates/email_templates/pull_request.html:28
 
#: kallithea/templates/email_templates/pull_request_comment.html:30
 
#: kallithea/templates/email_templates/pull_request_comment.html:36
 
#, fuzzy
 
#| msgid "Branch"
 
msgid "branch"
 
msgstr "Галіна"
 

	
 
#: kallithea/templates/email_templates/changeset_comment.html:29
 
#: kallithea/templates/email_templates/pull_request.html:15
 
#: kallithea/templates/email_templates/pull_request_comment.html:23
 
msgid "by"
 
msgstr ""
 

	
 
#: kallithea/templates/email_templates/comment.html:27
 
#, fuzzy
 
#| msgid "Status change"
 
msgid "Status change:"
 
msgstr "Змена статусу"
 

	
 
#: kallithea/templates/email_templates/comment.html:33
 
#, fuzzy
 
#| msgid "This pull request has been closed and can not be updated."
 
msgid "The pull request has been closed."
 
msgstr "Гэты pull-запыт быў зачынены і не можа быць абноўлены."
 

	
 
#: kallithea/templates/email_templates/password_reset.html:9
 
#, python-format
 
msgid "Hello %s"
 
msgstr "Добры дзень, %s"
 

	
 
#: kallithea/templates/email_templates/password_reset.html:16
 
msgid "We have received a request to reset the password for your account."
 
msgstr "Мы атрымалі запыт на скіданне пароля для вашага акаўнта."
 

	
 
#: kallithea/templates/email_templates/password_reset.html:25
 
msgid ""
 
"This account is however managed outside this system and the password "
 
"cannot be changed here."
 
msgstr ""
 

	
 
#: kallithea/templates/email_templates/password_reset.html:28
 
msgid "To set a new password, click the following link"
 
msgstr ""
 

	
 
#: kallithea/templates/email_templates/password_reset.html:33
 
msgid ""
 
"Should you not be able to use the link above, please type the following "
 
"code into the password reset form"
 
msgstr ""
 

	
 
#: kallithea/templates/email_templates/password_reset.html:44
 
msgid ""
 
"If it weren't you who requested the password reset, just disregard this "
 
"message."
 
msgstr ""
 

	
 
#: kallithea/templates/email_templates/pull_request.html:4
 
#, fuzzy, python-format
 
#| msgid "%s mentioned you on %s pull request \"%s\""
 
msgid "Mention on Pull Request %s \"%s\" by %s"
 
msgstr "%s згадаў Вас у каментары да pull-запыту %s \"%s\""
 

	
 
#: kallithea/templates/email_templates/pull_request.html:4
 
#, fuzzy, python-format
 
#| msgid "%s requested your review of %s pull request \"%s\""
 
msgid "Added as Reviewer of Pull Request %s \"%s\" by %s"
 
msgstr "%s запытаў рэцэнзаванне pull-запыту %s \"%s\""
 

	
 
#: kallithea/templates/email_templates/pull_request.html:12
 
#: kallithea/templates/email_templates/pull_request_comment.html:20
 
#, fuzzy
 
#| msgid "Pull request %s"
 
msgid "Pull request"
 
msgstr "Pull-запыт %s"
 

	
 
#: kallithea/templates/email_templates/pull_request.html:19
 
#: kallithea/templates/email_templates/pull_request_comment.html:27
 
msgid "from"
 
msgstr ""
 

	
 
#: kallithea/templates/email_templates/pull_request.html:25
 
#: kallithea/templates/email_templates/pull_request_comment.html:33
 
msgid "to"
 
msgstr ""
 

	
 
#: kallithea/templates/email_templates/pull_request_comment.html:4
 
#, fuzzy, python-format
 
#| msgid "%s mentioned you on %s pull request \"%s\""
 
msgid "Mention in Comment on Pull Request %s \"%s\""
 
msgstr "%s згадаў Вас у каментары да pull-запыту %s \"%s\""
 

	
 
#: kallithea/templates/email_templates/pull_request_comment.html:4
 
#, fuzzy, python-format
 
#| msgid "Pull request %s from %s#%s"
 
msgid "Pull Request %s \"%s\" Closed"
 
msgstr "Pull-запыт %s ад %s#%s"
 

	
 
#: kallithea/templates/email_templates/pull_request_comment.html:4
 
#, fuzzy, python-format
 
#| msgid "[commented] on pull request for"
 
msgid "Comment on Pull Request %s \"%s\""
 
msgstr "[каментар] у pull-запыце для"
 

	
 
#: kallithea/templates/email_templates/registration.html:22
 
#, fuzzy
 
#| msgid "Group name"
 
msgid "Full Name"
 
msgstr "Імя групы"
 

	
 
#: kallithea/templates/files/diff_2way.html:15
 
#, python-format
 
msgid "%s File side-by-side diff"
 
msgstr ""
 

	
 
#: kallithea/templates/files/diff_2way.html:19
 
#: kallithea/templates/files/file_diff.html:8
 
msgid "File diff"
 
msgstr "Параўнанне файлаў"
 

	
 
#: kallithea/templates/files/file_diff.html:4
 
#, python-format
 
msgid "%s File Diff"
 
msgstr "Параўнанне файла %s"
 

	
 
#: kallithea/templates/files/files.html:4
 
#: kallithea/templates/files/files.html:77
 
#, python-format
 
msgid "%s Files"
 
msgstr "%s Файлы"
 

	
 
#: kallithea/templates/files/files_add.html:4
 
#, python-format
 
msgid "%s Files Add"
 
msgstr "%s Файлаў дададзена"
 

	
 
#: kallithea/templates/files/files_add.html:21
 
#: kallithea/templates/files/files_ypjax.html:9
 
#: kallithea/templates/summary/summary.html:191
 
msgid "Add New File"
 
msgstr "Дадаць новы файл"
 

	
 
#: kallithea/templates/files/files_add.html:39
 
#: kallithea/templates/files/files_edit.html:39
 
#: kallithea/templates/files/files_ypjax.html:3
 
msgid "Location"
 
msgstr "Размяшчэнне"
 

	
 
#: kallithea/templates/files/files_add.html:41
 
msgid "Enter filename..."
 
msgstr "Увядзіце імя файла..."
 

	
 
#: kallithea/templates/files/files_add.html:43
 
#: kallithea/templates/files/files_add.html:47
 
msgid "or"
 
msgstr "ці"
 

	
 
#: kallithea/templates/files/files_add.html:43
 
msgid "Upload File"
 
msgstr "Адаслаць файл"
 

	
 
#: kallithea/templates/files/files_add.html:47
 
msgid "Create New File"
 
msgstr "Стварыць новы файл"
 

	
 
#: kallithea/templates/files/files_add.html:53
 
msgid "New file type"
 
msgstr "Тып новага файла"
 

	
 
#: kallithea/templates/files/files_add.html:64
 
#: kallithea/templates/files/files_delete.html:34
 
#: kallithea/templates/files/files_edit.html:67
 
msgid "Commit Message"
 
msgstr ""
 

	
 
#: kallithea/templates/files/files_add.html:68
 
#: kallithea/templates/files/files_delete.html:40
 
#: kallithea/templates/files/files_edit.html:71
 
msgid "Commit Changes"
 
msgstr "Захаваць змены"
 

	
 
#: kallithea/templates/files/files_browser.html:37
 
#: kallithea/templates/files/files_browser.html:40
 
msgid "Search File List"
 
msgstr ""
 

	
 
#: kallithea/templates/files/files_browser.html:42
 
#: kallithea/templates/files/files_browser.html:45
 
msgid "Loading file list..."
 
msgstr "Загружаецца спіс файлаў..."
 

	
 
#: kallithea/templates/files/files_browser.html:52
 
#: kallithea/templates/files/files_browser.html:55
 
#: kallithea/templates/summary/summary.html:145
 
msgid "Size"
 
msgstr "Памер"
 

	
 
#: kallithea/templates/files/files_browser.html:53
 
#: kallithea/templates/files/files_browser.html:56
 
msgid "Last Revision"
 
msgstr "Апошняя версія"
 

	
 
#: kallithea/templates/files/files_browser.html:54
 
#: kallithea/templates/files/files_browser.html:57
 
msgid "Last Modified"
 
msgstr "Апошняя змена"
 

	
 
#: kallithea/templates/files/files_browser.html:55
 
#: kallithea/templates/files/files_browser.html:58
 
msgid "Last Committer"
 
msgstr "Аўтар апошняй рэвізіі"
 

	
 
#: kallithea/templates/files/files_delete.html:4
 
#, python-format
 
msgid "%s Files Delete"
 
msgstr ""
 

	
 
#: kallithea/templates/files/files_delete.html:12
 
#: kallithea/templates/files/files_delete.html:30
 
msgid "Delete file"
 
msgstr "Выдаліць файл"
 

	
 
#: kallithea/templates/files/files_edit.html:4
 
#, python-format
 
msgid "%s File Edit"
 
msgstr ""
 

	
 
#: kallithea/templates/files/files_edit.html:21
 
msgid "Edit file"
 
msgstr "Рэдагаваць файл"
 

	
 
#: kallithea/templates/files/files_edit.html:51
 
#: kallithea/templates/files/files_source.html:28
 
msgid "Show Annotation"
 
msgstr ""
 

	
 
#: kallithea/templates/files/files_edit.html:53
 
#: kallithea/templates/files/files_source.html:31
 
msgid "Download as Raw"
 
msgstr ""
 

	
 
#: kallithea/templates/files/files_edit.html:56
 
msgid "Source"
 
msgstr "Зыходны код"
 

	
 
#: kallithea/templates/files/files_history_box.html:2
 
#, python-format
 
msgid "%s author"
 
msgid_plural "%s authors"
 
msgstr[0] "%s аўтар"
 
msgstr[1] "%s аўтараў"
 
msgstr[2] "%s аўтара"
 

	
 
#: kallithea/templates/files/files_source.html:6
 
msgid "Diff to Revision"
 
msgstr ""
 

	
 
#: kallithea/templates/files/files_source.html:7
 
msgid "Show at Revision"
 
msgstr ""
 

	
 
#: kallithea/templates/files/files_source.html:9
 
msgid "Show Full History"
 
msgstr "Паказаць ўсю гісторыю"
 

	
 
#: kallithea/templates/files/files_source.html:10
 
msgid "Show Authors"
 
msgstr "Паказаць аўтараў"
 

	
 
#: kallithea/templates/files/files_source.html:26
 
msgid "Show Source"
 
msgstr ""
 

	
 
#: kallithea/templates/files/files_source.html:34
 
#, fuzzy, python-format
 
#| msgid "Deleted branch: %s"
 
msgid "Edit on Branch: %s"
 
msgstr "Выдаленая галіна: %s"
 

	
 
#: kallithea/templates/files/files_source.html:37
 
msgid "Editing binary files not allowed"
 
msgstr "Рэдагаванне бінарных файлаў забароненае"
 

	
 
#: kallithea/templates/files/files_source.html:40
 
msgid "Editing files allowed only when on branch head revision"
 
msgstr "Рэдагаванне файлаў дазволенае толькі ў HEAD-рэвізіі дадзенай галіны"
 

	
 
#: kallithea/templates/files/files_source.html:41
 
msgid "Deleting files allowed only when on branch head revision"
 
msgstr ""
 

	
 
#: kallithea/templates/files/files_source.html:58
 
#, python-format
 
msgid "Binary file (%s)"
 
msgstr "Бінарны файл (%s)"
 

	
 
#: kallithea/templates/files/files_source.html:69
 
msgid "File is too big to display."
 
msgstr "Файл занадта вялікі для адлюстравання."
 

	
 
#: kallithea/templates/files/files_source.html:71
 
msgid "Show full annotation anyway."
 
msgstr "Паказаць поўныя анатацыі."
 

	
 
#: kallithea/templates/files/files_source.html:73
 
msgid "Show as raw."
 
msgstr "Паказаць сырым."
 

	
 
#: kallithea/templates/files/files_ypjax.html:5
 
msgid "annotation"
 
msgstr "анатацыя"
 

	
 
#: kallithea/templates/files/files_ypjax.html:23
 
msgid "Go Back"
 
msgstr "Вярнуцца"
 

	
 
#: kallithea/templates/files/files_ypjax.html:24
 
msgid "No files at given path"
 
msgstr "Па зададзеным шляху файлы адсутнічаюць"
 

	
 
#: kallithea/templates/followers/followers.html:5
 
#, python-format
 
msgid "%s Followers"
 
msgstr "%s Назіральнікі"
 

	
 
#: kallithea/templates/followers/followers.html:9
 
#: kallithea/templates/summary/summary.html:130
 
#: kallithea/templates/summary/summary.html:131
 
msgid "Followers"
 
msgstr "Назіральнікі"
 

	
 
#: kallithea/templates/followers/followers_data.html:9
 
msgid "Started following -"
 
msgstr "Назіраць за рэпазітаром"
 

	
 
#: kallithea/templates/forks/fork.html:5
 
#, python-format
 
msgid "Fork repository %s"
 
msgstr ""
 

	
 
#: kallithea/templates/forks/fork.html:25
 
msgid "Fork name"
 
msgstr "Імя форка"
 

	
 
#: kallithea/templates/forks/fork.html:53
 
msgid "Default revision for files page, downloads, whoosh, and readme."
 
msgstr ""
 
"Рэвізія па змаўчанні, з якой будзе вырабляцца выгрузка файлаў пры "
 
"спампоўцы."
 

	
 
#: kallithea/templates/forks/fork.html:58
 
msgid "Private"
 
msgstr "Прыватны"
 

	
 
#: kallithea/templates/forks/fork.html:66
 
msgid "Copy permissions"
 
msgstr "Скапіяваць прывілеі"
 

	
 
#: kallithea/templates/forks/fork.html:69
 
msgid "Copy permissions from forked repository"
 
msgstr "Скапіяваць прывілеі з форкнутага рэпазітара"
 

	
 
#: kallithea/templates/forks/fork.html:75
 
msgid "Update after clone"
 
msgstr "Абнаўляць пасля кланавання"
 

	
 
#: kallithea/templates/forks/fork.html:78
 
msgid "Checkout source after making a clone"
 
msgstr "Спампоўваць зыходнікі пасля стварэння клона"
 

	
 
#: kallithea/templates/forks/fork.html:85
 
msgid "Fork this Repository"
 
msgstr ""
 

	
 
#: kallithea/templates/forks/forks.html:5
 
#, python-format
 
msgid "%s Forks"
 
msgstr "Форкі %s"
 

	
 
#: kallithea/templates/forks/forks.html:9
 
#: kallithea/templates/summary/summary.html:136
 
#: kallithea/templates/summary/summary.html:137
 
msgid "Forks"
 
msgstr "Адгалінаванні"
 

	
 
#: kallithea/templates/forks/forks_data.html:14
 
msgid "Forked"
 
msgstr "Форкнута"
 

	
 
#: kallithea/templates/forks/forks_data.html:24
 
msgid "There are no forks yet"
 
msgstr "Форкі яшчэ не створаныя"
 

	
 
#: kallithea/templates/journal/journal.html:22
 
msgid "ATOM journal feed"
 
msgstr "Стужка часопіса Atom"
 

	
 
#: kallithea/templates/journal/journal.html:23
 
msgid "RSS journal feed"
 
msgstr "Стужка часопіса RSS"
 

	
 
@@ -5728,387 +5739,384 @@ msgstr "Спампаваць %s як %s"
 

	
 
#~ msgid "Group Name"
 
#~ msgstr "Імя групы"
 

	
 
#~ msgid "Remember me"
 
#~ msgstr "Запомніць"
 

	
 
#~ msgid "Change your avatar at"
 
#~ msgstr "Змяніць аватар можна праз"
 

	
 
#~ msgid "Using"
 
#~ msgstr "Выкарыстоўваецца"
 

	
 
#~ msgid "Missing email, please update your user email address."
 
#~ msgstr "Няма email адрэсы, калі ласка, абнавіце ваш email."
 

	
 
#~ msgid "Rescan option"
 
#~ msgstr "Опцыі перасканіравання"
 

	
 
#~ msgid "Web"
 
#~ msgstr "Вэб"
 

	
 
#~ msgid "Require SSL for vcs operations"
 
#~ msgstr "Запытваць SSL для аперацый з VCS"
 

	
 
#~ msgid "Use Gravatars in Kallithea"
 
#~ msgstr "Выкарыстоўваць Gravatars у Kallithea"
 

	
 
#~ msgid "Dashboard items"
 
#~ msgstr "Элементы панэлі"
 

	
 
#~ msgid ""
 
#~ "Number of items displayed in the main page dashboard before pagination "
 
#~ "is shown."
 
#~ msgstr ""
 
#~ "Колькасць элементаў, што паказваюцца на галоўнай старонцы панэлі "
 
#~ "кіравання перад паказам нумарацыі старонак."
 

	
 
#~ msgid "quick filter..."
 
#~ msgstr "фільтр..."
 

	
 
#~ msgid "Missing email, please update this user email address."
 
#~ msgstr "Не паказаны email. Калі ласка, абнавіце email карыстальніка."
 

	
 
#~ msgid "Keyboard shortcuts"
 
#~ msgstr "Гарачыя клавішы"
 

	
 
#~ msgid "Forgot password ?"
 
#~ msgstr "Забыліся на пароль?"
 

	
 
#~ msgid "Ancestor"
 
#~ msgstr "Продак"
 

	
 
#~ msgid "Comment from %s on %s changeset %s"
 
#~ msgstr "Каментар ад %s да набору змен %s %s"
 

	
 
#~ msgid "The changeset status was changed to"
 
#~ msgstr "Статус набору змен зменены на"
 

	
 
#~ msgid "This is an automatic notification. Don't reply to this mail."
 
#~ msgstr ""
 
#~ "Гэта аўтаматычнае апавяшчэнне. Не адказвайце на гэтае паведамленне."
 

	
 
#~ msgid "%s mentioned you on %s pull request \"%s\""
 
#~ msgstr "%s згадаў Вас у каментары да pull-запыту %s \"%s\""
 

	
 
#~ msgid "%s requested your review of %s pull request \"%s\""
 
#~ msgstr "%s запытаў рэцэнзаванне pull-запыту %s \"%s\""
 

	
 
#~ msgid "The comment closed the pull request with status"
 
#~ msgstr "Каментар зачыніў pull-запыт са статусам"
 

	
 
#~ msgid "The comment was made with status"
 
#~ msgstr "Каментар пакінуты са статусам"
 

	
 
#~ msgid "View this user here"
 
#~ msgstr "Падрабязней пра карыстальніка"
 

	
 
#~ msgid "Repository Size"
 
#~ msgstr "Памер рэпазітара"
 

	
 
#~ msgid "No comments."
 
#~ msgstr "Няма каментароў."
 

	
 
#~ msgid "public journal"
 
#~ msgstr "агульнадаступны часопіс"
 

	
 
#~ msgid "journal"
 
#~ msgstr "часопіс"
 

	
 
#~ msgid "Locked repository"
 
#~ msgstr "Зачынены рэпазітар"
 

	
 
#~ msgid "Unlocked repository"
 
#~ msgstr "Адкрыты рэпазітар"
 

	
 
#~ msgid "Unlocked"
 
#~ msgstr "Разблакавана"
 

	
 
#~ msgid "Locked"
 
#~ msgstr "Заблакавана"
 

	
 
#~ msgid "Repository has been %s"
 
#~ msgstr "Рэпазітар %s"
 

	
 
#~ msgid "You can't edit this user"
 
#~ msgstr "Вы не можаце рэдагаваць дадзенага карыстальніка"
 

	
 
#~ msgid "No Files"
 
#~ msgstr "Файлаў няма"
 

	
 
#~ msgid "Username \"%(username)s\" is forbidden"
 
#~ msgstr "Імя \"%(username)s\" адхілена"
 

	
 
#~ msgid "invalid user name"
 
#~ msgstr "няслушнае імя карыстальніка"
 

	
 
#~ msgid "Your account is disabled"
 
#~ msgstr "Ваш акаўнт выключаны"
 

	
 
#~ msgid "invalid clone URL"
 
#~ msgstr "няслушны URL для кланавання"
 

	
 
#~ msgid "Defaults"
 
#~ msgstr "Значэнні па змаўчанні"
 

	
 
#~ msgid "My Emails"
 
#~ msgstr "Мае адрасы E-mail"
 

	
 
#~ msgid "Watched"
 
#~ msgstr "Прагледжана"
 

	
 
#~ msgid "My Permissions"
 
#~ msgstr "Мае прывілеі"
 

	
 
#~ msgid "reset"
 
#~ msgstr "cкінуць"
 

	
 
#~ msgid "delete"
 
#~ msgstr "выдаліць"
 

	
 
#~ msgid "Permissions Administration"
 
#~ msgstr "Кіраванне прывілеямі"
 

	
 
#~ msgid "Overview"
 
#~ msgstr "Агляд"
 

	
 
#~ msgid "Overwrite existing settings"
 
#~ msgstr "Перазапісаць існыя налады"
 

	
 
#~ msgid "Default IP Whitelist for All Users"
 
#~ msgstr "Белы спіс IP для ўсіх карыстальнікаў"
 

	
 
#~ msgid "Default User Permissions Overview"
 
#~ msgstr "Агляд мае рацыю карыстальнікаў па змаўчанні"
 

	
 
#~ msgid "none"
 
#~ msgstr "нічога"
 

	
 
#~ msgid "read"
 
#~ msgstr "чытаць"
 

	
 
#~ msgid "write"
 
#~ msgstr "запісваць"
 

	
 
#~ msgid "admin"
 
#~ msgstr "адміністратар"
 

	
 
#~ msgid "Optional URL from which repository should be cloned."
 
#~ msgstr "Апцыянальны URL, з якога патрабуецца скланаваць рэпазітар."
 

	
 
#~ msgid "Remote URL"
 
#~ msgstr "Спасылка для кланавання"
 

	
 
#~ msgid "Pull Changes from Remote Location"
 
#~ msgstr "Атрымаць змены з выдаленага боку"
 

	
 
#~ msgid "Non-changeable id"
 
#~ msgstr "Нязменлівы id"
 

	
 
#~ msgid "edit"
 
#~ msgstr "рэдагаваць"
 

	
 
#~ msgid "new value"
 
#~ msgstr "новае значэнне"
 

	
 
#~ msgid "SMTP server"
 
#~ msgstr "SMTP-сервер"
 

	
 
#~ msgid "Destroy old data"
 
#~ msgstr "Знішчыць усе дадзеныя"
 

	
 
#~ msgid "Default permissions"
 
#~ msgstr "Стандартныя прывілеі"
 

	
 
#~ msgid "show"
 
#~ msgstr "паказа́ць"
 

	
 
#~ msgid "Status change from pull request"
 
#~ msgstr "Змена статусу"
 

	
 
#~ msgid "revision"
 
#~ msgstr "рэвізія"
 

	
 
#~ msgid "Mimetype"
 
#~ msgstr "Тып файла"
 

	
 
#~ msgid "My Repos"
 
#~ msgstr "Мае рэпазітары"
 

	
 
#~ msgid "Latest vote: %s"
 
#~ msgstr "Апошняя адзнака: %s"
 

	
 
#~ msgid "Nobody voted"
 
#~ msgstr "Ніхто не галасаваў"
 

	
 
#~ msgid "owner"
 
#~ msgstr "уладальнік"
 

	
 
#~ msgid "Your new password"
 
#~ msgstr "Ваш новы пароль"
 

	
 
#~ msgid "Your new Kallithea password:%s"
 
#~ msgstr "Ваш новы пароль ад Kallithea: %s"
 

	
 
#~ msgid "Open New Pull Request for Selected Changesets"
 
#~ msgstr "Адкрыць новы pull-request для абраных набораў змен"
 

	
 
#~ msgid "Show Selected Changeset __S"
 
#~ msgstr "Паказаць абраны набор змен: __S"
 

	
 
#~ msgid "You can generate it by clicking following URL"
 
#~ msgstr ""
 
#~ "Вы можаце нанова згенераваць яго, пяройдучы па наступнай спасылцы"
 

	
 
#~ msgid "Created by"
 
#~ msgstr "Створана"
 

	
 
#~ msgid "Closed, replaced by %s ."
 
#~ msgstr "Зачынены, заменены %s."
 

	
 
#~ msgid "Closing."
 
#~ msgstr "Зачынены."
 

	
 
#~ msgid "Changeset not found"
 
#~ msgstr "Набор змен не знойдзены"
 

	
 
#~ msgid "Repository no access"
 
#~ msgstr "Рэпазітар - няма доступу"
 

	
 
#~ msgid "Repository read access"
 
#~ msgstr "Рэпазітар - доступ на чытанне"
 

	
 
#~ msgid "Repository write access"
 
#~ msgstr "Рэпазітар - доступ на запіс"
 

	
 
#~ msgid "Repository admin access"
 
#~ msgstr "Рэпазітар - адміністраванне"
 

	
 
#~ msgid "Repository Group no access"
 
#~ msgstr "Група Рэпазітароў - няма доступу"
 

	
 
#~ msgid "Repository Group read access"
 
#~ msgstr "Група Рэпазітароў - доступ на чытанне"
 

	
 
#~ msgid "Repository Group write access"
 
#~ msgstr "Група Рэпазітароў - доступ на запіс"
 

	
 
#~ msgid "Repository Group admin access"
 
#~ msgstr "Група Рэпазітароў - адміністраванне"
 

	
 
#~ msgid "Repository creation disabled"
 
#~ msgstr "Стварэнне рэпазітароў адключанае"
 

	
 
#~ msgid "Repository creation enabled"
 
#~ msgstr "Стварэнне рэпазітароў уключанае"
 

	
 
#~ msgid "Repository forking disabled"
 
#~ msgstr "Магчымасць ствараць форк рэпазітара адключаная"
 

	
 
#~ msgid "Repository forking enabled"
 
#~ msgstr "Магчымасць ствараць форк рэпазітара ўключаная"
 

	
 
#~ msgid "Register disabled"
 
#~ msgstr "Рэгістрацыя адключаная"
 

	
 
#~ msgid "Register new user with Kallithea with manual activation"
 
#~ msgstr "Рэгістрацыя новага карыстальніка ў Kallithea з ручной актывацыяй"
 

	
 
#~ msgid "Register new user with Kallithea with auto activation"
 
#~ msgstr ""
 
#~ "Рэгістрацыя новага карыстальніка ў Kallithea з аўтаматычнай актывацыяй"
 

	
 
#~ msgid "Not Reviewed"
 
#~ msgstr "Не прагледжана"
 

	
 
#~ msgid "Rejected"
 
#~ msgstr "Адхілена"
 

	
 
#~ msgid "Under Review"
 
#~ msgstr "На разглядзе"
 

	
 
#~ msgid "Repository group no access"
 
#~ msgstr "Група Рэпазітароў - няма доступу"
 

	
 
#~ msgid "Repository group read access"
 
#~ msgstr "Група рэпазітароў - доступ на чытанне"
 

	
 
#~ msgid "Repository group write access"
 
#~ msgstr "Група рэпазітароў - доступ на запіс"
 

	
 
#~ msgid "Repository group admin access"
 
#~ msgstr "Група рэпазітароў - адміністраванне"
 

	
 
#~ msgid "User group no access"
 
#~ msgstr "Група карыстальнікаў - няма доступу"
 

	
 
#~ msgid "User group read access"
 
#~ msgstr "Група карыстальнікаў - доступ на чытанне"
 

	
 
#~ msgid "User group write access"
 
#~ msgstr "Група карыстальнікаў - доступ на запіс"
 

	
 
#~ msgid "User group admin access"
 
#~ msgstr "Група карыстальнікаў - адміністраванне"
 

	
 
#~ msgid "Repository Group creation disabled"
 
#~ msgstr "Стварэнне груп рэпазітароў адключанае"
 

	
 
#~ msgid "Repository Group creation enabled"
 
#~ msgstr "Стварэнне груп рэпазітароў уключанае"
 

	
 
#~ msgid "User Group creation disabled"
 
#~ msgstr "Стварэнне груп карыстальнікаў адключанае"
 

	
 
#~ msgid "User Group creation enabled"
 
#~ msgstr "Стварэнне груп карыстальнікаў уключанае"
 

	
 
#~ msgid "User Registration with manual account activation"
 
#~ msgstr "Рэгістрацыя карыстальніка з ручной актывацыяй уліковага запісу"
 

	
 
#~ msgid "User Registration with automatic account activation"
 
#~ msgstr "Рэгістрацыя карыстальніка з аўтаматычнай актывацыяй"
 

	
 
#~ msgid "[Added] %(repo_name)s pull request %(pr_nice_id)s from %(ref)s"
 
#~ msgstr ""
 
#~ "%(user)s просіць вас разгледзець pull request %(pr_nice_id)s: "
 
#~ "%(pr_title)s"
 

	
 
#~ msgid "repositories"
 
#~ msgstr "рэпазітары"
 

	
 
#~ msgid "No repositories found."
 
#~ msgstr "Рэпазітары не знойдзеныя."
 

	
 
#~ msgid "There are no branches yet"
 
#~ msgstr "Галіны яшчэ не створаныя"
 

	
 
#~ msgid "There are no tags yet"
 
#~ msgstr "Пазнакі адсутнічаюць"
 

	
 
#~ msgid "There are no bookmarks yet"
 
#~ msgstr "Закладак яшчэ няма"
 

	
 
#~ msgid "enabled"
 
#~ msgstr "уключана"
 

	
 
#~ msgid "%s Bookmarks"
 
#~ msgstr "Закладкі %s"
 

	
 
#~ msgid "Compare Bookmarks"
 
#~ msgstr "Параўнаць закладкі"
 

	
 
#~ msgid "%s Branches"
 
#~ msgstr "%s Галіны"
 

	
 
#~ msgid "Compare Branches"
 
#~ msgstr "Параўнаць галіны"
 

	
 
#~ msgid "Editing file"
 
#~ msgstr "Рэдагаванне файла"
 

	
 
#~ msgid "Update"
 
#~ msgstr "Абнавіць"
 

	
 
#~ msgid "Save Updates as New Pull Request"
 
#~ msgstr "Захаваць абнаўленні як новы pull-запыт"

Changeset was too big and was cut off... Show full diff anyway

0 comments (0 inline, 0 general)