##// END OF EJS Templates
SCM:...
Jean-Philippe Lang -
r2744:5b975706932d
parent child
Show More
@@ -1,321 +1,319
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2009 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 require 'SVG/Graph/Bar'
19 19 require 'SVG/Graph/BarHorizontal'
20 20 require 'digest/sha1'
21 21
22 22 class ChangesetNotFound < Exception; end
23 23 class InvalidRevisionParam < Exception; end
24 24
25 25 class RepositoriesController < ApplicationController
26 26 menu_item :repository
27 27 before_filter :find_repository, :except => :edit
28 28 before_filter :find_project, :only => :edit
29 29 before_filter :authorize
30 30 accept_key_auth :revisions
31 31
32 32 rescue_from Redmine::Scm::Adapters::CommandFailed, :with => :show_error_command_failed
33 33
34 34 def edit
35 35 @repository = @project.repository
36 36 if !@repository
37 37 @repository = Repository.factory(params[:repository_scm])
38 38 @repository.project = @project if @repository
39 39 end
40 40 if request.post? && @repository
41 41 @repository.attributes = params[:repository]
42 42 @repository.save
43 43 end
44 44 render(:update) {|page| page.replace_html "tab-content-repository", :partial => 'projects/settings/repository'}
45 45 end
46 46
47 47 def committers
48 48 @committers = @repository.committers
49 49 @users = @project.users
50 50 additional_user_ids = @committers.collect(&:last).collect(&:to_i) - @users.collect(&:id)
51 51 @users += User.find_all_by_id(additional_user_ids) unless additional_user_ids.empty?
52 52 @users.compact!
53 53 @users.sort!
54 54 if request.post? && params[:committers].is_a?(Hash)
55 55 # Build a hash with repository usernames as keys and corresponding user ids as values
56 56 @repository.committer_ids = params[:committers].values.inject({}) {|h, c| h[c.first] = c.last; h}
57 57 flash[:notice] = l(:notice_successful_update)
58 58 redirect_to :action => 'committers', :id => @project
59 59 end
60 60 end
61 61
62 62 def destroy
63 63 @repository.destroy
64 64 redirect_to :controller => 'projects', :action => 'settings', :id => @project, :tab => 'repository'
65 65 end
66 66
67 67 def show
68 68 @repository.fetch_changesets if Setting.autofetch_changesets? && @path.empty?
69 69
70 70 @entries = @repository.entries(@path, @rev)
71 71 if request.xhr?
72 72 @entries ? render(:partial => 'dir_list_content') : render(:nothing => true)
73 73 else
74 74 show_error_not_found and return unless @entries
75 if @path.blank?
76 75 @changesets = @repository.latest_changesets(@path, @rev)
77 end
78 76 @properties = @repository.properties(@path, @rev)
79 77 render :action => 'show'
80 78 end
81 79 end
82 80
83 81 alias_method :browse, :show
84 82
85 83 def changes
86 84 @entry = @repository.entry(@path, @rev)
87 85 show_error_not_found and return unless @entry
88 86 @changesets = @repository.latest_changesets(@path, @rev, Setting.repository_log_display_limit.to_i)
89 87 @properties = @repository.properties(@path, @rev)
90 88 end
91 89
92 90 def revisions
93 91 @changeset_count = @repository.changesets.count
94 92 @changeset_pages = Paginator.new self, @changeset_count,
95 93 per_page_option,
96 94 params['page']
97 95 @changesets = @repository.changesets.find(:all,
98 96 :limit => @changeset_pages.items_per_page,
99 97 :offset => @changeset_pages.current.offset,
100 98 :include => [:user, :repository])
101 99
102 100 respond_to do |format|
103 101 format.html { render :layout => false if request.xhr? }
104 102 format.atom { render_feed(@changesets, :title => "#{@project.name}: #{l(:label_revision_plural)}") }
105 103 end
106 104 end
107 105
108 106 def entry
109 107 @entry = @repository.entry(@path, @rev)
110 108 show_error_not_found and return unless @entry
111 109
112 110 # If the entry is a dir, show the browser
113 111 show and return if @entry.is_dir?
114 112
115 113 @content = @repository.cat(@path, @rev)
116 114 show_error_not_found and return unless @content
117 115 if 'raw' == params[:format] || @content.is_binary_data? || (@entry.size && @entry.size > Setting.file_max_size_displayed.to_i.kilobyte)
118 116 # Force the download
119 117 send_data @content, :filename => @path.split('/').last
120 118 else
121 119 # Prevent empty lines when displaying a file with Windows style eol
122 120 @content.gsub!("\r\n", "\n")
123 121 end
124 122 end
125 123
126 124 def annotate
127 125 @entry = @repository.entry(@path, @rev)
128 126 show_error_not_found and return unless @entry
129 127
130 128 @annotate = @repository.scm.annotate(@path, @rev)
131 129 render_error l(:error_scm_annotate) and return if @annotate.nil? || @annotate.empty?
132 130 end
133 131
134 132 def revision
135 133 @changeset = @repository.changesets.find(:first, :conditions => ["revision LIKE ?", @rev + '%'])
136 134 raise ChangesetNotFound unless @changeset
137 135
138 136 respond_to do |format|
139 137 format.html
140 138 format.js {render :layout => false}
141 139 end
142 140 rescue ChangesetNotFound
143 141 show_error_not_found
144 142 end
145 143
146 144 def diff
147 145 if params[:format] == 'diff'
148 146 @diff = @repository.diff(@path, @rev, @rev_to)
149 147 show_error_not_found and return unless @diff
150 148 filename = "changeset_r#{@rev}"
151 149 filename << "_r#{@rev_to}" if @rev_to
152 150 send_data @diff.join, :filename => "#{filename}.diff",
153 151 :type => 'text/x-patch',
154 152 :disposition => 'attachment'
155 153 else
156 154 @diff_type = params[:type] || User.current.pref[:diff_type] || 'inline'
157 155 @diff_type = 'inline' unless %w(inline sbs).include?(@diff_type)
158 156
159 157 # Save diff type as user preference
160 158 if User.current.logged? && @diff_type != User.current.pref[:diff_type]
161 159 User.current.pref[:diff_type] = @diff_type
162 160 User.current.preference.save
163 161 end
164 162
165 163 @cache_key = "repositories/diff/#{@repository.id}/" + Digest::MD5.hexdigest("#{@path}-#{@rev}-#{@rev_to}-#{@diff_type}")
166 164 unless read_fragment(@cache_key)
167 165 @diff = @repository.diff(@path, @rev, @rev_to)
168 166 show_error_not_found unless @diff
169 167 end
170 168 end
171 169 end
172 170
173 171 def stats
174 172 end
175 173
176 174 def graph
177 175 data = nil
178 176 case params[:graph]
179 177 when "commits_per_month"
180 178 data = graph_commits_per_month(@repository)
181 179 when "commits_per_author"
182 180 data = graph_commits_per_author(@repository)
183 181 end
184 182 if data
185 183 headers["Content-Type"] = "image/svg+xml"
186 184 send_data(data, :type => "image/svg+xml", :disposition => "inline")
187 185 else
188 186 render_404
189 187 end
190 188 end
191 189
192 190 private
193 191 def find_project
194 192 @project = Project.find(params[:id])
195 193 rescue ActiveRecord::RecordNotFound
196 194 render_404
197 195 end
198 196
199 197 def find_repository
200 198 @project = Project.find(params[:id])
201 199 @repository = @project.repository
202 200 render_404 and return false unless @repository
203 201 @path = params[:path].join('/') unless params[:path].nil?
204 202 @path ||= ''
205 203 @rev = params[:rev].blank? ? @repository.default_branch : params[:rev].strip
206 204 @rev_to = params[:rev_to]
207 205 rescue ActiveRecord::RecordNotFound
208 206 render_404
209 207 rescue InvalidRevisionParam
210 208 show_error_not_found
211 209 end
212 210
213 211 def show_error_not_found
214 212 render_error l(:error_scm_not_found)
215 213 end
216 214
217 215 # Handler for Redmine::Scm::Adapters::CommandFailed exception
218 216 def show_error_command_failed(exception)
219 217 render_error l(:error_scm_command_failed, exception.message)
220 218 end
221 219
222 220 def graph_commits_per_month(repository)
223 221 @date_to = Date.today
224 222 @date_from = @date_to << 11
225 223 @date_from = Date.civil(@date_from.year, @date_from.month, 1)
226 224 commits_by_day = repository.changesets.count(:all, :group => :commit_date, :conditions => ["commit_date BETWEEN ? AND ?", @date_from, @date_to])
227 225 commits_by_month = [0] * 12
228 226 commits_by_day.each {|c| commits_by_month[c.first.to_date.months_ago] += c.last }
229 227
230 228 changes_by_day = repository.changes.count(:all, :group => :commit_date, :conditions => ["commit_date BETWEEN ? AND ?", @date_from, @date_to])
231 229 changes_by_month = [0] * 12
232 230 changes_by_day.each {|c| changes_by_month[c.first.to_date.months_ago] += c.last }
233 231
234 232 fields = []
235 233 12.times {|m| fields << month_name(((Date.today.month - 1 - m) % 12) + 1)}
236 234
237 235 graph = SVG::Graph::Bar.new(
238 236 :height => 300,
239 237 :width => 800,
240 238 :fields => fields.reverse,
241 239 :stack => :side,
242 240 :scale_integers => true,
243 241 :step_x_labels => 2,
244 242 :show_data_values => false,
245 243 :graph_title => l(:label_commits_per_month),
246 244 :show_graph_title => true
247 245 )
248 246
249 247 graph.add_data(
250 248 :data => commits_by_month[0..11].reverse,
251 249 :title => l(:label_revision_plural)
252 250 )
253 251
254 252 graph.add_data(
255 253 :data => changes_by_month[0..11].reverse,
256 254 :title => l(:label_change_plural)
257 255 )
258 256
259 257 graph.burn
260 258 end
261 259
262 260 def graph_commits_per_author(repository)
263 261 commits_by_author = repository.changesets.count(:all, :group => :committer)
264 262 commits_by_author.sort! {|x, y| x.last <=> y.last}
265 263
266 264 changes_by_author = repository.changes.count(:all, :group => :committer)
267 265 h = changes_by_author.inject({}) {|o, i| o[i.first] = i.last; o}
268 266
269 267 fields = commits_by_author.collect {|r| r.first}
270 268 commits_data = commits_by_author.collect {|r| r.last}
271 269 changes_data = commits_by_author.collect {|r| h[r.first] || 0}
272 270
273 271 fields = fields + [""]*(10 - fields.length) if fields.length<10
274 272 commits_data = commits_data + [0]*(10 - commits_data.length) if commits_data.length<10
275 273 changes_data = changes_data + [0]*(10 - changes_data.length) if changes_data.length<10
276 274
277 275 # Remove email adress in usernames
278 276 fields = fields.collect {|c| c.gsub(%r{<.+@.+>}, '') }
279 277
280 278 graph = SVG::Graph::BarHorizontal.new(
281 279 :height => 400,
282 280 :width => 800,
283 281 :fields => fields,
284 282 :stack => :side,
285 283 :scale_integers => true,
286 284 :show_data_values => false,
287 285 :rotate_y_labels => false,
288 286 :graph_title => l(:label_commits_per_author),
289 287 :show_graph_title => true
290 288 )
291 289
292 290 graph.add_data(
293 291 :data => commits_data,
294 292 :title => l(:label_revision_plural)
295 293 )
296 294
297 295 graph.add_data(
298 296 :data => changes_data,
299 297 :title => l(:label_change_plural)
300 298 )
301 299
302 300 graph.burn
303 301 end
304 302
305 303 end
306 304
307 305 class Date
308 306 def months_ago(date = Date.today)
309 307 (date.year - self.year)*12 + (date.month - self.month)
310 308 end
311 309
312 310 def weeks_ago(date = Date.today)
313 311 (date.year - self.year)*52 + (date.cweek - self.cweek)
314 312 end
315 313 end
316 314
317 315 class String
318 316 def with_leading_slash
319 317 starts_with?('/') ? self : "/#{self}"
320 318 end
321 319 end
@@ -1,28 +1,28
1 1 <% form_tag({:controller => 'repositories', :action => 'diff', :id => @project, :path => to_path_param(path)}, :method => :get) do %>
2 2 <table class="list changesets">
3 3 <thead><tr>
4 4 <th>#</th>
5 5 <th></th>
6 6 <th></th>
7 7 <th><%= l(:label_date) %></th>
8 8 <th><%= l(:field_author) %></th>
9 9 <th><%= l(:field_comments) %></th>
10 10 </tr></thead>
11 11 <tbody>
12 <% show_diff = entry && entry.is_file? && revisions.size > 1 %>
12 <% show_diff = revisions.size > 1 %>
13 13 <% line_num = 1 %>
14 14 <% revisions.each do |changeset| %>
15 15 <tr class="changeset <%= cycle 'odd', 'even' %>">
16 16 <td class="id"><%= link_to format_revision(changeset.revision), :action => 'revision', :id => project, :rev => changeset.revision %></td>
17 17 <td class="checkbox"><%= radio_button_tag('rev', changeset.revision, (line_num==1), :id => "cb-#{line_num}", :onclick => "$('cbto-#{line_num+1}').checked=true;") if show_diff && (line_num < revisions.size) %></td>
18 18 <td class="checkbox"><%= radio_button_tag('rev_to', changeset.revision, (line_num==2), :id => "cbto-#{line_num}", :onclick => "if ($('cb-#{line_num}').checked==true) {$('cb-#{line_num-1}').checked=true;}") if show_diff && (line_num > 1) %></td>
19 19 <td class="committed_on"><%= format_time(changeset.committed_on) %></td>
20 20 <td class="author"><%=h changeset.author %></td>
21 21 <td class="comments"><%= textilizable(truncate_at_line_break(changeset.comments)) %></td>
22 22 </tr>
23 23 <% line_num += 1 %>
24 24 <% end %>
25 25 </tbody>
26 26 </table>
27 27 <%= submit_tag(l(:label_view_diff), :name => nil) if show_diff %>
28 28 <% end %>
@@ -1,23 +1,23
1 <h2><%= l(:label_revision) %> <%= format_revision(@rev) %> <%= @path.gsub(/^.*\//, '') %></h2>
1 <h2><%= l(:label_revision) %> <%= format_revision(@rev_to) + ':' if @rev_to %><%= format_revision(@rev) %> <%=h @path %></h2>
2 2
3 3 <!-- Choose view type -->
4 4 <% form_tag({}, :method => 'get') do %>
5 5 <%= hidden_field_tag('rev', params[:rev]) if params[:rev] %>
6 6 <%= hidden_field_tag('rev_to', params[:rev_to]) if params[:rev_to] %>
7 7 <p><label><%= l(:label_view_diff) %></label>
8 8 <%= select_tag 'type', options_for_select([[l(:label_diff_inline), "inline"], [l(:label_diff_side_by_side), "sbs"]], @diff_type), :onchange => "if (this.value != '') {this.form.submit()}" %></p>
9 9 <% end %>
10 10
11 11 <% cache(@cache_key) do -%>
12 12 <%= render :partial => 'common/diff', :locals => {:diff => @diff, :diff_type => @diff_type} %>
13 13 <% end -%>
14 14
15 15 <% other_formats_links do |f| %>
16 16 <%= f.link_to 'Diff', :url => params, :caption => 'Unified diff' %>
17 17 <% end %>
18 18
19 19 <% html_title(with_leading_slash(@path), 'Diff') -%>
20 20
21 21 <% content_for :header_tags do %>
22 22 <%= stylesheet_link_tag "scm" %>
23 23 <% end %>
@@ -1,32 +1,38
1 1 <%= call_hook(:view_repositories_show_contextual, { :repository => @repository, :project => @project }) %>
2 2
3 3 <div class="contextual">
4 4 <%= render :partial => 'navigation' %>
5 5 </div>
6 6
7 7 <h2><%= render :partial => 'breadcrumbs', :locals => { :path => @path, :kind => 'dir', :revision => @rev } %></h2>
8 8
9 9 <% if !@entries.nil? && authorize_for('repositories', 'browse') %>
10 10 <%= render :partial => 'dir_list' %>
11 11 <% end %>
12 12
13 13 <%= render_properties(@properties) %>
14 14
15 15 <% if @changesets && !@changesets.empty? && authorize_for('repositories', 'revisions') %>
16 16 <h3><%= l(:label_latest_revision_plural) %></h3>
17 <%= render :partial => 'revisions', :locals => {:project => @project, :path => '', :revisions => @changesets, :entry => nil }%>
17 <%= render :partial => 'revisions', :locals => {:project => @project, :path => @path, :revisions => @changesets, :entry => nil }%>
18
19 <% if @path.blank? %>
18 20 <p><%= link_to l(:label_view_all_revisions), :action => 'revisions', :id => @project %></p>
21 <% else %>
22 <p><%= link_to l(:label_view_revisions), :action => 'changes', :path => to_path_param(@path), :id => @project %></p>
23 <% end %>
24
19 25 <% content_for :header_tags do %>
20 26 <%= auto_discovery_link_tag(:atom, params.merge({:format => 'atom', :action => 'revisions', :id => @project, :page => nil, :key => User.current.rss_key})) %>
21 27 <% end %>
22 28
23 29 <% other_formats_links do |f| %>
24 30 <%= f.link_to 'Atom', :url => {:action => 'revisions', :id => @project, :key => User.current.rss_key} %>
25 31 <% end %>
26 32 <% end %>
27 33
28 34 <% content_for :header_tags do %>
29 35 <%= stylesheet_link_tag "scm" %>
30 36 <% end %>
31 37
32 38 <% html_title(l(:label_repository)) -%>
@@ -1,840 +1,840
1 1 # French translations for Ruby on Rails
2 2 # by Christian Lescuyer (christian@flyingcoders.com)
3 3 # contributor: Sebastien Grosjean - ZenCocoon.com
4 4
5 5 fr:
6 6 date:
7 7 formats:
8 8 default: "%d/%m/%Y"
9 9 short: "%e %b"
10 10 long: "%e %B %Y"
11 11 long_ordinal: "%e %B %Y"
12 12 only_day: "%e"
13 13
14 14 day_names: [dimanche, lundi, mardi, mercredi, jeudi, vendredi, samedi]
15 15 abbr_day_names: [dim, lun, mar, mer, jeu, ven, sam]
16 16 month_names: [~, janvier, fΓ©vrier, mars, avril, mai, juin, juillet, aoΓ»t, septembre, octobre, novembre, dΓ©cembre]
17 17 abbr_month_names: [~, jan., fΓ©v., mar., avr., mai, juin, juil., aoΓ»t, sept., oct., nov., dΓ©c.]
18 18 order: [ :day, :month, :year ]
19 19
20 20 time:
21 21 formats:
22 22 default: "%d/%m/%Y %H:%M"
23 23 time: "%H:%M"
24 24 short: "%d %b %H:%M"
25 25 long: "%A %d %B %Y %H:%M:%S %Z"
26 26 long_ordinal: "%A %d %B %Y %H:%M:%S %Z"
27 27 only_second: "%S"
28 28 am: 'am'
29 29 pm: 'pm'
30 30
31 31 datetime:
32 32 distance_in_words:
33 33 half_a_minute: "30 secondes"
34 34 less_than_x_seconds:
35 35 zero: "moins d'une seconde"
36 36 one: "moins de 1Β seconde"
37 37 other: "moins de {{count}}Β secondes"
38 38 x_seconds:
39 39 one: "1Β seconde"
40 40 other: "{{count}}Β secondes"
41 41 less_than_x_minutes:
42 42 zero: "moins d'une minute"
43 43 one: "moins de 1Β minute"
44 44 other: "moins de {{count}}Β minutes"
45 45 x_minutes:
46 46 one: "1Β minute"
47 47 other: "{{count}}Β minutes"
48 48 about_x_hours:
49 49 one: "environ une heure"
50 50 other: "environ {{count}}Β heures"
51 51 x_days:
52 52 one: "1Β jour"
53 53 other: "{{count}}Β jours"
54 54 about_x_months:
55 55 one: "environ un mois"
56 56 other: "environ {{count}}Β mois"
57 57 x_months:
58 58 one: "1Β mois"
59 59 other: "{{count}}Β mois"
60 60 about_x_years:
61 61 one: "environ un an"
62 62 other: "environ {{count}}Β ans"
63 63 over_x_years:
64 64 one: "plus d'un an"
65 65 other: "plus de {{count}}Β ans"
66 66 prompts:
67 67 year: "AnnΓ©e"
68 68 month: "Mois"
69 69 day: "Jour"
70 70 hour: "Heure"
71 71 minute: "Minute"
72 72 second: "Seconde"
73 73
74 74 number:
75 75 format:
76 76 precision: 3
77 77 separator: ','
78 78 delimiter: 'Β '
79 79 currency:
80 80 format:
81 81 unit: '€'
82 82 precision: 2
83 83 format: '%nΒ %u'
84 84 human:
85 85 format:
86 86 precision: 2
87 87 storage_units: [ Octet, ko, Mo, Go, To ]
88 88
89 89 support:
90 90 array:
91 91 sentence_connector: 'et'
92 92 skip_last_comma: true
93 93 word_connector: ", "
94 94 two_words_connector: " et "
95 95 last_word_connector: " et "
96 96
97 97 activerecord:
98 98 errors:
99 99 template:
100 100 header:
101 101 one: "Impossible d'enregistrer {{model}}: 1 erreur"
102 102 other: "Impossible d'enregistrer {{model}}: {{count}} erreurs."
103 103 body: "Veuillez vΓ©rifier les champs suivantsΒ :"
104 104 messages:
105 105 inclusion: "n'est pas inclus(e) dans la liste"
106 106 exclusion: "n'est pas disponible"
107 107 invalid: "n'est pas valide"
108 108 confirmation: "ne concorde pas avec la confirmation"
109 109 accepted: "doit Γͺtre acceptΓ©(e)"
110 110 empty: "doit Γͺtre renseignΓ©(e)"
111 111 blank: "doit Γͺtre renseignΓ©(e)"
112 112 too_long: "est trop long (pas plus de {{count}} caractères)"
113 113 too_short: "est trop court (au moins {{count}} caractères)"
114 114 wrong_length: "ne fait pas la bonne longueur (doit comporter {{count}} caractères)"
115 115 taken: "est dΓ©jΓ  utilisΓ©"
116 116 not_a_number: "n'est pas un nombre"
117 117 greater_than: "doit Γͺtre supΓ©rieur Γ  {{count}}"
118 118 greater_than_or_equal_to: "doit Γͺtre supΓ©rieur ou Γ©gal Γ  {{count}}"
119 119 equal_to: "doit Γͺtre Γ©gal Γ  {{count}}"
120 120 less_than: "doit Γͺtre infΓ©rieur Γ  {{count}}"
121 121 less_than_or_equal_to: "doit Γͺtre infΓ©rieur ou Γ©gal Γ  {{count}}"
122 122 odd: "doit Γͺtre impair"
123 123 even: "doit Γͺtre pair"
124 124 greater_than_start_date: "doit Γͺtre postΓ©rieure Γ  la date de dΓ©but"
125 125 not_same_project: "n'appartient pas au mΓͺme projet"
126 126 circular_dependency: "Cette relation crΓ©erait une dΓ©pendance circulaire"
127 127
128 128 actionview_instancetag_blank_option: Choisir
129 129
130 130 general_text_No: 'Non'
131 131 general_text_Yes: 'Oui'
132 132 general_text_no: 'non'
133 133 general_text_yes: 'oui'
134 134 general_lang_name: 'FranΓ§ais'
135 135 general_csv_separator: ';'
136 136 general_csv_decimal_separator: ','
137 137 general_csv_encoding: ISO-8859-1
138 138 general_pdf_encoding: ISO-8859-1
139 139 general_first_day_of_week: '1'
140 140
141 141 notice_account_updated: Le compte a été mis à jour avec succès.
142 142 notice_account_invalid_creditentials: Identifiant ou mot de passe invalide.
143 143 notice_account_password_updated: Mot de passe mis à jour avec succès.
144 144 notice_account_wrong_password: Mot de passe incorrect
145 145 notice_account_register_done: Un message contenant les instructions pour activer votre compte vous a Γ©tΓ© envoyΓ©.
146 146 notice_account_unknown_email: Aucun compte ne correspond Γ  cette adresse.
147 147 notice_can_t_change_password: Ce compte utilise une authentification externe. Impossible de changer le mot de passe.
148 148 notice_account_lost_email_sent: Un message contenant les instructions pour choisir un nouveau mot de passe vous a Γ©tΓ© envoyΓ©.
149 149 notice_account_activated: Votre compte a Γ©tΓ© activΓ©. Vous pouvez Γ  prΓ©sent vous connecter.
150 150 notice_successful_create: Création effectuée avec succès.
151 151 notice_successful_update: Mise à jour effectuée avec succès.
152 152 notice_successful_delete: Suppression effectuée avec succès.
153 153 notice_successful_connection: Connection rΓ©ussie.
154 154 notice_file_not_found: "La page Γ  laquelle vous souhaitez accΓ©der n'existe pas ou a Γ©tΓ© supprimΓ©e."
155 155 notice_locking_conflict: Les donnΓ©es ont Γ©tΓ© mises Γ  jour par un autre utilisateur. Mise Γ  jour impossible.
156 156 notice_not_authorized: "Vous n'Γͺtes pas autorisΓ©s Γ  accΓ©der Γ  cette page."
157 157 notice_email_sent: "Un email a Γ©tΓ© envoyΓ© Γ  {{value}}"
158 158 notice_email_error: "Erreur lors de l'envoi de l'email ({{value}})"
159 159 notice_feeds_access_key_reseted: "Votre clé d'accès aux flux RSS a été réinitialisée."
160 160 notice_failed_to_save_issues: "{{count}} demande(s) sur les {{total}} sΓ©lectionnΓ©es n'ont pas pu Γͺtre mise(s) Γ  jour: {{ids}}."
161 161 notice_no_issue_selected: "Aucune demande sΓ©lectionnΓ©e ! Cochez les demandes que vous voulez mettre Γ  jour."
162 162 notice_account_pending: "Votre compte a été créé et attend l'approbation de l'administrateur."
163 163 notice_default_data_loaded: Paramétrage par défaut chargé avec succès.
164 164 notice_unable_delete_version: Impossible de supprimer cette version.
165 165
166 166 error_can_t_load_default_data: "Une erreur s'est produite lors du chargement du paramΓ©trage: {{value}}"
167 167 error_scm_not_found: "L'entrΓ©e et/ou la rΓ©vision demandΓ©e n'existe pas dans le dΓ©pΓ΄t."
168 168 error_scm_command_failed: "Une erreur s'est produite lors de l'accès au dépôt: {{value}}"
169 169 error_scm_annotate: "L'entrΓ©e n'existe pas ou ne peut pas Γͺtre annotΓ©e."
170 170 error_issue_not_found_in_project: "La demande n'existe pas ou n'appartient pas Γ  ce projet"
171 171
172 172 warning_attachments_not_saved: "{{count}} fichier(s) n'ont pas pu Γͺtre sauvegardΓ©s."
173 173
174 174 mail_subject_lost_password: "Votre mot de passe {{value}}"
175 175 mail_body_lost_password: 'Pour changer votre mot de passe, cliquez sur le lien suivant:'
176 176 mail_subject_register: "Activation de votre compte {{value}}"
177 177 mail_body_register: 'Pour activer votre compte, cliquez sur le lien suivant:'
178 178 mail_body_account_information_external: "Vous pouvez utiliser votre compte {{value}} pour vous connecter."
179 179 mail_body_account_information: Paramètres de connexion de votre compte
180 180 mail_subject_account_activation_request: "Demande d'activation d'un compte {{value}}"
181 181 mail_body_account_activation_request: "Un nouvel utilisateur ({{value}}) s'est inscrit. Son compte nΓ©cessite votre approbation:"
182 182 mail_subject_reminder: "{{count}} demande(s) arrivent Γ  Γ©chΓ©ance"
183 183 mail_body_reminder: "{{count}} demande(s) qui vous sont assignΓ©es arrivent Γ  Γ©chΓ©ance dans les {{days}} prochains jours:"
184 184 mail_subject_wiki_content_added: "Page wiki '{{page}}' ajoutΓ©e"
185 185 mail_body_wiki_content_added: "La page wiki '{{page}}' a Γ©tΓ© ajoutΓ©e par {{author}}."
186 186 mail_subject_wiki_content_updated: "Page wiki '{{page}}' mise Γ  jour"
187 187 mail_body_wiki_content_updated: "La page wiki '{{page}}' a Γ©tΓ© mise Γ  jour par {{author}}."
188 188
189 189 gui_validation_error: 1 erreur
190 190 gui_validation_error_plural: "{{count}} erreurs"
191 191
192 192 field_name: Nom
193 193 field_description: Description
194 194 field_summary: RΓ©sumΓ©
195 195 field_is_required: Obligatoire
196 196 field_firstname: PrΓ©nom
197 197 field_lastname: Nom
198 198 field_mail: Email
199 199 field_filename: Fichier
200 200 field_filesize: Taille
201 201 field_downloads: TΓ©lΓ©chargements
202 202 field_author: Auteur
203 203 field_created_on: Créé
204 204 field_updated_on: Mis Γ  jour
205 205 field_field_format: Format
206 206 field_is_for_all: Pour tous les projets
207 207 field_possible_values: Valeurs possibles
208 208 field_regexp: Expression régulière
209 209 field_min_length: Longueur minimum
210 210 field_max_length: Longueur maximum
211 211 field_value: Valeur
212 212 field_category: CatΓ©gorie
213 213 field_title: Titre
214 214 field_project: Projet
215 215 field_issue: Demande
216 216 field_status: Statut
217 217 field_notes: Notes
218 218 field_is_closed: Demande fermΓ©e
219 219 field_is_default: Valeur par dΓ©faut
220 220 field_tracker: Tracker
221 221 field_subject: Sujet
222 222 field_due_date: EchΓ©ance
223 223 field_assigned_to: AssignΓ© Γ 
224 224 field_priority: PrioritΓ©
225 225 field_fixed_version: Version cible
226 226 field_user: Utilisateur
227 227 field_role: RΓ΄le
228 228 field_homepage: Site web
229 229 field_is_public: Public
230 230 field_parent: Sous-projet de
231 231 field_is_in_chlog: Demandes affichΓ©es dans l'historique
232 232 field_is_in_roadmap: Demandes affichΓ©es dans la roadmap
233 233 field_login: Identifiant
234 234 field_mail_notification: Notifications par mail
235 235 field_admin: Administrateur
236 236 field_last_login_on: Dernière connexion
237 237 field_language: Langue
238 238 field_effective_date: Date
239 239 field_password: Mot de passe
240 240 field_new_password: Nouveau mot de passe
241 241 field_password_confirmation: Confirmation
242 242 field_version: Version
243 243 field_type: Type
244 244 field_host: HΓ΄te
245 245 field_port: Port
246 246 field_account: Compte
247 247 field_base_dn: Base DN
248 248 field_attr_login: Attribut Identifiant
249 249 field_attr_firstname: Attribut PrΓ©nom
250 250 field_attr_lastname: Attribut Nom
251 251 field_attr_mail: Attribut Email
252 252 field_onthefly: CrΓ©ation des utilisateurs Γ  la volΓ©e
253 253 field_start_date: DΓ©but
254 254 field_done_ratio: % RΓ©alisΓ©
255 255 field_auth_source: Mode d'authentification
256 256 field_hide_mail: Cacher mon adresse mail
257 257 field_comments: Commentaire
258 258 field_url: URL
259 259 field_start_page: Page de dΓ©marrage
260 260 field_subproject: Sous-projet
261 261 field_hours: Heures
262 262 field_activity: ActivitΓ©
263 263 field_spent_on: Date
264 264 field_identifier: Identifiant
265 265 field_is_filter: UtilisΓ© comme filtre
266 266 field_issue_to: Demande liΓ©e
267 267 field_delay: Retard
268 268 field_assignable: Demandes assignables Γ  ce rΓ΄le
269 269 field_redirect_existing_links: Rediriger les liens existants
270 270 field_estimated_hours: Temps estimΓ©
271 271 field_column_names: Colonnes
272 272 field_time_zone: Fuseau horaire
273 273 field_searchable: UtilisΓ© pour les recherches
274 274 field_default_value: Valeur par dΓ©faut
275 275 field_comments_sorting: Afficher les commentaires
276 276 field_parent_title: Page parent
277 277 field_editable: Modifiable
278 278 field_watcher: Observateur
279 279 field_identity_url: URL OpenID
280 280 field_content: Contenu
281 281 field_group_by: Grouper par
282 282
283 283 setting_app_title: Titre de l'application
284 284 setting_app_subtitle: Sous-titre de l'application
285 285 setting_welcome_text: Texte d'accueil
286 286 setting_default_language: Langue par dΓ©faut
287 287 setting_login_required: Authentification obligatoire
288 288 setting_self_registration: Inscription des nouveaux utilisateurs
289 289 setting_attachment_max_size: Taille max des fichiers
290 290 setting_issues_export_limit: Limite export demandes
291 291 setting_mail_from: Adresse d'Γ©mission
292 292 setting_bcc_recipients: Destinataires en copie cachΓ©e (cci)
293 293 setting_plain_text_mail: Mail texte brut (non HTML)
294 294 setting_host_name: Nom d'hΓ΄te et chemin
295 295 setting_text_formatting: Formatage du texte
296 296 setting_wiki_compression: Compression historique wiki
297 297 setting_feeds_limit: Limite du contenu des flux RSS
298 298 setting_default_projects_public: DΓ©finir les nouveaux projects comme publics par dΓ©faut
299 299 setting_autofetch_changesets: RΓ©cupΓ©ration auto. des commits
300 300 setting_sys_api_enabled: Activer les WS pour la gestion des dΓ©pΓ΄ts
301 301 setting_commit_ref_keywords: Mot-clΓ©s de rΓ©fΓ©rencement
302 302 setting_commit_fix_keywords: Mot-clΓ©s de rΓ©solution
303 303 setting_autologin: Autologin
304 304 setting_date_format: Format de date
305 305 setting_time_format: Format d'heure
306 306 setting_cross_project_issue_relations: Autoriser les relations entre demandes de diffΓ©rents projets
307 307 setting_issue_list_default_columns: Colonnes affichΓ©es par dΓ©faut sur la liste des demandes
308 308 setting_repositories_encodings: Encodages des dΓ©pΓ΄ts
309 309 setting_commit_logs_encoding: Encodage des messages de commit
310 310 setting_emails_footer: Pied-de-page des emails
311 311 setting_protocol: Protocole
312 312 setting_per_page_options: Options d'objets affichΓ©s par page
313 313 setting_user_format: Format d'affichage des utilisateurs
314 314 setting_activity_days_default: Nombre de jours affichΓ©s sur l'activitΓ© des projets
315 315 setting_display_subprojects_issues: Afficher par dΓ©faut les demandes des sous-projets sur les projets principaux
316 316 setting_enabled_scm: SCM activΓ©s
317 317 setting_mail_handler_api_enabled: "Activer le WS pour la rΓ©ception d'emails"
318 318 setting_mail_handler_api_key: ClΓ© de protection de l'API
319 319 setting_sequential_project_identifiers: GΓ©nΓ©rer des identifiants de projet sΓ©quentiels
320 320 setting_gravatar_enabled: Afficher les Gravatar des utilisateurs
321 321 setting_diff_max_lines_displayed: Nombre maximum de lignes de diff affichΓ©es
322 322 setting_file_max_size_displayed: Taille maximum des fichiers texte affichΓ©s en ligne
323 323 setting_repository_log_display_limit: "Nombre maximum de revisions affichΓ©es sur l'historique d'un fichier"
324 324 setting_openid: "Autoriser l'authentification et l'enregistrement OpenID"
325 325 setting_password_min_length: Longueur minimum des mots de passe
326 326 setting_new_project_user_role_id: RΓ΄le donnΓ© Γ  un utilisateur non-administrateur qui crΓ©e un projet
327 327
328 328 permission_add_project: CrΓ©er un projet
329 329 permission_edit_project: Modifier le projet
330 330 permission_select_project_modules: Choisir les modules
331 331 permission_manage_members: GΓ©rer les members
332 332 permission_manage_versions: GΓ©rer les versions
333 333 permission_manage_categories: GΓ©rer les catΓ©gories de demandes
334 334 permission_add_issues: CrΓ©er des demandes
335 335 permission_edit_issues: Modifier les demandes
336 336 permission_manage_issue_relations: GΓ©rer les relations
337 337 permission_add_issue_notes: Ajouter des notes
338 338 permission_edit_issue_notes: Modifier les notes
339 339 permission_edit_own_issue_notes: Modifier ses propres notes
340 340 permission_move_issues: DΓ©placer les demandes
341 341 permission_delete_issues: Supprimer les demandes
342 342 permission_manage_public_queries: GΓ©rer les requΓͺtes publiques
343 343 permission_save_queries: Sauvegarder les requΓͺtes
344 344 permission_view_gantt: Voir le gantt
345 345 permission_view_calendar: Voir le calendrier
346 346 permission_view_issue_watchers: Voir la liste des observateurs
347 347 permission_add_issue_watchers: Ajouter des observateurs
348 348 permission_log_time: Saisir le temps passΓ©
349 349 permission_view_time_entries: Voir le temps passΓ©
350 350 permission_edit_time_entries: Modifier les temps passΓ©s
351 351 permission_edit_own_time_entries: Modifier son propre temps passΓ©
352 352 permission_manage_news: GΓ©rer les annonces
353 353 permission_comment_news: Commenter les annonces
354 354 permission_manage_documents: GΓ©rer les documents
355 355 permission_view_documents: Voir les documents
356 356 permission_manage_files: GΓ©rer les fichiers
357 357 permission_view_files: Voir les fichiers
358 358 permission_manage_wiki: GΓ©rer le wiki
359 359 permission_rename_wiki_pages: Renommer les pages
360 360 permission_delete_wiki_pages: Supprimer les pages
361 361 permission_view_wiki_pages: Voir le wiki
362 362 permission_view_wiki_edits: "Voir l'historique des modifications"
363 363 permission_edit_wiki_pages: Modifier les pages
364 364 permission_delete_wiki_pages_attachments: Supprimer les fichiers joints
365 365 permission_protect_wiki_pages: ProtΓ©ger les pages
366 366 permission_manage_repository: GΓ©rer le dΓ©pΓ΄t de sources
367 367 permission_browse_repository: Parcourir les sources
368 368 permission_view_changesets: Voir les rΓ©visions
369 369 permission_commit_access: Droit de commit
370 370 permission_manage_boards: GΓ©rer les forums
371 371 permission_view_messages: Voir les messages
372 372 permission_add_messages: Poster un message
373 373 permission_edit_messages: Modifier les messages
374 374 permission_edit_own_messages: Modifier ses propres messages
375 375 permission_delete_messages: Supprimer les messages
376 376 permission_delete_own_messages: Supprimer ses propres messages
377 377
378 378 project_module_issue_tracking: Suivi des demandes
379 379 project_module_time_tracking: Suivi du temps passΓ©
380 380 project_module_news: Publication d'annonces
381 381 project_module_documents: Publication de documents
382 382 project_module_files: Publication de fichiers
383 383 project_module_wiki: Wiki
384 384 project_module_repository: DΓ©pΓ΄t de sources
385 385 project_module_boards: Forums de discussion
386 386
387 387 label_user: Utilisateur
388 388 label_user_plural: Utilisateurs
389 389 label_user_new: Nouvel utilisateur
390 390 label_project: Projet
391 391 label_project_new: Nouveau projet
392 392 label_project_plural: Projets
393 393 label_x_projects:
394 394 zero: aucun projet
395 395 one: 1 projet
396 396 other: "{{count}} projets"
397 397 label_project_all: Tous les projets
398 398 label_project_latest: Derniers projets
399 399 label_issue: Demande
400 400 label_issue_new: Nouvelle demande
401 401 label_issue_plural: Demandes
402 402 label_issue_view_all: Voir toutes les demandes
403 403 label_issue_added: Demande ajoutΓ©e
404 404 label_issue_updated: Demande mise Γ  jour
405 405 label_issues_by: "Demandes par {{value}}"
406 406 label_document: Document
407 407 label_document_new: Nouveau document
408 408 label_document_plural: Documents
409 409 label_document_added: Document ajoutΓ©
410 410 label_role: RΓ΄le
411 411 label_role_plural: RΓ΄les
412 412 label_role_new: Nouveau rΓ΄le
413 413 label_role_and_permissions: RΓ΄les et permissions
414 414 label_member: Membre
415 415 label_member_new: Nouveau membre
416 416 label_member_plural: Membres
417 417 label_tracker: Tracker
418 418 label_tracker_plural: Trackers
419 419 label_tracker_new: Nouveau tracker
420 420 label_workflow: Workflow
421 421 label_issue_status: Statut de demandes
422 422 label_issue_status_plural: Statuts de demandes
423 423 label_issue_status_new: Nouveau statut
424 424 label_issue_category: CatΓ©gorie de demandes
425 425 label_issue_category_plural: CatΓ©gories de demandes
426 426 label_issue_category_new: Nouvelle catΓ©gorie
427 427 label_custom_field: Champ personnalisΓ©
428 428 label_custom_field_plural: Champs personnalisΓ©s
429 429 label_custom_field_new: Nouveau champ personnalisΓ©
430 430 label_enumerations: Listes de valeurs
431 431 label_enumeration_new: Nouvelle valeur
432 432 label_information: Information
433 433 label_information_plural: Informations
434 434 label_please_login: Identification
435 435 label_register: S'enregistrer
436 436 label_login_with_open_id_option: S'authentifier avec OpenID
437 437 label_password_lost: Mot de passe perdu
438 438 label_home: Accueil
439 439 label_my_page: Ma page
440 440 label_my_account: Mon compte
441 441 label_my_projects: Mes projets
442 442 label_administration: Administration
443 443 label_login: Connexion
444 444 label_logout: DΓ©connexion
445 445 label_help: Aide
446 446 label_reported_issues: Demandes soumises
447 447 label_assigned_to_me_issues: Demandes qui me sont assignΓ©es
448 448 label_last_login: Dernière connexion
449 449 label_registered_on: Inscrit le
450 450 label_activity: ActivitΓ©
451 451 label_overall_activity: ActivitΓ© globale
452 452 label_user_activity: "ActivitΓ© de {{value}}"
453 453 label_new: Nouveau
454 454 label_logged_as: ConnectΓ© en tant que
455 455 label_environment: Environnement
456 456 label_authentication: Authentification
457 457 label_auth_source: Mode d'authentification
458 458 label_auth_source_new: Nouveau mode d'authentification
459 459 label_auth_source_plural: Modes d'authentification
460 460 label_subproject_plural: Sous-projets
461 461 label_and_its_subprojects: "{{value}} et ses sous-projets"
462 462 label_min_max_length: Longueurs mini - maxi
463 463 label_list: Liste
464 464 label_date: Date
465 465 label_integer: Entier
466 466 label_float: Nombre dΓ©cimal
467 467 label_boolean: BoolΓ©en
468 468 label_string: Texte
469 469 label_text: Texte long
470 470 label_attribute: Attribut
471 471 label_attribute_plural: Attributs
472 472 label_download: "{{count}} TΓ©lΓ©chargement"
473 473 label_download_plural: "{{count}} TΓ©lΓ©chargements"
474 474 label_no_data: Aucune donnΓ©e Γ  afficher
475 475 label_change_status: Changer le statut
476 476 label_history: Historique
477 477 label_attachment: Fichier
478 478 label_attachment_new: Nouveau fichier
479 479 label_attachment_delete: Supprimer le fichier
480 480 label_attachment_plural: Fichiers
481 481 label_file_added: Fichier ajoutΓ©
482 482 label_report: Rapport
483 483 label_report_plural: Rapports
484 484 label_news: Annonce
485 485 label_news_new: Nouvelle annonce
486 486 label_news_plural: Annonces
487 487 label_news_latest: Dernières annonces
488 488 label_news_view_all: Voir toutes les annonces
489 489 label_news_added: Annonce ajoutΓ©e
490 490 label_change_log: Historique
491 491 label_settings: Configuration
492 492 label_overview: AperΓ§u
493 493 label_version: Version
494 494 label_version_new: Nouvelle version
495 495 label_version_plural: Versions
496 496 label_confirmation: Confirmation
497 497 label_export_to: 'Formats disponibles:'
498 498 label_read: Lire...
499 499 label_public_projects: Projets publics
500 500 label_open_issues: ouvert
501 501 label_open_issues_plural: ouverts
502 502 label_closed_issues: fermΓ©
503 503 label_closed_issues_plural: fermΓ©s
504 504 label_x_open_issues_abbr_on_total:
505 505 zero: 0 ouvert sur {{total}}
506 506 one: 1 ouvert sur {{total}}
507 507 other: "{{count}} ouverts sur {{total}}"
508 508 label_x_open_issues_abbr:
509 509 zero: 0 ouvert
510 510 one: 1 ouvert
511 511 other: "{{count}} ouverts"
512 512 label_x_closed_issues_abbr:
513 513 zero: 0 fermΓ©
514 514 one: 1 fermΓ©
515 515 other: "{{count}} fermΓ©s"
516 516 label_total: Total
517 517 label_permissions: Permissions
518 518 label_current_status: Statut actuel
519 519 label_new_statuses_allowed: Nouveaux statuts autorisΓ©s
520 520 label_all: tous
521 521 label_none: aucun
522 522 label_nobody: personne
523 523 label_next: Suivant
524 524 label_previous: PrΓ©cΓ©dent
525 525 label_used_by: UtilisΓ© par
526 526 label_details: DΓ©tails
527 527 label_add_note: Ajouter une note
528 528 label_per_page: Par page
529 529 label_calendar: Calendrier
530 530 label_months_from: mois depuis
531 531 label_gantt: Gantt
532 532 label_internal: Interne
533 533 label_last_changes: "{{count}} derniers changements"
534 534 label_change_view_all: Voir tous les changements
535 535 label_personalize_page: Personnaliser cette page
536 536 label_comment: Commentaire
537 537 label_comment_plural: Commentaires
538 538 label_x_comments:
539 539 zero: aucun commentaire
540 540 one: 1 commentaire
541 541 other: "{{count}} commentaires"
542 542 label_comment_add: Ajouter un commentaire
543 543 label_comment_added: Commentaire ajoutΓ©
544 544 label_comment_delete: Supprimer les commentaires
545 545 label_query: Rapport personnalisΓ©
546 546 label_query_plural: Rapports personnalisΓ©s
547 547 label_query_new: Nouveau rapport
548 548 label_filter_add: Ajouter le filtre
549 549 label_filter_plural: Filtres
550 550 label_equals: Γ©gal
551 551 label_not_equals: diffΓ©rent
552 552 label_in_less_than: dans moins de
553 553 label_in_more_than: dans plus de
554 554 label_in: dans
555 555 label_today: aujourd'hui
556 556 label_all_time: toute la pΓ©riode
557 557 label_yesterday: hier
558 558 label_this_week: cette semaine
559 559 label_last_week: la semaine dernière
560 560 label_last_n_days: "les {{count}} derniers jours"
561 561 label_this_month: ce mois-ci
562 562 label_last_month: le mois dernier
563 563 label_this_year: cette annΓ©e
564 564 label_date_range: PΓ©riode
565 565 label_less_than_ago: il y a moins de
566 566 label_more_than_ago: il y a plus de
567 567 label_ago: il y a
568 568 label_contains: contient
569 569 label_not_contains: ne contient pas
570 570 label_day_plural: jours
571 571 label_repository: DΓ©pΓ΄t
572 572 label_repository_plural: DΓ©pΓ΄ts
573 573 label_browse: Parcourir
574 574 label_modification: "{{count}} modification"
575 575 label_modification_plural: "{{count}} modifications"
576 576 label_revision: RΓ©vision
577 577 label_revision_plural: RΓ©visions
578 578 label_associated_revisions: RΓ©visions associΓ©es
579 579 label_added: ajoutΓ©
580 580 label_modified: modifiΓ©
581 581 label_copied: copiΓ©
582 582 label_renamed: renommΓ©
583 583 label_deleted: supprimΓ©
584 584 label_latest_revision: Dernière révision
585 585 label_latest_revision_plural: Dernières révisions
586 586 label_view_revisions: Voir les rΓ©visions
587 587 label_max_size: Taille maximale
588 588 label_sort_highest: Remonter en premier
589 589 label_sort_higher: Remonter
590 590 label_sort_lower: Descendre
591 591 label_sort_lowest: Descendre en dernier
592 592 label_roadmap: Roadmap
593 593 label_roadmap_due_in: "EchΓ©ance dans {{value}}"
594 594 label_roadmap_overdue: "En retard de {{value}}"
595 595 label_roadmap_no_issues: Aucune demande pour cette version
596 596 label_search: Recherche
597 597 label_result_plural: RΓ©sultats
598 598 label_all_words: Tous les mots
599 599 label_wiki: Wiki
600 600 label_wiki_edit: RΓ©vision wiki
601 601 label_wiki_edit_plural: RΓ©visions wiki
602 602 label_wiki_page: Page wiki
603 603 label_wiki_page_plural: Pages wiki
604 604 label_index_by_title: Index par titre
605 605 label_index_by_date: Index par date
606 606 label_current_version: Version actuelle
607 607 label_preview: PrΓ©visualisation
608 608 label_feed_plural: Flux RSS
609 609 label_changes_details: DΓ©tails de tous les changements
610 610 label_issue_tracking: Suivi des demandes
611 611 label_spent_time: Temps passΓ©
612 612 label_f_hour: "{{value}} heure"
613 613 label_f_hour_plural: "{{value}} heures"
614 614 label_time_tracking: Suivi du temps
615 615 label_change_plural: Changements
616 616 label_statistics: Statistiques
617 617 label_commits_per_month: Commits par mois
618 618 label_commits_per_author: Commits par auteur
619 619 label_view_diff: Voir les diffΓ©rences
620 620 label_diff_inline: en ligne
621 621 label_diff_side_by_side: cΓ΄te Γ  cΓ΄te
622 622 label_options: Options
623 623 label_copy_workflow_from: Copier le workflow de
624 624 label_permissions_report: Synthèse des permissions
625 625 label_watched_issues: Demandes surveillΓ©es
626 626 label_related_issues: Demandes liΓ©es
627 627 label_applied_status: Statut appliquΓ©
628 628 label_loading: Chargement...
629 629 label_relation_new: Nouvelle relation
630 630 label_relation_delete: Supprimer la relation
631 631 label_relates_to: liΓ© Γ 
632 632 label_duplicates: duplique
633 633 label_duplicated_by: dupliquΓ© par
634 634 label_blocks: bloque
635 635 label_blocked_by: bloquΓ© par
636 636 label_precedes: précède
637 637 label_follows: suit
638 638 label_end_to_start: fin Γ  dΓ©but
639 639 label_end_to_end: fin Γ  fin
640 640 label_start_to_start: dΓ©but Γ  dΓ©but
641 641 label_start_to_end: dΓ©but Γ  fin
642 642 label_stay_logged_in: Rester connectΓ©
643 643 label_disabled: dΓ©sactivΓ©
644 644 label_show_completed_versions: Voir les versions passΓ©es
645 645 label_me: moi
646 646 label_board: Forum
647 647 label_board_new: Nouveau forum
648 648 label_board_plural: Forums
649 649 label_topic_plural: Discussions
650 650 label_message_plural: Messages
651 651 label_message_last: Dernier message
652 652 label_message_new: Nouveau message
653 653 label_message_posted: Message ajoutΓ©
654 654 label_reply_plural: RΓ©ponses
655 655 label_send_information: Envoyer les informations Γ  l'utilisateur
656 656 label_year: AnnΓ©e
657 657 label_month: Mois
658 658 label_week: Semaine
659 659 label_date_from: Du
660 660 label_date_to: Au
661 661 label_language_based: BasΓ© sur la langue de l'utilisateur
662 662 label_sort_by: "Trier par {{value}}"
663 663 label_send_test_email: Envoyer un email de test
664 664 label_feeds_access_key_created_on: "Clé d'accès RSS créée il y a {{value}}"
665 665 label_module_plural: Modules
666 666 label_added_time_by: "AjoutΓ© par {{author}} il y a {{age}}"
667 667 label_updated_time_by: "Mis Γ  jour par {{author}} il y a {{age}}"
668 668 label_updated_time: "Mis Γ  jour il y a {{value}}"
669 669 label_jump_to_a_project: Aller Γ  un projet...
670 670 label_file_plural: Fichiers
671 671 label_changeset_plural: RΓ©visions
672 672 label_default_columns: Colonnes par dΓ©faut
673 673 label_no_change_option: (Pas de changement)
674 674 label_bulk_edit_selected_issues: Modifier les demandes sΓ©lectionnΓ©es
675 675 label_theme: Thème
676 676 label_default: DΓ©faut
677 677 label_search_titles_only: Uniquement dans les titres
678 678 label_user_mail_option_all: "Pour tous les Γ©vΓ©nements de tous mes projets"
679 679 label_user_mail_option_selected: "Pour tous les Γ©vΓ©nements des projets sΓ©lectionnΓ©s..."
680 680 label_user_mail_option_none: "Seulement pour ce que je surveille ou Γ  quoi je participe"
681 681 label_user_mail_no_self_notified: "Je ne veux pas Γͺtre notifiΓ© des changements que j'effectue"
682 682 label_registration_activation_by_email: activation du compte par email
683 683 label_registration_manual_activation: activation manuelle du compte
684 684 label_registration_automatic_activation: activation automatique du compte
685 685 label_display_per_page: "Par page: {{value}}"
686 686 label_age: Age
687 687 label_change_properties: Changer les propriΓ©tΓ©s
688 688 label_general: GΓ©nΓ©ral
689 689 label_more: Plus
690 690 label_scm: SCM
691 691 label_plugins: Plugins
692 692 label_ldap_authentication: Authentification LDAP
693 693 label_downloads_abbr: D/L
694 694 label_optional_description: Description facultative
695 695 label_add_another_file: Ajouter un autre fichier
696 696 label_preferences: PrΓ©fΓ©rences
697 697 label_chronological_order: Dans l'ordre chronologique
698 698 label_reverse_chronological_order: Dans l'ordre chronologique inverse
699 699 label_planning: Planning
700 700 label_incoming_emails: Emails entrants
701 701 label_generate_key: GΓ©nΓ©rer une clΓ©
702 702 label_issue_watchers: Observateurs
703 703 label_example: Exemple
704 704 label_display: Affichage
705 705 label_sort: Tri
706 706 label_ascending: Croissant
707 707 label_descending: DΓ©croissant
708 708 label_date_from_to: Du {{start}} au {{end}}
709 709 label_wiki_content_added: Page wiki ajoutΓ©e
710 710 label_wiki_content_updated: Page wiki mise Γ  jour
711 711
712 712 button_login: Connexion
713 713 button_submit: Soumettre
714 714 button_save: Sauvegarder
715 715 button_check_all: Tout cocher
716 716 button_uncheck_all: Tout dΓ©cocher
717 717 button_delete: Supprimer
718 718 button_create: CrΓ©er
719 719 button_create_and_continue: CrΓ©er et continuer
720 720 button_test: Tester
721 721 button_edit: Modifier
722 722 button_add: Ajouter
723 723 button_change: Changer
724 724 button_apply: Appliquer
725 725 button_clear: Effacer
726 726 button_lock: Verrouiller
727 727 button_unlock: DΓ©verrouiller
728 728 button_download: TΓ©lΓ©charger
729 729 button_list: Lister
730 730 button_view: Voir
731 731 button_move: DΓ©placer
732 732 button_back: Retour
733 733 button_cancel: Annuler
734 734 button_activate: Activer
735 735 button_sort: Trier
736 736 button_log_time: Saisir temps
737 737 button_rollback: Revenir Γ  cette version
738 738 button_watch: Surveiller
739 739 button_unwatch: Ne plus surveiller
740 740 button_reply: RΓ©pondre
741 741 button_archive: Archiver
742 742 button_unarchive: DΓ©sarchiver
743 743 button_reset: RΓ©initialiser
744 744 button_rename: Renommer
745 745 button_change_password: Changer de mot de passe
746 746 button_copy: Copier
747 747 button_annotate: Annoter
748 748 button_update: Mettre Γ  jour
749 749 button_configure: Configurer
750 750 button_quote: Citer
751 751
752 752 status_active: actif
753 753 status_registered: enregistrΓ©
754 754 status_locked: vΓ©rouillΓ©
755 755
756 756 text_select_mail_notifications: Actions pour lesquelles une notification par e-mail est envoyΓ©e
757 757 text_regexp_info: ex. ^[A-Z0-9]+$
758 758 text_min_max_length_info: 0 pour aucune restriction
759 759 text_project_destroy_confirmation: Etes-vous sΓ»r de vouloir supprimer ce projet et toutes ses donnΓ©es ?
760 760 text_subprojects_destroy_warning: "Ses sous-projets: {{value}} seront Γ©galement supprimΓ©s."
761 761 text_workflow_edit: SΓ©lectionner un tracker et un rΓ΄le pour Γ©diter le workflow
762 762 text_are_you_sure: Etes-vous sΓ»r ?
763 763 text_journal_changed: "changΓ© de {{old}} Γ  {{new}}"
764 764 text_journal_set_to: "mis Γ  {{value}}"
765 765 text_journal_deleted: supprimΓ©
766 766 text_tip_task_begin_day: tΓ’che commenΓ§ant ce jour
767 767 text_tip_task_end_day: tΓ’che finissant ce jour
768 768 text_tip_task_begin_end_day: tΓ’che commenΓ§ant et finissant ce jour
769 769 text_project_identifier_info: 'Seuls les lettres minuscules (a-z), chiffres et tirets sont autorisΓ©s.<br />Un fois sauvegardΓ©, l''identifiant ne pourra plus Γͺtre modifiΓ©.'
770 770 text_caracters_maximum: "{{count}} caractères maximum."
771 771 text_caracters_minimum: "{{count}} caractères minimum."
772 772 text_length_between: "Longueur comprise entre {{min}} et {{max}} caractères."
773 773 text_tracker_no_workflow: Aucun worflow n'est dΓ©fini pour ce tracker
774 774 text_unallowed_characters: Caractères non autorisés
775 775 text_comma_separated: Plusieurs valeurs possibles (sΓ©parΓ©es par des virgules).
776 776 text_issues_ref_in_commit_messages: RΓ©fΓ©rencement et rΓ©solution des demandes dans les commentaires de commits
777 777 text_issue_added: "La demande {{id}} a Γ©tΓ© soumise par {{author}}."
778 778 text_issue_updated: "La demande {{id}} a Γ©tΓ© mise Γ  jour par {{author}}."
779 779 text_wiki_destroy_confirmation: Etes-vous sΓ»r de vouloir supprimer ce wiki et tout son contenu ?
780 780 text_issue_category_destroy_question: "{{count}} demandes sont affectΓ©es Γ  cette catΓ©gories. Que voulez-vous faire ?"
781 781 text_issue_category_destroy_assignments: N'affecter les demandes Γ  aucune autre catΓ©gorie
782 782 text_issue_category_reassign_to: RΓ©affecter les demandes Γ  cette catΓ©gorie
783 783 text_user_mail_option: "Pour les projets non sΓ©lectionnΓ©s, vous recevrez seulement des notifications pour ce que vous surveillez ou Γ  quoi vous participez (exemple: demandes dont vous Γͺtes l'auteur ou la personne assignΓ©e)."
784 784 text_no_configuration_data: "Les rΓ΄les, trackers, statuts et le workflow ne sont pas encore paramΓ©trΓ©s.\nIl est vivement recommandΓ© de charger le paramΓ©trage par defaut. Vous pourrez le modifier une fois chargΓ©."
785 785 text_load_default_configuration: Charger le paramΓ©trage par dΓ©faut
786 786 text_status_changed_by_changeset: "AppliquΓ© par commit {{value}}."
787 787 text_issues_destroy_confirmation: 'Etes-vous sΓ»r de vouloir supprimer le(s) demandes(s) selectionnΓ©e(s) ?'
788 788 text_select_project_modules: 'Selectionner les modules Γ  activer pour ce project:'
789 789 text_default_administrator_account_changed: Compte administrateur par dΓ©faut changΓ©
790 790 text_file_repository_writable: RΓ©pertoire de stockage des fichiers accessible en Γ©criture
791 791 text_plugin_assets_writable: RΓ©pertoire public des plugins accessible en Γ©criture
792 792 text_rmagick_available: Bibliothèque RMagick présente (optionnelle)
793 793 text_destroy_time_entries_question: "{{hours}} heures ont Γ©tΓ© enregistrΓ©es sur les demandes Γ  supprimer. Que voulez-vous faire ?"
794 794 text_destroy_time_entries: Supprimer les heures
795 795 text_assign_time_entries_to_project: Reporter les heures sur le projet
796 796 text_reassign_time_entries: 'Reporter les heures sur cette demande:'
797 797 text_user_wrote: "{{value}} a Γ©crit:"
798 798 text_enumeration_destroy_question: "Cette valeur est affectΓ©e Γ  {{count}} objets."
799 799 text_enumeration_category_reassign_to: 'RΓ©affecter les objets Γ  cette valeur:'
800 800 text_email_delivery_not_configured: "L'envoi de mail n'est pas configurΓ©, les notifications sont dΓ©sactivΓ©es.\nConfigurez votre serveur SMTP dans config/email.yml et redΓ©marrez l'application pour les activer."
801 801 text_repository_usernames_mapping: "Vous pouvez sΓ©lectionner ou modifier l'utilisateur Redmine associΓ© Γ  chaque nom d'utilisateur figurant dans l'historique du dΓ©pΓ΄t.\nLes utilisateurs avec le mΓͺme identifiant ou la mΓͺme adresse mail seront automatiquement associΓ©s."
802 802 text_diff_truncated: '... Ce diffΓ©rentiel a Γ©tΓ© tronquΓ© car il excΓ¨de la taille maximale pouvant Γͺtre affichΓ©e.'
803 803 text_custom_field_possible_values_info: 'Une ligne par valeur'
804 804 text_wiki_page_destroy_question: "Cette page possède {{descendants}} sous-page(s) et descendante(s). Que voulez-vous faire ?"
805 805 text_wiki_page_nullify_children: "Conserver les sous-pages en tant que pages racines"
806 806 text_wiki_page_destroy_children: "Supprimer les sous-pages et toutes leurs descedantes"
807 807 text_wiki_page_reassign_children: "RΓ©affecter les sous-pages Γ  cette page"
808 808
809 809 default_role_manager: Manager
810 810 default_role_developper: DΓ©veloppeur
811 811 default_role_reporter: Rapporteur
812 812 default_tracker_bug: Anomalie
813 813 default_tracker_feature: Evolution
814 814 default_tracker_support: Assistance
815 815 default_issue_status_new: Nouveau
816 816 default_issue_status_assigned: AssignΓ©
817 817 default_issue_status_resolved: RΓ©solu
818 818 default_issue_status_feedback: Commentaire
819 819 default_issue_status_closed: FermΓ©
820 820 default_issue_status_rejected: RejetΓ©
821 821 default_doc_category_user: Documentation utilisateur
822 822 default_doc_category_tech: Documentation technique
823 823 default_priority_low: Bas
824 824 default_priority_normal: Normal
825 825 default_priority_high: Haut
826 826 default_priority_urgent: Urgent
827 827 default_priority_immediate: ImmΓ©diat
828 828 default_activity_design: Conception
829 829 default_activity_development: DΓ©veloppement
830 830
831 831 enumeration_issue_priorities: PrioritΓ©s des demandes
832 832 enumeration_doc_categories: CatΓ©gories des documents
833 833 enumeration_activities: ActivitΓ©s (suivi du temps)
834 834 label_greater_or_equal: ">="
835 835 label_less_or_equal: "<="
836 label_view_all_revisions: View all revisions
836 label_view_all_revisions: Voir toutes les rΓ©visions
837 837 label_tag: Tag
838 838 label_branch: Branch
839 839 error_no_tracker_in_project: No tracker is associated to this project. Please check the Project settings.
840 840 error_no_default_issue_status: No default issue status is defined. Please check your configuration (Go to "Administration -> Issue statuses").
@@ -1,199 +1,220
1 1 # redMine - project management software
2 2 # Copyright (C) 2006-2008 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 require File.dirname(__FILE__) + '/../test_helper'
19 19 require 'repositories_controller'
20 20
21 21 # Re-raise errors caught by the controller.
22 22 class RepositoriesController; def rescue_action(e) raise e end; end
23 23
24 24 class RepositoriesSubversionControllerTest < Test::Unit::TestCase
25 25 fixtures :projects, :users, :roles, :members, :member_roles, :enabled_modules,
26 26 :repositories, :issues, :issue_statuses, :changesets, :changes,
27 27 :issue_categories, :enumerations, :custom_fields, :custom_values, :trackers
28 28
29 29 # No '..' in the repository path for svn
30 30 REPOSITORY_PATH = RAILS_ROOT.gsub(%r{config\/\.\.}, '') + '/tmp/test/subversion_repository'
31 31
32 32 def setup
33 33 @controller = RepositoriesController.new
34 34 @request = ActionController::TestRequest.new
35 35 @response = ActionController::TestResponse.new
36 36 Setting.default_language = 'en'
37 37 User.current = nil
38 38 end
39 39
40 40 if File.directory?(REPOSITORY_PATH)
41 41 def test_show
42 42 get :show, :id => 1
43 43 assert_response :success
44 44 assert_template 'show'
45 45 assert_not_nil assigns(:entries)
46 46 assert_not_nil assigns(:changesets)
47 47 end
48 48
49 49 def test_browse_root
50 50 get :show, :id => 1
51 51 assert_response :success
52 52 assert_template 'show'
53 53 assert_not_nil assigns(:entries)
54 54 entry = assigns(:entries).detect {|e| e.name == 'subversion_test'}
55 55 assert_equal 'dir', entry.kind
56 56 end
57 57
58 58 def test_browse_directory
59 59 get :show, :id => 1, :path => ['subversion_test']
60 60 assert_response :success
61 61 assert_template 'show'
62 62 assert_not_nil assigns(:entries)
63 63 assert_equal ['folder', '.project', 'helloworld.c', 'textfile.txt'], assigns(:entries).collect(&:name)
64 64 entry = assigns(:entries).detect {|e| e.name == 'helloworld.c'}
65 65 assert_equal 'file', entry.kind
66 66 assert_equal 'subversion_test/helloworld.c', entry.path
67 67 assert_tag :a, :content => 'helloworld.c', :attributes => { :class => /text\-x\-c/ }
68 68 end
69 69
70 70 def test_browse_at_given_revision
71 71 get :show, :id => 1, :path => ['subversion_test'], :rev => 4
72 72 assert_response :success
73 73 assert_template 'show'
74 74 assert_not_nil assigns(:entries)
75 75 assert_equal ['folder', '.project', 'helloworld.c', 'helloworld.rb', 'textfile.txt'], assigns(:entries).collect(&:name)
76 76 end
77 77
78 def test_changes
78 def test_file_changes
79 79 get :changes, :id => 1, :path => ['subversion_test', 'folder', 'helloworld.rb' ]
80 80 assert_response :success
81 81 assert_template 'changes'
82 82
83 83 changesets = assigns(:changesets)
84 84 assert_not_nil changesets
85 85 assert_equal %w(6 3 2), changesets.collect(&:revision)
86 86
87 87 # svn properties displayed with svn >= 1.5 only
88 88 if Redmine::Scm::Adapters::SubversionAdapter.client_version_above?([1, 5, 0])
89 89 assert_not_nil assigns(:properties)
90 90 assert_equal 'native', assigns(:properties)['svn:eol-style']
91 91 assert_tag :ul,
92 92 :child => { :tag => 'li',
93 93 :child => { :tag => 'b', :content => 'svn:eol-style' },
94 94 :child => { :tag => 'span', :content => 'native' } }
95 95 end
96 96 end
97 97
98 def test_directory_changes
99 get :changes, :id => 1, :path => ['subversion_test', 'folder' ]
100 assert_response :success
101 assert_template 'changes'
102
103 changesets = assigns(:changesets)
104 assert_not_nil changesets
105 assert_equal %w(7 6 5 2), changesets.collect(&:revision)
106 end
107
98 108 def test_entry
99 109 get :entry, :id => 1, :path => ['subversion_test', 'helloworld.c']
100 110 assert_response :success
101 111 assert_template 'entry'
102 112 end
103 113
104 114 def test_entry_should_send_if_too_big
105 115 # no files in the test repo is larger than 1KB...
106 116 with_settings :file_max_size_displayed => 0 do
107 117 get :entry, :id => 1, :path => ['subversion_test', 'helloworld.c']
108 118 assert_response :success
109 119 assert_template ''
110 120 assert_equal 'attachment; filename="helloworld.c"', @response.headers['Content-Disposition']
111 121 end
112 122 end
113 123
114 124 def test_entry_at_given_revision
115 125 get :entry, :id => 1, :path => ['subversion_test', 'helloworld.rb'], :rev => 2
116 126 assert_response :success
117 127 assert_template 'entry'
118 128 # this line was removed in r3 and file was moved in r6
119 129 assert_tag :tag => 'td', :attributes => { :class => /line-code/},
120 130 :content => /Here's the code/
121 131 end
122 132
123 133 def test_entry_not_found
124 134 get :entry, :id => 1, :path => ['subversion_test', 'zzz.c']
125 135 assert_tag :tag => 'div', :attributes => { :class => /error/ },
126 136 :content => /The entry or revision was not found in the repository/
127 137 end
128 138
129 139 def test_entry_download
130 140 get :entry, :id => 1, :path => ['subversion_test', 'helloworld.c'], :format => 'raw'
131 141 assert_response :success
132 142 assert_template ''
133 143 assert_equal 'attachment; filename="helloworld.c"', @response.headers['Content-Disposition']
134 144 end
135 145
136 146 def test_directory_entry
137 147 get :entry, :id => 1, :path => ['subversion_test', 'folder']
138 148 assert_response :success
139 149 assert_template 'show'
140 150 assert_not_nil assigns(:entry)
141 151 assert_equal 'folder', assigns(:entry).name
142 152 end
143 153
144 154 def test_revision
145 155 get :revision, :id => 1, :rev => 2
146 156 assert_response :success
147 157 assert_template 'revision'
148 158 assert_tag :tag => 'ul',
149 159 :child => { :tag => 'li',
150 160 # link to the entry at rev 2
151 161 :child => { :tag => 'a',
152 162 :attributes => {:href => '/projects/ecookbook/repository/revisions/2/entry/test/some/path/in/the/repo'},
153 163 :content => 'repo',
154 164 # link to partial diff
155 165 :sibling => { :tag => 'a',
156 166 :attributes => { :href => '/projects/ecookbook/repository/revisions/2/diff/test/some/path/in/the/repo' }
157 167 }
158 168 }
159 169 }
160 170 end
161 171
162 172 def test_revision_with_repository_pointing_to_a_subdirectory
163 173 r = Project.find(1).repository
164 174 # Changes repository url to a subdirectory
165 175 r.update_attribute :url, (r.url + '/test/some')
166 176
167 177 get :revision, :id => 1, :rev => 2
168 178 assert_response :success
169 179 assert_template 'revision'
170 180 assert_tag :tag => 'ul',
171 181 :child => { :tag => 'li',
172 182 # link to the entry at rev 2
173 183 :child => { :tag => 'a',
174 184 :attributes => {:href => '/projects/ecookbook/repository/revisions/2/entry/path/in/the/repo'},
175 185 :content => 'repo',
176 186 # link to partial diff
177 187 :sibling => { :tag => 'a',
178 188 :attributes => { :href => '/projects/ecookbook/repository/revisions/2/diff/path/in/the/repo' }
179 189 }
180 190 }
181 191 }
182 192 end
183 193
184 def test_diff
194 def test_revision_diff
185 195 get :diff, :id => 1, :rev => 3
186 196 assert_response :success
187 197 assert_template 'diff'
188 198 end
189 199
200 def test_directory_diff
201 get :diff, :id => 1, :rev => 6, :rev_to => 2, :path => ['subversion_test', 'folder']
202 assert_response :success
203 assert_template 'diff'
204
205 diff = assigns(:diff)
206 assert_not_nil diff
207 # 2 files modified
208 assert_equal 2, Redmine::UnifiedDiff.new(diff).size
209 end
210
190 211 def test_annotate
191 212 get :annotate, :id => 1, :path => ['subversion_test', 'helloworld.c']
192 213 assert_response :success
193 214 assert_template 'annotate'
194 215 end
195 216 else
196 217 puts "Subversion test repository NOT FOUND. Skipping functional tests !!!"
197 218 def test_fake; assert true end
198 219 end
199 220 end
General Comments 0
You need to be logged in to leave comments. Login now