Commit dec34d91e2f438ecb15254e4a34aeb09e1df089d

Authored by Joenio Costa
2 parents 82012975 2015618d

Merge branch 'stable'

Conflicts:
	app/views/content_viewer/view_page.rhtml
app/controllers/my_profile/cms_controller.rb
... ... @@ -169,7 +169,7 @@ class CmsController < MyProfileController
169 169 profile.home_page = @article
170 170 profile.save(false)
171 171 session[:notice] = _('"%s" configured as home page.') % @article.name
172   - redirect_to :action => 'view', :id => @article.id
  172 + redirect_to (request.referer || profile.url)
173 173 end
174 174  
175 175 def upload_files
... ...
app/models/article.rb
... ... @@ -417,6 +417,7 @@ class Article < ActiveRecord::Base
417 417 :profile_id,
418 418 :parent_id,
419 419 :path,
  420 + :slug,
420 421 :updated_at,
421 422 :created_at,
422 423 :last_changed_by_id,
... ... @@ -504,6 +505,10 @@ class Article < ActiveRecord::Base
504 505 false
505 506 end
506 507  
  508 + def accept_uploads?
  509 + self.parent && self.parent.accept_uploads?
  510 + end
  511 +
507 512 private
508 513  
509 514 def sanitize_tag_list
... ...
app/models/folder.rb
... ... @@ -53,4 +53,9 @@ class Folder < Article
53 53 :foreign_key => 'parent_id',
54 54 :order => 'articles.type, articles.name',
55 55 :conditions => ["articles.type = 'UploadedFile' and articles.content_type in (?) or articles.type in ('Folder','Gallery')", UploadedFile.content_types]
  56 +
  57 + def accept_uploads?
  58 + !self.has_posts? || self.gallery?
  59 + end
  60 +
56 61 end
... ...
app/views/admin_panel/site_info.rhtml
... ... @@ -8,7 +8,7 @@
8 8  
9 9 <%= labelled_form_field(_('Site name'), text_field(:environment, :name)) %>
10 10  
11   - <%= labelled_form_field _('Homepage content'), text_area(:environment, :description, :cols => 40, :style => 'width: 90%') %>
  11 + <%= labelled_form_field _('Homepage content'), text_area(:environment, :description, :cols => 40, :style => 'width: 90%', :class => 'mceEditor') %>
12 12  
13 13 <% button_bar do %>
14 14 <%= submit_button(:save, _('Save')) %>
... ...
app/views/catalog/index.rhtml
1 1 <%= display_products_list @profile, @products %>
2 2  
3   -<%= will_paginate @products %>
  3 +<%= pagination_links @products %>
... ...
app/views/content_viewer/_article_toolbar.rhtml
... ... @@ -33,12 +33,9 @@
33 33 :class => 'button with-text icon-locale' if @page.translatable? && !@page.native_translation.language.blank? %>
34 34 <%= lightbox_remote_button(:new, label_for_new_article(@page), profile.admin_url.merge(:controller => 'cms', :action => 'new', :parent_id => (@page.folder? ? @page : (@page.parent.nil? ? nil : @page.parent)))) %>
35 35 <% end %>
36   - <% if (@page.folder? && !@page.has_posts?) || (@page.parent && @page.parent.folder? && !@page.parent.has_posts?) %>
37   - <%= button('upload-file', _('Upload files'), profile.admin_url.merge(:controller => 'cms', :action => 'upload_files', :parent_id => (@page.folder? ? @page : @page.parent))) %>
38   - <% end %>
39 36 <% end %>
40   - <% if profile.kind_of?(Enterprise) && @page.gallery? %>
41   - <%= button('upload-file', _('Upload files'), :controller => 'cms', :action => 'upload_files', :parent_id => (@page.folder? ? @page : @page.parent)) %>
  37 + <% if @page.accept_uploads? %>
  38 + <%= button('upload-file', _('Upload files'), profile.admin_url.merge(:controller => 'cms', :action => 'upload_files', :parent_id => (@page.folder? ? @page : @page.parent))) %>
42 39 <% end %>
43 40 </div>
44 41 <% elsif profile.community? && (@page.blog? || @page.parent && @page.parent.blog?) %>
... ...
app/views/content_viewer/image_gallery.rhtml
... ... @@ -16,5 +16,5 @@
16 16 <% end %>
17 17 </ul>
18 18 <br style="clear:both" />
19   - <%= will_paginate @images, :param_name => 'npage' %>
  19 + <%= pagination_links @images, :param_name => 'npage' %>
