##// END OF EJS Templates
update-copyrights: fixup double entry for Lars Kruse and regenerate...
Thomas De Schampheleire -
r7475:6b4a1302 default
parent child Browse files
Show More
@@ -1,136 +1,145 b''
1 1 List of contributors to Kallithea project:
2 2
3 Andrej Shadura <andrew@shadura.me> 2012 2014-2017 2019
4 Thomas De Schampheleire <thomas.de_schampheleire@nokia.com> 2014-2019
5 Mads Kiilerich <mads@kiilerich.com> 2016-2019
6 Edmund Wong <ewong@crazy-cat.org> 2019
7 Hosted Weblate <hosted@weblate.org> 2019
8 Manuel Jacob <me@manueljacob.de> 2019
3 9 Dominik Ruf <dominikruf@gmail.com> 2012 2014-2018
4 Thomas De Schampheleire <thomas.de_schampheleire@nokia.com> 2014-2018
10 Michal ČihaΕ™ <michal@cihar.com> 2014-2015 2018
5 11 Branko Majic <branko@majic.rs> 2015 2018
6 Mads Kiilerich <mads@kiilerich.com> 2016-2018
12 Allan NordhΓΈy <epost@anotheragency.no> 2017-2018
7 13 Chris Rule <crule@aegistg.com> 2018
14 JesΓΊs SΓ‘nchez <jsanchezfdz95@gmail.com> 2018
8 15 Patrick Vane <patrick_vane@lowentry.com> 2018
16 Pheng Heong Tan <phtan90@gmail.com> 2018
17 ssantos <ssantos@web.de> 2018
18 Максим Π―ΠΊΠΈΠΌΡ‡ΡƒΠΊ <xpinovo@gmail.com> 2018
19 ΠœΠ°Ρ€Ρ Π―ΠΌΠ±Π°Ρ€ <mjambarmeta@gmail.com> 2018
9 20 Mads Kiilerich <madski@unity3d.com> 2012-2017
10 21 Unity Technologies 2012-2017
11 Andrej Shadura <andrew@shadura.me> 2012 2014-2017
12 22 Γ‰tienne Gilli <etienne.gilli@gmail.com> 2015-2017
13 23 SΓΈren LΓΈvborg <sorenl@unity3d.com> 2015-2017
14 24 Sam Jaques <sam.jaques@me.com> 2015 2017
15 25 Asterios Dimitriou <steve@pci.gr> 2016-2017
16 26 Alessandro Molina <alessandro.molina@axant.it> 2017
17 27 Anton Schur <tonich.sh@gmail.com> 2017
18 28 Ching-Chen Mao <mao@lins.fju.edu.tw> 2017
19 29 Eivind Tagseth <eivindt@gmail.com> 2017
20 30 FUJIWARA Katsunori <foozy@lares.dti.ne.jp> 2017
21 31 Holger Schramm <info@schramm.by> 2017
22 32 Karl Goetz <karl@kgoetz.id.au> 2017
23 33 Lars Kruse <devel@sumpfralle.de> 2017
24 34 Marko Semet <markosemet@googlemail.com> 2017
25 35 Viktar Vauchkevich <victorenator@gmail.com> 2017
26 36 Takumi IINO <trot.thunder@gmail.com> 2012-2016
27 37 Jan Heylen <heyleke@gmail.com> 2015-2016
28 38 Robert Martinez <ntttq@inboxen.org> 2015-2016
29 39 Robert Rauch <mail@robertrauch.de> 2015-2016
30 40 Angel Ezquerra <angel.ezquerra@gmail.com> 2016
31 41 Anton Shestakov <av6@dwimlabs.net> 2016
32 42 Brandon Jones <bjones14@gmail.com> 2016
33 43 Kateryna Musina <kateryna@unity3d.com> 2016
34 44 Konstantin Veretennicov <kveretennicov@gmail.com> 2016
35 45 Oscar Curero <oscar@naiandei.net> 2016
36 46 Robert James Dennington <tinytimrob@googlemail.com> 2016
37 47 timeless@gmail.com 2016
38 48 YFdyh000 <yfdyh000@gmail.com> 2016
39 49 Aras Pranckevičius <aras@unity3d.com> 2012-2013 2015
40 50 Sean Farley <sean.michael.farley@gmail.com> 2013-2015
41 51 Christian Oyarzun <oyarzun@gmail.com> 2014-2015
42 52 Joseph Rivera <rivera.d.joseph@gmail.com> 2014-2015
43 Michal ČihaΕ™ <michal@cihar.com> 2014-2015
44 53 Anatoly Bubenkov <bubenkoff@gmail.com> 2015
45 54 Andrew Bartlett <abartlet@catalyst.net.nz> 2015
46 55 BalÑzs Úr <urbalazs@gmail.com> 2015
47 56 Ben Finney <ben@benfinney.id.au> 2015
48 57 Daniel Hobley <danielh@unity3d.com> 2015
49 58 David Avigni <david.avigni@ankapi.com> 2015
50 59 Denis Blanchette <dblanchette@coveo.com> 2015
51 60 duanhongyi <duanhongyi@doopai.com> 2015
52 61 EriCSN Chang <ericsning@gmail.com> 2015
53 62 Grzegorz Krason <grzegorz.krason@gmail.com> 2015
54 63 JiΕ™Γ­ Suchan <yed@vanyli.net> 2015
55 64 Kazunari Kobayashi <kobanari@nifty.com> 2015
56 65 Kevin Bullock <kbullock@ringworld.org> 2015
57 66 kobanari <kobanari@nifty.com> 2015
58 67 Marc Abramowitz <marc@marc-abramowitz.com> 2015
59 68 Marc Villetard <marc.villetard@gmail.com> 2015
60 69 Matthias Zilk <matthias.zilk@gmail.com> 2015
61 70 Michael Pohl <michael@mipapo.de> 2015
62 71 Michael V. DePalatis <mike@depalatis.net> 2015
63 72 Morten Skaaning <mortens@unity3d.com> 2015
64 73 Nick High <nick@silverchip.org> 2015
65 74 Niemand Jedermann <predatorix@web.de> 2015
66 75 Peter Vitt <petervitt@web.de> 2015
67 76 Ronny Pfannschmidt <opensource@ronnypfannschmidt.de> 2015
68 77 Tuux <tuxa@galaxie.eu.org> 2015
69 78 Viktar Palstsiuk <vipals@gmail.com> 2015
70 79 Ante Ilic <ante@unity3d.com> 2014
71 80 Bradley M. Kuhn <bkuhn@sfconservancy.org> 2014
72 81 Calinou <calinou@opmbx.org> 2014
73 82 Daniel Anderson <daniel@dattrix.com> 2014
74 83 Henrik Stuart <hg@hstuart.dk> 2014
75 84 Ingo von Borstel <kallithea@planetmaker.de> 2014
76 85 Jelmer VernooΔ³ <jelmer@samba.org> 2014
77 86 Jim Hague <jim.hague@acm.org> 2014
78 87 Matt Fellows <kallithea@matt-fellows.me.uk> 2014
79 88 Max Roman <max@choloclos.se> 2014
80 89 Na'Tosha Bard <natosha@unity3d.com> 2014
81 90 Rasmus Selsmark <rasmuss@unity3d.com> 2014
82 91 Tim Freund <tim@freunds.net> 2014
83 92 Travis Burtrum <android@moparisthebest.com> 2014
84 93 Zoltan Gyarmati <mr.zoltan.gyarmati@gmail.com> 2014
85 94 Marcin KuΕΊmiΕ„ski <marcin@python-works.com> 2010-2013
86 95 xpol <xpolife@gmail.com> 2012-2013
87 96 Aparkar <aparkar@icloud.com> 2013
88 97 Dennis Brakhane <brakhane@googlemail.com> 2013
89 98 Grzegorz RoΕΌniecki <xaerxess@gmail.com> 2013
90 99 Jonathan Sternberg <jonathansternberg@gmail.com> 2013
91 100 Leonardo Carneiro <leonardo@unity3d.com> 2013
92 101 Magnus Ericmats <magnus.ericmats@gmail.com> 2013
93 102 Martin Vium <martinv@unity3d.com> 2013
94 103 Simon Lopez <simon.lopez@slopez.org> 2013
95 104 Ton Plomp <tcplomp@gmail.com> 2013
96 105 Augusto Herrmann <augusto.herrmann@planejamento.gov.br> 2011-2012
97 106 Dan Sheridan <djs@adelard.com> 2012
98 107 Dies Koper <diesk@fast.au.fujitsu.com> 2012
99 108 Erwin Kroon <e.kroon@smartmetersolutions.nl> 2012
100 109 H Waldo G <gwaldo@gmail.com> 2012
101 110 hppj <hppj@postmage.biz> 2012
102 111 Indra Talip <indra.talip@gmail.com> 2012
103 112 mikespook 2012
104 113 nansenat16 <nansenat16@null.tw> 2012
105 114 Philip Jameson <philip.j@hostdime.com> 2012
106 115 Raoul Thill <raoul.thill@gmail.com> 2012
107 116 Stefan Engel <mail@engel-stefan.de> 2012
108 117 Tony Bussieres <t.bussieres@gmail.com> 2012
109 118 Vincent Caron <vcaron@bearstech.com> 2012
110 119 Vincent Duvert <vincent@duvert.net> 2012
111 120 Vladislav Poluhin <nuklea@gmail.com> 2012
112 121 Zachary Auclair <zach101@gmail.com> 2012
113 122 Ankit Solanki <ankit.solanki@gmail.com> 2011
114 123 Dmitri Kuznetsov 2011
115 124 Jared Bunting <jared.bunting@peachjean.com> 2011
116 125 Jason Harris <jason@jasonfharris.com> 2011
117 126 Les Peabody <lpeabody@gmail.com> 2011
118 127 Liad Shani <liadff@gmail.com> 2011
119 128 Lorenzo M. Catucci <lorenzo@sancho.ccd.uniroma2.it> 2011
120 129 Matt Zuba <matt.zuba@goodwillaz.org> 2011
121 130 Nicolas VINOT <aeris@imirhil.fr> 2011
122 131 Shawn K. O'Shea <shawn@eth0.net> 2011
123 132 Thayne Harbaugh <thayne@fusionio.com> 2011
124 133 Łukasz Balcerzak <lukaszbalcerzak@gmail.com> 2010
125 134 Andrew Kesterson <andrew@aklabs.net>
126 135 cejones
127 136 David A. SjΓΈen <david.sjoen@westcon.no>
128 137 James Rhodes <jrhodes@redpointsoftware.com.au>
129 138 Jonas Oberschweiber <jonas.oberschweiber@d-velop.de>
130 139 larikale
131 140 RhodeCode GmbH
132 141 Sebastian Kreutzberger <sebastian@rhodecode.com>
133 142 Steve Romanow <slestak989@gmail.com>
134 143 SteveCohen
135 144 Thomas <thomas@rhodecode.com>
136 145 Thomas Waldmann <tw-public@gmx.de>
@@ -1,175 +1,184 b''
1 1 ## -*- coding: utf-8 -*-
2 2 <%inherit file="/base/base.html"/>
3 3 <%block name="title">
4 4 ${_('About')}
5 5 </%block>
6 6 <%block name="header_menu">
7 7 ${self.menu('about')}
8 8 </%block>
9 9 <%def name="main()">
10 10
11 11 <div class="panel panel-primary">
12 12 <div class="panel-heading">
13 13 <h5 class="panel-title">${_('About')} Kallithea</h5>
14 14 </div>
15 15
16 16 <div class="panel-body panel-about">
17 17 <p><a href="https://kallithea-scm.org/">Kallithea</a> is a project of the
18 18 <a href="http://sfconservancy.org/">Software Freedom Conservancy, Inc.</a>
19 19 and is released under the terms of the
20 20 <a href="http://www.gnu.org/copyleft/gpl.html">GNU General Public License,
21 21 v 3.0 (GPLv3)</a>.</p>
22 22
23 23 <p>Kallithea is copyrighted by various authors, including but not
24 24 necessarily limited to the following:</p>
25 25 <ul>
26 26
27 <li>Copyright &copy; 2012&ndash;2018, Mads Kiilerich</li>
27 <li>Copyright &copy; 2012&ndash;2019, Mads Kiilerich</li>
28 <li>Copyright &copy; 2012, 2014&ndash;2017, 2019, Andrej Shadura</li>
29 <li>Copyright &copy; 2014&ndash;2019, Thomas De Schampheleire</li>
30 <li>Copyright &copy; 2019, Edmund Wong</li>
31 <li>Copyright &copy; 2019, Hosted Weblate</li>
32 <li>Copyright &copy; 2019, Manuel Jacob</li>
28 33 <li>Copyright &copy; 2012, 2014&ndash;2018, Dominik Ruf</li>
29 <li>Copyright &copy; 2014&ndash;2018, Thomas De Schampheleire</li>
34 <li>Copyright &copy; 2014&ndash;2015, 2018, Michal ČihaΕ™</li>
30 35 <li>Copyright &copy; 2015, 2018, Branko Majic</li>
36 <li>Copyright &copy; 2017&ndash;2018, Allan NordhΓΈy</li>
31 37 <li>Copyright &copy; 2018, Chris Rule</li>
38 <li>Copyright &copy; 2018, JesΓΊs SΓ‘nchez</li>
32 39 <li>Copyright &copy; 2018, Patrick Vane</li>
40 <li>Copyright &copy; 2018, Pheng Heong Tan</li>
41 <li>Copyright &copy; 2018, ssantos</li>
42 <li>Copyright &copy; 2018, Максим Π―ΠΊΠΈΠΌΡ‡ΡƒΠΊ</li>
43 <li>Copyright &copy; 2018, ΠœΠ°Ρ€Ρ Π―ΠΌΠ±Π°Ρ€</li>
33 44 <li>Copyright &copy; 2012&ndash;2017, Unity Technologies</li>
34 <li>Copyright &copy; 2012, 2014&ndash;2017, Andrej Shadura</li>
35 45 <li>Copyright &copy; 2015&ndash;2017, Γ‰tienne Gilli</li>
36 46 <li>Copyright &copy; 2015&ndash;2017, SΓΈren LΓΈvborg</li>
37 47 <li>Copyright &copy; 2015, 2017, Sam Jaques</li>
38 48 <li>Copyright &copy; 2016&ndash;2017, Asterios Dimitriou</li>
39 49 <li>Copyright &copy; 2017, Alessandro Molina</li>
40 50 <li>Copyright &copy; 2017, Anton Schur</li>
41 51 <li>Copyright &copy; 2017, Ching-Chen Mao</li>
42 52 <li>Copyright &copy; 2017, Eivind Tagseth</li>
43 53 <li>Copyright &copy; 2017, FUJIWARA Katsunori</li>
44 54 <li>Copyright &copy; 2017, Holger Schramm</li>
45 55 <li>Copyright &copy; 2017, Karl Goetz</li>
46 56 <li>Copyright &copy; 2017, Lars Kruse</li>
47 57 <li>Copyright &copy; 2017, Marko Semet</li>
48 58 <li>Copyright &copy; 2017, Viktar Vauchkevich</li>
49 59 <li>Copyright &copy; 2012&ndash;2016, Takumi IINO</li>
50 60 <li>Copyright &copy; 2015&ndash;2016, Jan Heylen</li>
51 61 <li>Copyright &copy; 2015&ndash;2016, Robert Martinez</li>
52 62 <li>Copyright &copy; 2015&ndash;2016, Robert Rauch</li>
53 63 <li>Copyright &copy; 2016, Angel Ezquerra</li>
54 64 <li>Copyright &copy; 2016, Anton Shestakov</li>
55 65 <li>Copyright &copy; 2016, Brandon Jones</li>
56 66 <li>Copyright &copy; 2016, Kateryna Musina</li>
57 67 <li>Copyright &copy; 2016, Konstantin Veretennicov</li>
58 68 <li>Copyright &copy; 2016, Oscar Curero</li>
59 69 <li>Copyright &copy; 2016, Robert James Dennington</li>
60 70 <li>Copyright &copy; 2016, timeless@gmail.com</li>
61 71 <li>Copyright &copy; 2016, YFdyh000</li>
62 72 <li>Copyright &copy; 2012&ndash;2013, 2015, Aras Pranckevičius</li>
63 73 <li>Copyright &copy; 2014&ndash;2015, Christian Oyarzun</li>
64 74 <li>Copyright &copy; 2014&ndash;2015, Joseph Rivera</li>
65 <li>Copyright &copy; 2014&ndash;2015, Michal ČihaΕ™</li>
66 75 <li>Copyright &copy; 2014&ndash;2015, Sean Farley</li>
67 76 <li>Copyright &copy; 2015, Anatoly Bubenkov</li>
68 77 <li>Copyright &copy; 2015, Andrew Bartlett</li>
69 78 <li>Copyright &copy; 2015, BalÑzs Úr</li>
70 79 <li>Copyright &copy; 2015, Ben Finney</li>
71 80 <li>Copyright &copy; 2015, Daniel Hobley</li>
72 81 <li>Copyright &copy; 2015, David Avigni</li>
73 82 <li>Copyright &copy; 2015, Denis Blanchette</li>
74 83 <li>Copyright &copy; 2015, duanhongyi</li>
75 84 <li>Copyright &copy; 2015, EriCSN Chang</li>
76 85 <li>Copyright &copy; 2015, Grzegorz Krason</li>
77 86 <li>Copyright &copy; 2015, JiΕ™Γ­ Suchan</li>
78 87 <li>Copyright &copy; 2015, Kazunari Kobayashi</li>
79 88 <li>Copyright &copy; 2015, Kevin Bullock</li>
80 89 <li>Copyright &copy; 2015, kobanari</li>
81 90 <li>Copyright &copy; 2015, Marc Abramowitz</li>
82 91 <li>Copyright &copy; 2015, Marc Villetard</li>
83 92 <li>Copyright &copy; 2015, Matthias Zilk</li>
84 93 <li>Copyright &copy; 2015, Michael Pohl</li>
85 94 <li>Copyright &copy; 2015, Michael V. DePalatis</li>
86 95 <li>Copyright &copy; 2015, Morten Skaaning</li>
87 96 <li>Copyright &copy; 2015, Nick High</li>
88 97 <li>Copyright &copy; 2015, Niemand Jedermann</li>
89 98 <li>Copyright &copy; 2015, Peter Vitt</li>
90 99 <li>Copyright &copy; 2015, Ronny Pfannschmidt</li>
91 100 <li>Copyright &copy; 2015, Tuux</li>
92 101 <li>Copyright &copy; 2015, Viktar Palstsiuk</li>
93 102 <li>Copyright &copy; 2014, Ante Ilic</li>
94 103 <li>Copyright &copy; 2014, Bradley M. Kuhn</li>
95 104 <li>Copyright &copy; 2014, Calinou</li>
96 105 <li>Copyright &copy; 2014, Daniel Anderson</li>
97 106 <li>Copyright &copy; 2014, Henrik Stuart</li>
98 107 <li>Copyright &copy; 2014, Ingo von Borstel</li>
99 108 <li>Copyright &copy; 2014, Jelmer VernooΔ³</li>
100 109 <li>Copyright &copy; 2014, Jim Hague</li>
101 110 <li>Copyright &copy; 2014, Matt Fellows</li>
102 111 <li>Copyright &copy; 2014, Max Roman</li>
103 112 <li>Copyright &copy; 2014, Na'Tosha Bard</li>
104 113 <li>Copyright &copy; 2014, Rasmus Selsmark</li>
105 114 <li>Copyright &copy; 2014, Tim Freund</li>
106 115 <li>Copyright &copy; 2014, Travis Burtrum</li>
107 116 <li>Copyright &copy; 2014, Zoltan Gyarmati</li>
108 117 <li>Copyright &copy; 2010&ndash;2013, Marcin KuΕΊmiΕ„ski</li>
109 118 <li>Copyright &copy; 2010&ndash;2013, RhodeCode GmbH</li>
110 119 <li>Copyright &copy; 2011, 2013, Aparkar</li>
111 120 <li>Copyright &copy; 2012&ndash;2013, xpol</li>
112 121 <li>Copyright &copy; 2013, Dennis Brakhane</li>
113 122 <li>Copyright &copy; 2013, Grzegorz RoΕΌniecki</li>
114 123 <li>Copyright &copy; 2013, Jonathan Sternberg</li>
115 124 <li>Copyright &copy; 2013, Leonardo Carneiro</li>
116 125 <li>Copyright &copy; 2013, Magnus Ericmats</li>
117 126 <li>Copyright &copy; 2013, Martin Vium</li>
118 127 <li>Copyright &copy; 2013, Simon Lopez</li>
119 128 <li>Copyright &copy; 2011&ndash;2012, Augusto Herrmann</li>
120 129 <li>Copyright &copy; 2012, Dan Sheridan</li>
121 130 <li>Copyright &copy; 2012, H Waldo G</li>
122 131 <li>Copyright &copy; 2012, hppj</li>
123 132 <li>Copyright &copy; 2012, Indra Talip</li>
124 133 <li>Copyright &copy; 2012, mikespook</li>
125 134 <li>Copyright &copy; 2012, nansenat16</li>
126 135 <li>Copyright &copy; 2012, Philip Jameson</li>
127 136 <li>Copyright &copy; 2012, Raoul Thill</li>
128 137 <li>Copyright &copy; 2012, Tony Bussieres</li>
129 138 <li>Copyright &copy; 2012, Vincent Duvert</li>
130 139 <li>Copyright &copy; 2012, Vladislav Poluhin</li>
131 140 <li>Copyright &copy; 2012, Zachary Auclair</li>
132 141 <li>Copyright &copy; 2011, Ankit Solanki</li>
133 142 <li>Copyright &copy; 2011, Dmitri Kuznetsov</li>
134 143 <li>Copyright &copy; 2011, Jared Bunting</li>
135 144 <li>Copyright &copy; 2011, Jason Harris</li>
136 145 <li>Copyright &copy; 2011, Les Peabody</li>
137 146 <li>Copyright &copy; 2011, Liad Shani</li>
138 147 <li>Copyright &copy; 2011, Lorenzo M. Catucci</li>
139 148 <li>Copyright &copy; 2011, Matt Zuba</li>
140 149 <li>Copyright &copy; 2011, Nicolas VINOT</li>
141 150 <li>Copyright &copy; 2011, Shawn K. O'Shea</li>
142 151 <li>Copyright &copy; 2010, Łukasz Balcerzak</li>
143 152
144 153 ## We did not list the following copyright holders, given that they appeared
145 154 ## to use for-profit company affiliations in their contribution in the
146 155 ## Mercurial log and therefore I didn't know if copyright was theirs or
147 156 ## their company's.
148 157 ## Copyright &copy; 2011 Thayne Harbaugh <thayne@fusionio.com>
149 158 ## Copyright &copy; 2012 Dies Koper <diesk@fast.au.fujitsu.com>
150 159 ## Copyright &copy; 2012 Erwin Kroon <e.kroon@smartmetersolutions.nl>
151 160 ## Copyright &copy; 2012 Vincent Caron <vcaron@bearstech.com>
152 161 ##
153 162 ## These contributors' contributions may not be copyrightable:
154 163 ## philip.j@hostdime.com in 2012
155 164 ## Stefan Engel <mail@engel-stefan.de> in 2012
156 165 ## Ton Plomp <tcplomp@gmail.com> in 2013
157 166 ##
158 167 </ul>
159 168
160 169 <p>The above are the copyright holders who have submitted direct
161 170 contributions to the Kallithea repository.</p>
162 171
163 172 <p>In the <a href="https://kallithea-scm.org/repos/kallithea">Kallithea
164 173 source code</a>, there is a
165 174 <a href="https://kallithea-scm.org/repos/kallithea/files/tip/LICENSE.md">list
166 175 of third-party libraries and code that Kallithea incorporates</a>.</p>
167 176
168 177 <p>The front-end contains a <a href="${h.url('/LICENSES.txt')}">list of
169 178 software that is used to build the front-end</a> but isn't distributed as a
170 179 part of Kallithea.</p>
171 180
172 181 </div>
173 182 </div>
174 183
175 184 </%def>
@@ -1,542 +1,542 b''
1 1 ## -*- coding: utf-8 -*-
2 2 <%inherit file="root.html"/>
3 3
4 4 <!-- CONTENT -->
5 5 <div id="content" class="container-fluid">
6 6 ${self.flash_msg()}
7 7 <div id="main">
8 8 ${next.main()}
9 9 </div>
10 10 </div>
11 11 <!-- END CONTENT -->
12 12
13 13 <!-- FOOTER -->
14 14 <div class="footer navbar navbar-inverse">
15 15 <span class="navbar-text pull-left">
16 16 ${_('Server instance: %s') % c.instance_id if c.instance_id else ''}
17 17 </span>
18 18 <span class="navbar-text pull-right">
19 19 This site is powered by
20 20 %if c.visual.show_version:
21 21 <a class="navbar-link" href="${h.url('kallithea_project_url')}" target="_blank">Kallithea</a> ${c.kallithea_version},
22 22 %else:
23 23 <a class="navbar-link" href="${h.url('kallithea_project_url')}" target="_blank">Kallithea</a>,
24 24 %endif
25 25 which is
26 <a class="navbar-link" href="${h.canonical_url('about')}#copyright">&copy; 2010&ndash;2018 by various authors &amp; licensed under GPLv3</a>.
26 <a class="navbar-link" href="${h.canonical_url('about')}#copyright">&copy; 2010&ndash;2019 by various authors &amp; licensed under GPLv3</a>.
27 27 %if c.issues_url:
28 28 &ndash; <a class="navbar-link" href="${c.issues_url}" target="_blank">${_('Support')}</a>
29 29 %endif
30 30 </span>
31 31 </div>
32 32
33 33 <!-- END FOOTER -->
34 34
35 35 ### MAKO DEFS ###
36 36
37 37 <%block name="branding_title">
38 38 %if c.site_name:
39 39 &middot; ${c.site_name}
40 40 %endif
41 41 </%block>
42 42
43 43 <%def name="flash_msg()">
44 44 <%include file="/base/flash_msg.html"/>
45 45 </%def>
46 46
47 47 <%def name="breadcrumbs()">
48 48 <div class="panel-title">
49 49 ${self.breadcrumbs_links()}
50 50 </div>
51 51 </%def>
52 52
53 53 <%def name="admin_menu()">
54 54 <ul class="dropdown-menu" role="menu">
55 55 <li><a href="${h.url('admin_home')}"><i class="icon-book"></i>${_('Admin Journal')}</a></li>
56 56 <li><a href="${h.url('repos')}"><i class="icon-database"></i>${_('Repositories')}</a></li>
57 57 <li><a href="${h.url('repos_groups')}"><i class="icon-folder"></i>${_('Repository Groups')}</a></li>
58 58 <li><a href="${h.url('users')}"><i class="icon-user"></i>${_('Users')}</a></li>
59 59 <li><a href="${h.url('users_groups')}"><i class="icon-users"></i>${_('User Groups')}</a></li>
60 60 <li><a href="${h.url('admin_permissions')}"><i class="icon-block"></i>${_('Default Permissions')}</a></li>
61 61 <li><a href="${h.url('auth_home')}"><i class="icon-key"></i>${_('Authentication')}</a></li>
62 62 <li><a href="${h.url('defaults')}"><i class="icon-wrench"></i>${_('Repository Defaults')}</a></li>
63 63 <li class="last"><a href="${h.url('admin_settings')}"><i class="icon-gear"></i>${_('Settings')}</a></li>
64 64 </ul>
65 65
66 66 </%def>
67 67
68 68
69 69 ## admin menu used for people that have some admin resources
70 70 <%def name="admin_menu_simple(repositories=None, repository_groups=None, user_groups=None)">
71 71 <ul class="dropdown-menu" role="menu">
72 72 %if repositories:
73 73 <li><a href="${h.url('repos')}"><i class="icon-database"></i>${_('Repositories')}</a></li>
74 74 %endif
75 75 %if repository_groups:
76 76 <li><a href="${h.url('repos_groups')}"><i class="icon-folder"></i>${_('Repository Groups')}</a></li>
77 77 %endif
78 78 %if user_groups:
79 79 <li><a href="${h.url('users_groups')}"><i class="icon-users"></i>${_('User Groups')}</a></li>
80 80 %endif
81 81 </ul>
82 82 </%def>
83 83
84 84 <%def name="repolabel(repo)">
85 85 %if h.is_hg(repo):
86 86 <span class="label label-repo" title="${_('Mercurial repository')}">hg</span>
87 87 %endif
88 88 %if h.is_git(repo):
89 89 <span class="label label-repo" title="${_('Git repository')}">git</span>
90 90 %endif
91 91 </%def>
92 92
93 93 <%def name="repo_context_bar(current=None, rev=None)">
94 94 <% rev = None if rev == 'tip' else rev %>
95 95 <!--- CONTEXT BAR -->
96 96 <nav id="context-bar" class="navbar navbar-inverse">
97 97 <div class="container-fluid">
98 98 <div class="navbar-header">
99 99 <div class="navbar-brand">
100 100 ${repolabel(c.db_repo)}
101 101
102 102 ## public/private
103 103 %if c.db_repo.private:
104 104 <i class="icon-lock"></i>
105 105 %else:
106 106 <i class="icon-globe"></i>
107 107 %endif
108 108 %for group in c.db_repo.groups_with_parents:
109 109 ${h.link_to(group.name, url('repos_group_home', group_name=group.group_name), class_='navbar-link')}
110 110 &raquo;
111 111 %endfor
112 112 ${h.link_to(c.db_repo.just_name, url('summary_home', repo_name=c.db_repo.repo_name), class_='navbar-link')}
113 113
114 114 %if current == 'createfork':
115 115 - ${_('Create Fork')}
116 116 %endif
117 117 </div>
118 118 <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#context-pages" aria-expanded="false">
119 119 <span class="sr-only">Toggle navigation</span>
120 120 <span class="icon-bar"></span>
121 121 <span class="icon-bar"></span>
122 122 <span class="icon-bar"></span>
123 123 </button>
124 124 </div>
125 125 <div id="context-pages" class="navbar-collapse collapse">
126 126 <ul class="nav navbar-nav navbar-right">
127 127 <li class="${'active' if current == 'summary' else ''}" data-context="summary"><a href="${h.url('summary_home', repo_name=c.repo_name)}"><i class="icon-doc-text"></i>${_('Summary')}</a></li>
128 128 %if rev:
129 129 <li class="${'active' if current == 'changelog' else ''}" data-context="changelog"><a href="${h.url('changelog_file_home', repo_name=c.repo_name, revision=rev, f_path='')}"><i class="icon-clock"></i>${_('Changelog')}</a></li>
130 130 %else:
131 131 <li class="${'active' if current == 'changelog' else ''}" data-context="changelog"><a href="${h.url('changelog_home', repo_name=c.repo_name)}"><i class="icon-clock"></i>${_('Changelog')}</a></li>
132 132 %endif
133 133 <li class="${'active' if current == 'files' else ''}" data-context="files"><a href="${h.url('files_home', repo_name=c.repo_name, revision=rev or 'tip')}"><i class="icon-doc-inv"></i>${_('Files')}</a></li>
134 134 <li class="${'active' if current == 'showpullrequest' else ''}" data-context="showpullrequest">
135 135 <a href="${h.url('pullrequest_show_all',repo_name=c.repo_name)}" title="${_('Show Pull Requests for %s') % c.repo_name}"> <i class="icon-git-pull-request"></i>${_('Pull Requests')}
136 136 %if c.repository_pull_requests:
137 137 <span class="badge">${c.repository_pull_requests}</span>
138 138 %endif
139 139 </a>
140 140 </li>
141 141 <li class="${'active' if current == 'switch-to' else ''}" data-context="switch-to">
142 142 <input id="branch_switcher" name="branch_switcher" type="hidden">
143 143 </li>
144 144 <li class="${'active' if current == 'options' else ''} dropdown" data-context="options">
145 145 %if h.HasRepoPermissionLevel('admin')(c.repo_name):
146 146 <a href="${h.url('edit_repo',repo_name=c.repo_name)}" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false" aria-haspopup="true"><i class="icon-wrench"></i>${_('Options')} <i class="caret"></i></a>
147 147 %else:
148 148 <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false" aria-haspopup="true"><i class="icon-wrench"></i>${_('Options')} <i class="caret"></i></a>
149 149 %endif
150 150 <ul class="dropdown-menu" role="menu" aria-hidden="true">
151 151 %if h.HasRepoPermissionLevel('admin')(c.repo_name):
152 152 <li><a href="${h.url('edit_repo',repo_name=c.repo_name)}"><i class="icon-gear"></i>${_('Settings')}</a></li>
153 153 %endif
154 154 %if c.db_repo.fork:
155 155 <li><a href="${h.url('compare_url',repo_name=c.db_repo.fork.repo_name,org_ref_type=c.db_repo.landing_rev[0],org_ref_name=c.db_repo.landing_rev[1], other_repo=c.repo_name,other_ref_type='branch' if request.GET.get('branch') else c.db_repo.landing_rev[0],other_ref_name=request.GET.get('branch') or c.db_repo.landing_rev[1], merge=1)}">
156 156 <i class="icon-git-compare"></i>${_('Compare Fork')}</a></li>
157 157 %endif
158 158 <li><a href="${h.url('compare_home',repo_name=c.repo_name)}"><i class="icon-git-compare"></i>${_('Compare')}</a></li>
159 159
160 160 <li><a href="${h.url('search_repo',repo_name=c.repo_name)}"><i class="icon-search"></i>${_('Search')}</a></li>
161 161
162 162 %if h.HasRepoPermissionLevel('write')(c.repo_name) and c.db_repo.enable_locking:
163 163 %if c.db_repo.locked[0]:
164 164 <li><a href="${h.url('toggle_locking', repo_name=c.repo_name)}"><i class="icon-lock"></i>${_('Unlock')}</a></li>
165 165 %else:
166 166 <li><a href="${h.url('toggle_locking', repo_name=c.repo_name)}"><i class="icon-lock-open-alt"></i>${_('Lock')}</a></li>
167 167 %endif
168 168 %endif
169 169 ## TODO: this check feels wrong, it would be better to have a check for permissions
170 170 ## also it feels like a job for the controller
171 171 %if request.authuser.username != 'default':
172 172 <li>
173 173 <a href="#" class="${'following' if c.repository_following else 'follow'}" onclick="toggleFollowingRepo(this, ${c.db_repo.repo_id});">
174 174 <span class="show-follow"><i class="icon-heart-empty"></i>${_('Follow')}</span>
175 175 <span class="show-following"><i class="icon-heart"></i>${_('Unfollow')}</span>
176 176 </a>
177 177 </li>
178 178 <li><a href="${h.url('repo_fork_home',repo_name=c.repo_name)}"><i class="icon-git-pull-request"></i>${_('Fork')}</a></li>
179 179 <li><a href="${h.url('pullrequest_home',repo_name=c.repo_name)}"><i class="icon-git-pull-request"></i>${_('Create Pull Request')}</a></li>
180 180 %endif
181 181 </ul>
182 182 </li>
183 183 </ul>
184 184 </div>
185 185 </div>
186 186 </nav>
187 187 <script type="text/javascript">
188 188 $(document).ready(function() {
189 189 var bcache = {};
190 190
191 191 var branch_switcher_placeholder = '<i class="icon-exchange"></i>' + ${h.jshtml(_('Switch To'))} + ' <span class="caret"></span>';
192 192 $("#branch_switcher").select2({
193 193 placeholder: branch_switcher_placeholder,
194 194 dropdownAutoWidth: true,
195 195 sortResults: prefixFirstSort,
196 196 formatResult: function(obj) {
197 197 return obj.text.html_escape();
198 198 },
199 199 formatSelection: function(obj) {
200 200 return obj.text.html_escape();
201 201 },
202 202 formatNoMatches: function(term) {
203 203 return ${h.jshtml(_('No matches found'))};
204 204 },
205 205 escapeMarkup: function(m) {
206 206 if (m == branch_switcher_placeholder)
207 207 return branch_switcher_placeholder;
208 208 return Select2.util.escapeMarkup(m);
209 209 },
210 210 containerCssClass: "branch-switcher",
211 211 dropdownCssClass: "repo-switcher-dropdown",
212 212 query: function(query) {
213 213 var key = 'cache';
214 214 var cached = bcache[key];
215 215 if (cached) {
216 216 var data = {
217 217 results: []
218 218 };
219 219 // filter results
220 220 $.each(cached.results, function() {
221 221 var section = this.text;
222 222 var children = [];
223 223 $.each(this.children, function() {
224 224 if (query.term.length === 0 || this.text.toUpperCase().indexOf(query.term.toUpperCase()) >= 0) {
225 225 children.push({
226 226 'id': this.id,
227 227 'text': this.text,
228 228 'type': this.type,
229 229 'obj': this.obj
230 230 });
231 231 }
232 232 });
233 233 if (children.length !== 0) {
234 234 data.results.push({
235 235 'text': section,
236 236 'children': children
237 237 });
238 238 }
239 239
240 240 });
241 241 query.callback(data);
242 242 } else {
243 243 $.ajax({
244 244 url: pyroutes.url('repo_refs_data', {
245 245 'repo_name': ${h.js(c.repo_name)}
246 246 }),
247 247 data: {},
248 248 dataType: 'json',
249 249 type: 'GET',
250 250 success: function(data) {
251 251 bcache[key] = data;
252 252 query.callback(data);
253 253 }
254 254 });
255 255 }
256 256 }
257 257 });
258 258
259 259 $("#branch_switcher").on('select2-selecting', function(e) {
260 260 e.preventDefault();
261 261 var context = $('#context-bar .active').data('context');
262 262 if (context == 'files') {
263 263 window.location = pyroutes.url('files_home', {
264 264 'repo_name': REPO_NAME,
265 265 'revision': e.choice.id,
266 266 'f_path': '',
267 267 'at': e.choice.text
268 268 });
269 269 } else if (context == 'changelog') {
270 270 if (e.choice.type == 'tag' || e.choice.type == 'book') {
271 271 $("#branch_filter").append($('<'+'option/>').val(e.choice.text));
272 272 }
273 273 $("#branch_filter").val(e.choice.text).change();
274 274 } else {
275 275 window.location = pyroutes.url('changelog_home', {
276 276 'repo_name': ${h.js(c.repo_name)},
277 277 'branch': e.choice.text
278 278 });
279 279 }
280 280 });
281 281 });
282 282 </script>
283 283 <!--- END CONTEXT BAR -->
284 284 </%def>
285 285
286 286 <%def name="menu(current=None)">
287 287 <ul id="quick" class="nav navbar-nav navbar-right">
288 288 <!-- repo switcher -->
289 289 <li class="${'active' if current == 'repositories' else ''}">
290 290 <input id="repo_switcher" name="repo_switcher" type="hidden">
291 291 </li>
292 292
293 293 ##ROOT MENU
294 294 %if request.authuser.username != 'default':
295 295 <li class="${'active' if current == 'journal' else ''}">
296 296 <a class="menu_link" title="${_('Show recent activity')}" href="${h.url('journal')}">
297 297 <i class="icon-book"></i>${_('Journal')}
298 298 </a>
299 299 </li>
300 300 %else:
301 301 <li class="${'active' if current == 'journal' else ''}">
302 302 <a class="menu_link" title="${_('Public journal')}" href="${h.url('public_journal')}">
303 303 <i class="icon-book"></i>${_('Public journal')}
304 304 </a>
305 305 </li>
306 306 %endif
307 307 <li class="${'active' if current == 'gists' else ''} dropdown">
308 308 <a class="menu_link dropdown-toggle" data-toggle="dropdown" role="button" title="${_('Show public gists')}" href="${h.url('gists')}">
309 309 <i class="icon-clippy"></i>${_('Gists')} <span class="caret"></span>
310 310 </a>
311 311 <ul class="dropdown-menu" role="menu">
312 312 <li><a href="${h.url('new_gist', public=1)}"><i class="icon-paste"></i>${_('Create New Gist')}</a></li>
313 313 <li><a href="${h.url('gists')}"><i class="icon-globe"></i>${_('All Public Gists')}</a></li>
314 314 %if request.authuser.username != 'default':
315 315 <li><a href="${h.url('gists', public=1)}"><i class="icon-user"></i>${_('My Public Gists')}</a></li>
316 316 <li><a href="${h.url('gists', private=1)}"><i class="icon-lock"></i>${_('My Private Gists')}</a></li>
317 317 %endif
318 318 </ul>
319 319 </li>
320 320 <li class="${'active' if current == 'search' else ''}">
321 321 <a class="menu_link" title="${_('Search in repositories')}" href="${h.url('search')}">
322 322 <i class="icon-search"></i>${_('Search')}
323 323 </a>
324 324 </li>
325 325 % if h.HasPermissionAny('hg.admin')('access admin main page'):
326 326 <li class="${'active' if current == 'admin' else ''} dropdown">
327 327 <a class="menu_link dropdown-toggle" data-toggle="dropdown" role="button" title="${_('Admin')}" href="${h.url('admin_home')}">
328 328 <i class="icon-gear"></i>${_('Admin')} <span class="caret"></span>
329 329 </a>
330 330 ${admin_menu()}
331 331 </li>
332 332 % elif request.authuser.repositories_admin or request.authuser.repository_groups_admin or request.authuser.user_groups_admin:
333 333 <li class="${'active' if current == 'admin' else ''} dropdown">
334 334 <a class="menu_link dropdown-toggle" data-toggle="dropdown" role="button" title="${_('Admin')}" href="">
335 335 <i class="icon-gear"></i>${_('Admin')}
336 336 </a>
337 337 ${admin_menu_simple(request.authuser.repositories_admin,
338 338 request.authuser.repository_groups_admin,
339 339 request.authuser.user_groups_admin or h.HasPermissionAny('hg.usergroup.create.true')())}
340 340 </li>
341 341 % endif
342 342
343 343 <li class="${'active' if current == 'my_pullrequests' else ''}">
344 344 <a class="menu_link" title="${_('My Pull Requests')}" href="${h.url('my_pullrequests')}">
345 345 <i class="icon-git-pull-request"></i>${_('My Pull Requests')}
346 346 %if c.my_pr_count != 0:
347 347 <span class="badge">${c.my_pr_count}</span>
348 348 %endif
349 349 </a>
350 350 </li>
351 351
352 352 ## USER MENU
353 353 <li class="dropdown">
354 354 <a class="menu_link dropdown-toggle" data-toggle="dropdown" role="button" id="quick_login_link"
355 355 aria-expanded="false" aria-controls="quick_login" href="#">
356 356 ${h.gravatar_div(request.authuser.email, size=20, div_class="icon")}
357 357 %if request.authuser.username != 'default':
358 358 <span class="menu_link_user">${request.authuser.username}</span>
359 359 %else:
360 360 <span>${_('Not Logged In')}</span>
361 361 %endif
362 362 <i class="caret"></i>
363 363 </a>
364 364
365 365 <div class="dropdown-menu user-menu" role="menu">
366 366 <div id="quick_login" role="form" aria-describedby="quick_login_h" aria-hidden="true" class="container-fluid">
367 367 %if request.authuser.username == 'default' or request.authuser.user_id is None:
368 368 ${h.form(h.url('login_home', came_from=request.path_qs), class_='form clearfix')}
369 369 <h4 id="quick_login_h">${_('Login to Your Account')}</h4>
370 370 <label>
371 371 ${_('Username')}:
372 372 ${h.text('username',class_='form-control')}
373 373 </label>
374 374 <label>
375 375 ${_('Password')}:
376 376 ${h.password('password',class_='form-control')}
377 377 </label>
378 378 <div class="password_forgotten">
379 379 ${h.link_to(_('Forgot password?'),h.url('reset_password'))}
380 380 </div>
381 381 <div class="register">
382 382 %if h.HasPermissionAny('hg.admin', 'hg.register.auto_activate', 'hg.register.manual_activate')():
383 383 ${h.link_to(_("Don't have an account?"),h.url('register'))}
384 384 %endif
385 385 </div>
386 386 <div class="submit">
387 387 ${h.submit('sign_in',_('Log In'),class_="btn btn-default btn-xs")}
388 388 </div>
389 389 ${h.end_form()}
390 390 %else:
391 391 <div class="pull-left">
392 392 ${h.gravatar_div(request.authuser.email, size=48, div_class="big_gravatar")}
393 393 <b class="full_name">${request.authuser.full_name_or_username}</b>
394 394 <div class="email">${request.authuser.email}</div>
395 395 </div>
396 396 <div id="quick_login_h" class="pull-right list-group text-right">
397 397 ${h.link_to(_('My Account'),h.url('my_account'),class_='list-group-item')}
398 398 %if not request.authuser.is_external_auth:
399 399 ## Cannot log out if using external (container) authentication.
400 400 ${h.link_to(_('Log Out'), h.url('logout_home'),class_='list-group-item')}
401 401 %endif
402 402 </div>
403 403 %endif
404 404 </div>
405 405 </div>
406 406 </li>
407 407 </ul>
408 408
409 409 <script type="text/javascript">
410 410 $(document).ready(function(){
411 411 var visual_show_public_icon = ${h.js(c.visual.show_public_icon)};
412 412 var cache = {}
413 413 /*format the look of items in the list*/
414 414 var format = function(state){
415 415 if (!state.id){
416 416 return state.text.html_escape(); // optgroup
417 417 }
418 418 var obj_dict = state.obj;
419 419 var tmpl = '';
420 420
421 421 if(obj_dict && state.type == 'repo'){
422 422 tmpl += '<span class="repo-icons">';
423 423 if(obj_dict['repo_type'] === 'hg'){
424 424 tmpl += '<span class="label label-repo" title="${_('Mercurial repository')}">hg</span> ';
425 425 }
426 426 else if(obj_dict['repo_type'] === 'git'){
427 427 tmpl += '<span class="label label-repo" title="${_('Git repository')}">git</span> ';
428 428 }
429 429 if(obj_dict['private']){
430 430 tmpl += '<i class="icon-lock"></i>';
431 431 }
432 432 else if(visual_show_public_icon){
433 433 tmpl += '<i class="icon-globe"></i>';
434 434 }
435 435 tmpl += '</span>';
436 436 }
437 437 if(obj_dict && state.type == 'group'){
438 438 tmpl += '<i class="icon-folder"></i>';
439 439 }
440 440 tmpl += state.text.html_escape();
441 441 return tmpl;
442 442 }
443 443
444 444 var repo_switcher_placeholder = '<i class="icon-database"></i>' + ${h.jshtml(_('Repositories'))} + ' <span class="caret"></span>';
445 445 $("#repo_switcher").select2({
446 446 placeholder: repo_switcher_placeholder,
447 447 dropdownAutoWidth: true,
448 448 sortResults: prefixFirstSort,
449 449 formatResult: format,
450 450 formatSelection: format,
451 451 formatNoMatches: function(term){
452 452 return ${h.jshtml(_('No matches found'))};
453 453 },
454 454 containerCssClass: "repo-switcher",
455 455 dropdownCssClass: "repo-switcher-dropdown",
456 456 escapeMarkup: function(m){
457 457 if (m == repo_switcher_placeholder)
458 458 return repo_switcher_placeholder;
459 459 return Select2.util.escapeMarkup(m);
460 460 },
461 461 query: function(query){
462 462 var key = 'cache';
463 463 var cached = cache[key] ;
464 464 if(cached) {
465 465 var data = {results: []};
466 466 //filter results
467 467 $.each(cached.results, function(){
468 468 var section = this.text;
469 469 var children = [];
470 470 $.each(this.children, function(){
471 471 if(query.term.length == 0 || this.text.toUpperCase().indexOf(query.term.toUpperCase()) >= 0 ){
472 472 children.push({'id': this.id, 'text': this.text, 'type': this.type, 'obj': this.obj});
473 473 }
474 474 });
475 475 if(children.length !== 0){
476 476 data.results.push({'text': section, 'children': children});
477 477 }
478 478
479 479 });
480 480 query.callback(data);
481 481 }else{
482 482 $.ajax({
483 483 url: ${h.js(h.url('repo_switcher_data'))},
484 484 data: {},
485 485 dataType: 'json',
486 486 type: 'GET',
487 487 success: function(data) {
488 488 cache[key] = data;
489 489 query.callback({results: data.results});
490 490 }
491 491 });
492 492 }
493 493 }
494 494 });
495 495
496 496 $("#repo_switcher").on('select2-selecting', function(e){
497 497 e.preventDefault();
498 498 window.location = pyroutes.url('summary_home', {'repo_name': e.val});
499 499 });
500 500
501 501 $(document).on('shown.bs.dropdown', function(event) {
502 502 var dropdown = $(event.target);
503 503
504 504 dropdown.attr('aria-expanded', true);
505 505 dropdown.find('.dropdown-menu').attr('aria-hidden', false);
506 506 });
507 507
508 508 $(document).on('hidden.bs.dropdown', function(event) {
509 509 var dropdown = $(event.target);
510 510
511 511 dropdown.attr('aria-expanded', false);
512 512 dropdown.find('.dropdown-menu').attr('aria-hidden', true);
513 513 });
514 514 });
515 515 </script>
516 516 </%def>
517 517
518 518 <%def name="parent_child_navigation()">
519 519 <div class="pull-left">
520 520 <div class="parent-child-link"
521 521 data-ajax-url="${h.url('changeset_parents',repo_name=c.repo_name, revision=c.changeset.raw_id)}"
522 522 data-linktype="parent"
523 523 data-reponame="${c.repo_name}">
524 524 <i class="icon-left-open"></i><a href="#">${_('Parent rev.')}</a>
525 525 </div>
526 526 </div>
527 527
528 528 <div class="pull-right">
529 529 <div class="parent-child-link"
530 530 data-ajax-url="${h.url('changeset_children',repo_name=c.repo_name, revision=c.changeset.raw_id)}"
531 531 data-linktype="child"
532 532 data-reponame="${c.repo_name}">
533 533 <a href="#">${_('Child rev.')}</a><i class="icon-right-open"></i>
534 534 </div>
535 535 </div>
536 536
537 537 <script type="text/javascript">
538 538 $(document).ready(function(){
539 539 activate_parent_child_links();
540 540 });
541 541 </script>
542 542 </%def>
@@ -1,253 +1,254 b''
1 1 #!/usr/bin/env python2
2 2 # -*- coding: utf-8 -*-
3 3
4 4 """
5 5 Kallithea script for maintaining contributor lists from version control
6 6 history.
7 7
8 8 This script and the data in it is a best effort attempt at reverse engineering
9 9 previous attributions and correlate that with version control history while
10 10 preserving all existing copyright statements and attribution. This script is
11 11 processing and summarizing information found elsewhere - it is not by itself
12 12 making any claims. Comments in the script are an attempt at reverse engineering
13 13 possible explanations - they are not showing any intent or confirming it is
14 14 correct.
15 15
16 16 Three files are generated / modified by this script:
17 17
18 18 kallithea/templates/about.html claims to show copyright holders, and the GPL
19 19 license requires such existing "legal notices" to be preserved. We also try to
20 20 keep it updated with copyright holders, but do not claim it is a correct list.
21 21
22 22 CONTRIBUTORS has the purpose of giving credit where credit is due and list all
23 23 the contributor names in the source.
24 24
25 25 kallithea/templates/base/base.html contains the copyright years in the page
26 26 footer.
27 27
28 28 Both make a best effort of listing all copyright holders, but revision control
29 29 history might be a better and more definitive source.
30 30
31 31 Contributors are sorted "fairly" by copyright year and amount of
32 32 contribution.
33 33
34 34 New contributors are listed, without considering if the contribution contains
35 35 copyrightable work.
36 36
37 37 When the copyright might belong to a different legal entity than the
38 38 contributor, the legal entity is given credit too.
39 39 """
40 40
41 41
42 42 # Some committers are so wrong that it doesn't point at any contributor:
43 43 total_ignore = set()
44 44 total_ignore.add('*** failed to import extension hggit: No module named hggit')
45 45 total_ignore.add('<>')
46 46
47 47 # Normalize some committer names where people have contributed under different
48 48 # names or email addresses:
49 49 name_fixes = {}
50 50 name_fixes['Andrew Shadura'] = "Andrej Shadura <andrew@shadura.me>"
51 51 name_fixes['aparkar'] = "Aparkar <aparkar@icloud.com>"
52 52 name_fixes['Aras Pranckevicius'] = "Aras Pranckevičius <aras@unity3d.com>"
53 53 name_fixes['Augosto Hermann'] = "Augusto Herrmann <augusto.herrmann@planejamento.gov.br>"
54 54 name_fixes['"Bradley M. Kuhn" <bkuhn@ebb.org>'] = "Bradley M. Kuhn <bkuhn@sfconservancy.org>"
55 55 name_fixes['dmitri.kuznetsov'] = "Dmitri Kuznetsov"
56 56 name_fixes['Dmitri Kuznetsov'] = "Dmitri Kuznetsov"
57 57 name_fixes['domruf'] = "Dominik Ruf <dominikruf@gmail.com>"
58 58 name_fixes['Ingo von borstel'] = "Ingo von Borstel <kallithea@planetmaker.de>"
59 59 name_fixes['Jan Heylen'] = "Jan Heylen <heyleke@gmail.com>"
60 60 name_fixes['Jason F. Harris'] = "Jason Harris <jason@jasonfharris.com>"
61 61 name_fixes['Jelmer Vernooij'] = "Jelmer VernooΔ³ <jelmer@samba.org>"
62 62 name_fixes['jfh <jason@jasonfharris.com>'] = "Jason Harris <jason@jasonfharris.com>"
63 63 name_fixes['Leonardo Carneiro<leonardo@unity3d.com>'] = "Leonardo Carneiro <leonardo@unity3d.com>"
64 64 name_fixes['leonardo'] = "Leonardo Carneiro <leonardo@unity3d.com>"
65 65 name_fixes['Leonardo <leo@unity3d.com>'] = "Leonardo Carneiro <leonardo@unity3d.com>"
66 66 name_fixes['Les Peabody'] = "Les Peabody <lpeabody@gmail.com>"
67 67 name_fixes['"Lorenzo M. Catucci" <lorenzo@sancho.ccd.uniroma2.it>'] = "Lorenzo M. Catucci <lorenzo@sancho.ccd.uniroma2.it>"
68 68 name_fixes['Lukasz Balcerzak'] = "Łukasz Balcerzak <lukaszbalcerzak@gmail.com>"
69 69 name_fixes['mao <mao@lins.fju.edu.tw>'] = "Ching-Chen Mao <mao@lins.fju.edu.tw>"
70 70 name_fixes['marcink'] = "Marcin KuΕΊmiΕ„ski <marcin@python-works.com>"
71 71 name_fixes['Marcin Kuzminski'] = "Marcin KuΕΊmiΕ„ski <marcin@python-works.com>"
72 72 name_fixes['nansenat16@null.tw'] = "nansenat16 <nansenat16@null.tw>"
73 73 name_fixes['Peter Vitt'] = "Peter Vitt <petervitt@web.de>"
74 74 name_fixes['philip.j@hostdime.com'] = "Philip Jameson <philip.j@hostdime.com>"
75 75 name_fixes['SΓΈren LΓΈvborg'] = "SΓΈren LΓΈvborg <sorenl@unity3d.com>"
76 76 name_fixes['Thomas De Schampheleire'] = "Thomas De Schampheleire <thomas.de_schampheleire@nokia.com>"
77 77 name_fixes['Weblate'] = "<>"
78 78 name_fixes['xpol'] = "xpol <xpolife@gmail.com>"
79 name_fixes['Lars <devel@sumpfralle.de>'] = "Lars Kruse <devel@sumpfralle.de>"
79 80
80 81
81 82 # Some committer email address domains that indicate that another entity might
82 83 # hold some copyright too:
83 84 domain_extra = {}
84 85 domain_extra['unity3d.com'] = "Unity Technologies"
85 86 domain_extra['rhodecode.com'] = "RhodeCode GmbH"
86 87
87 88 # Repository history show some old contributions that traditionally hasn't been
88 89 # listed in about.html - preserve that:
89 90 no_about = set(total_ignore)
90 91 # The following contributors were traditionally not listed in about.html and it
91 92 # seems unclear if the copyright is personal or belongs to a company.
92 93 no_about.add(('Thayne Harbaugh <thayne@fusionio.com>', '2011'))
93 94 no_about.add(('Dies Koper <diesk@fast.au.fujitsu.com>', '2012'))
94 95 no_about.add(('Erwin Kroon <e.kroon@smartmetersolutions.nl>', '2012'))
95 96 no_about.add(('Vincent Caron <vcaron@bearstech.com>', '2012'))
96 97 # These contributors' contributions might be too small to be copyrightable:
97 98 no_about.add(('philip.j@hostdime.com', '2012'))
98 99 no_about.add(('Stefan Engel <mail@engel-stefan.de>', '2012'))
99 100 no_about.add(('Ton Plomp <tcplomp@gmail.com>', '2013'))
100 101 # Was reworked and contributed later and shadowed by other contributions:
101 102 no_about.add(('Sean Farley <sean.michael.farley@gmail.com>', '2013'))
102 103
103 104 # Preserve contributors listed in about.html but not appearing in repository
104 105 # history:
105 106 other_about = [
106 107 ("2011", "Aparkar <aparkar@icloud.com>"),
107 108 ("2010", "RhodeCode GmbH"),
108 109 ("2011", "RhodeCode GmbH"),
109 110 ("2012", "RhodeCode GmbH"),
110 111 ("2013", "RhodeCode GmbH"),
111 112 ]
112 113
113 114 # Preserve contributors listed in CONTRIBUTORS but not appearing in repository
114 115 # history:
115 116 other_contributors = [
116 117 ("", "Andrew Kesterson <andrew@aklabs.net>"),
117 118 ("", "cejones"),
118 119 ("", "David A. SjΓΈen <david.sjoen@westcon.no>"),
119 120 ("", "James Rhodes <jrhodes@redpointsoftware.com.au>"),
120 121 ("", "Jonas Oberschweiber <jonas.oberschweiber@d-velop.de>"),
121 122 ("", "larikale"),
122 123 ("", "RhodeCode GmbH"),
123 124 ("", "Sebastian Kreutzberger <sebastian@rhodecode.com>"),
124 125 ("", "Steve Romanow <slestak989@gmail.com>"),
125 126 ("", "SteveCohen"),
126 127 ("", "Thomas <thomas@rhodecode.com>"),
127 128 ("", "Thomas Waldmann <tw-public@gmx.de>"),
128 129 ]
129 130
130 131
131 132 import os
132 133 import re
133 134 from collections import defaultdict
134 135
135 136
136 137 def sortkey(x):
137 138 """Return key for sorting contributors "fairly":
138 139 * latest contribution
139 140 * first contribution
140 141 * number of contribution years
141 142 * name (with some unicode normalization)
142 143 The entries must be 2-tuples of a list of string years and the unicode name"""
143 144 return (x[0] and -int(x[0][-1]),
144 145 x[0] and int(x[0][0]),
145 146 -len(x[0]),
146 147 x[1].decode('utf-8').lower().replace(u'\xe9', u'e').replace(u'\u0142', u'l')
147 148 )
148 149
149 150
150 151 def nice_years(l, dash='-', join=' '):
151 152 """Convert a list of years into brief range like '1900-1901, 1921'."""
152 153 if not l:
153 154 return ''
154 155 start = end = int(l[0])
155 156 ranges = []
156 157 for year in l[1:] + [0]:
157 158 year = int(year)
158 159 if year == end + 1:
159 160 end = year
160 161 continue
161 162 if start == end:
162 163 ranges.append('%s' % start)
163 164 else:
164 165 ranges.append('%s%s%s' % (start, dash, end))
165 166 start = end = year
166 167 assert start == 0 and end == 0, (start, end)
167 168 return join.join(ranges)
168 169
169 170
170 171 def insert_entries(
171 172 filename,
172 173 all_entries,
173 174 no_entries,
174 175 domain_extra,
175 176 split_re,
176 177 normalize_name,
177 178 format_f):
178 179 """Update file with contributor information.
179 180 all_entries: list of tuples with year and name
180 181 no_entries: set of names or name and year tuples to ignore
181 182 domain_extra: map domain name to extra credit name
182 183 split_re: regexp matching the part of file to rewrite
183 184 normalize_name: function to normalize names for grouping and display
184 185 format_f: function formatting year list and name to a string
185 186 """
186 187 name_years = defaultdict(set)
187 188
188 189 for year, name in all_entries:
189 190 if name in no_entries or (name, year) in no_entries:
190 191 continue
191 192 domain = name.split('@', 1)[-1].rstrip('>')
192 193 if domain in domain_extra:
193 194 name_years[domain_extra[domain]].add(year)
194 195 name_years[normalize_name(name)].add(year)
195 196
196 197 l = [(list(sorted(year for year in years if year)), name)
197 198 for name, years in name_years.items()]
198 199 l.sort(key=sortkey)
199 200
200 201 with open(filename) as f:
201 202 pre, post = re.split(split_re, f.read())
202 203
203 204 with open(filename, 'w') as f:
204 205 f.write(pre +
205 206 ''.join(format_f(years, name) for years, name in l) +
206 207 post)
207 208
208 209
209 210 def main():
210 211 repo_entries = [
211 212 (year, name_fixes.get(name) or name_fixes.get(name.rsplit('<', 1)[0].strip()) or name)
212 213 for year, name in
213 214 (line.strip().split(' ', 1)
214 215 for line in os.popen("""hg log -r '::.' -T '{date(date,"%Y")} {author}\n'""").readlines())
215 216 ]
216 217
217 218 insert_entries(
218 219 filename='kallithea/templates/about.html',
219 220 all_entries=repo_entries + other_about,
220 221 no_entries=no_about,
221 222 domain_extra=domain_extra,
222 223 split_re=r'(?: <li>Copyright &copy; [^\n]*</li>\n)*',
223 224 normalize_name=lambda name: name.split('<', 1)[0].strip(),
224 225 format_f=lambda years, name: ' <li>Copyright &copy; %s, %s</li>\n' % (nice_years(years, '&ndash;', ', '), name),
225 226 )
226 227
227 228 insert_entries(
228 229 filename='CONTRIBUTORS',
229 230 all_entries=repo_entries + other_contributors,
230 231 no_entries=total_ignore,
231 232 domain_extra=domain_extra,
232 233 split_re=r'(?: [^\n]*\n)*',
233 234 normalize_name=lambda name: name,
234 235 format_f=lambda years, name: (' %s%s%s\n' % (name, ' ' if years else '', nice_years(years))),
235 236 )
236 237
237 238 insert_entries(
238 239 filename='kallithea/templates/base/base.html',
239 240 all_entries=repo_entries,
240 241 no_entries=total_ignore,
241 242 domain_extra={},
242 243 split_re=r'(?<=&copy;) .* (?=by various authors)',
243 244 normalize_name=lambda name: '',
244 245 format_f=lambda years, name: ' ' + nice_years(years, '&ndash;', ', ') + ' ',
245 246 )
246 247
247 248
248 249 if __name__ == '__main__':
249 250 main()
250 251
251 252
252 253 # To list new contributors since last tagging:
253 254 # { hg log -r '::tagged()' -T ' {author}\n {author}\n'; hg log -r '::.' -T ' {author}\n' | sort | uniq; } | sort | uniq -u
General Comments 0
You need to be logged in to leave comments. Login now