20 20 </div>
... ...
app/views/content_viewer/view_page.rhtml
... ... @@ -33,6 +33,18 @@
33 33  
34 34 <%= render :partial => 'shared/disabled_enterprise' %>
35 35  
  36 +<% if NOOSFERO_CONF['addthis_enabled'] %>
  37 +<div id="addThis">
  38 +<script type="text/javascript">
  39 + addthis_brand = '<%= escape_javascript( @environment.name ) %>';
  40 + addthis_pub = '<%= escape_javascript( NOOSFERO_CONF['addthis_pub'] ) %>';
  41 + addthis_logo = '<%= escape_javascript( NOOSFERO_CONF['addthis_logo'] ) %>';
  42 + addthis_options = '<%= escape_javascript( NOOSFERO_CONF['addthis_options'] ) %>';
  43 +</script>
  44 +<a href="http://www.addthis.com/bookmark.php" id="bt_addThis" target="_blank" onmouseover="return addthis_open(this, '', '[URL]')" onmouseout="addthis_close()" onclick="return addthis_sendto()"><img src="/images/bt-bookmark.gif" width="53" height="16" border="0" alt="" /></a><script type="text/javascript" src="http://s7.addthis.com/js/152/addthis_widget.js"></script>
  45 +</div>
  46 +<% end %>
  47 +
36 48 <% cache(@page.cache_key(params, user)) do %>
37 49 <div class="<%="article-body article-body-" + @page.css_class_name %>">
38 50 <% options = @page.image? ? {:gallery_view => true} : {} %>
... ... @@ -50,18 +62,6 @@
50 62  
51 63 <%= display_source_info(@page) %>
52 64  
53   -<% if NOOSFERO_CONF['addthis_enabled'] %>
54   -<div id="addThis">
55   -<script type="text/javascript">
56   - addthis_brand = '<%= escape_javascript( @environment.name ) %>';
57   - addthis_pub = '<%= escape_javascript( NOOSFERO_CONF['addthis_pub'] ) %>';
58   - addthis_logo = '<%= escape_javascript( NOOSFERO_CONF['addthis_logo'] ) %>';
59   - addthis_options = '<%= escape_javascript( NOOSFERO_CONF['addthis_options'] ) %>';
60   -</script>
61   -<a href="http://www.addthis.com/bookmark.php" id="bt_addThis" target="_blank" onmouseover="return addthis_open(this, '', '[URL]')" onmouseout="addthis_close()" onclick="return addthis_sendto()"><img src="/images/bt-bookmark.gif" width="53" height="16" border="0" alt="" /></a><script type="text/javascript" src="http://s7.addthis.com/js/152/addthis_widget.js"></script>
62   -</div>
63   -<% end %>
64   -
65 65 <div class="comments" id="comments_list">
66 66 <% if @page.accept_comments? %>
67 67 <h3 <%= 'class="no-comments-yet"' if @comments.size == 0 %>>
... ...
app/views/layouts/chat.rhtml
... ... @@ -26,7 +26,7 @@
26 26 </head>
27 27 <body id='chat'>
28 28 <div id='title-bar'>
29   - <h1 class='title'><%= _("%s - Friends online (<span id='friends-online'>%d</span>)") % [h(page_title), 0] %></h1>
  29 + <h1 class='title'><%= _("%s - Friends in chat (<span id='friends-online'>%d</span>)") % [h(page_title), 0] %></h1>
30 30 </div>
31 31 <div id='buddy-list'>
32 32 <div id='environment-logo'>
... ...
app/views/manage_products/_edit_description.rhtml
... ... @@ -6,7 +6,7 @@
6 6 :url => {:controller => 'manage_products', :action => 'edit', :id => @product, :field => 'description'},
7 7 :html => {:id => 'product-description-form', :method => 'post'}) do |f| %>
8 8  
9   - <%= labelled_form_field(_('Description:'), f.text_area(:description, :rows => 15, :style => 'width: 90%;')) %>
  9 + <%= labelled_form_field(_('Description:'), f.text_area(:description, :rows => 15, :style => 'width: 90%;', :class => 'mceEditor')) %>
10 10 <% button_bar do %>
11 11 <%= submit_button :save, _('Save') %>
12 12 <%= cancel_edit_product_link(@product, 'description') %>
... ...
app/views/manage_products/_form.rhtml
... ... @@ -5,7 +5,7 @@
5 5  
6 6 <%= display_form_field( _('Name:'), f.text_field(:name) ) %>
7 7 <%= display_form_field( _('Price:'), f.text_field(:price) ) %>
8   - <%= display_form_field( _('Description:'), f.text_area(:description, :rows => 10) ) %>
  8 + <%= display_form_field( _('Description:'), f.text_area(:description, :rows => 10, :class => 'mceEditor') ) %>
9 9 <%= labelled_form_field(f.check_box(:highlighted) + _('Highlight this product'),'') %>
10 10 <% f.fields_for :image_builder, @product.image do |i| %>
11 11 <%= file_field_or_thumbnail(_('Image:'), @product.image, i) %>
... ...
app/views/manage_products/index.rhtml
... ... @@ -22,7 +22,7 @@
22 22 <% end %>
23 23 </table>
24 24  
25   -<%= will_paginate @products %>
  25 +<%= pagination_links @products %>
26 26  
27 27 <% button_bar do %>
28 28 <%= button :add, _('New product or service'), :action => 'new' %>
... ...
app/views/profile_members/send_mail.rhtml
... ... @@ -8,7 +8,7 @@
8 8  
9 9 <% form_for :mailing, :url => {:action => 'send_mail'}, :html => {:id => 'mailing-form'} do |f| %>
10 10 <%= labelled_form_field(_('Subject:'), f.text_field(:subject)) %>
11   - <%= labelled_form_field(_('Body:'), f.text_area(:body)) %>
  11 + <%= labelled_form_field(_('Body:'), f.text_area(:body, :class => 'mceEditor')) %>
12 12 <%= submit_button(:send, _('Send')) %>
13 13 <%= button :cancel, _('Cancel e-mail'), :action => 'index' %>
14 14 <% end %>
... ...
app/views/search/_event.rhtml
1   -<li>
2   - <strong><%= link_to(event.title, event.url, :class => icon_for_article(event)) %></strong>
  1 +<li class="<%= icon_for_article(event) %>">
  2 + <strong><%= link_to(event.title, event.url) %></strong>
3 3 <div class="item_meta">
4 4 <%= show_period(event.start_date, event.end_date) %>
5 5 </div>
... ...
app/views/search/products.rhtml
... ... @@ -23,6 +23,6 @@
23 23 </div><!-- class="has_cat_list" -->
24 24 <% end %>
25 25  
26   -<%= will_paginate @results[:products] %>
  26 +<%= pagination_links @results[:products] %>
27 27  
28 28 <br style="clear:both" />
... ...
app/views/shared/_organization_custom_fields.rhtml
1 1 <%= optional_field(profile, 'display_name', f.text_field(:display_name)) %>
  2 +<% if profile.enterprise? %>
  3 + <%= optional_field(profile, 'business_name', f.text_field(:business_name)) %>
  4 +<% end %>
2 5 <%= optional_field(profile, 'description', f.text_area(:description, :rows => 5)) %> <!-- , :maxlength => 10 -->
3 6 <%= optional_field(profile, 'contact_person', f.text_field(:contact_person)) %>
4 7 <%= optional_field(profile, 'contact_email', f.text_field(:contact_email)) %>
... ... @@ -18,7 +21,6 @@
18 21 <% end %>
19 22  
20 23 <% if profile.enterprise? %>
21   - <%= optional_field(profile, 'business_name', f.text_field(:business_name)) %>
22 24 <%= optional_field(profile, 'organization_website', f.text_field(:organization_website)) %>
23 25 <%= optional_field(profile, 'historic_and_current_context', f.text_area(:historic_and_current_context, :rows => 5)) %>
24 26 <%= optional_field(profile, 'activities_short_description', f.text_area(:activities_short_description, :rows => 5)) %>
... ...
app/views/shared/tiny_mce.rhtml
... ... @@ -21,7 +21,6 @@ tinyMCE.init({
21 21 theme : "advanced",
22 22 relative_urls : false,
23 23 remove_script_host : true,
24   - document_base_url : <%= environment.top_url.to_json %>,
25 24 plugins: myplugins,
26 25 theme_advanced_toolbar_location : "top",
27 26 theme_advanced_layout_manager: 'SimpleLayout',
... ...
app/views/users/send_mail.rhtml
... ... @@ -6,7 +6,7 @@
6 6  
7 7 <% form_for :mailing, :url => {:action => 'send_mail'} do |f| %>
8 8 <%= labelled_form_field(_('Subject:'), f.text_field(:subject)) %>
9   - <%= labelled_form_field(_('Body:'), f.text_area(:body)) %>
  9 + <%= labelled_form_field(_('Body:'), f.text_area(:body, :class => 'mceEditor')) %>
10 10 <%= submit_button(:send, _('Send')) %>
11 11 <%= button :cancel, _('Cancel e-mail'), :controller => 'users' %>
12 12 <% end %>
... ...
db/migrate/20110316171323_change_discount_to_decimal.rb 0 → 100644
... ... @@ -0,0 +1,13 @@
  1 +class ChangeDiscountToDecimal < ActiveRecord::Migration
  2 + def self.up
  3 + change_table :products do |t|
  4 + t.change :discount, :decimal
  5 + end
  6 + end
  7 +
  8 + def self.down
  9 + change_table :products do |t|
  10 + t.change :discount, :float
  11 + end
  12 + end
  13 +end
... ...
db/schema.rb
... ... @@ -9,7 +9,7 @@
9 9 #
10 10 # It's strongly recommended to check this file into your version control system.
11 11  
12   -ActiveRecord::Schema.define(:version => 20110302214607) do
  12 +ActiveRecord::Schema.define(:version => 20110316171323) do
13 13  
14 14 create_table "action_tracker", :force => true do |t|
15 15 t.integer "user_id"
... ... @@ -345,7 +345,7 @@ ActiveRecord::Schema.define(:version =&gt; 20110302214607) do
345 345 t.datetime "updated_at"
346 346 t.float "lat"
347 347 t.float "lng"
348   - t.float "discount"
  348 + t.decimal "discount"
349 349 t.boolean "available", :default => true
350 350 t.boolean "highlighted"
351 351 t.integer "unit_id"
... ...
debian/changelog
  1 +noosfero (0.29.4) unstable; urgency=low
  2 +
  3 + * Bugfixes Version release. (Closes: AI#1938 AI#1943 AI#1928 AI#1929 AI#1932 AI#1946 AI#1909 AI#1947 AI#1935 AI#1930 AI#1936 AI#1926 AI#1922)
  4 +
  5 + -- Joenio Costa <joenio@colivre.coop.br> Thu, 24 Mar 2011 10:31:35 -0300
  6 +
1 7 noosfero (0.29.3) unstable; urgency=low
2 8  
3 9 * Bugfixes Version release. (Closes: AI#1760 AI#1907 AI#1899 AI#1891 AI#1904 AI#1888 AI#1869 AI#1900 AI#1914)
... ...
features/chat.feature
... ... @@ -64,7 +64,7 @@ Feature: chat
64 64 And I am logged in as "tame"
65 65 When I follow "Open chat"
66 66 And I select window "noosfero_chat"
67   - Then I should see "Chat - Colivre.net - Friends online (0)"
  67 + Then I should see "Chat - Colivre.net - Friends in chat (0)"
68 68  
69 69 @selenium
70 70 Scenario: open chat with an online user in a new window
... ... @@ -75,7 +75,7 @@ Feature: chat
75 75 When I click "#chat-online-users-title"
76 76 And I follow "Maria Silva"
77 77 And I select window "noosfero_chat"
78   - Then I should see "Chat - Colivre.net - Friends online (0)"
  78 + Then I should see "Chat - Colivre.net - Friends in chat (0)"
79 79  
80 80 @selenium
81 81 Scenario: chat starts disconnected by default
... ... @@ -141,4 +141,4 @@ Feature: chat
141 141 When I go to Autoramas's profile
142 142 And I follow "Enter chat room"
143 143 And I select window "noosfero_chat"
144   - Then I should see "Chat - Colivre.net - Friends online (0)"
  144 + Then I should see "Chat - Colivre.net - Friends in chat (0)"
... ...
features/upload_files.feature 0 → 100644
... ... @@ -0,0 +1,42 @@
  1 +Feature: upload files
  2 + As a logged user
  3 + I want to upload files
  4 +
  5 + Background:
  6 + Given the following users
  7 + | login | name |
  8 + | joaosilva | Joao Silva |
  9 + And I am logged in as "joaosilva"
  10 +
  11 +
  12 + Scenario: provile links to upload files to community's gallery
  13 + Given the following communities
  14 + | identifier | name | owner |
  15 + | sample-community | Sample Community | joaosilva |
  16 + And the following galleries
  17 + | owner | name |
  18 + | sample-community | Gallery test |
  19 + And I go to Sample Community's profile
  20 + And I follow "0 pictures"
  21 + And I should see "Upload files"
  22 +
  23 + Scenario: provile links to upload files to enterprise's gallery
  24 + Given the following enterprises
  25 + | identifier | name | owner |
  26 + | sample-enterprise | Sample Enterprise | joaosilva |
  27 + And the following galleries
  28 + | owner | name |
  29 + | sample-enterprise | Gallery test |
  30 + And I go to Sample Enterprise's profile
  31 + And I follow "0 pictures"
  32 + And I should see "Upload files"
  33 +
  34 + Scenario: not provile links to upload files on blogs
  35 + Given the following communities
  36 + | identifier | name | owner |
  37 + | sample-community | Sample Community | joaosilva |
  38 + And the following blogs
  39 + | owner | name |
  40 + | sample-community | Blog test |
  41 + And I go to Sample Community's blog
  42 + And I should not see "Upload files"
... ...
lib/noosfero.rb
1 1 module Noosfero
2 2 PROJECT = 'noosfero'
3   - VERSION = '0.29.3'
  3 + VERSION = '0.29.4'
4 4  
5 5 def self.pattern_for_controllers_in_directory(dir)
6 6 disjunction = controllers_in_directory(dir).join('|')
... ...
public/stylesheets/application.css
... ... @@ -3935,6 +3935,7 @@ h1#agenda-title {
3935 3935 float: right;
3936 3936 padding: 5px;
3937 3937 margin-bottom: 5px;
  3938 + margin-left: 10px;
3938 3939 }
3939 3940 .controller-memberships #memberships-index li .may-clear {
3940 3941 clear: right;
... ...
test/functional/cms_controller_test.rb
... ... @@ -115,9 +115,7 @@ class CmsControllerTest &lt; Test::Unit::TestCase
115 115  
116 116 post :set_home_page, :profile => profile.identifier, :id => a.id
117 117  
118   - assert_redirected_to :action => 'view', :id => a.id
119   -
120   - profile = Profile.find(@profile.id)
  118 + profile.reload
121 119 assert_equal a, profile.home_page
122 120 end
123 121  
... ... @@ -133,12 +131,26 @@ class CmsControllerTest &lt; Test::Unit::TestCase
133 131  
134 132 post :set_home_page, :profile => profile.identifier, :id => a.id
135 133  
136   - assert_redirected_to :action => 'view', :id => a.id
137   -
138   - profile = Profile.find(@profile.id)
  134 + profile.reload
139 135 assert_equal a, profile.home_page
140 136 end
141 137  
  138 + should 'redirect to previous page after setting home page' do
  139 + a = profile.articles.build(:name => 'my new home page')
  140 + a.save!
  141 +
  142 + @request.env['HTTP_REFERER'] = '/random_page'
  143 + post :set_home_page, :profile => profile.identifier, :id => a.id
  144 + assert_redirected_to '/random_page'
  145 + end
  146 +
  147 + should 'redirect to profile homepage after setting home page if no referer' do
  148 + a = profile.articles.build(:name => 'my new home page')
  149 + a.save!
  150 +
  151 + post :set_home_page, :profile => profile.identifier, :id => a.id
  152 + assert_redirected_to profile.url
  153 + end
142 154  
143 155 should 'set last_changed_by when creating article' do
144 156 login_as(profile.identifier)
... ...
test/unit/approve_article_test.rb
... ... @@ -378,4 +378,31 @@ class ApproveArticleTest &lt; ActiveSupport::TestCase
378 378 end
379 379 end
380 380  
  381 + should 'approve same article twice changing its name' do
  382 + task1 = ApproveArticle.create!(:article => article, :target => community, :requestor => profile)
  383 + assert_difference article.class, :count do
  384 + task1.finish
  385 + end
  386 + task2 = ApproveArticle.create!(:name => article.name + ' v2', :article => article, :target => community, :requestor => profile)
  387 + assert_difference article.class, :count do
  388 + assert_nothing_raised ActiveRecord::RecordInvalid do
  389 + task2.finish
  390 + end
  391 + end
  392 + end
  393 +
  394 + should 'not approve same article twice if not changing its name' do
  395 + task1 = ApproveArticle.create!(:article => article, :target => community, :requestor => profile)
  396 + assert_difference article.class, :count do
  397 + task1.finish
  398 + end
  399 + task2 = ApproveArticle.create!(:article => article, :target => community, :requestor => profile)
  400 + assert_no_difference article.class, :count do
  401 + assert_raises ActiveRecord::RecordInvalid do
  402 + task2.finish
  403 + end
  404 + end
  405 + end
  406 +
  407 +
381 408 end
... ...
test/unit/article_test.rb
... ... @@ -576,10 +576,10 @@ class ArticleTest &lt; Test::Unit::TestCase
576 576 assert_kind_of Folder, b
577 577 end
578 578  
579   - should 'copy slug' do
  579 + should 'not copy slug' do
580 580 a = fast_create(Article, :slug => 'slug123')
581 581 b = a.copy({})
582   - assert_equal a.slug, b.slug
  582 + assert a.slug != b.slug
583 583 end
584 584  
585 585 should 'load article under an old path' do
... ... @@ -1474,4 +1474,28 @@ class ArticleTest &lt; Test::Unit::TestCase
1474 1474 end
1475 1475 end
1476 1476  
  1477 + should 'accept uploads if parent accept uploads' do
  1478 + folder = fast_create(Folder)
  1479 + child = fast_create(UploadedFile, :parent_id => folder.id)
  1480 + assert folder.accept_uploads?
  1481 + assert child.accept_uploads?
  1482 + end
  1483 +
  1484 + should 'not accept uploads if has no parent' do
  1485 + child = fast_create(UploadedFile)
  1486 + assert !child.accept_uploads?
  1487 + end
  1488 +
  1489 + should 'not accept uploads if parent is a blog' do
  1490 + folder = fast_create(Blog)
  1491 + child = fast_create(UploadedFile, :parent_id => folder.id)
  1492 + assert !child.accept_uploads?
  1493 + end
  1494 +
  1495 + should 'not accept uploads if parent is a forum' do
  1496 + folder = fast_create(Forum)
  1497 + child = fast_create(UploadedFile, :parent_id => folder.id)
  1498 + assert !child.accept_uploads?
  1499 + end
  1500 +
1477 1501 end
... ...
test/unit/blog_test.rb
... ... @@ -206,4 +206,9 @@ class BlogTest &lt; ActiveSupport::TestCase
206 206 assert_includes blog.posts, article
207 207 end
208 208  
  209 + should 'not accept uploads' do
  210 + folder = fast_create(Blog)
  211 + assert !folder.accept_uploads?
  212 + end
  213 +
209 214 end
... ...
test/unit/folder_test.rb
... ... @@ -140,4 +140,9 @@ class FolderTest &lt; ActiveSupport::TestCase
140 140 assert folder.errors.on(:parent)
141 141 end
142 142  
  143 + should 'accept uploads' do
  144 + folder = fast_create(Folder)
  145 + assert folder.accept_uploads?
  146 + end
  147 +
143 148 end
... ...
test/unit/forum_test.rb
... ... @@ -104,4 +104,9 @@ class ForumTest &lt; ActiveSupport::TestCase
104 104 assert Forum.new.has_posts?
105 105 end
106 106  
  107 + should 'not accept uploads' do
  108 + folder = fast_create(Forum)
  109 + assert !folder.accept_uploads?
  110 + end
  111 +
107 112 end
... ...
test/unit/gallery_test.rb
... ... @@ -141,4 +141,9 @@ class GalleryTest &lt; ActiveSupport::TestCase
141 141 assert_no_match /[<>]/, gallery.body
142 142 end
143 143  
  144 + should 'accept uploads' do
  145 + folder = fast_create(Gallery)
  146 + assert folder.accept_uploads?
  147 + end
  148 +
144 149 end
... ...