Commit 619223c680bd8fcedc16ed16ceb432223922df94

Authored by Rodrigo Souto
Committed by Joenio Costa
1 parent 4fe87ea2

Bsc Plugin

* Refactoring profile management to use tokeninput
  * Also, adding support of tokeninput to the core
* Adding attributes validated and cnpj to enterprise
* Environment option to define enterprise as validated by defaul
* Making profile namedscopes consider subclasses too
* Adapting enterprise icon and identification to meet Bsc expectations
* Adapting profile info actions to meet Bsc expectations
* Adapting control panel buttons to meet Bsc expectations
* Adapting core product to meed Bsc expectations
* Adding and fixing plugin hotspots

(ActionItem2085, ActionItem2087, ActionItem2086, ActionItem2088)
Showing 104 changed files with 6763 additions and 434 deletions   Show diff stats

Too many changes.

To preserve performance only 100 of 104 files displayed.

app/controllers/application.rb
... ... @@ -128,6 +128,21 @@ class ApplicationController < ActionController::Base
128 128  
129 129 def init_noosfero_plugins
130 130 @plugins = Noosfero::Plugin::Manager.new(self)
  131 + @plugins.enabled_plugins.map(&:class).each do |plugin|
  132 + prepend_view_path(plugin.view_path)
  133 + end
  134 + init_noosfero_plugins_controller_filters
  135 + end
  136 +
  137 + # This is a generic method that initialize any possible filter defined by a
  138 + # plugin to the current controller being initialized.
  139 + def init_noosfero_plugins_controller_filters
  140 + @plugins.enabled_plugins.each do |plugin|
  141 + plugin.send(self.class.name.underscore + '_filters').each do |plugin_filter|
  142 + self.class.send(plugin_filter[:type], plugin.class.name.underscore + '_' + plugin_filter[:method_name], (plugin_filter[:options] || {}))
  143 + self.class.send(:define_method, plugin.class.name.underscore + '_' + plugin_filter[:method_name], plugin_filter[:block])
  144 + end
  145 + end
131 146 end
132 147  
133 148 def load_terminology
... ...
app/controllers/my_profile/manage_products_controller.rb
... ... @@ -4,6 +4,7 @@ class ManageProductsController < ApplicationController
4 4 protect 'manage_products', :profile, :except => [:show]
5 5 before_filter :check_environment_feature
6 6 before_filter :login_required, :except => [:show]
  7 + before_filter :create_product?, :only => [:new]
7 8  
8 9 protected
9 10  
... ... @@ -14,6 +15,13 @@ class ManageProductsController < ApplicationController
14 15 end
15 16 end
16 17  
  18 + def create_product?
  19 + if !profile.create_product?
  20 + render_access_denied
  21 + return
  22 + end
  23 + end
  24 +
17 25 public
18 26  
19 27 def index
... ...
app/controllers/my_profile/profile_members_controller.rb
1 1 class ProfileMembersController < MyProfileController
2 2 protect 'manage_memberships', :profile
3   - no_design_blocks
4 3  
5 4 def index
6 5 @members = profile.members
... ... @@ -15,29 +14,23 @@ class ProfileMembersController &lt; MyProfileController
15 14 rescue ActiveRecord::RecordNotFound
16 15 @person = nil
17 16 end
18   - if !params[:confirmation] && @person && @person.is_last_admin_leaving?(profile, @roles)
19   - redirect_to :action => :last_admin, :roles => params[:roles], :person => @person
20   - else
21   - if @person && @person.define_roles(@roles, profile)
  17 +
  18 + if @person
  19 + if@person.is_last_admin_leaving?(profile, @roles)
  20 + redirect_to :action => :last_admin
  21 + elsif @person.define_roles(@roles, profile)
22 22 session[:notice] = _('Roles successfuly updated')
  23 + redirect_to :controller => 'profile_editor'
23 24 else
24 25 session[:notice] = _('Couldn\'t change the roles')
25   - end
26   - if params[:confirmation]
27   - redirect_to profile.url
28   - else
29   - redirect_to :action => :index
  26 + redirect_to :action => 'index'
30 27 end
31 28 end
32 29 end
33 30  
34 31 def last_admin
35   - @person = params[:person]
36   - @roles = params[:roles] || []
37   - @members = profile.members.select {|member| !profile.admins.include?(member)}
38   - @title = _('Current admins')
39   - @collection = :profile_admins
40   - @remove_action = {:action => 'remove_admin'}
  32 + @roles = [Profile::Roles.admin(environment.id)]
  33 + @pre_population = [].to_json
41 34 end
42 35  
43 36 def add_role
... ... @@ -90,6 +83,7 @@ class ProfileMembersController &lt; MyProfileController
90 83 end
91 84  
92 85 def add_members
  86 + @roles = Profile::Roles.organization_member_roles(environment.id)
93 87 end
94 88  
95 89 def add_member
... ... @@ -122,19 +116,42 @@ class ProfileMembersController &lt; MyProfileController
122 116 render :layout => false
123 117 end
124 118  
125   - def find_users
126   - if !params[:query] || params[:query].length <= 2
127   - @users_found = []
128   - elsif params[:scope] == 'all_users'
129   - @users_found = Person.find_by_contents(params[:query] + '*').select {|user| !profile.members.include?(user)}
130   - @button_alt = _('Add member')
131   - @add_action = {:action => 'add_member'}
132   - elsif params[:scope] == 'new_admins'
133   - @users_found = Person.find_by_contents(params[:query] + '*').select {|user| profile.members.include?(user) && !profile.admins.include?(user)}
134   - @button_alt = _('Add member')
135   - @add_action = {:action => 'add_admin'}
  119 + def search_user
  120 + role = Role.find(params[:role])
  121 + render :text => environment.people.find(:all, :conditions => ['LOWER(name) LIKE ? OR LOWER(identifier) LIKE ?', "%#{params['q_'+role.key]}%", "%#{params['q_'+role.key]}%"]).
  122 + select { |person| !profile.members_by_role(role).include?(person) }.
  123 + map {|person| {:id => person.id, :name => person.name} }.
  124 + to_json
  125 + end
  126 +
  127 + def save_associations
  128 + error = false
  129 + roles = Profile::Roles.organization_member_roles(environment.id)
  130 + roles.select { |role| params['q_'+role.key] }.each do |role|
  131 + people = [Person.find(params['q_'+role.key].split(','))].flatten
  132 + to_remove = profile.members_by_role(role) - people
  133 + to_add = people - profile.members_by_role(role)
  134 +
  135 + begin
  136 + to_remove.each { |person| profile.disaffiliate(person, role) }
  137 + to_add.each { |person| profile.affiliate(person, role) }
  138 + rescue Exception => ex
  139 + logger.info ex
  140 + error = true
  141 + end
  142 + end
  143 +
  144 + if error
  145 + session[:notice] = _('The members list couldn\'t be updated. Please contact the administrator.')
  146 + redirect_to :action => 'add_members'
  147 + else
  148 + if profile.admins.blank? && !params[:last_admin]
  149 + redirect_to :action => 'last_admin'
  150 + else
  151 + session[:notice] = _('The members list was updated.')
  152 + redirect_to :controller => 'profile_editor'
  153 + end
136 154 end
137   - render :layout => false
138 155 end
139 156  
140 157 def send_mail
... ...
app/helpers/application_helper.rb
... ... @@ -298,6 +298,17 @@ module ApplicationHelper
298 298 partial_for_task_class(klass.superclass, action)
299 299 end
300 300  
  301 + def view_for_profile_actions(klass)
  302 + raise ArgumentError, 'No profile actions view for this class.' if klass.nil?
  303 +
  304 + name = klass.name.underscore
  305 + VIEW_EXTENSIONS.each do |ext|
  306 + return "blocks/profile_info_actions/"+name+ext if File.exists?(File.join(RAILS_ROOT, 'app', 'views', 'blocks', 'profile_info_actions', name+ext))
  307 + end
  308 +
  309 + view_for_profile_actions(klass.superclass)
  310 + end
  311 +
301 312 def user
302 313 @controller.send(:user)
303 314 end
... ... @@ -970,7 +981,8 @@ module ApplicationHelper
970 981 'lightbox',
971 982 'colorpicker',
972 983 pngfix_stylesheet_path,
973   - ]
  984 + ] +
  985 + tokeninput_stylesheets
974 986 end
975 987  
976 988 # DEPRECATED. Do not use this·
... ... @@ -982,6 +994,10 @@ module ApplicationHelper
982 994 'iepngfix/iepngfix.css'
983 995 end
984 996  
  997 + def tokeninput_stylesheets
  998 + ['token-input', 'token-input-facebook', 'token-input-mac']
  999 + end
  1000 +
985 1001 def noosfero_layout_features
986 1002 render :file => 'shared/noosfero_layout_features'
987 1003 end
... ... @@ -1127,7 +1143,7 @@ module ApplicationHelper
1127 1143 def manage_enterprises
1128 1144 if user && !user.enterprises.empty?
1129 1145 enterprises_link = user.enterprises.map do |enterprise|
1130   - link_to(content_tag('strong', [_('<span>Manage</span> %s') % enterprise.short_name(25)]), @environment.top_url + "/myprofile/#{enterprise.identifier}", :class => "icon-menu-enterprise", :title => [_('Manage %s') % enterprise.short_name])
  1146 + link_to(content_tag('strong', [_('<span>Manage</span> %s') % enterprise.short_name(25)]), @environment.top_url + "/myprofile/#{enterprise.identifier}", :class => "icon-menu-"+enterprise.class.identification.underscore, :title => [_('Manage %s') % enterprise.short_name])
1131 1147 end
1132 1148 render :partial => 'shared/manage_enterprises', :locals => {:enterprises_link => enterprises_link}
1133 1149 end
... ...
app/helpers/catalog_helper.rb
... ... @@ -6,14 +6,17 @@ include ManageProductsHelper
6 6 def display_products_list(profile, products)
7 7 data = ''
8 8 extra_content = []
  9 + extra_content_list = []
9 10 products.each { |product|
10 11 extra_content = @plugins.map(:catalog_item_extras, product).collect { |content| instance_eval(&content) } if @plugins
  12 + extra_content_list = @plugins.map(:catalog_list_item_extras, product).collect { |content| instance_eval(&content) } if @plugins
11 13 data << content_tag('li',
12 14 link_to_product(product, :class => 'product-pic', :style => 'background-image:url(%s)' % product.default_image(:portrait) ) +
13 15 content_tag('h3', link_to_product(product)) +
14 16 content_tag('ul',
15 17 (product.price ? content_tag('li', _('Price: %s') % ( "%.2f" % product.price), :class => 'product_price') : '') +
16   - content_tag('li', product_category_name(profile, product.product_category), :class => 'product_category')
  18 + content_tag('li', product_category_name(profile, product.product_category), :class => 'product_category') +
  19 + extra_content_list.map { |content| content_tag('li', content)}.join("\n")
17 20 ) +
18 21 (product.description ? content_tag('div',
19 22 txt2html(product.description),
... ...
app/models/community.rb
... ... @@ -75,4 +75,8 @@ class Community &lt; Organization
75 75 end
76 76 end
77 77  
  78 + def control_panel_settings_button
  79 + {:title => __('Community Info and settings'), :icon => 'edit-profile-group'}
  80 + end
  81 +
78 82 end
... ...
app/models/enterprise.rb
... ... @@ -147,6 +147,7 @@ class Enterprise &lt; Organization
147 147 end
148 148  
149 149 before_create do |enterprise|
  150 + enterprise.validated = enterprise.environment.enabled?('enterprises_are_validated_when_created')
150 151 if enterprise.environment.enabled?('enterprises_are_disabled_when_created')
151 152 enterprise.enabled = false
152 153 end
... ... @@ -167,4 +168,12 @@ class Enterprise &lt; Organization
167 168 enable_contact_us
168 169 end
169 170  
  171 + def control_panel_settings_button
  172 + {:title => __('Enterprise Info and settings'), :icon => 'edit-profile-enterprise'}
  173 + end
  174 +
  175 + def create_product?
  176 + true
  177 + end
  178 +
170 179 end
... ...
app/models/environment.rb
... ... @@ -117,6 +117,7 @@ class Environment &lt; ActiveRecord::Base
117 117 'enable_organization_url_change' => _("Allow organizations to change their URL"),
118 118 'admin_must_approve_new_communities' => _("Admin must approve creation of communities"),
119 119 'enterprises_are_disabled_when_created' => __('Enterprises are disabled when created'),
  120 + 'enterprises_are_validated_when_created' => __('Enterprises are validated when created'),
120 121 'show_balloon_with_profile_links_when_clicked' => _('Show a balloon with profile links when a profile image is clicked'),
121 122 'xmpp_chat' => _('XMPP/Jabber based chat'),
122 123 'show_zoom_button_on_article_images' => _('Show a zoom link on all article images')
... ... @@ -255,11 +256,22 @@ class Environment &lt; ActiveRecord::Base
255 256 self.settings["#{feature}_enabled".to_sym] = true
256 257 end
257 258  
  259 + def enable_plugin(plugin)
  260 + self.enabled_plugins += [plugin]
  261 + self.enabled_plugins.uniq!
  262 + self.save!
  263 + end
  264 +
258 265 # Disables a feature identified by its name
259 266 def disable(feature)
260 267 self.settings["#{feature}_enabled".to_sym] = false
261 268 end
262 269  
  270 + def disable_plugin(plugin)
  271 + self.enabled_plugins.delete(plugin)
  272 + self.save!
  273 + end
  274 +
263 275 # Tells if a feature, identified by its name, is enabled
264 276 def enabled?(feature)
265 277 self.settings["#{feature}_enabled".to_sym] == true
... ...
app/models/organization.rb
... ... @@ -95,12 +95,12 @@ class Organization &lt; Profile
95 95 []
96 96 end
97 97  
98   - N_('Display name'); N_('Description'); N_('Contact person'); N_('Contact email'); N_('Acronym'); N_('Foundation year'); N_('Legal form'); N_('Economic activity'); N_('Management information'); N_('Validated'); N_('Tag list')
99   - settings_items :display_name, :description, :contact_person, :contact_email, :acronym, :foundation_year, :legal_form, :economic_activity, :management_information, :validated, :cnpj
  98 + N_('Display name'); N_('Description'); N_('Contact person'); N_('Contact email'); N_('Acronym'); N_('Foundation year'); N_('Legal form'); N_('Economic activity'); N_('Management information'); N_('Tag list')
  99 + settings_items :display_name, :description, :contact_person, :contact_email, :acronym, :foundation_year, :legal_form, :economic_activity, :management_information
100 100  
101 101 validates_format_of :foundation_year, :with => Noosfero::Constants::INTEGER_FORMAT
102   -
103 102 validates_format_of :contact_email, :with => Noosfero::Constants::EMAIL_FORMAT, :if => (lambda { |org| !org.contact_email.blank? })
  103 + validates_as_cnpj :cnpj
104 104  
105 105 xss_terminate :only => [ :acronym, :contact_person, :contact_email, :legal_form, :economic_activity, :management_information ], :on => 'validation'
106 106  
... ... @@ -149,4 +149,12 @@ class Organization &lt; Profile
149 149 false
150 150 end
151 151  
  152 + def members_to_json
  153 + members.map { |member| {:id => member.id, :name => member.name} }.to_json
  154 + end
  155 +
  156 + def members_by_role_to_json(role)
  157 + members_by_role(role).map { |member| {:id => member.id, :name => member.name} }.to_json
  158 + end
  159 +
152 160 end
... ...
app/models/person.rb
... ... @@ -389,6 +389,10 @@ class Person &lt; Profile
389 389 leave_hash.to_json
390 390 end
391 391  
  392 + def control_panel_settings_button
  393 + {:title => _('Profile Info and settings'), :icon => 'edit-profile'}
  394 + end
  395 +
392 396 protected
393 397  
394 398 def followed_by?(profile)
... ...
app/models/product.rb
... ... @@ -149,4 +149,8 @@ class Product &lt; ActiveRecord::Base
149 149 unit.blank? ? name : "#{name} - #{unit.name.downcase}"
150 150 end
151 151  
  152 + def display_supplier_on_search?
  153 + true
  154 + end
  155 +
152 156 end
... ...
app/models/profile.rb
... ... @@ -52,8 +52,9 @@ class Profile &lt; ActiveRecord::Base
52 52 acts_as_accessible
53 53  
54 54 named_scope :memberships_of, lambda { |person| { :select => 'DISTINCT profiles.*', :joins => :role_assignments, :conditions => ['role_assignments.accessor_type = ? AND role_assignments.accessor_id = ?', person.class.base_class.name, person.id ] } }
55   - named_scope :enterprises, :conditions => "profiles.type = 'Enterprise'"
56   - named_scope :communities, :conditions => "profiles.type = 'Community'"
  55 + #FIXME: these will work only if the subclass is already loaded
  56 + named_scope :enterprises, lambda { {:conditions => (Enterprise.send(:subclasses).map(&:name) << 'Enterprise').map { |klass| "profiles.type = '#{klass}'"}.join(" OR ")} }
  57 + named_scope :communities, lambda { {:conditions => (Community.send(:subclasses).map(&:name) << 'Community').map { |klass| "profiles.type = '#{klass}'"}.join(" OR ")} }
57 58  
58 59 def members
59 60 Person.members_of(self)
... ... @@ -564,9 +565,7 @@ private :generate_url, :url_options
564 565 if self.closed? && members_count > 0
565 566 AddMember.create!(:person => person, :organization => self) unless self.already_request_membership?(person)
566 567 else
567   - if members_count == 0
568   - self.affiliate(person, Profile::Roles.admin(environment.id))
569   - end
  568 + self.affiliate(person, Profile::Roles.admin(environment.id)) if members_count == 0
570 569 self.affiliate(person, Profile::Roles.member(environment.id))
571 570 end
572 571 else
... ... @@ -817,6 +816,14 @@ private :generate_url, :url_options
817 816 end
818 817 end
819 818  
  819 + def control_panel_settings_button
  820 + {:title => _('Profile Info and settings'), :icon => 'edit-profile'}
  821 + end
  822 +
  823 + def self.identification
  824 + name
  825 + end
  826 +
820 827 protected
821 828  
822 829 def followed_by?(person)
... ...
app/views/admin_panel/index.rhtml
... ... @@ -16,4 +16,7 @@
16 16 <tr><td><%= link_to _('Manage Fields'), :controller => 'features', :action => 'manage_fields' %></td></tr>
17 17 <tr><td><%= link_to _('Set Portal'), :action => 'set_portal_community' %></td></tr>
18 18 <tr><td><%= link_to _('Terms of use'), :action => 'terms_of_use' %></td></tr>
  19 + <% @plugins.map(:admin_panel_links).each do |link| %>
  20 + <tr><td><%= link_to link[:title], link[:url] %></td></tr>
  21 + <% end %>
19 22 </table>
... ...
app/views/layouts/_javascript.rhtml
1   -<%= javascript_include_tag :defaults, 'jquery-latest.js', 'jquery.noconflict.js', 'jquery.cycle.all.min.js', 'thickbox.js', 'lightbox', 'jquery-ui-1.8.2.custom.min', 'jquery.scrollTo', 'jquery.form.js', 'jquery.cookie', 'reflection', 'add-and-join', :cache => 'cache-general' %>
  1 +<%= javascript_include_tag :defaults, 'jquery-latest.js', 'jquery.noconflict.js', 'jquery.cycle.all.min.js', 'thickbox.js', 'lightbox', 'jquery-ui-1.8.2.custom.min', 'jquery.scrollTo', 'jquery.form.js', 'jquery.cookie', 'reflection', 'add-and-join', 'jquery.tokeninput', :cache => 'cache-general' %>
... ...
app/views/manage_products/index.rhtml
... ... @@ -25,6 +25,6 @@
25 25 <%= pagination_links @products %>
26 26  
27 27 <% button_bar do %>
28   - <%= button :add, _('New product or service'), :action => 'new' %>
  28 + <%= button :add, _('New product or service'), :action => 'new' if @profile.create_product? %>
29 29 <%= button :back, _('Back'), { :controller => 'profile_editor', :profile => @profile.identifier, :action => 'index' } %>
30 30 <% end %>
... ...
app/views/memberships/index.rhtml
... ... @@ -17,7 +17,7 @@
17 17 <span class='profile-details'>
18 18 <strong><%= membership.name %></strong><br/>
19 19 <%= _('Role: %s') % rolename_for(profile, membership) %> <br/>
20   - <%= _('Type: %s') % getterm(membership.class.name) %> <br/>
  20 + <%= _('Type: %s') % getterm(membership.class.identification) %> <br/>
21 21 <%= _('Description: %s') % membership.description + '<br/>' if membership.community? %>
22 22 <%= _('Members: %s') % membership.members.size.to_s %> <br/>
23 23 <%= _('Created at: %s') % show_date(membership.created_at) unless membership.enterprise? %> <br/>
... ...
app/views/profile/_profile.rhtml
1 1 <tr>
2 2 <td colspan='2'>
3 3  
4   - <% plugins_tabs = @plugins.map(:profile_tabs) %>
  4 + <% plugins_tabs = @plugins.map(:profile_tabs).
  5 + map { |tab| {:title => tab[:title], :id => tab[:id], :content => instance_eval(&tab[:content]), :start => tab[:title]} }%>
5 6  
6 7 <% tabs = plugins_tabs.select { |tab| tab[:start] } %>
7 8  
... ...
app/views/profile/profile_info.rjs
... ... @@ -3,4 +3,4 @@ if !user.nil? and user.has_permission?(&#39;edit_profile&#39;, profile)
3 3 else
4 4 page.hide "profile-admin-url-#{@block.id}"
5 5 end
6   -page.replace_html "profile-info-options-#{@block.id}", :file => 'blocks/profile_info_actions/' + @block.owner.class.name.underscore
  6 +page.replace_html "profile-info-options-#{@block.id}", :file => view_for_profile_actions(@block.owner.class)
... ...
app/views/profile_editor/_moderation.html.erb 0 → 100644
... ... @@ -0,0 +1,35 @@
  1 +<h2><%= _('Moderation options') %></h2>
  2 +<% if profile.community? %>
  3 + <div style='margin-bottom: 1em'>
  4 + <%= _('New members must be approved:')%>
  5 + </div>
  6 + <div style='margin-bottom: 0.5em'>
  7 + <%= radio_button 'profile_data', 'closed', 'true', :style => 'float: left' %>
  8 + <div style='margin-left: 30px'>
  9 + <%= _('<strong>Before</strong> joining this group (a moderator has to accept the member in pending request before member can access the intranet and/or the website).') %>
  10 + </div>
  11 + </div>
  12 + <div>
  13 + <%= radio_button 'profile_data', 'closed', 'false', :style => 'float: left' %>
  14 + <div style='margin-left: 30px'>
  15 + <%= _('<strong>After</strong> joining this group (a moderator can always desactivate access for users later).') %>
  16 + </div>
  17 + </div>
  18 + <br>
  19 +<% end %>
  20 +<div style='margin-bottom: 1em'>
  21 + <%= _('New articles posted by members of this group must be approved:')%>
  22 +
  23 +</div>
  24 +<div style='margin-bottom: 0.5em'>
  25 + <%= radio_button 'profile_data', 'moderated_articles', 'true', :style => 'float: left' %>
  26 + <div style='margin-left: 30px'>
  27 + <%= _('<strong>Before</strong> being published in this group (a moderator has to accept the article in pending request before the article be listed as a article of this group).') %>
  28 + </div>
  29 +</div>
  30 +<div>
  31 + <%= radio_button 'profile_data', 'moderated_articles', 'false', :style => 'float: left' %>
  32 + <div style='margin-left: 30px'>
  33 + <%= _('<strong>After</strong> being published in this group (a moderator can always remove publicated articles later).') %>
  34 + </div>
  35 +</div>
... ...
app/views/profile_editor/_organization.rhtml
... ... @@ -58,42 +58,8 @@
58 58 </div>
59 59 <% end %>
60 60  
61   - <%= render :partial => 'shared/organization_custom_fields', :locals => { :f => f, :object_name => 'profile_data', :profile => @profile } %>
  61 +<%= render :partial => 'shared/organization_custom_fields', :locals => { :f => f, :object_name => 'profile_data', :profile => @profile } %>
62 62  
63   - <%= labelled_check_box(_('Enable "contact us"'), 'profile_data[enable_contact_us]', "1", @profile.enable_contact_us) if @profile.enterprise? %>
  63 +<%= labelled_check_box(_('Enable "contact us"'), 'profile_data[enable_contact_us]', "1", @profile.enable_contact_us) if @profile.enterprise? %>
64 64  
65   - <h1><%= _('Moderation options') %></h1>
66   - <% if profile.community? %>
67   - <div style='margin-bottom: 1em'>
68   - <%= _('New members must be approved:')%>
69   - </div>
70   - <div style='margin-bottom: 0.5em'>
71   - <%= radio_button 'profile_data', 'closed', 'true', :style => 'float: left' %>
72   - <div style='margin-left: 30px'>
73   - <%= _('<strong>Before</strong> joining this group (a moderator has to accept the member in pending request before member can access the intranet and/or the website).') %>
74   - </div>
75   - </div>
76   - <div>
77   - <%= radio_button 'profile_data', 'closed', 'false', :style => 'float: left' %>
78   - <div style='margin-left: 30px'>
79   - <%= _('<strong>After</strong> joining this group (a moderator can always desactivate access for users later).') %>
80   - </div>
81   - </div>
82   - <br>
83   - <% end %>
84   - <div style='margin-bottom: 1em'>
85   - <%= _('New articles posted by members of this group must be approved:')%>
86   -
87   - </div>
88   - <div style='margin-bottom: 0.5em'>
89   - <%= radio_button 'profile_data', 'moderated_articles', 'true', :style => 'float: left' %>
90   - <div style='margin-left: 30px'>
91   - <%= _('<strong>Before</strong> being published in this group (a moderator has to accept the article in pending request before the article be listed as a article of this group).') %>
92   - </div>
93   - </div>
94   - <div>
95   - <%= radio_button 'profile_data', 'moderated_articles', 'false', :style => 'float: left' %>
96   - <div style='margin-left: 30px'>
97   - <%= _('<strong>After</strong> being published in this group (a moderator can always remove publicated articles later).') %>
98   - </div>
99   - </div>
  65 +<%= render :partial => 'moderation', :locals => { :profile => @profile } %>
... ...
app/views/profile_editor/index.rhtml
... ... @@ -10,9 +10,9 @@
10 10  
11 11 <% control_panel do %>
12 12  
13   - <%= control_panel_button(_('Profile Info and settings'), 'edit-profile', :controller => 'profile_editor', :action => 'edit') if profile.person? %>
14   - <%= control_panel_button(__('Community Info and settings'), 'edit-profile-group', :controller => 'profile_editor', :action => 'edit') if profile.community? %>
15   - <%= control_panel_button(__('Enterprise Info and settings'), 'edit-profile-enterprise', :controller => 'profile_editor', :action => 'edit') if profile.enterprise? %>
  13 + <%= control_panel_button(profile.control_panel_settings_button[:title],
  14 + profile.control_panel_settings_button[:icon],
  15 + :controller => 'profile_editor', :action => 'edit') %>
16 16  
17 17 <%= control_panel_button(_('Location'), 'edit-location', :controller => 'maps', :action => 'edit_location') %>
18 18  
... ... @@ -58,9 +58,9 @@
58 58  
59 59 <% if profile.enterprise? %>
60 60 <% if profile.enabled? %>
61   - <%= control_panel_button(__('Disable Enterprise'), 'disable', :action => 'disable') %>
  61 + <%= control_panel_button(__('Disable'), 'disable', :action => 'disable') %>
62 62 <% else %>
63   - <%= control_panel_button(__('Enable Enterprise'), 'enable', :action => 'enable') %>
  63 + <%= control_panel_button(__('Enable'), 'enable', :action => 'enable') %>
64 64 <% end %>
65 65 <% end %>
66 66  
... ...
app/views/profile_members/_find_users.rhtml
... ... @@ -1 +0,0 @@
1   -find_users.rhtml
2 0 \ No newline at end of file
app/views/profile_members/_index_buttons.rhtml
... ... @@ -5,4 +5,7 @@
5 5 <%= button :search, _('Invite your friends to join %s') % profile.short_name, :controller => 'invite', :action => 'select_address_book' %>
6 6 <% end %>
7 7 <%= button :send, _('Send e-mail to members'), :action => 'send_mail' %>
  8 + <% @plugins.map(:manage_members_extra_buttons).each do |plugin_button| %>
  9 + <%= button plugin_button[:icon], plugin_button[:title], plugin_button[:url] %>
  10 + <% end %>
8 11 <% end %>
... ...
app/views/profile_members/_manage_roles.html.erb 0 → 100644
... ... @@ -0,0 +1,42 @@
  1 +<% form_tag :action => 'save_associations' do %>
  2 + <% @roles.each do |role|%>
  3 + <%= content_tag('p', content_tag('b', role.name.pluralize+':'), :style => 'margin-top: 30px; margin-bottom: 0px;') %>
  4 + <%= text_field_tag('q_'+role.key, nil, :id => 'search_'+role.key) %>
  5 + <%= hidden_field_tag(:last_admin, true) if from == 'last_admin'%>
  6 + <% end %>
  7 +
  8 + <% button_bar(:style => 'margin-top: 30px;') do %>
  9 + <%= submit_button('save', _('Save'))%>
  10 + <%= button('cancel', _('Cancel'), {:controller => 'profile_editor'})%>
  11 + <% end %>
  12 +<% end %>
  13 +
  14 +<% @roles.each do |role| %>
  15 + <% search_url = url_for(:action => 'search_user', :profile => profile.identifier, :role => role.id) %>
  16 + <% @pre_population ||= profile.members_by_role_to_json(role) %>
  17 + <script type="text/javascript">
  18 + jQuery(<%= ('#search_' + role.key).to_json %>)
  19 + .tokenInput("<%= search_url %>", {
  20 + prePopulate: <%= @pre_population %>,
  21 + hintText: <%= _('Type in a search term for users').to_json %>,
  22 + noResultsText: <%= _('No results').to_json %>,
  23 + searchingText: <%= _('Searching...').to_json %>,
  24 + searchDelay: 500,
  25 + backspaceDeleteItem: false,
  26 + preventDuplicates: true,
  27 + queryParam: <%= ('q_'+role.key).to_json %>
  28 + });
  29 +
  30 + jQuery("#token-input-search-enterprises")
  31 + .live("keydown", function(event){
  32 + if(event.keyCode == "13") return false;
  33 + });
  34 + </script>
  35 +<% end %>
  36 +
  37 +<script>
  38 + jQuery(function(){
  39 + jQuery('.token-input-input-token input').blur();
  40 + jQuery('.token-input-input-token input')[0].focus();
  41 + });
  42 +</script>
... ...
app/views/profile_members/add_members.rhtml
1   -<h2><%= _('Add members to %s') % profile.name %></h2>
  1 +<h1><%= _('Add members to %s') % profile.name %></h1>
2 2  
3   -<% form_remote_tag :url => {:action => 'find_users', :profile => profile.identifier, :scope => 'all_users'}, :update => 'users-list', :loading => '$("users-list").addClassName("loading")', :complete => '$("users-list").removeClassName("loading")' do %>
4   - <%= text_field_tag('query', '', :autocomplete => 'off') %>
5   - <%= submit_tag(_('Search')) %>
6   -<% end %>
7   -
8   -<%= observe_field('query', :url => {:action => 'find_users', :profile => profile.identifier, :scope => 'all_users'}, :update => 'users-list', :frequency => 1, :with => 'query', :condition => '$("query").value.length > 2', :loading => '$("users-list").addClassName("loading")', :complete => '$("users-list").removeClassName("loading")') %>
9   -<%= observe_field('query', :frequency => 1, :condition => '$("query").value.length <= 2', :function => '$("users-list").update($("empty-query").innerHTML)') %>
10   -
11   -<div id="users-list">
12   - <%= render :partial => 'find_users' %>
13   -</div>
14   -
15   -<div id='empty-query' style='display: none'>
16   - <%= render :partial => 'find_users' %>
17   -</div>
18   -
19   -<div id="members-list" class="add-members">
20   - <%= render :partial => 'members_list' %>
21   -</div>
22   -<%= drop_receiving_element('members-list',
23   - :url => {:action => 'add_member', :profile => profile.identifier},
24   - :before => '$("tr-" + element.id).hide()',
25   - :loading => '$("members-list").addClassName("loading")',
26   - :update => 'members-list',
27   - :success => '$("tr-" + element.id).hide(); $(element.id).show();',
28   - :complete => '$("members-list").removeClassName("loading")') %>
29   -
30   -<br style="clear:both" />
  3 +<%= render :partial => 'manage_roles', :locals => {:from => 'add_members'} %>
... ...
app/views/profile_members/find_users.rhtml
... ... @@ -1,35 +0,0 @@
1   -<h3> <%= _('Users') %> </h3>
2   -<table>
3   - <tr><th><%= _('Name') %></th><th></th></tr>
4   - <% @users_found.each do |user| %>
5   - <tr id="tr-<%= user.identifier %>">
6   - <td>
7   - <div id="<%= user.identifier %>" class="draggable-user">
8   - <%= image_tag('/images/grip-clue.png') %>
9   - <%= profile_image(user, :icon) %>
10   - <%= [link_to_profile(user.short_name + " (#{user.identifier})", user.identifier, :title => user.name),
11   - (user.sex ? gettext(user.sex.capitalize) : _('Sex not informed')),
12   - user.location.empty? ? nil : user.location ].compact.join(' &#151; ') %>
13   - </div>
14   - <%= draggable_element(user.identifier, :revert => true) %>
15   - </td>
16   - <td>
17   - <%= button_to_remote_without_text(:add, @button_alt,
18   - { :loading => '$("members-list").addClassName("loading")',
19   - :update => 'members-list',
20   - :url => {:id => user.id, :profile => profile.identifier}.merge(@add_action),
21   - :success => "$('tr-#{user.identifier}').hide()",
22   - :complete => '$("members-list").removeClassName("loading")'}) %>
23   -
24   -
25   - </td>
26   - </tr>
27   - <% end if @users_found %>
28   - <% if !params[:query] || params[:query].length <= 2 %>
29   - <tr>
30   - <td style='text-align: center'>
31   - <em><%= _('You must type at least 3 characters') %></em>
32   - </td>
33   - </tr>
34   - <% end %>
35   -</table>
app/views/profile_members/last_admin.rhtml
1 1 <h1><%= _('Last administrator leaving %s') % profile.name %></h1>
2 2  
3   -<% if profile.members_count > 1 %>
4   - <div id='last-admin-message'>
5   - <%= _('Since you are the last administrator, you must choose at least one member to administer this community.') % profile.name %>
6   - </div>
  3 +<div id='last-admin-message'>
  4 + <%= _('Since you are the last administrator, you must choose at least one member to administer this community.') % profile.name %>
  5 +</div>
7 6  
8   - <%= render :partial => 'add_admins' %>
  7 +<%= render :partial => 'manage_roles', :locals => {:from => 'last_admin'} %>
9 8  
10   - <% form_tag :action => 'update_roles', :roles => @roles, :person => @person, :confirmation => profile.admins.count > 1 do %>
11   - <% button_bar do %>
12   - <%= submit_button(:save, _("Leave administration and save"), :cancel => {:action => 'index'}) %>
13   - <% end %>
14   - <% end %>
15   -
16   -<% else %>
17   -
18   - <div id='last-admin-message'>
19   - <%= _('Since you are the last administrator and there is no other member in this community, the next user to join this community will assume the administrator role.') % profile.name %>
20   - </div>
21   -
22   - <% form_tag :action => 'update_roles', :roles => @roles, :person => @person, :confirmation => true do %>
23   - <% button_bar do %>
24   - <%= submit_button(:ok, _("Ok, I want to leave"), :cancel => {:action => 'index'}) %>
25   - <% end %>
26   - <% end %>
27   -<% end %>
... ...
app/views/search/_product.rhtml
... ... @@ -6,6 +6,7 @@ product_item_pos += 1
6 6 %>
7 7  
8 8 <% extra_content = @plugins.map(:asset_product_extras, product, product.enterprise).collect { |content| instance_eval(&content) } %>
  9 +<% extra_properties = @plugins.map(:asset_product_properties, product)%>
9 10  
10 11 <li class="product-item <%= ( pos % 2 == 0 ) ? 'odd' : 'even' %>">
11 12 <%= link_to_product product, :class => 'product-pic', :style => 'background-image:url(%s)' % product.default_image(:minor) %>
... ... @@ -14,10 +15,15 @@ product_item_pos += 1
14 15 </strong>
15 16 <ul>
16 17 <li> <%= _('Price: %s') % (product.price ? product.price : _('Not informed')) %> </li>
17   - <% if product.enterprise %>
18   - <li> <%= _('Suplier: %s') % link_to_homepage(product.enterprise.name, product.enterprise.identifier) %> </li>
  18 + <% if product.enterprise && product.display_supplier_on_search? %>
  19 + <li> <%= _('Supplier: %s') % link_to_homepage(product.enterprise.name, product.enterprise.identifier) %> </li>
  20 + <% end %>
  21 +
  22 + <li> <%= _('Category:') + ' ' + link_to_product_category(product.product_category) %> </li>
  23 +
  24 + <% extra_properties.each do |property| %>
  25 + <li><%= property[:name] + ': ' + instance_eval(&property[:content]) %></li>
19 26 <% end %>
20   - <li> <%=_('Category:') + ' ' + link_to_product_category(product.product_category) %> </li>
21 27 </ul>
22 28  
23 29 <%= extra_content.join('\n') %>
... ...
db/migrate/20111004184103_add_field_validated_to_enterprises.rb 0 → 100644
... ... @@ -0,0 +1,9 @@
  1 +class AddFieldValidatedToEnterprises < ActiveRecord::Migration
  2 + def self.up
  3 + add_column :profiles, :validated, :boolean, :default => true
  4 + end
  5 +
  6 + def self.down
  7 + add_column :profiles, :validated
  8 + end
  9 +end
... ...
db/migrate/20111004184104_add_cnpj_to_enterprises.rb 0 → 100644
... ... @@ -0,0 +1,9 @@
  1 +class AddCnpjToEnterprises < ActiveRecord::Migration
  2 + def self.up
  3 + add_column :profiles, :cnpj, :string
  4 + end
  5 +
  6 + def self.down
  7 + remove_column :profiles, :cnpj
  8 + end
  9 +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 => 20110824192153) do
  12 +ActiveRecord::Schema.define(:version => 20111004184104) do
13 13  
14 14 create_table "action_tracker", :force => true do |t|
15 15 t.integer "user_id"
... ... @@ -378,6 +378,8 @@ ActiveRecord::Schema.define(:version =&gt; 20110824192153) do
378 378 t.datetime "updated_at"
379 379 t.boolean "visible", :default => true
380 380 t.integer "image_id"
  381 + t.boolean "validated", :default => true
  382 + t.string "cnpj"
381 383 end
382 384  
383 385 add_index "profiles", ["environment_id"], :name => "index_profiles_on_environment_id"
... ...
features/activate_enterprise.feature
... ... @@ -55,7 +55,7 @@ Feature: activate enterprise
55 55 Given feature "enterprise_activation" is enabled on environment
56 56 And the following enterprises
57 57 | identifier | name | enabled | cnpj |
58   - | services-provider | Services Provider | false | 00000000000000 |
  58 + | services-provider | Services Provider | false | 94.132.024/0001-48 |
59 59 And I am on Joao Silva's control panel
60 60 And I fill in "Enterprise activation code" with code of "Services Provider"
61 61 And I press "Activate"
... ...
features/bsc.feature 0 → 100644
... ... @@ -0,0 +1,164 @@
  1 +Feature: bsc
  2 +
  3 + Background:
  4 + Given "Bsc" plugin is enabled
  5 +
  6 + Scenario: display link to bsc creation on admin panel when bsc plugin active
  7 + Given I am logged in as admin
  8 + When I am on the environment control panel
  9 + Then I should see "Create Bsc"
  10 + When "Bsc" plugin is disabled
  11 + And I am on the environment control panel
  12 + Then I should not see "Create Bsc"
  13 +
  14 + Scenario: be able to create a bsc
  15 + Given I am logged in as admin
  16 + And I am on the environment control panel
  17 + And I follow "Create Bsc"
  18 + And I fill in the following:
  19 + | Business name | Sample Bsc |
  20 + | Company name | Sample Bsc |
  21 + | profile_data_identifier | sample-identifier |
  22 + | Cnpj | 07.970.746/0001-77 |
  23 + When I press "Save"
  24 + Then there should be a profile named "Sample Bsc"
  25 +
  26 + Scenario: display a button on bsc control panel to manage associated enterprises
  27 + Given the folllowing "bsc" from "bsc_plugin"
  28 + | business_name | identifier | company_name | cnpj |
  29 + | Bsc Test | bsc-test | Bsc Test Ltda | 94.132.024/0001-48 |
  30 + And I am logged in as admin
  31 + When I am on Bsc Test's control panel
  32 + Then I should see "Manage associated enterprises"
  33 +
  34 + Scenario: display a button on bsc control panel to transfer ownership
  35 + Given the folllowing "bsc" from "bsc_plugin"
  36 + | business_name | identifier | company_name | cnpj |
  37 + | Bsc Test | bsc-test | Bsc Test Ltda | 94.132.024/0001-48 |
  38 + And I am logged in as admin
  39 + When I am on Bsc Test's control panel
  40 + Then I should see "Transfer ownership"
  41 +
  42 + Scenario: create a new enterprise already associated with a bsc
  43 + Given the following user
  44 + | login | name |
  45 + | pedro-silva | Pedro Silva |
  46 + And the folllowing "bsc" from "bsc_plugin"
  47 + | business_name | identifier | company_name | cnpj | owner |
  48 + | Bsc Test | bsc-test | Bsc Test Ltda | 94.132.024/0001-48 | pedro-silva |
  49 + And organization_approval_method is "none" on environment
  50 + And I am logged in as "pedro-silva"
  51 + And I am on Bsc Test's control panel
  52 + And I follow "Manage associated enterprises"
  53 + And I follow "Add new enterprise"
  54 + And I fill in the following:
  55 + | Name | Associated Enterprise |
  56 + | Address | associated-enterprise |
  57 + When I press "Save"
  58 + Then "Associated Enterprise" should be associated with "Bsc Test"
  59 +
  60 + Scenario: do not display "add new product" button
  61 + Given the following user
  62 + | login | name |
  63 + | pedro-silva | Pedro Silva |
  64 + And the folllowing "bsc" from "bsc_plugin"
  65 + | business_name | identifier | company_name | cnpj | owner |
  66 + | Bsc Test | bsc-test | Bsc Test Ltda | 94.132.024/0001-48 | pedro-silva |
  67 + And feature "disable_products_for_enterprises" is disabled on environment
  68 + And I am logged in as "pedro-silva"
  69 + And I am on Bsc Test's control panel
  70 + When I follow "Manage Products and Services"
  71 + Then I should not see "New product or service"
  72 +
  73 + Scenario: display bsc's enterprises' products name on the bsc catalog
  74 + Given the following user
  75 + | login | name |
  76 + | pedro-silva | Pedro Silva |
  77 + And the folllowing "bsc" from "bsc_plugin"
  78 + | business_name | identifier | company_name | cnpj | owner |
  79 + | Bsc Test | bsc-test | Bsc Test Ltda | 94.132.024/0001-48 | pedro-silva |
  80 + And the following enterprise
  81 + | identifier | name |
  82 + | sample-enterprise | Sample Enterprise |
  83 + And the following product_category
  84 + | name |
  85 + | bike |
  86 + And the following products
  87 + | owner | category | name |
  88 + | sample-enterprise | bike | Master Bike |
  89 + And "Sample Enterprise" is associated with "Bsc Test"
  90 + And I am logged in as "pedro-silva"
  91 + When I go to Bsc Test's products page
  92 + Then I should see "Master Bike"
  93 + And I should see "Sample Enterprise"
  94 +
  95 + Scenario: display enterprise name linked only if person is member of any Bsc
  96 + Given the folllowing "bsc" from "bsc_plugin"
  97 + | business_name | identifier | company_name | cnpj |
  98 + | Bsc Test | bsc-test | Bsc Test Ltda | 94.132.024/0001-48 |
  99 + | Another Bsc | another-bsc | Another Bsc Test Ltda | 07.970.746/0001-77 |
  100 + And the following enterprise
  101 + | identifier | name |
  102 + | sample-enterprise | Sample Enterprise |
  103 + And the following product_category
  104 + | name |
  105 + | bike |
  106 + And the following products
  107 + | owner | category | name |
  108 + | sample-enterprise | bike | Master Bike |
  109 + And "Sample Enterprise" is associated with "Bsc Test"
  110 + And the folllowing "bsc" from "bsc_plugin"
  111 + | business_name | identifier | company_name | cnpj |
  112 + And the following user
  113 + | login | name |
  114 + | pedro | Pedro Souto |
  115 + | maria | Maria Souto |
  116 + And pedro is member of another-bsc
  117 + And I am logged in as "pedro"
  118 + When I go to Bsc Test's products page
  119 + Then I should see "Sample Enterprise"
  120 + And I should see "Sample Enterprise" within "a.bsc-catalog-enterprise-link"
  121 + But I am logged in as "maria"
  122 + When I go to Bsc Test's products page
  123 + Then I should see "Sample Enterprise"
  124 + #TODO -> test that it's not a link
  125 +
  126 + Scenario: allow only environment administrators to delete bsc profile
  127 + Given the folllowing "bsc" from "bsc_plugin"
  128 + | business_name | identifier | company_name | cnpj |
  129 + | Bsc Test | bsc-test | Bsc Test Ltda | 94.132.024/0001-48 |
  130 + And the following user
  131 + | login | name |
  132 + | pedro | Pedro Souto |
  133 + And "Pedro Souto" is admin of "Bsc Test"
  134 + And I am logged in as "pedro"
  135 + And I am on Bsc Test's control panel
  136 + And I follow "Bsc info and settings"
  137 + When I follow "Delete profile"
  138 + Then I should see "Access denied"
  139 + And "Bsc Test" profile should exist
  140 + But I am logged in as admin
  141 + And I am on Bsc Test's control panel
  142 + And I follow "Bsc info and settings"
  143 + When I follow "Delete profile"
  144 + Then I should see "Deleting profile Bsc Test"
  145 + And I follow "Yes, I am sure"
  146 + Then "Bsc Test" profile should not exist
  147 +
  148 + # Like we can believe that selenium is going to work...
  149 + @selenium
  150 + Scenario: list already associated enterprises on manage associated enterprises
  151 + Given the folllowing "bsc" from "bsc_plugin"
  152 + | business_name | identifier | company_name | cnpj |
  153 + | Bsc Test | bsc-test | Bsc Test Ltda | 94.132.024/0001-48 |
  154 + And the following enterprises
  155 + | identifier | name |
  156 + | enterprise-1 | Enterprise 1 |
  157 + | enterprise-2 | Enterprise 2 |
  158 + And "Enterprise 1" is associated with "Bsc Test"
  159 + And "Enterprise 2" is associated with "Bsc Test"
  160 + And I am logged in as admin
  161 + And I am on Bsc Test's control panel
  162 + When I follow "Manage associated enterprises"
  163 + Then I should see "Enterprise 1"
  164 + And I should see "Enterprise 2"
... ...
features/last_administrator_leaving.feature
... ... @@ -11,7 +11,7 @@ Feature: remove administrator role
11 11 And the following community
12 12 | name | identifier |
13 13 | Nice people | nice-people |
14   - And "Joao Silva" is a member of "Nice people"
  14 + And "Joao Silva" is admin of "Nice people"
15 15 And I am logged in as "joaosilva"
16 16  
17 17 Scenario: the last administrator removes his administrator role and must choose the new administrator
... ... @@ -28,8 +28,8 @@ Feature: remove administrator role
28 28 And I uncheck "Profile Administrator"
29 29 And I uncheck "Profile Member"
30 30 When I press "Save changes"
31   - Then I should see "Since you are the last administrator and there is no other member in this community"
32   - And I press "Ok, I want to leave"
  31 + Then I should see "Since you are the last administrator, you must choose at least one member to administer this community."
  32 + And I press "Save"
33 33 And I am logged in as "mariasouza"
34 34 When I go to Nice people's join page
35 35 Then "Maria Souza" should be admin of "Nice people"
... ... @@ -41,8 +41,8 @@ Feature: remove administrator role
41 41 And I uncheck "Profile Administrator"
42 42 And I uncheck "Profile Member"
43 43 When I press "Save changes"
44   - Then I should see "Since you are the last administrator and there is no other member in this community"
45   - And I press "Ok, I want to leave"
  44 + Then I should see "Since you are the last administrator, you must choose at least one member to administer this community."
  45 + And I press "Save"
46 46 And I am logged in as "mariasouza"
47 47 When I go to Nice people's join page
48 48 Then "Maria Souza" should be admin of "Nice people"
... ...
features/manage_products.feature
... ... @@ -11,6 +11,12 @@ Feature: manage products
11 11 | redemoinho | joaosilva | Rede Moinho | true |
12 12 And feature "disable_products_for_enterprises" is disabled on environment
13 13  
  14 + Scenario: display "create new product" button
  15 + Given I am logged in as "joaosilva"
  16 + And I am on Rede Moinho's control panel
  17 + When I follow "Manage Products and Services"
  18 + Then I should see "New product or service"
  19 +
14 20 Scenario: paginate public listing products and services
15 21 Given the following product_category
16 22 | name |
... ...
features/plugins.feature
... ... @@ -19,7 +19,7 @@ Feature: plugins
19 19 And the following events of TestPlugin
20 20 | event | body |
21 21 | control_panel_buttons | lambda { {:title => 'Test plugin button', :icon => '', :url => ''} } |
22   - | profile_tabs | lambda { {:title => 'Test plugin tab', :id => 'test_plugin', :content => 'Test plugin random content'} } |
  22 + | profile_tabs | lambda { {:title => 'Test plugin tab', :id => 'test_plugin', :content => lambda {'Test plugin random content'} } } |
23 23  
24 24 Scenario: a user must see the plugin\'s button in the control panel if the plugin is enabled
25 25 Given plugin TestPlugin is enabled on environment
... ...
features/step_definitions/noosfero_steps.rb
... ... @@ -36,6 +36,36 @@ Given /^the following (community|communities|enterprises?|organizations?)$/ do |
36 36 end
37 37 end
38 38  
  39 +Given /^"([^\"]*)" is associated with "([^\"]*)"$/ do |enterprise, bsc|
  40 + enterprise = Enterprise.find_by_name(enterprise) || Enterprise[enterprise]
  41 + bsc = BscPlugin::Bsc.find_by_name(bsc) || BscPlugin::Bsc[bsc]
  42 +
  43 + bsc.enterprises << enterprise
  44 +end
  45 +
  46 +Then /^"([^\"]*)" should be associated with "([^\"]*)"$/ do |enterprise, bsc|
  47 + enterprise = Enterprise.find_by_name(enterprise) || Enterprise[enterprise]
  48 + bsc = BscPlugin::Bsc.find_by_name(bsc) || BscPlugin::Bsc[bsc]
  49 +
  50 + bsc.enterprises.should include(enterprise)
  51 +end
  52 +
  53 +Given /^the folllowing "([^\"]*)" from "([^\"]*)"$/ do |kind, plugin, table|
  54 + klass = (plugin.camelize+'::'+kind.singularize.camelize).constantize
  55 + table.hashes.each do |row|
  56 + owner = row.delete("owner")
  57 + domain = row.delete("domain")
  58 + organization = klass.create!(row)
  59 + if owner
  60 + organization.add_admin(Profile[owner])
  61 + end
  62 + if domain
  63 + d = Domain.new :name => domain, :owner => organization
  64 + d.save(false)
  65 + end
  66 + end
  67 +end
  68 +
39 69 Given /^the following blocks$/ do |table|
40 70 table.hashes.map{|item| item.dup}.each do |item|
41 71 klass = item.delete('type')
... ... @@ -298,12 +328,12 @@ Given /^&quot;(.+)&quot; is friend of &quot;(.+)&quot;$/ do |person, friend|
298 328 Person[person].add_friend(Person[friend])
299 329 end
300 330  
301   -Given /^(.+) is blocked$/ do |enterprise_name|
  331 +Given /^enterprise "([^\"]*)" is blocked$/ do |enterprise_name|
302 332 enterprise = Enterprise.find_by_name(enterprise_name)
303 333 enterprise.block
304 334 end
305 335  
306   -Given /^(.+) is disabled$/ do |enterprise_name|
  336 +Given /^enterprise "([^\"]*)" is disabled$/ do |enterprise_name|
307 337 enterprise = Enterprise.find_by_name(enterprise_name)
308 338 enterprise.enabled = false
309 339 enterprise.save
... ... @@ -428,3 +458,33 @@ Then /^I should receive an e-mail on (.*)$/ do |address|
428 458 last_mail = ActionMailer::Base.deliveries.last
429 459 last_mail['to'].to_s.should == address
430 460 end
  461 +
  462 +Given /^"([^\"]*)" plugin is (enabled|disabled)$/ do |plugin_name, status|
  463 + environment = Environment.default
  464 + environment.send(status.chop + '_plugin', plugin_name+'Plugin')
  465 +end
  466 +
  467 +Then /^there should be an? (.+) named "([^\"]*)"$/ do |klass_name, profile_name|
  468 + klass = klass_name.camelize.constantize
  469 + klass.find_by_name(profile_name).nil?.should be_false
  470 +end
  471 +
  472 +Then /^"([^\"]*)" profile should exist$/ do |profile_selector|
  473 + profile = nil
  474 + begin
  475 + profile = Profile.find_by_name(profile_selector)
  476 + profile.nil?.should be_false
  477 + rescue
  478 + profile.nil?.should be_false
  479 + end
  480 +end
  481 +
  482 +Then /^"([^\"]*)" profile should not exist$/ do |profile_selector|
  483 + profile = nil
  484 + begin
  485 + profile = Profile.find_by_name(profile_selector)
  486 + profile.nil?.should be_true
  487 + rescue
  488 + profile.nil?.should be_true
  489 + end
  490 +end
... ...
features/unblock_button.feature
... ... @@ -10,11 +10,11 @@ Feature: unblock button
10 10 And the following blocks
11 11 | owner | type |
12 12 | sample-enterprise | DisabledEnterpriseMessageBlock |
13   - And Sample Enterprise is disabled
  13 + And enterprise "Sample Enterprise" is disabled
14 14  
15 15 Scenario: the environment administrator unblocks a blocked enterprise
16 16 Given I am logged in as admin
17   - And Sample Enterprise is blocked
  17 + And enterprise "Sample Enterprise" is blocked
18 18 And I am on Sample Enterprise's homepage
19 19 When I follow "Unblock"
20 20 Then I should not see "Unblock"
... ... @@ -24,7 +24,7 @@ Feature: unblock button
24 24 | login | name |
25 25 | joaosilva | Joao Silva |
26 26 And I am logged in as "joaosilva"
27   - And Sample Enterprise is blocked
  27 + And enterprise "Sample Enterprise" is blocked
28 28 When I am on Sample Enterprise's homepage
29 29 Then I should not see "Unblock"
30 30  
... ...
lib/noosfero/plugin.rb
... ... @@ -40,7 +40,11 @@ class Noosfero::Plugin
40 40 end
41 41  
42 42 def root_path
43   - Rails.root+'/plugins/'+public_name
  43 + File.join(RAILS_ROOT, 'plugins', public_name)
  44 + end
  45 +
  46 + def view_path
  47 + File.join(root_path,'views')
44 48 end
45 49  
46 50 # Here the developer should specify the meta-informations that the plugin can
... ... @@ -61,11 +65,6 @@ class Noosfero::Plugin
61 65 end
62 66 end
63 67  
64   - def expanded_template(file_path, locals = {})
65   - views_path = "#{RAILS_ROOT}/plugins/#{self.class.public_name}/views"
66   - ERB.new(File.read("#{views_path}/#{file_path}")).result(binding)
67   - end
68   -
69 68 # Here the developer may specify the events to which the plugins can
70 69 # register and must return true or false. The default value must be false.
71 70  
... ... @@ -92,7 +91,7 @@ class Noosfero::Plugin
92 91 # returns = { :title => title, :id => id, :content => content, :start => start }
93 92 # title = name that will be displayed.
94 93 # id = div id.
95   - # content = content of the tab (use expanded_template method to import content from another file).
  94 + # content = lambda block that creates a html code.
96 95 # start = boolean that specifies if the tab must come before noosfero tabs (optional).
97 96 def profile_tabs
98 97 nil
... ... @@ -104,6 +103,12 @@ class Noosfero::Plugin
104 103 nil
105 104 end
106 105  
  106 + # -> Adds content to calalog list item
  107 + # returns = lambda block that creates a html code
  108 + def catalog_list_item_extras(item)
  109 + nil
  110 + end
  111 +
107 112 # -> Adds content to products info
108 113 # returns = lambda block that creates a html code
109 114 def product_info_extras(product)
... ... @@ -116,13 +121,21 @@ class Noosfero::Plugin
116 121 nil
117 122 end
118 123  
  124 + # -> Adds a property to the product on asset products
  125 + # returns = {:name => name, :content => content}
  126 + # name = Name of the property
  127 + # content = lambda block that creates an html
  128 + def asset_product_properties(product)
  129 + nil
  130 + end
  131 +
119 132 # -> Adds content to the beginning of the page
120 133 # returns = lambda block that creates html code or raw rhtml/html.erb
121 134 def body_beginning
122 135 nil
123 136 end
124 137  
125   - # -> Add plugins' javascript files to application
  138 + # -> Adds plugins' javascript files to application
126 139 # returns = ['example1.js', 'javascripts/example2.js', 'example3.js']
127 140 def js_files
128 141 []
... ... @@ -140,4 +153,43 @@ class Noosfero::Plugin
140 153 raw_content
141 154 end
142 155  
  156 + # -> Adds links to the admin panel
  157 + # returns = {:title => title, :url => url}
  158 + # title = name that will be displayed in the link
  159 + # url = url or route to which the link will redirect to.
  160 + def admin_panel_links
  161 + nil
  162 + end
  163 +
  164 + # -> Adds buttons to manage members page
  165 + # returns = { :title => title, :icon => icon, :url => url }
  166 + # title = name that will be displayed.
  167 + # icon = css class name (for customized icons include them in a css file).
  168 + # url = url or route to which the button will redirect.
  169 + def manage_members_extra_buttons
  170 + nil
  171 + end
  172 +
  173 + # This is a generic hotspot for all controllers on Noosfero.
  174 + # If any plugin wants to define filters to run on any controller, the name of
  175 + # the hotspot must be in the following form: <underscored_controller_name>_filters.
  176 + # Example: for ProfileController the hotspot is profile_controller_filters
  177 + #
  178 + # -> Adds a filter to a controller
  179 + # returns = { :type => type,
  180 + # :method_name => method_name,
  181 + # :options => {:opt1 => opt1, :opt2 => opt2},
  182 + # :block => Proc or lambda block}
  183 + # type = 'before_filter' or 'after_filter'
  184 + # method_name = The name of the filter
  185 + # option = Filter options, like :only or :except
  186 + # block = Block that the filter will call
  187 + def method_missing(method, *args, &block)
  188 + if method.to_s =~ /^(.+)_controller_filters$/
  189 + []
  190 + else
  191 + super
  192 + end
  193 + end
  194 +
143 195 end
... ...
lib/noosfero/plugin/context.rb
... ... @@ -30,4 +30,8 @@ class Noosfero::Plugin::Context
30 30 @session ||= @controller.send(:session)
31 31 end
32 32  
  33 + def user
  34 + @user ||= @controller.send(:user)
  35 + end
  36 +
33 37 end
... ...
plugins/bsc/controllers/bsc_plugin_environment_controller.rb 0 → 100644
... ... @@ -0,0 +1,35 @@
  1 +class BscPluginEnvironmentController < AdminController
  2 +
  3 + def new
  4 + @bsc = BscPlugin::Bsc.new(params[:profile_data])
  5 + if request.post? && @bsc.valid?
  6 + @bsc.user = current_user
  7 + @bsc.save!
  8 + @bsc.add_admin(user)
  9 + session[:notice] = _('Your Bsc was created.')
  10 + redirect_to :controller => 'profile_editor', :profile => @bsc.identifier
  11 + end
  12 + end
  13 +
  14 + def save_validations
  15 + enterprises = [Enterprise.find(params[:q].split(','))].flatten
  16 +
  17 + begin
  18 + enterprises.each { |enterprise| enterprise.validated = true ; enterprise.save! }
  19 + session[:notice] = _('Enterprises validated.')
  20 + redirect_to :controller => 'admin_panel'
  21 + rescue Exception => ex
  22 + session[:notice] = _('Enterprise validations couldn\'t be saved.')
  23 + logger.info ex
  24 + redirect_to :action => 'validate_enterprises'
  25 + end
  26 + end
  27 +
  28 + def search_enterprise
  29 + render :text => Enterprise.not_validated.find(:all, :conditions => ["type <> 'BscPlugin::Bsc' AND (name LIKE ? OR identifier LIKE ?)", "%#{params[:q]}%", "%#{params[:q]}%"]).
  30 + map {|enterprise| {:id => enterprise.id, :name => enterprise.name} }.
  31 + to_json
  32 + end
  33 +
  34 +end
  35 +
... ...
plugins/bsc/controllers/bsc_plugin_myprofile_controller.rb 0 → 100644
... ... @@ -0,0 +1,88 @@
  1 +class BscPluginMyprofileController < MyProfileController
  2 +
  3 + def manage_associated_enterprises
  4 + @associated_enterprises = profile.enterprises
  5 + @pending_enterprises = profile.enterprise_requests.pending.map(&:enterprise)
  6 + end
  7 +
  8 + def search_enterprise
  9 + render :text => environment.enterprises.find(:all, :conditions => ["type <> 'BscPlugin::Bsc' AND (LOWER(name) LIKE ? OR LOWER(identifier) LIKE ?)", "%#{params[:q]}%", "%#{params[:q]}%"]).
  10 + select { |enterprise| enterprise.bsc.nil? && !profile.already_requested?(enterprise)}.
  11 + map {|enterprise| {:id => enterprise.id, :name => enterprise.name} }.
  12 + to_json
  13 + end
  14 +
  15 + def save_associations
  16 + enterprises = [Enterprise.find(params[:q].split(','))].flatten
  17 + to_remove = profile.enterprises - enterprises
  18 + to_add = enterprises - profile.enterprises
  19 +
  20 + to_remove.each do |enterprise|
  21 + enterprise.bsc = nil
  22 + enterprise.save!
  23 + profile.enterprises.delete(enterprise)
  24 + end
  25 +
  26 + to_add.each do |enterprise|
  27 + if enterprise.enabled
  28 + BscPlugin::AssociateEnterprise.create!(:requestor => user, :target => enterprise, :bsc => profile)
  29 + else
  30 + enterprise.bsc = profile
  31 + enterprise.save!
  32 + profile.enterprises << enterprise
  33 + end
  34 + end
  35 +
  36 + session[:notice] = _('This Bsc associations were saved successfully.')
  37 + begin
  38 + redirect_to :controller => 'profile_editor'
  39 + rescue Exception => ex
  40 + session[:notice] = _('This Bsc associations couldn\'t be saved.')
  41 + logger.info ex
  42 + redirect_to :action => 'manage_associated_enterprises'
  43 + end
  44 + end
  45 +
  46 + def similar_enterprises
  47 + name = params[:name]
  48 + city = params[:city]
  49 +
  50 + result = []
  51 + if !name.blank?
  52 + enterprises = (profile.environment.enterprises - profile.enterprises).select { |enterprise| enterprise.bsc_id.nil? && enterprise.city == city && enterprise.name.downcase.include?(name.downcase)}
  53 + result = enterprises.inject(result) {|result, enterprise| result << [enterprise.id, enterprise.name]}
  54 + end
  55 + render :text => result.to_json
  56 + end
  57 +
  58 + def transfer_ownership
  59 + role = Profile::Roles.admin(profile.environment.id)
  60 + @roles = [role]
  61 + if request.post?
  62 + person = Person.find(params['q_'+role.key])
  63 +
  64 + profile.admins.map { |admin| profile.remove_admin(admin) }
  65 + profile.add_admin(person)
  66 +
  67 + BscPlugin::Mailer.deliver_admin_notification(person, profile)
  68 +
  69 + session[:notice] = _('Enterprise ownership transferred.')
  70 + redirect_to :controller => 'profile_editor'
  71 + end
  72 + end
  73 +
  74 + def create_enterprise
  75 + @create_enterprise = CreateEnterprise.new(params[:create_enterprise])
  76 + @create_enterprise.requestor = user
  77 + @create_enterprise.target = environment
  78 + @create_enterprise.bsc_id = profile.id
  79 + @create_enterprise.enabled = true
  80 + @create_enterprise.validated = false
  81 + if request.post? && @create_enterprise.valid?
  82 + @create_enterprise.perform
  83 + session[:notice] = _('Enterprise was created in association with %s.') % profile.name
  84 + redirect_to :controller => 'profile_editor', :profile => @create_enterprise.identifier
  85 + end
  86 + end
  87 +
  88 +end
... ...
plugins/bsc/db/migrate/20110609143043_add_bsc_to_enterprise.rb 0 → 100644
... ... @@ -0,0 +1,9 @@
  1 +class AddBscToEnterprise < ActiveRecord::Migration
  2 + def self.up
  3 + add_column :profiles, :bsc_id, :integer
  4 + end
  5 +
  6 + def self.down
  7 + remove_column :profiles, :bsc_id
  8 + end
  9 +end
... ...
plugins/bsc/db/migrate/20110610145112_add_bsc_fields.rb 0 → 100644
... ... @@ -0,0 +1,9 @@
  1 +class AddBscFields < ActiveRecord::Migration
  2 + def self.up
  3 + add_column :profiles, :company_name, :string
  4 + end
  5 +
  6 + def self.down
  7 + remove_column :profiles, :company_name
  8 + end
  9 +end
... ...
plugins/bsc/db/migrate/20110614183624_add_bsc_to_tasks.rb 0 → 100644
... ... @@ -0,0 +1,9 @@
  1 +class AddBscToTasks < ActiveRecord::Migration
  2 + def self.up
  3 + add_column :tasks, :bsc_id, :integer
  4 + end
  5 +
  6 + def self.down
  7 + remove_column :tasks, :bsc_id
  8 + end
  9 +end
... ...
plugins/bsc/lib/bsc_plugin.rb 0 → 100644
... ... @@ -0,0 +1,121 @@
  1 +require_dependency 'ext/enterprise'
  2 +require_dependency 'ext/product'
  3 +
  4 +class BscPlugin < Noosfero::Plugin
  5 +
  6 + Bsc
  7 +
  8 + def self.plugin_name
  9 + "Bsc"
  10 + end
  11 +
  12 + def self.plugin_description
  13 + _("Adds the Bsc feature")
  14 + end
  15 +
  16 + def admin_panel_links
  17 + [{:title => _('Create Bsc'), :url => {:controller => 'bsc_plugin_environment', :action => 'new'}},
  18 + {:title => _('Validate Enterprises'), :url => {:controller => 'bsc_plugin_environment', :action => 'validate_enterprises'}} ]
  19 + end
  20 +
  21 + def control_panel_buttons
  22 + buttons = []
  23 + buttons << {:title => _("Manage associated enterprises"), :icon => 'bsc-enterprises', :url => {:controller => 'bsc_plugin_myprofile', :action => 'manage_associated_enterprises'}} if bsc?(context.profile)
  24 + buttons << {:title => _('Transfer ownership'), :icon => 'transfer-enterprise-ownership', :url => {:controller => 'bsc_plugin_myprofile', :action => 'transfer_ownership'}} if context.profile.enterprise?
  25 + buttons
  26 + end
  27 +
  28 + def manage_members_extra_buttons
  29 + {:title => _('Transfer ownership'), :icon => '', :url => {:controller => 'bsc_plugin_myprofile', :action => 'transfer_enterprises_management'}} if context.profile.enterprise?
  30 + end
  31 +
  32 + def stylesheet?
  33 + true
  34 + end
  35 +
  36 + def catalog_list_item_extras(product)
  37 + if bsc?(context.profile)
  38 + enterprise = product.enterprise
  39 + if is_member_of_any_bsc?(context.user)
  40 + lambda {link_to(enterprise.short_name, enterprise.url, :class => 'bsc-catalog-enterprise-link')}
  41 + else
  42 + lambda {enterprise.short_name}
  43 + end
  44 + end
  45 + end
  46 +
  47 + def profile_controller_filters
  48 + if profile
  49 + special_enterprise = profile.enterprise? && !profile.validated && profile.bsc
  50 + is_member_of_any_bsc = is_member_of_any_bsc?(context.user)
  51 + block = lambda {
  52 + render_access_denied if special_enterprise && !is_member_of_any_bsc
  53 + }
  54 +
  55 + [{ :type => 'before_filter', :method_name => 'bsc_access', :block => block }]
  56 + else
  57 + []
  58 + end
  59 + end
  60 +
  61 + def content_viewer_controller_filters
  62 + if profile
  63 + special_enterprise = profile.enterprise? && !profile.validated && profile.bsc
  64 + is_member_of_any_bsc = is_member_of_any_bsc?(context.user)
  65 + block = lambda {
  66 + render_access_denied if special_enterprise && !is_member_of_any_bsc
  67 + }
  68 +
  69 + [{ :type => 'before_filter', :method_name => 'bsc_access', :block => block }]
  70 + else
  71 + []
  72 + end
  73 + end
  74 +
  75 + def profile_editor_controller_filters
  76 + if context.user
  77 + is_not_admin = !context.environment.admins.include?(context.user)
  78 + [{ :type => 'before_filter',
  79 + :method_name => 'bsc_destroy_access',
  80 + :options => {:only => :destroy_profile},
  81 + :block => lambda { render_access_denied if is_not_admin } }]
  82 + else
  83 + []
  84 + end
  85 + end
  86 +
  87 + def asset_product_properties(product)
  88 + properties = []
  89 + properties << { :name => _('Bsc'), :content => lambda { link_to(product.bsc.name, product.bsc.url) } } if product.bsc
  90 + if product.enterprise.validated || is_member_of_any_bsc?(context.user)
  91 + content = lambda { link_to_homepage(product.enterprise.name, product.enterprise.identifier) }
  92 + else
  93 + content = lambda { product.enterprise.name }
  94 + end
  95 + properties << { :name => _('Supplier'), :content => content }
  96 + end
  97 +
  98 + def profile_tabs
  99 + if bsc?(context.profile)
  100 + { :title => _("Contact"),
  101 + :id => 'bsc-contact',
  102 + :content => lambda { render :partial => 'profile_tab' },
  103 + :start => true }
  104 + end
  105 + end
  106 +
  107 + private
  108 +
  109 + def bsc?(profile)
  110 + profile.kind_of?(BscPlugin::Bsc)
  111 + end
  112 +
  113 + def is_member_of_any_bsc?(user)
  114 + BscPlugin::Bsc.all.any? { |bsc| bsc.members.include?(user) }
  115 + end
  116 +
  117 + def profile
  118 + context.environment.profiles.find_by_identifier(context.params[:profile])
  119 + end
  120 +
  121 +end
... ...
plugins/bsc/lib/bsc_plugin/associate_enterprise.rb 0 → 100644
... ... @@ -0,0 +1,49 @@
  1 +class BscPlugin::AssociateEnterprise < Task
  2 +
  3 + alias :enterprise :target
  4 +
  5 + belongs_to :bsc, :class_name => 'BscPlugin::Bsc'
  6 +
  7 + validates_presence_of :bsc
  8 +
  9 + def title
  10 + _("BSC association")
  11 + end
  12 +
  13 + def linked_subject
  14 + {:text => bsc.name, :url => bsc.url}
  15 + end
  16 +
  17 + def information
  18 + {:message => _('%{requestor} wants to associate this enterprise with %{linked_subject}.')}
  19 + end
  20 +
  21 + def icon
  22 + src = bsc.image ? bsc.image.public_filename(:minor) : '/images/icons-app/enterprise-minor.png'
  23 + {:type => :defined_image, :src => src, :name => bsc.name}
  24 + end
  25 +
  26 + def reject_details
  27 + true
  28 + end
  29 +
  30 + def perform
  31 + bsc.enterprises << enterprise
  32 + end
  33 +
  34 + def task_finished_message
  35 + _('%{enterprise} accepted your request to associate it with %{bsc}.') % {:enterprise => enterprise.name, :bsc => bsc.name}
  36 + end
  37 +
  38 + def task_cancelled_message
  39 + message = _("%{enterprise} rejected your request to associate it with %{bsc}.") % {:enterprise => enterprise.name, :bsc => bsc.name}
  40 + if !reject_explanation.blank?
  41 + message += " " + _("Here is the reject explanation left by the administrator:\n\n%{reject_explanation}") % {:reject_explanation => reject_explanation}
  42 + end
  43 + end
  44 +
  45 + def target_notification_message
  46 + _('%{requestor} wants assoaciate %{bsc} as your BSC.') % {:requestor => requestor.name, :enterprise => enterprise.name, :bsc => bsc.name}
  47 + end
  48 +
  49 +end
... ...
plugins/bsc/lib/bsc_plugin/bsc.rb 0 → 100644
... ... @@ -0,0 +1,42 @@
  1 +class BscPlugin::Bsc < Enterprise
  2 +
  3 + has_many :enterprises
  4 + has_many :enterprise_requests, :class_name => 'BscPlugin::AssociateEnterprise'
  5 +
  6 + validates_presence_of :nickname
  7 + validates_presence_of :company_name
  8 + validates_presence_of :cnpj
  9 + validates_uniqueness_of :nickname
  10 + validates_uniqueness_of :company_name
  11 + validates_uniqueness_of :cnpj
  12 +
  13 + before_validation do |bsc|
  14 + bsc.name = bsc.business_name || 'Sample name'
  15 + end
  16 +
  17 + def already_requested?(enterprise)
  18 + enterprise_requests.pending.map(&:enterprise).include?(enterprise)
  19 + end
  20 +
  21 + def enterprises_to_json
  22 + enterprises.map { |enterprise| {:id => enterprise.id, :name => enterprise.name} }.to_json
  23 + end
  24 +
  25 + def control_panel_settings_button
  26 + {:title => _('Bsc info and settings'), :icon => 'edit-profile-enterprise'}
  27 + end
  28 +
  29 + def products(reload_flag=false)
  30 + reload if reload_flag
  31 + enterprises.map { |enterprise| enterprise.products }.flatten
  32 + end
  33 +
  34 + def create_product?
  35 + false
  36 + end
  37 +
  38 + def self.identification
  39 + 'Bsc'
  40 + end
  41 +
  42 +end
... ...
plugins/bsc/lib/bsc_plugin/mailer.rb 0 → 100644
... ... @@ -0,0 +1,13 @@
  1 +class BscPlugin::Mailer < Noosfero::Plugin::MailerBase
  2 +
  3 + prepend_view_path(BscPlugin.root_path+'/views')
  4 +
  5 + def admin_notification(admin, bsc)
  6 + domain = bsc.hostname || bsc.environment.default_hostname
  7 + recipients admin.contact_email
  8 + from 'no-reply@' + domain
  9 + subject _("[%s] Bsc management transferred to you.") % bsc.name
  10 + content_type 'text/html'
  11 + body :bsc => bsc
  12 + end
  13 +end
... ...
plugins/bsc/lib/ext/enterprise.rb 0 → 100644
... ... @@ -0,0 +1,11 @@
  1 +require_dependency 'enterprise'
  2 +
  3 +class Enterprise
  4 + belongs_to :bsc, :class_name => 'BscPlugin::Bsc'
  5 + FIELDS << 'bsc_id'
  6 + FIELDS << 'enabled'
  7 + FIELDS << 'validated'
  8 +
  9 + named_scope :validated, :conditions => {:validated => true}
  10 + named_scope :not_validated, :conditions => {:validated => false}
  11 +end
... ...
plugins/bsc/lib/ext/product.rb 0 → 100644
... ... @@ -0,0 +1,11 @@
  1 +require_dependency 'product'
  2 +
  3 +class Product
  4 + def bsc
  5 + enterprise.bsc if enterprise
  6 + end
  7 +
  8 + def display_supplier_on_search?
  9 + false
  10 + end
  11 +end
... ...
plugins/bsc/public/images/manage-bsc-enterprises-icon.png 0 → 100644

978 Bytes

plugins/bsc/public/images/manage-bsc-enterprises.gif 0 → 100644

2.05 KB

plugins/bsc/public/images/manage-bsc-enterprises.png 0 → 100644

3.84 KB

plugins/bsc/public/images/manage-bsc-enterprises.svg 0 → 100644
... ... @@ -0,0 +1,1309 @@
  1 +<?xml version="1.0" encoding="UTF-8" standalone="no"?>
  2 +<svg
  3 + xmlns:dc="http://purl.org/dc/elements/1.1/"
  4 + xmlns:cc="http://creativecommons.org/ns#"
  5 + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
  6 + xmlns:svg="http://www.w3.org/2000/svg"
  7 + xmlns="http://www.w3.org/2000/svg"
  8 + xmlns:xlink="http://www.w3.org/1999/xlink"
  9 + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
  10 + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
  11 + width="48"
  12 + height="48"
  13 + overflow="visible"
  14 + enable-background="new 0 0 128 129.396"
  15 + xml:space="preserve"
  16 + id="svg2"
  17 + sodipodi:version="0.32"
  18 + inkscape:version="0.47 r22583"
  19 + sodipodi:docname="BSC.svg"
  20 + version="1.0"
  21 + inkscape:export-filename="/home/tigert/My Downloads/go-home.png"
  22 + inkscape:export-xdpi="90.000000"
  23 + inkscape:export-ydpi="90.000000"><metadata
  24 + id="metadata367"><rdf:RDF><cc:Work
  25 + rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
  26 + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><cc:license
  27 + rdf:resource="http://creativecommons.org/licenses/by-sa/2.0/" /><dc:title /><dc:creator><cc:Agent><dc:title>Jakub Steiner</dc:title></cc:Agent></dc:creator><dc:source>http://jimmac.musichall.cz</dc:source><dc:subject><rdf:Bag><rdf:li>home</rdf:li><rdf:li>return</rdf:li><rdf:li>go</rdf:li><rdf:li>default</rdf:li><rdf:li>user</rdf:li><rdf:li>directory</rdf:li></rdf:Bag></dc:subject><dc:contributor><cc:Agent><dc:title>Tuomas Kuosmanen</dc:title></cc:Agent></dc:contributor></cc:Work><cc:License
  28 + rdf:about="http://creativecommons.org/licenses/by-sa/2.0/"><cc:permits
  29 + rdf:resource="http://web.resource.org/cc/Reproduction" /><cc:permits
  30 + rdf:resource="http://web.resource.org/cc/Distribution" /><cc:requires
  31 + rdf:resource="http://web.resource.org/cc/Notice" /><cc:requires
  32 + rdf:resource="http://web.resource.org/cc/Attribution" /><cc:permits
  33 + rdf:resource="http://web.resource.org/cc/DerivativeWorks" /><cc:requires
  34 + rdf:resource="http://web.resource.org/cc/ShareAlike" /></cc:License></rdf:RDF></metadata><defs
  35 + id="defs365"><linearGradient
  36 + inkscape:collect="always"
  37 + id="linearGradient3177"><stop
  38 + style="stop-color:#729fcf;stop-opacity:1"
  39 + offset="0"
  40 + id="stop3179" /><stop
  41 + style="stop-color:#204a87;stop-opacity:1"
  42 + offset="1"
  43 + id="stop3181" /></linearGradient><linearGradient
  44 + id="linearGradient3171"><stop
  45 + id="stop3173"
  46 + offset="0"
  47 + style="stop-color:#d3d7cf;stop-opacity:1" /><stop
  48 + id="stop3175"
  49 + offset="1"
  50 + style="stop-color:#888a85;stop-opacity:1" /></linearGradient><linearGradient
  51 + inkscape:collect="always"
  52 + id="linearGradient5161"><stop
  53 + style="stop-color:#c17d11;stop-opacity:1;"
  54 + offset="0"
  55 + id="stop5163" /><stop
  56 + style="stop-color:#8f5902;stop-opacity:1"
  57 + offset="1"
  58 + id="stop5165" /></linearGradient><linearGradient
  59 + inkscape:collect="always"
  60 + id="linearGradient3771"><stop
  61 + style="stop-color:#ffffff;stop-opacity:1;"
  62 + offset="0"
  63 + id="stop3773" /><stop
  64 + style="stop-color:#ffffff;stop-opacity:0;"
  65 + offset="1"
  66 + id="stop3775" /></linearGradient><linearGradient
  67 + gradientTransform="matrix(0.314683,0.000000,0.000000,0.314683,4.128264,3.742874)"
  68 + y2="59.7995"
  69 + x2="48.046001"
  70 + y1="117.5205"
  71 + x1="80.223602"
  72 + gradientUnits="userSpaceOnUse"
  73 + id="linearGradient3736">
  74 + <stop
  75 + id="stop3738"
  76 + style="stop-color:#CCCCCC"
  77 + offset="0" />
  78 + <stop
  79 + id="stop3740"
  80 + style="stop-color:#FFFFFF"
  81 + offset="0.81071424" />
  82 + <midPointStop
  83 + id="midPointStop3742"
  84 + style="stop-color:#CCCCCC"
  85 + offset="0" />
  86 + <midPointStop
  87 + id="midPointStop3744"
  88 + style="stop-color:#CCCCCC"
  89 + offset="0.5" />
  90 + <midPointStop
  91 + id="midPointStop3746"
  92 + style="stop-color:#FFFFFF"
  93 + offset="0.9831" />
  94 + </linearGradient><inkscape:perspective
  95 + sodipodi:type="inkscape:persp3d"
  96 + inkscape:vp_x="0 : 24 : 1"
  97 + inkscape:vp_y="0 : 1000 : 0"
  98 + inkscape:vp_z="48 : 24 : 1"
  99 + inkscape:persp3d-origin="24 : 16 : 1"
  100 + id="perspective92" /><linearGradient
  101 + inkscape:collect="always"
  102 + id="linearGradient5060"><stop
  103 + style="stop-color:black;stop-opacity:1;"
  104 + offset="0"
  105 + id="stop5062" /><stop
  106 + style="stop-color:black;stop-opacity:0;"
  107 + offset="1"
  108 + id="stop5064" /></linearGradient><linearGradient
  109 + id="linearGradient5048"><stop
  110 + style="stop-color:black;stop-opacity:0;"
  111 + offset="0"
  112 + id="stop5050" /><stop
  113 + id="stop5056"
  114 + offset="0.5"
  115 + style="stop-color:black;stop-opacity:1;" /><stop
  116 + style="stop-color:black;stop-opacity:0;"
  117 + offset="1"
  118 + id="stop5052" /></linearGradient><linearGradient
  119 + id="linearGradient2406"><stop
  120 + style="stop-color:#7c7e79;stop-opacity:1;"
  121 + offset="0"
  122 + id="stop2408" /><stop
  123 + id="stop2414"
  124 + offset="0.1724138"
  125 + style="stop-color:#848681;stop-opacity:1;" /><stop
  126 + style="stop-color:#898c86;stop-opacity:1;"
  127 + offset="1"
  128 + id="stop2410" /></linearGradient><linearGradient
  129 + inkscape:collect="always"
  130 + id="linearGradient2390"><stop
  131 + style="stop-color:#919191;stop-opacity:1;"
  132 + offset="0"
  133 + id="stop2392" /><stop
  134 + style="stop-color:#919191;stop-opacity:0;"
  135 + offset="1"
  136 + id="stop2394" /></linearGradient><linearGradient
  137 + inkscape:collect="always"
  138 + id="linearGradient2378"><stop
  139 + style="stop-color:#575757;stop-opacity:1;"
  140 + offset="0"
  141 + id="stop2380" /><stop
  142 + style="stop-color:#575757;stop-opacity:0;"
  143 + offset="1"
  144 + id="stop2382" /></linearGradient><linearGradient
  145 + inkscape:collect="always"
  146 + id="linearGradient2368"><stop
  147 + style="stop-color:#ffffff;stop-opacity:1;"
  148 + offset="0"
  149 + id="stop2370" /><stop
  150 + style="stop-color:#ffffff;stop-opacity:0;"
  151 + offset="1"
  152 + id="stop2372" /></linearGradient><linearGradient
  153 + inkscape:collect="always"
  154 + id="linearGradient2349"><stop
  155 + style="stop-color:#000000;stop-opacity:1;"
  156 + offset="0"
  157 + id="stop2351" /><stop
  158 + style="stop-color:#000000;stop-opacity:0;"
  159 + offset="1"
  160 + id="stop2353" /></linearGradient><linearGradient
  161 + id="linearGradient2341"><stop
  162 + id="stop2343"
  163 + offset="0"
  164 + style="stop-color:#000000;stop-opacity:1;" /><stop
  165 + id="stop2345"
  166 + offset="1"
  167 + style="stop-color:#000000;stop-opacity:0;" /></linearGradient><linearGradient
  168 + id="linearGradient2329"><stop
  169 + style="stop-color:#000000;stop-opacity:0.18556701;"
  170 + offset="0"
  171 + id="stop2331" /><stop
  172 + style="stop-color:#ffffff;stop-opacity:1;"
  173 + offset="1"
  174 + id="stop2333" /></linearGradient><linearGradient
  175 + inkscape:collect="always"
  176 + id="linearGradient2319"><stop
  177 + style="stop-color:#000000;stop-opacity:1;"
  178 + offset="0"
  179 + id="stop2321" /><stop
  180 + style="stop-color:#000000;stop-opacity:0;"
  181 + offset="1"
  182 + id="stop2323" /></linearGradient><linearGradient
  183 + id="linearGradient2307"><stop
  184 + style="stop-color:#edd400;stop-opacity:1;"
  185 + offset="0"
  186 + id="stop2309" /><stop
  187 + style="stop-color:#998800;stop-opacity:1;"
  188 + offset="1"
  189 + id="stop2311" /></linearGradient><linearGradient
  190 + inkscape:collect="always"
  191 + id="linearGradient2299"><stop
  192 + style="stop-color:#ffffff;stop-opacity:1;"
  193 + offset="0"
  194 + id="stop2301" /><stop
  195 + style="stop-color:#ffffff;stop-opacity:0;"
  196 + offset="1"
  197 + id="stop2303" /></linearGradient><linearGradient
  198 + id="XMLID_2_"
  199 + gradientUnits="userSpaceOnUse"
  200 + x1="80.223602"
  201 + y1="117.5205"
  202 + x2="48.046001"
  203 + y2="59.7995"
  204 + gradientTransform="matrix(0.314683,0.000000,0.000000,0.314683,4.128264,3.742874)">
  205 + <stop
  206 + offset="0"
  207 + style="stop-color:#CCCCCC"
  208 + id="stop17" />
  209 + <stop
  210 + offset="0.9831"
  211 + style="stop-color:#FFFFFF"
  212 + id="stop19" />
  213 + <midPointStop
  214 + offset="0"
  215 + style="stop-color:#CCCCCC"
  216 + id="midPointStop48" />
  217 + <midPointStop
  218 + offset="0.5"
  219 + style="stop-color:#CCCCCC"
  220 + id="midPointStop50" />
  221 + <midPointStop
  222 + offset="0.9831"
  223 + style="stop-color:#FFFFFF"
  224 + id="midPointStop52" />
  225 + </linearGradient><linearGradient
  226 + id="XMLID_39_"
  227 + gradientUnits="userSpaceOnUse"
  228 + x1="64.387703"
  229 + y1="65.124001"
  230 + x2="64.387703"
  231 + y2="35.569"
  232 + gradientTransform="matrix(0.354101,0.000000,0.000000,0.354101,1.638679,-8.364921e-2)">
  233 + <stop
  234 + offset="0"
  235 + style="stop-color:#FFFFFF"
  236 + id="stop336" />
  237 + <stop
  238 + offset="0.8539"
  239 + style="stop-color:#FF6200"
  240 + id="stop338" />
  241 + <stop
  242 + offset="1"
  243 + style="stop-color:#F25D00"
  244 + id="stop340" />
  245 + <midPointStop
  246 + offset="0"
  247 + style="stop-color:#FFFFFF"
  248 + id="midPointStop335" />
  249 + <midPointStop
  250 + offset="0.5"
  251 + style="stop-color:#FFFFFF"
  252 + id="midPointStop337" />
  253 + <midPointStop
  254 + offset="0.8539"
  255 + style="stop-color:#FF6200"
  256 + id="midPointStop339" />
  257 + <midPointStop
  258 + offset="0.5"
  259 + style="stop-color:#FF6200"
  260 + id="midPointStop341" />
  261 + <midPointStop
  262 + offset="1"
  263 + style="stop-color:#F25D00"
  264 + id="midPointStop343" />
  265 + </linearGradient><radialGradient
  266 + inkscape:collect="always"
  267 + xlink:href="#linearGradient2307"
  268 + id="radialGradient2313"
  269 + cx="19.985598"
  270 + cy="36.77816"
  271 + fx="19.985598"
  272 + fy="36.77816"
  273 + r="1.0821035"
  274 + gradientTransform="matrix(1.125263,0,0,0.982744,-4.428678,0.565787)"
  275 + gradientUnits="userSpaceOnUse" /><radialGradient
  276 + inkscape:collect="always"
  277 + xlink:href="#linearGradient2319"
  278 + id="radialGradient2325"
  279 + cx="20.443665"
  280 + cy="37.425829"
  281 + fx="20.443665"
  282 + fy="37.425829"
  283 + r="1.0821035"
  284 + gradientTransform="matrix(1.125263,0,0,0.982744,-4.428678,0.731106)"
  285 + gradientUnits="userSpaceOnUse" /><radialGradient
  286 + inkscape:collect="always"
  287 + xlink:href="#linearGradient2349"
  288 + id="radialGradient2355"
  289 + cx="24.023088"
  290 + cy="40.56913"
  291 + fx="24.023088"
  292 + fy="40.56913"
  293 + r="16.28684"
  294 + gradientTransform="matrix(1.000000,0.000000,0.000000,0.431250,1.157278e-15,23.07369)"
  295 + gradientUnits="userSpaceOnUse" /><linearGradient
  296 + inkscape:collect="always"
  297 + xlink:href="#linearGradient2390"
  298 + id="linearGradient2396"
  299 + x1="30.603519"
  300 + y1="37.337803"
  301 + x2="30.603519"
  302 + y2="36.112415"
  303 + gradientUnits="userSpaceOnUse"
  304 + gradientTransform="matrix(1.263867,0,0,0.859794,-6.499556,8.390924)" /><linearGradient
  305 + inkscape:collect="always"
  306 + xlink:href="#linearGradient5048"
  307 + id="linearGradient3710"
  308 + gradientUnits="userSpaceOnUse"
  309 + gradientTransform="matrix(2.774389,0,0,1.969706,-1892.179,-872.8854)"
  310 + x1="302.85715"
  311 + y1="366.64789"
  312 + x2="302.85715"
  313 + y2="609.50507" /><radialGradient
  314 + inkscape:collect="always"
  315 + xlink:href="#linearGradient5060"
  316 + id="radialGradient3712"
  317 + gradientUnits="userSpaceOnUse"
  318 + gradientTransform="matrix(2.774389,0,0,1.969706,-1891.633,-872.8854)"
  319 + cx="605.71429"
  320 + cy="486.64789"
  321 + fx="605.71429"
  322 + fy="486.64789"
  323 + r="117.14286" /><radialGradient
  324 + inkscape:collect="always"
  325 + xlink:href="#linearGradient5060"
  326 + id="radialGradient3714"
  327 + gradientUnits="userSpaceOnUse"
  328 + gradientTransform="matrix(-2.774389,0,0,1.969706,112.7623,-872.8854)"
  329 + cx="605.71429"
  330 + cy="486.64789"
  331 + fx="605.71429"
  332 + fy="486.64789"
  333 + r="117.14286" /><linearGradient
  334 + inkscape:collect="always"
  335 + xlink:href="#XMLID_2_"
  336 + id="linearGradient3716"
  337 + gradientUnits="userSpaceOnUse"
  338 + gradientTransform="matrix(0.336922,0,0,0.166888,-42.01712,15.46151)"
  339 + x1="52.006104"
  340 + y1="166.1331"
  341 + x2="14.049017"
  342 + y2="-42.218513" /><linearGradient
  343 + inkscape:collect="always"
  344 + xlink:href="#linearGradient2329"
  345 + id="linearGradient3718"
  346 + gradientUnits="userSpaceOnUse"
  347 + gradientTransform="matrix(0.898789,0,0,1.071914,-59.521975,-2.080838)"
  348 + x1="17.602522"
  349 + y1="26.057423"
  350 + x2="17.682528"
  351 + y2="32.654099" /><radialGradient
  352 + inkscape:collect="always"
  353 + xlink:href="#linearGradient2378"
  354 + id="radialGradient3720"
  355 + gradientUnits="userSpaceOnUse"
  356 + gradientTransform="matrix(1.125263,-3.585417e-8,4.269819e-8,1.340059,-63.006704,1.355395)"
  357 + cx="24.195112"
  358 + cy="10.577631"
  359 + fx="24.195112"
  360 + fy="10.577631"
  361 + r="15.242914" /><linearGradient
  362 + inkscape:collect="always"
  363 + xlink:href="#linearGradient2406"
  364 + id="linearGradient3722"
  365 + gradientUnits="userSpaceOnUse"
  366 + gradientTransform="matrix(0.888785,0,0,1.08932,-57.58901,-1.524336)"
  367 + x1="17.850183"
  368 + y1="28.939463"
  369 + x2="19.040216"
  370 + y2="41.03223" /><radialGradient
  371 + inkscape:collect="always"
  372 + xlink:href="#linearGradient2319"
  373 + id="radialGradient3724"
  374 + gradientUnits="userSpaceOnUse"
  375 + gradientTransform="matrix(1.125263,0,0,0.982744,-63.428678,0.731106)"
  376 + cx="20.443665"
  377 + cy="37.425829"
  378 + fx="20.443665"
  379 + fy="37.425829"
  380 + r="1.0821035" /><radialGradient
  381 + inkscape:collect="always"
  382 + xlink:href="#linearGradient2307"
  383 + id="radialGradient3726"
  384 + gradientUnits="userSpaceOnUse"
  385 + gradientTransform="matrix(1.125263,0,0,0.982744,-63.428678,0.565787)"
  386 + cx="19.985598"
  387 + cy="36.77816"
  388 + fx="19.985598"
  389 + fy="36.77816"
  390 + r="1.0821035" /><linearGradient
  391 + inkscape:collect="always"
  392 + xlink:href="#XMLID_39_"
  393 + id="linearGradient3728"
  394 + gradientUnits="userSpaceOnUse"
  395 + gradientTransform="matrix(0.354101,0,0,0.354101,-58.361321,-0.08364921)"
  396 + x1="64.387703"
  397 + y1="65.124001"
  398 + x2="64.387703"
  399 + y2="35.569" /><radialGradient
  400 + inkscape:collect="always"
  401 + xlink:href="#linearGradient2299"
  402 + id="radialGradient3730"
  403 + gradientUnits="userSpaceOnUse"
  404 + gradientTransform="matrix(4.100086,0,0,4.201322,-85.41506,-78.53967)"
  405 + cx="7.5326638"
  406 + cy="24.202574"
  407 + fx="7.5326638"
  408 + fy="24.202574"
  409 + r="8.2452128" /><radialGradient
  410 + inkscape:collect="always"
  411 + xlink:href="#linearGradient2341"
  412 + id="radialGradient3732"
  413 + gradientUnits="userSpaceOnUse"
  414 + gradientTransform="matrix(4.100086,0,0,-4.201322,-65.198109,105.3535)"
  415 + cx="11.68129"
  416 + cy="19.554111"
  417 + fx="11.68129"
  418 + fy="19.554111"
  419 + r="8.2452126" /><radialGradient
  420 + inkscape:collect="always"
  421 + xlink:href="#linearGradient2368"
  422 + id="radialGradient3734"
  423 + gradientUnits="userSpaceOnUse"
  424 + gradientTransform="matrix(3.751495,0,0,3.147818,-142.00907,-65.70704)"
  425 + cx="29.913452"
  426 + cy="30.442923"
  427 + fx="29.913452"
  428 + fy="30.442923"
  429 + r="4.0018832" /><linearGradient
  430 + inkscape:collect="always"
  431 + xlink:href="#linearGradient3736"
  432 + id="linearGradient4355"
  433 + gradientUnits="userSpaceOnUse"
  434 + gradientTransform="matrix(0.336922,0.000000,0.000000,0.166888,17.98288,15.46151)"
  435 + x1="49.023571"
  436 + y1="173.99986"
  437 + x2="19.343113"
  438 + y2="-5.7614088" /><radialGradient
  439 + inkscape:collect="always"
  440 + xlink:href="#linearGradient2378"
  441 + id="radialGradient4379"
  442 + gradientUnits="userSpaceOnUse"
  443 + gradientTransform="matrix(-2.7847815e-8,0.91845951,-1.1152723,-3.3815205e-8,39.60096,1.4161083)"
  444 + cx="28.399611"
  445 + cy="15.333439"
  446 + fx="28.399611"
  447 + fy="15.333439"
  448 + r="15.242914" /><radialGradient
  449 + inkscape:collect="always"
  450 + xlink:href="#linearGradient2341"
  451 + id="radialGradient4473"
  452 + gradientUnits="userSpaceOnUse"
  453 + gradientTransform="matrix(-2.0618025,-2.0407128e-7,-3.2411324e-7,3.2746279,61.522713,-37.078328)"
  454 + cx="11.651313"
  455 + cy="20.026194"
  456 + fx="11.651313"
  457 + fy="20.026194"
  458 + r="8.2452126" /><radialGradient
  459 + inkscape:collect="always"
  460 + xlink:href="#linearGradient2299"
  461 + id="radialGradient4657"
  462 + gradientUnits="userSpaceOnUse"
  463 + gradientTransform="matrix(3.39591,-4.6697806e-7,4.6697814e-7,3.3959105,-19.762019,-53.978222)"
  464 + cx="8.027895"
  465 + cy="24.287516"
  466 + fx="8.027895"
  467 + fy="24.287516"
  468 + r="8.2452128" /><linearGradient
  469 + inkscape:collect="always"
  470 + xlink:href="#linearGradient2329"
  471 + id="linearGradient4661"
  472 + gradientUnits="userSpaceOnUse"
  473 + gradientTransform="matrix(0.67409175,0,0,0.92339382,5.1085187,4.2256015)"
  474 + x1="15.415529"
  475 + y1="23.833527"
  476 + x2="16.899008"
  477 + y2="33.219193" /><linearGradient
  478 + inkscape:collect="always"
  479 + xlink:href="#linearGradient3771"
  480 + id="linearGradient4665"
  481 + gradientUnits="userSpaceOnUse"
  482 + gradientTransform="translate(-1,1)"
  483 + x1="26.5"
  484 + y1="36.5"
  485 + x2="24.5"
  486 + y2="28.5" /><radialGradient
  487 + inkscape:collect="always"
  488 + xlink:href="#linearGradient2368"
  489 + id="radialGradient4669"
  490 + gradientUnits="userSpaceOnUse"
  491 + gradientTransform="matrix(0.11004748,1.8133708,-1.8164852,0.18222563,79.460078,-26.062392)"
  492 + cx="29.913452"
  493 + cy="30.442923"
  494 + fx="29.913452"
  495 + fy="30.442923"
  496 + r="4.0018832" /><radialGradient
  497 + inkscape:collect="always"
  498 + xlink:href="#linearGradient5060"
  499 + id="radialGradient4693"
  500 + gradientUnits="userSpaceOnUse"
  501 + gradientTransform="matrix(-2.6052648,0,0,1.9930785,128.02878,-872.62632)"
  502 + cx="605.71429"
  503 + cy="486.64789"
  504 + fx="605.71429"
  505 + fy="486.64789"
  506 + r="117.14286" /><linearGradient
  507 + inkscape:collect="always"
  508 + xlink:href="#linearGradient5048"
  509 + id="linearGradient4697"
  510 + gradientUnits="userSpaceOnUse"
  511 + gradientTransform="matrix(2.3780477,0,0,1.969706,-1808.0185,-845.99583)"
  512 + x1="304.19855"
  513 + y1="357.48697"
  514 + x2="304.19855"
  515 + y2="603.21515" /><radialGradient
  516 + inkscape:collect="always"
  517 + xlink:href="#linearGradient5060"
  518 + id="radialGradient4701"
  519 + gradientUnits="userSpaceOnUse"
  520 + gradientTransform="matrix(2.6052656,0,0,1.9930785,-2039.1167,-872.62632)"
  521 + cx="605.71429"
  522 + cy="486.64789"
  523 + fx="605.71429"
  524 + fy="486.64789"
  525 + r="117.14286" /><linearGradient
  526 + inkscape:collect="always"
  527 + xlink:href="#linearGradient5048"
  528 + id="linearGradient4765"
  529 + gradientUnits="userSpaceOnUse"
  530 + gradientTransform="matrix(2.3780477,0,0,1.969706,-1808.0185,-845.99583)"
  531 + x1="304.19855"
  532 + y1="357.48697"
  533 + x2="304.19855"
  534 + y2="603.21515" /><radialGradient
  535 + inkscape:collect="always"
  536 + xlink:href="#linearGradient5060"
  537 + id="radialGradient4767"
  538 + gradientUnits="userSpaceOnUse"
  539 + gradientTransform="matrix(2.6052656,0,0,1.9930785,-2039.1167,-872.62632)"
  540 + cx="605.71429"
  541 + cy="486.64789"
  542 + fx="605.71429"
  543 + fy="486.64789"
  544 + r="117.14286" /><radialGradient
  545 + inkscape:collect="always"
  546 + xlink:href="#linearGradient5060"
  547 + id="radialGradient4769"
  548 + gradientUnits="userSpaceOnUse"
  549 + gradientTransform="matrix(-2.6052648,0,0,1.9930785,128.02878,-872.62632)"
  550 + cx="605.71429"
  551 + cy="486.64789"
  552 + fx="605.71429"
  553 + fy="486.64789"
  554 + r="117.14286" /><linearGradient
  555 + inkscape:collect="always"
  556 + xlink:href="#linearGradient3736"
  557 + id="linearGradient4771"
  558 + gradientUnits="userSpaceOnUse"
  559 + gradientTransform="matrix(0.336922,0,0,0.166888,17.98288,15.46151)"
  560 + x1="49.023571"
  561 + y1="173.99986"
  562 + x2="19.343113"
  563 + y2="-5.7614088" /><linearGradient
  564 + inkscape:collect="always"
  565 + xlink:href="#linearGradient2329"
  566 + id="linearGradient4773"
  567 + gradientUnits="userSpaceOnUse"
  568 + gradientTransform="matrix(0.67409175,0,0,0.92339382,5.1085187,4.2256015)"
  569 + x1="15.415529"
  570 + y1="23.833527"
  571 + x2="16.899008"
  572 + y2="33.219193" /><radialGradient
  573 + inkscape:collect="always"
  574 + xlink:href="#linearGradient2319"
  575 + id="radialGradient4775"
  576 + gradientUnits="userSpaceOnUse"
  577 + gradientTransform="matrix(1.125263,0,0,0.982744,-4.428678,0.731106)"
  578 + cx="20.443665"
  579 + cy="37.425829"
  580 + fx="20.443665"
  581 + fy="37.425829"
  582 + r="1.0821035" /><radialGradient
  583 + inkscape:collect="always"
  584 + xlink:href="#linearGradient2307"
  585 + id="radialGradient4777"
  586 + gradientUnits="userSpaceOnUse"
  587 + gradientTransform="matrix(1.125263,0,0,0.982744,-4.428678,0.565787)"
  588 + cx="19.985598"
  589 + cy="36.77816"
  590 + fx="19.985598"
  591 + fy="36.77816"
  592 + r="1.0821035" /><radialGradient
  593 + inkscape:collect="always"
  594 + xlink:href="#linearGradient2368"
  595 + id="radialGradient4779"
  596 + gradientUnits="userSpaceOnUse"
  597 + gradientTransform="matrix(0.11004748,1.8133708,-1.8164852,0.18222563,79.460078,-26.062392)"
  598 + cx="29.913452"
  599 + cy="30.442923"
  600 + fx="29.913452"
  601 + fy="30.442923"
  602 + r="4.0018832" /><linearGradient
  603 + inkscape:collect="always"
  604 + xlink:href="#linearGradient3771"
  605 + id="linearGradient4781"
  606 + gradientUnits="userSpaceOnUse"
  607 + gradientTransform="translate(-1,1)"
  608 + x1="26.5"
  609 + y1="36.5"
  610 + x2="24.5"
  611 + y2="28.5" /><radialGradient
  612 + inkscape:collect="always"
  613 + xlink:href="#linearGradient2378"
  614 + id="radialGradient4783"
  615 + gradientUnits="userSpaceOnUse"
  616 + gradientTransform="matrix(-2.7847815e-8,0.91845951,-1.1152723,-3.3815205e-8,39.60096,1.4161083)"
  617 + cx="28.399611"
  618 + cy="15.333439"
  619 + fx="28.399611"
  620 + fy="15.333439"
  621 + r="15.242914" /><radialGradient
  622 + inkscape:collect="always"
  623 + xlink:href="#linearGradient2299"
  624 + id="radialGradient4785"
  625 + gradientUnits="userSpaceOnUse"
  626 + gradientTransform="matrix(3.39591,-4.6697806e-7,4.6697814e-7,3.3959105,-19.762019,-53.978222)"
  627 + cx="8.027895"
  628 + cy="24.287516"
  629 + fx="8.027895"
  630 + fy="24.287516"
  631 + r="8.2452128" /><radialGradient
  632 + inkscape:collect="always"
  633 + xlink:href="#linearGradient2341"
  634 + id="radialGradient4787"
  635 + gradientUnits="userSpaceOnUse"
  636 + gradientTransform="matrix(-2.0618025,-2.0407128e-7,-3.2411324e-7,3.2746279,61.522713,-37.078328)"
  637 + cx="11.651313"
  638 + cy="20.026194"
  639 + fx="11.651313"
  640 + fy="20.026194"
  641 + r="8.2452126" /><linearGradient
  642 + inkscape:collect="always"
  643 + xlink:href="#linearGradient5048"
  644 + id="linearGradient5003"
  645 + gradientUnits="userSpaceOnUse"
  646 + gradientTransform="matrix(2.3780477,0,0,1.969706,-1808.0185,-845.99583)"
  647 + x1="304.19855"
  648 + y1="357.48697"
  649 + x2="304.19855"
  650 + y2="603.21515" /><radialGradient
  651 + inkscape:collect="always"
  652 + xlink:href="#linearGradient5060"
  653 + id="radialGradient5005"
  654 + gradientUnits="userSpaceOnUse"
  655 + gradientTransform="matrix(2.6052656,0,0,1.9930785,-2039.1167,-872.62632)"
  656 + cx="605.71429"
  657 + cy="486.64789"
  658 + fx="605.71429"
  659 + fy="486.64789"
  660 + r="117.14286" /><radialGradient
  661 + inkscape:collect="always"
  662 + xlink:href="#linearGradient5060"
  663 + id="radialGradient5007"
  664 + gradientUnits="userSpaceOnUse"
  665 + gradientTransform="matrix(-2.6052648,0,0,1.9930785,128.02878,-872.62632)"
  666 + cx="605.71429"
  667 + cy="486.64789"
  668 + fx="605.71429"
  669 + fy="486.64789"
  670 + r="117.14286" /><linearGradient
  671 + inkscape:collect="always"
  672 + xlink:href="#linearGradient3736"
  673 + id="linearGradient5009"
  674 + gradientUnits="userSpaceOnUse"
  675 + gradientTransform="matrix(0.336922,0,0,0.166888,17.98288,15.46151)"
  676 + x1="49.023571"
  677 + y1="173.99986"
  678 + x2="19.343113"
  679 + y2="-5.7614088" /><linearGradient
  680 + inkscape:collect="always"
  681 + xlink:href="#linearGradient2329"
  682 + id="linearGradient5011"
  683 + gradientUnits="userSpaceOnUse"
  684 + gradientTransform="matrix(0.67409175,0,0,0.92339382,5.1085187,4.2256015)"
  685 + x1="15.415529"
  686 + y1="23.833527"
  687 + x2="16.899008"
  688 + y2="33.219193" /><radialGradient
  689 + inkscape:collect="always"
  690 + xlink:href="#linearGradient2319"
  691 + id="radialGradient5013"
  692 + gradientUnits="userSpaceOnUse"
  693 + gradientTransform="matrix(1.125263,0,0,0.982744,-4.428678,0.731106)"
  694 + cx="20.443665"
  695 + cy="37.425829"
  696 + fx="20.443665"
  697 + fy="37.425829"
  698 + r="1.0821035" /><radialGradient
  699 + inkscape:collect="always"
  700 + xlink:href="#linearGradient2307"
  701 + id="radialGradient5015"
  702 + gradientUnits="userSpaceOnUse"
  703 + gradientTransform="matrix(1.125263,0,0,0.982744,-4.428678,2.0807369)"
  704 + cx="19.985598"
  705 + cy="36.77816"
  706 + fx="19.985598"
  707 + fy="36.77816"
  708 + r="1.0821035" /><radialGradient
  709 + inkscape:collect="always"
  710 + xlink:href="#linearGradient2368"
  711 + id="radialGradient5017"
  712 + gradientUnits="userSpaceOnUse"
  713 + gradientTransform="matrix(0.11004748,1.8133708,-1.8164852,0.18222563,79.460078,-26.062392)"
  714 + cx="29.913452"
  715 + cy="30.442923"
  716 + fx="29.913452"
  717 + fy="30.442923"
  718 + r="4.0018832" /><linearGradient
  719 + inkscape:collect="always"
  720 + xlink:href="#linearGradient3771"
  721 + id="linearGradient5019"
  722 + gradientUnits="userSpaceOnUse"
  723 + gradientTransform="translate(-1,1)"
  724 + x1="26.5"
  725 + y1="36.5"
  726 + x2="24.5"
  727 + y2="28.5" /><radialGradient
  728 + inkscape:collect="always"
  729 + xlink:href="#linearGradient2378"
  730 + id="radialGradient5021"
  731 + gradientUnits="userSpaceOnUse"
  732 + gradientTransform="matrix(-2.7847815e-8,0.91845951,-1.1152723,-3.3815205e-8,39.60096,1.4161083)"
  733 + cx="28.399611"
  734 + cy="15.333439"
  735 + fx="28.399611"
  736 + fy="15.333439"
  737 + r="15.242914" /><radialGradient
  738 + inkscape:collect="always"
  739 + xlink:href="#linearGradient2299"
  740 + id="radialGradient5023"
  741 + gradientUnits="userSpaceOnUse"
  742 + gradientTransform="matrix(3.39591,-4.6697806e-7,4.6697814e-7,3.3959105,-19.762019,-53.978222)"
  743 + cx="8.027895"
  744 + cy="24.287516"
  745 + fx="8.027895"
  746 + fy="24.287516"
  747 + r="8.2452128" /><radialGradient
  748 + inkscape:collect="always"
  749 + xlink:href="#linearGradient2341"
  750 + id="radialGradient5025"
  751 + gradientUnits="userSpaceOnUse"
  752 + gradientTransform="matrix(-2.0618025,-2.0407128e-7,-3.2411324e-7,3.2746279,61.522713,-37.078328)"
  753 + cx="11.651313"
  754 + cy="20.026194"
  755 + fx="11.651313"
  756 + fy="20.026194"
  757 + r="8.2452126" /><linearGradient
  758 + inkscape:collect="always"
  759 + xlink:href="#linearGradient5048"
  760 + id="linearGradient5077"
  761 + gradientUnits="userSpaceOnUse"
  762 + gradientTransform="matrix(2.1515669,0,0,1.969706,-1773.1654,-845.99583)"
  763 + x1="304.19855"
  764 + y1="357.48697"
  765 + x2="304.19855"
  766 + y2="603.21515" /><radialGradient
  767 + inkscape:collect="always"
  768 + xlink:href="#linearGradient5060"
  769 + id="radialGradient5079"
  770 + gradientUnits="userSpaceOnUse"
  771 + gradientTransform="matrix(2.6052656,0,0,1.9930785,-2131.7867,-872.62632)"
  772 + cx="605.71429"
  773 + cy="486.64789"
  774 + fx="605.71429"
  775 + fy="486.64789"
  776 + r="117.14286" /><radialGradient
  777 + inkscape:collect="always"
  778 + xlink:href="#linearGradient5060"
  779 + id="radialGradient5081"
  780 + gradientUnits="userSpaceOnUse"
  781 + gradientTransform="matrix(-2.6052648,0,0,1.9930785,128.02878,-872.62632)"
  782 + cx="605.71429"
  783 + cy="486.64789"
  784 + fx="605.71429"
  785 + fy="486.64789"
  786 + r="117.14286" /><linearGradient
  787 + inkscape:collect="always"
  788 + xlink:href="#linearGradient3736"
  789 + id="linearGradient5083"
  790 + gradientUnits="userSpaceOnUse"
  791 + gradientTransform="matrix(0.336922,0,0,0.166888,17.98288,15.46151)"
  792 + x1="49.023571"
  793 + y1="173.99986"
  794 + x2="19.343113"
  795 + y2="-5.7614088" /><linearGradient
  796 + inkscape:collect="always"
  797 + xlink:href="#linearGradient2329"
  798 + id="linearGradient5085"
  799 + gradientUnits="userSpaceOnUse"
  800 + gradientTransform="matrix(0.59919267,0,0,0.92339382,6.9853499,4.2256015)"
  801 + x1="15.415529"
  802 + y1="23.833527"
  803 + x2="16.899008"
  804 + y2="33.219193" /><radialGradient
  805 + inkscape:collect="always"
  806 + xlink:href="#linearGradient2319"
  807 + id="radialGradient5087"
  808 + gradientUnits="userSpaceOnUse"
  809 + gradientTransform="matrix(1.125263,0,0,0.982744,-4.428678,0.731106)"
  810 + cx="20.443665"
  811 + cy="37.425829"
  812 + fx="20.443665"
  813 + fy="37.425829"
  814 + r="1.0821035" /><radialGradient
  815 + inkscape:collect="always"
  816 + xlink:href="#linearGradient2368"
  817 + id="radialGradient5091"
  818 + gradientUnits="userSpaceOnUse"
  819 + gradientTransform="matrix(0.11004748,1.8133708,-1.8164852,0.18222563,79.460078,-26.062392)"
  820 + cx="29.913452"
  821 + cy="30.442923"
  822 + fx="29.913452"
  823 + fy="30.442923"
  824 + r="4.0018832" /><linearGradient
  825 + inkscape:collect="always"
  826 + xlink:href="#linearGradient3771"
  827 + id="linearGradient5093"
  828 + gradientUnits="userSpaceOnUse"
  829 + gradientTransform="translate(-1,1)"
  830 + x1="26.5"
  831 + y1="36.5"
  832 + x2="24.5"
  833 + y2="28.5" /><radialGradient
  834 + inkscape:collect="always"
  835 + xlink:href="#linearGradient2378"
  836 + id="radialGradient5095"
  837 + gradientUnits="userSpaceOnUse"
  838 + gradientTransform="matrix(-2.7847815e-8,0.91845951,-1.1152723,-3.3815205e-8,39.60096,1.4161083)"
  839 + cx="29.48839"
  840 + cy="15.333439"
  841 + fx="29.48839"
  842 + fy="15.333439"
  843 + r="15.242914" /><radialGradient
  844 + inkscape:collect="always"
  845 + xlink:href="#linearGradient2299"
  846 + id="radialGradient5097"
  847 + gradientUnits="userSpaceOnUse"
  848 + gradientTransform="matrix(3.39591,-4.6697806e-7,4.6697814e-7,3.3959105,-19.762019,-52.978222)"
  849 + cx="8.027895"
  850 + cy="24.287516"
  851 + fx="8.027895"
  852 + fy="24.287516"
  853 + r="8.2452128" /><radialGradient
  854 + inkscape:collect="always"
  855 + xlink:href="#linearGradient2341"
  856 + id="radialGradient5099"
  857 + gradientUnits="userSpaceOnUse"
  858 + gradientTransform="matrix(-2.0618025,-2.0407128e-7,-3.2411324e-7,3.2746279,61.522713,-36.078328)"
  859 + cx="11.651313"
  860 + cy="20.026194"
  861 + fx="11.651313"
  862 + fy="20.026194"
  863 + r="8.2452126" /><linearGradient
  864 + inkscape:collect="always"
  865 + xlink:href="#linearGradient3177"
  866 + id="linearGradient3259"
  867 + gradientUnits="userSpaceOnUse"
  868 + x1="25.621262"
  869 + y1="33.817276"
  870 + x2="28.5"
  871 + y2="36.5" /><linearGradient
  872 + inkscape:collect="always"
  873 + xlink:href="#linearGradient5048"
  874 + id="linearGradient3297"
  875 + gradientUnits="userSpaceOnUse"
  876 + gradientTransform="matrix(2.1515669,0,0,1.969706,-1773.1654,-845.99583)"
  877 + x1="304.19855"
  878 + y1="357.48697"
  879 + x2="304.19855"
  880 + y2="603.21515" /><radialGradient
  881 + inkscape:collect="always"
  882 + xlink:href="#linearGradient5060"
  883 + id="radialGradient3299"
  884 + gradientUnits="userSpaceOnUse"
  885 + gradientTransform="matrix(2.6052656,0,0,1.9930785,-2131.7867,-872.62632)"
  886 + cx="605.71429"
  887 + cy="486.64789"
  888 + fx="605.71429"
  889 + fy="486.64789"
  890 + r="117.14286" /><radialGradient
  891 + inkscape:collect="always"
  892 + xlink:href="#linearGradient5060"
  893 + id="radialGradient3301"
  894 + gradientUnits="userSpaceOnUse"
  895 + gradientTransform="matrix(-2.6052648,0,0,1.9930785,128.02878,-872.62632)"
  896 + cx="605.71429"
  897 + cy="486.64789"
  898 + fx="605.71429"
  899 + fy="486.64789"
  900 + r="117.14286" /><linearGradient
  901 + inkscape:collect="always"
  902 + xlink:href="#linearGradient3736"
  903 + id="linearGradient3303"
  904 + gradientUnits="userSpaceOnUse"
  905 + gradientTransform="matrix(0.336922,0,0,0.166888,17.98288,15.46151)"
  906 + x1="49.023571"
  907 + y1="173.99986"
  908 + x2="19.343113"
  909 + y2="-5.7614088" /><linearGradient
  910 + inkscape:collect="always"
  911 + xlink:href="#linearGradient2329"
  912 + id="linearGradient3305"
  913 + gradientUnits="userSpaceOnUse"
  914 + gradientTransform="matrix(0.59919267,0,0,0.92339382,6.9853499,4.2256015)"
  915 + x1="15.415529"
  916 + y1="23.833527"
  917 + x2="16.899008"
  918 + y2="33.219193" /><radialGradient
  919 + inkscape:collect="always"
  920 + xlink:href="#linearGradient2319"
  921 + id="radialGradient3307"
  922 + gradientUnits="userSpaceOnUse"
  923 + gradientTransform="matrix(1.125263,0,0,0.982744,-4.428678,0.731106)"
  924 + cx="20.443665"
  925 + cy="37.425829"
  926 + fx="20.443665"
  927 + fy="37.425829"
  928 + r="1.0821035" /><linearGradient
  929 + inkscape:collect="always"
  930 + xlink:href="#linearGradient5161"
  931 + id="linearGradient3309"
  932 + gradientUnits="userSpaceOnUse"
  933 + x1="17.5"
  934 + y1="35.5"
  935 + x2="20.5"
  936 + y2="39.5" /><radialGradient
  937 + inkscape:collect="always"
  938 + xlink:href="#linearGradient3171"
  939 + id="radialGradient3311"
  940 + gradientUnits="userSpaceOnUse"
  941 + gradientTransform="matrix(1.125263,0,0,0.982744,-4.3489438,1.0441923)"
  942 + cx="19.985598"
  943 + cy="36.77816"
  944 + fx="19.985598"
  945 + fy="36.77816"
  946 + r="1.0821035" /><linearGradient
  947 + inkscape:collect="always"
  948 + xlink:href="#linearGradient3771"
  949 + id="linearGradient3315"
  950 + gradientUnits="userSpaceOnUse"
  951 + gradientTransform="translate(-1,1)"
  952 + x1="26.5"
  953 + y1="36.5"
  954 + x2="24.5"
  955 + y2="28.5" /><radialGradient
  956 + inkscape:collect="always"
  957 + xlink:href="#linearGradient2378"
  958 + id="radialGradient3317"
  959 + gradientUnits="userSpaceOnUse"
  960 + gradientTransform="matrix(-2.7847815e-8,0.91845951,-1.1152723,-3.3815205e-8,39.60096,1.4161083)"
  961 + cx="29.48839"
  962 + cy="15.333439"
  963 + fx="29.48839"
  964 + fy="15.333439"
  965 + r="15.242914" /><radialGradient
  966 + inkscape:collect="always"
  967 + xlink:href="#linearGradient2299"
  968 + id="radialGradient3319"
  969 + gradientUnits="userSpaceOnUse"
  970 + gradientTransform="matrix(3.39591,-4.6697806e-7,4.6697814e-7,3.3959105,-19.762019,-52.978222)"
  971 + cx="8.027895"
  972 + cy="24.287516"
  973 + fx="8.027895"
  974 + fy="24.287516"
  975 + r="8.2452128" /><radialGradient
  976 + inkscape:collect="always"
  977 + xlink:href="#linearGradient2341"
  978 + id="radialGradient3321"
  979 + gradientUnits="userSpaceOnUse"
  980 + gradientTransform="matrix(-2.0618025,-2.0407128e-7,-3.2411324e-7,3.2746279,61.522713,-36.078328)"
  981 + cx="11.651313"
  982 + cy="20.026194"
  983 + fx="11.651313"
  984 + fy="20.026194"
  985 + r="8.2452126" /><inkscape:perspective
  986 + id="perspective3331"
  987 + inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
  988 + inkscape:vp_z="1 : 0.5 : 1"
  989 + inkscape:vp_y="0 : 1000 : 0"
  990 + inkscape:vp_x="0 : 0.5 : 1"
  991 + sodipodi:type="inkscape:persp3d" /><radialGradient
  992 + inkscape:collect="always"
  993 + xlink:href="#linearGradient2368-5"
  994 + id="radialGradient5017-4"
  995 + gradientUnits="userSpaceOnUse"
  996 + gradientTransform="matrix(0.11004748,1.8133708,-1.8164852,0.18222563,79.460078,-26.062392)"
  997 + cx="29.913452"
  998 + cy="30.442923"
  999 + fx="29.913452"
  1000 + fy="30.442923"
  1001 + r="4.001883" /><linearGradient
  1002 + inkscape:collect="always"
  1003 + id="linearGradient2368-5"><stop
  1004 + style="stop-color:#ffffff;stop-opacity:1;"
  1005 + offset="0"
  1006 + id="stop2370-2" /><stop
  1007 + style="stop-color:#ffffff;stop-opacity:0;"
  1008 + offset="1"
  1009 + id="stop2372-0" /></linearGradient><radialGradient
  1010 + r="4.001883"
  1011 + fy="30.442923"
  1012 + fx="29.913452"
  1013 + cy="30.442923"
  1014 + cx="29.913452"
  1015 + gradientTransform="matrix(0.11004748,1.8133708,-1.8164852,0.18222563,79.460083,-26.062392)"
  1016 + gradientUnits="userSpaceOnUse"
  1017 + id="radialGradient3340"
  1018 + xlink:href="#linearGradient2368-5"
  1019 + inkscape:collect="always" /><inkscape:perspective
  1020 + id="perspective4157"
  1021 + inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
  1022 + inkscape:vp_z="1 : 0.5 : 1"
  1023 + inkscape:vp_y="0 : 1000 : 0"
  1024 + inkscape:vp_x="0 : 0.5 : 1"
  1025 + sodipodi:type="inkscape:persp3d" /><radialGradient
  1026 + inkscape:collect="always"
  1027 + xlink:href="#linearGradient2307-6"
  1028 + id="radialGradient5015-8"
  1029 + gradientUnits="userSpaceOnUse"
  1030 + gradientTransform="matrix(1.125263,0,0,0.982744,-4.428678,2.0807369)"
  1031 + cx="20.09285"
  1032 + cy="35.716652"
  1033 + fx="20.09285"
  1034 + fy="35.716652"
  1035 + r="1.0821035" /><linearGradient
  1036 + id="linearGradient2307-6"><stop
  1037 + style="stop-color:#edd400;stop-opacity:1;"
  1038 + offset="0"
  1039 + id="stop2309-3" /><stop
  1040 + style="stop-color:#998800;stop-opacity:1;"
  1041 + offset="1"
  1042 + id="stop2311-5" /></linearGradient><radialGradient
  1043 + r="1.0821035"
  1044 + fy="36.77816"
  1045 + fx="19.985598"
  1046 + cy="36.77816"
  1047 + cx="19.985598"
  1048 + gradientTransform="matrix(1.125263,0,0,0.982744,-21.672305,-35.366438)"
  1049 + gradientUnits="userSpaceOnUse"
  1050 + id="radialGradient4166"
  1051 + xlink:href="#linearGradient2307-6"
  1052 + inkscape:collect="always" /></defs><sodipodi:namedview
  1053 + inkscape:cy="24"
  1054 + inkscape:cx="24"
  1055 + inkscape:zoom="12.541667"
  1056 + inkscape:window-height="827"
  1057 + inkscape:window-width="1440"
  1058 + inkscape:pageshadow="2"
  1059 + inkscape:pageopacity="0.0"
  1060 + borderopacity="0.21568627"
  1061 + bordercolor="#666666"
  1062 + pagecolor="#ffffff"
  1063 + id="base"
  1064 + inkscape:showpageshadow="false"
  1065 + inkscape:window-x="0"
  1066 + inkscape:window-y="25"
  1067 + inkscape:current-layer="svg2"
  1068 + fill="#555753"
  1069 + showgrid="true"
  1070 + stroke="#a40000"
  1071 + showguides="true"
  1072 + inkscape:guide-bbox="true"
  1073 + inkscape:snap-grids="true"
  1074 + inkscape:window-maximized="1"><inkscape:grid
  1075 + type="xygrid"
  1076 + id="grid3670"
  1077 + empspacing="5"
  1078 + visible="true"
  1079 + enabled="true"
  1080 + snapvisiblegridlinesonly="true"
  1081 + originx="0.5px"
  1082 + originy="0.5px" /></sodipodi:namedview>
  1083 +
  1084 +<g
  1085 + transform="translate(15,-6)"
  1086 + id="use5027"><g
  1087 + transform="matrix(0.02158196,0,0,0.01859457,39.12251,27.63767)"
  1088 + id="g3263"
  1089 + style="display:inline"><rect
  1090 + style="opacity:0.40206185;color:#000000;fill:url(#linearGradient3297);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible"
  1091 + id="rect3265"
  1092 + width="880.36487"
  1093 + height="484.0123"
  1094 + x="-1442.0613"
  1095 + y="-141.85165" /><path
  1096 + style="opacity:0.40206185;color:#000000;fill:url(#radialGradient3299);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible"
  1097 + d="m -561.69644,-141.85163 c 0,0 0,484.00662 0,484.00662 134.16473,0.91119 324.34504,-108.44127 324.34497,-242.03439 0,-133.593226 -149.71775,-241.97221 -324.34497,-241.97223 z"
  1098 + id="path3267"
  1099 + sodipodi:nodetypes="cccc" /><path
  1100 + sodipodi:nodetypes="cccc"
  1101 + id="path3269"
  1102 + d="m -1442.0613,-141.85163 c 0,0 0,484.00662 0,484.00662 -134.1648,0.91119 -324.345,-108.44127 -324.345,-242.03439 0,-133.593226 149.7177,-241.97221 324.345,-241.97223 z"
  1103 + style="opacity:0.40206185;color:#000000;fill:url(#radialGradient3301);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible" /></g><g
  1104 + id="g3271"
  1105 + transform="translate(-5.9999999,-13)"><path
  1106 + style="color:#000000;fill:url(#linearGradient3303);fill-opacity:1;fill-rule:nonzero;stroke:#757575;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible"
  1107 + d="m 35.5,26.5 0,16 c 0,0.905333 -0.160268,1 -1,1 l -22,0 c -0.839733,0 -1,-0.09467 -1,-1 l 0,-16 24,0 z"
  1108 + id="path3273"
  1109 + sodipodi:nodetypes="ccccccc" /><path
  1110 + sodipodi:nodetypes="ccccc"
  1111 + id="path3277"
  1112 + d="m 34.5,26.5 0,16 -22,0 0,-16 22,0 z"
  1113 + style="opacity:0.35;color:#000000;fill:none;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible" /><rect
  1114 + style="color:#000000;fill:#3465a4;fill-opacity:1;fill-rule:nonzero;stroke:#757575;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible"
  1115 + id="rect3285"
  1116 + width="7"
  1117 + height="6"
  1118 + x="24.5"
  1119 + y="32.5" /><rect
  1120 + y="31.5"
  1121 + x="23.5"
  1122 + height="8"
  1123 + width="9"
  1124 + id="rect3287"
  1125 + style="opacity:0.5;color:#000000;fill:none;stroke:url(#linearGradient3315);stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible"
  1126 + ry="1"
  1127 + rx="1" /><path
  1128 + clip-rule="evenodd"
  1129 + d="m 12.5,31.5 0,5 13,-6 9,5 0,-4 -10,-7 -12,7 z"
  1130 + id="path3289"
  1131 + style="opacity:0.20000000000000001;fill:url(#radialGradient3317);fill-opacity:1;fill-rule:evenodd"
  1132 + sodipodi:nodetypes="ccccccc" /><path
  1133 + style="fill:#ef2929;stroke:#a40000;stroke-linecap:round;stroke-linejoin:round"
  1134 + id="path3291"
  1135 + d="m 8.4999999,27.5 -1e-7,5 1.5,2 14.5000002,-7 12.5,7 1.5,-2 0,-5 -14,-8 -16.0000001,8 z"
  1136 + sodipodi:nodetypes="ccccccccc" /><path
  1137 + style="opacity:0.40909089;color:#000000;fill:url(#radialGradient3319);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible"
  1138 + d="m 9.0215946,27.818937 -10e-8,4 L 24.5,24.5 l 0,-4.318937 -15.4784054,7.637874 z"
  1139 + id="path3293"
  1140 + sodipodi:nodetypes="ccccc" /><path
  1141 + sodipodi:nodetypes="ccccc"
  1142 + id="path3295"
  1143 + d="m 24.5,24.5 0,-4.318937 13.478405,7.637874 0,4 L 24.5,24.5 z"
  1144 + style="opacity:0.13636367;color:#000000;fill:url(#radialGradient3321);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible" /><path
  1145 + style="opacity:0.39772728;color:#000000;fill:url(#radialGradient3340);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999958;marker:none;visibility:visible;display:inline;overflow:visible"
  1146 + d="m 25,36.954984 c 2.841896,0.362925 3.37612,-1.584298 6,-1.701594 L 31,33 l -6,0 0,3.954959 0,2.5e-5 z"
  1147 + id="rect2363-2"
  1148 + sodipodi:nodetypes="cccccc" /></g></g><g
  1149 + id="g4807"
  1150 + transform="translate(-1.9999999,-1.0000001)"><g
  1151 + style="display:inline"
  1152 + id="g4729"
  1153 + transform="matrix(0.02158196,0,0,0.01859457,39.12251,28.63767)"><rect
  1154 + y="-141.85165"
  1155 + x="-1442.0613"
  1156 + height="484.0123"
  1157 + width="880.36487"
  1158 + id="rect4731"
  1159 + style="opacity:0.40206185;color:#000000;fill:url(#linearGradient5077);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible" /><path
  1160 + sodipodi:nodetypes="cccc"
  1161 + id="path4733"
  1162 + d="m -561.69644,-141.85163 c 0,0 0,484.00662 0,484.00662 134.16473,0.91119 324.34504,-108.44127 324.34497,-242.03439 0,-133.593226 -149.71775,-241.97221 -324.34497,-241.97223 z"
  1163 + style="opacity:0.40206185;color:#000000;fill:url(#radialGradient5079);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible" /><path
  1164 + style="opacity:0.40206185;color:#000000;fill:url(#radialGradient5081);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible"
  1165 + d="m -1442.0613,-141.85163 c 0,0 0,484.00662 0,484.00662 -134.1648,0.91119 -324.345,-108.44127 -324.345,-242.03439 0,-133.593226 149.7177,-241.97221 324.345,-241.97223 z"
  1166 + id="path4735"
  1167 + sodipodi:nodetypes="cccc" /></g><g
  1168 + transform="translate(-5.9999999,-13)"
  1169 + id="g4737"><path
  1170 + sodipodi:nodetypes="ccccccc"
  1171 + id="path4739"
  1172 + d="m 35.5,26.5 0,17 c 0,0.905333 -0.160268,1 -1,1 l -22,0 c -0.839733,0 -1,-0.09467 -1,-1 l 0,-17 24,0 z"
  1173 + style="color:#000000;fill:url(#linearGradient5083);fill-opacity:1;fill-rule:nonzero;stroke:#757575;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible" /><path
  1174 + sodipodi:nodetypes="ccccc"
  1175 + clip-rule="evenodd"
  1176 + d="M 22,31 21.969511,44 14.074317,44 14,31 l 8,0 z"
  1177 + id="path4741"
  1178 + style="fill:url(#linearGradient5085);fill-opacity:1;fill-rule:evenodd" /><path
  1179 + style="opacity:0.35;color:#000000;fill:none;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible"
  1180 + d="m 34.5,26.5 0,17 -22,0 0,-17 22,0 z"
  1181 + id="path4743"
  1182 + sodipodi:nodetypes="ccccc" /><path
  1183 + clip-rule="evenodd"
  1184 + d="m 18.576856,36.44767 c 0.67279,0 1.216616,0.474605 1.216616,1.058507 0,0.589811 -0.543826,1.068355 -1.216616,1.068355 -0.672272,0 -1.218686,-0.478544 -1.218686,-1.068355 5.15e-4,-0.583902 0.546414,-1.058507 1.218686,-1.058507 z"
  1185 + id="path4745"
  1186 + style="opacity:0.40909089;fill:url(#radialGradient5087);fill-opacity:1;fill-rule:evenodd" /><rect
  1187 + y="32"
  1188 + x="15"
  1189 + height="12"
  1190 + width="6"
  1191 + id="rect4747"
  1192 + style="color:#000000;fill:#8f5902;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /><path
  1193 + style="color:#000000;fill:url(#radialGradient5015-8);fill-opacity:1;fill-rule:evenodd;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
  1194 + id="path4749"
  1195 + d="m 18.542048,36.410633 c 0.672789,0 1.216615,0.474605 1.216615,1.058507 0,0.589809 -0.543826,1.068353 -1.216615,1.068353 -0.672273,0 -1.218687,-0.478544 -1.218687,-1.068353 5.15e-4,-0.583902 0.546414,-1.058507 1.218687,-1.058507 z"
  1196 + clip-rule="evenodd" /><rect
  1197 + y="32.5"
  1198 + x="24.5"
  1199 + height="6.999999"
  1200 + width="8"
  1201 + id="rect4751"
  1202 + style="color:#000000;fill:url(#linearGradient3259);fill-opacity:1;fill-rule:nonzero;stroke:#757575;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible" /><rect
  1203 + rx="1"
  1204 + ry="1"
  1205 + style="opacity:0.5;color:#000000;fill:none;stroke:url(#linearGradient5093);stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible"
  1206 + id="rect4755"
  1207 + width="10"
  1208 + height="9"
  1209 + x="23.5"
  1210 + y="31.5" /><path
  1211 + sodipodi:nodetypes="ccccccc"
  1212 + style="opacity:0.20000000000000001;fill:url(#radialGradient5095);fill-opacity:1;fill-rule:evenodd"
  1213 + id="path4757"
  1214 + d="m 12.5,31.5 0,5 13,-6 9,5 0,-5 -10,-6 -12,7 z"
  1215 + clip-rule="evenodd" /><path
  1216 + sodipodi:nodetypes="ccccccccc"
  1217 + d="m 8.4999999,27.5 -1e-7,5 1.5,2 14.5000002,-7 12.5,7 1.5,-2 0,-5 -14,-8 -16.0000001,8 z"
  1218 + id="path4759"
  1219 + style="fill:#ef2929;stroke:#a40000;stroke-linecap:round;stroke-linejoin:round" /><path
  1220 + sodipodi:nodetypes="ccccc"
  1221 + id="path4761"
  1222 + d="m 9.0215946,27.818937 -10e-8,4 L 24.5,24.5 l 0,-4.318937 -15.4784054,7.637874 z"
  1223 + style="opacity:0.40909089;color:#000000;fill:url(#radialGradient5097);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible" /><path
  1224 + style="opacity:0.13636367;color:#000000;fill:url(#radialGradient5099);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible"
  1225 + d="m 24.5,24.5 0,-4.318937 13.478405,7.637874 0,4 L 24.5,24.5 z"
  1226 + id="path4763"
  1227 + sodipodi:nodetypes="ccccc" /></g></g><g
  1228 + id="g3829"
  1229 + transform="translate(2.0000001,0)"><g
  1230 + transform="matrix(0.02158196,0,0,0.01859457,44.12251,41.63767)"
  1231 + id="g5022"
  1232 + style="display:inline"><rect
  1233 + style="opacity:0.40206185;color:#000000;fill:url(#linearGradient5003);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible"
  1234 + id="rect4173"
  1235 + width="973.03491"
  1236 + height="484.0123"
  1237 + x="-1442.0613"
  1238 + y="-141.85165" /><path
  1239 + style="opacity:0.40206185;color:#000000;fill:url(#radialGradient5005);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible"
  1240 + d="m -469.02645,-141.85163 c 0,0 0,484.00662 0,484.00662 134.16473,0.91119 324.34504,-108.44127 324.34497,-242.03439 0,-133.593226 -149.71775,-241.97221 -324.34497,-241.97223 z"
  1241 + id="path5058"
  1242 + sodipodi:nodetypes="cccc" /><path
  1243 + sodipodi:nodetypes="cccc"
  1244 + id="path5018"
  1245 + d="m -1442.0613,-141.85163 c 0,0 0,484.00662 0,484.00662 -134.1648,0.91119 -324.345,-108.44127 -324.345,-242.03439 0,-133.593226 149.7177,-241.97221 324.345,-241.97223 z"
  1246 + style="opacity:0.40206185;color:#000000;fill:url(#radialGradient5007);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible" /></g><g
  1247 + id="g3812"><path
  1248 + style="color:#000000;fill:url(#linearGradient5009);fill-opacity:1;fill-rule:nonzero;stroke:#757575;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible"
  1249 + d="m 36.5,25.5 0,18 c 0,0.905333 -0.160268,1 -1,1 l -24,0 c -0.839733,0 -1,-0.09467 -1,-1 l 0,-18 26,0 z"
  1250 + id="rect1512"
  1251 + sodipodi:nodetypes="ccccccc" /><path
  1252 + style="fill:url(#linearGradient5011);fill-opacity:1;fill-rule:evenodd"
  1253 + id="path2327"
  1254 + d="M 22,31 21.9657,44 13.083607,44 13,31 l 9,0 z"
  1255 + clip-rule="evenodd"
  1256 + sodipodi:nodetypes="ccccc" /><path
  1257 + sodipodi:nodetypes="ccccc"
  1258 + id="path2357"
  1259 + d="m 35.5,25.5 0,18 -24,0 0,-18 24,0 z"
  1260 + style="opacity:0.35;color:#000000;fill:none;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible" /><path
  1261 + style="opacity:0.40909089;fill:url(#radialGradient5013);fill-opacity:1;fill-rule:evenodd"
  1262 + id="path2315"
  1263 + d="m 18.576856,36.44767 c 0.67279,0 1.216616,0.474605 1.216616,1.058507 0,0.589811 -0.543826,1.068355 -1.216616,1.068355 -0.672272,0 -1.218686,-0.478544 -1.218686,-1.068355 5.15e-4,-0.583902 0.546414,-1.058507 1.218686,-1.058507 z"
  1264 + clip-rule="evenodd" /><rect
  1265 + style="color:#000000;fill:#8f5902;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
  1266 + id="rect3851"
  1267 + width="7"
  1268 + height="12"
  1269 + x="14"
  1270 + y="32" /><path
  1271 + clip-rule="evenodd"
  1272 + d="m 18.462314,37.447175 c 0.672789,0 1.216615,0.474605 1.216615,1.058507 0,0.589809 -0.543826,1.068353 -1.216615,1.068353 -0.672273,0 -1.218687,-0.478544 -1.218687,-1.068353 5.15e-4,-0.583902 0.546414,-1.058507 1.218687,-1.058507 z"
  1273 + id="path217"
  1274 + style="fill:url(#radialGradient5015);fill-opacity:1;fill-rule:evenodd" /><rect
  1275 + style="color:#000000;fill:#3465a4;fill-opacity:1;fill-rule:nonzero;stroke:#757575;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible"
  1276 + id="rect3263"
  1277 + width="8"
  1278 + height="6.999999"
  1279 + x="24.5"
  1280 + y="32.5" /><path
  1281 + style="opacity:0.39772728;color:#000000;fill:url(#radialGradient5017);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999958;marker:none;visibility:visible;display:inline;overflow:visible"
  1282 + d="m 25.014716,36.954984 c 2.841896,0.362925 4.341979,-1.584298 6.965859,-1.701594 L 32,33 l -7,0 0.01472,3.954959 -4e-6,2.5e-5 z"
  1283 + id="rect2363"
  1284 + sodipodi:nodetypes="cccccc" /><rect
  1285 + y="31.5"
  1286 + x="23.5"
  1287 + height="9"
  1288 + width="10"
  1289 + id="rect3748"
  1290 + style="opacity:0.5;color:#000000;fill:none;stroke:url(#linearGradient5019);stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible"
  1291 + ry="1"
  1292 + rx="1" /><path
  1293 + clip-rule="evenodd"
  1294 + d="m 11.5,31.5 0,5 14,-7 10,6 0,-4 -11,-7 -13,7 z"
  1295 + id="path23"
  1296 + style="opacity:0.2;fill:url(#radialGradient5021);fill-opacity:1;fill-rule:evenodd"
  1297 + sodipodi:nodetypes="ccccccc" /><path
  1298 + style="fill:#ef2929;stroke:#a40000;stroke-linecap:round;stroke-linejoin:round"
  1299 + id="path362"
  1300 + d="m 7.5,26.5 0,6 1.5,2 15.5,-8 13.5,8 1.5,-2 0,-6 -15,-9 -17,9 z"
  1301 + sodipodi:nodetypes="ccccccccc" /><path
  1302 + style="opacity:0.40909089;color:#000000;fill:url(#radialGradient5023);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible"
  1303 + d="m 7.9418605,26.898671 0,5 L 24.5,23.5 l 0,-5.318937 -16.5581395,8.717608 z"
  1304 + id="path1536"
  1305 + sodipodi:nodetypes="ccccc" /><path
  1306 + sodipodi:nodetypes="ccccc"
  1307 + id="path2337"
  1308 + d="m 24.5,23.5 0,-5.318937 14.558139,8.637874 0,5 L 24.5,23.5 z"
  1309 + style="opacity:0.13636367;color:#000000;fill:url(#radialGradient5025);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible" /></g></g></svg>
0 1310 \ No newline at end of file
... ...
plugins/bsc/public/images/transfer-ownership.png 0 → 100644

3.99 KB

plugins/bsc/public/images/transfer-ownership.svg 0 → 100644
... ... @@ -0,0 +1,1965 @@
  1 +<?xml version="1.0" encoding="UTF-8" standalone="no"?>
  2 +<!-- Created with Inkscape (http://www.inkscape.org/) -->
  3 +
  4 +<svg
  5 + xmlns:dc="http://purl.org/dc/elements/1.1/"
  6 + xmlns:cc="http://creativecommons.org/ns#"
  7 + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
  8 + xmlns:svg="http://www.w3.org/2000/svg"
  9 + xmlns="http://www.w3.org/2000/svg"
  10 + xmlns:xlink="http://www.w3.org/1999/xlink"
  11 + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
  12 + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
  13 + width="48"
  14 + height="48"
  15 + id="svg2"
  16 + version="1.1"
  17 + inkscape:version="0.47 r22583"
  18 + sodipodi:docname="Ícone BSC 2.svg"
  19 + inkscape:export-filename="/home/caiosba/Colivre/Documentos/Ícones BSC 2.png"
  20 + inkscape:export-xdpi="90"
  21 + inkscape:export-ydpi="90">
  22 + <defs
  23 + id="defs4">
  24 + <inkscape:perspective
  25 + sodipodi:type="inkscape:persp3d"
  26 + inkscape:vp_x="0 : 526.18109 : 1"
  27 + inkscape:vp_y="0 : 1000 : 0"
  28 + inkscape:vp_z="744.09448 : 526.18109 : 1"
  29 + inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
  30 + id="perspective10" />
  31 + <linearGradient
  32 + id="linearGradient5036">
  33 + <stop
  34 + id="stop5038"
  35 + offset="0"
  36 + style="stop-color:#f5f5f5;stop-opacity:0.09;" />
  37 + <stop
  38 + style="stop-color:#ffffff;stop-opacity:0.89999998;"
  39 + offset="0.2631579"
  40 + id="stop5044" />
  41 + <stop
  42 + id="stop5088"
  43 + offset="0.74792242"
  44 + style="stop-color:#c7c7c7;stop-opacity:0.46000001;" />
  45 + <stop
  46 + id="stop5040"
  47 + offset="1"
  48 + style="stop-color:#ffffff;stop-opacity:0.78039217;" />
  49 + </linearGradient>
  50 + <linearGradient
  51 + id="linearGradient5058">
  52 + <stop
  53 + id="stop5060"
  54 + offset="0"
  55 + style="stop-color:#959791;stop-opacity:1;" />
  56 + <stop
  57 + style="stop-color:#f8f8f8;stop-opacity:1;"
  58 + offset="0.5"
  59 + id="stop5066" />
  60 + <stop
  61 + id="stop5062"
  62 + offset="1"
  63 + style="stop-color:#8c8c8c;stop-opacity:1;" />
  64 + </linearGradient>
  65 + <linearGradient
  66 + id="linearGradient5068">
  67 + <stop
  68 + id="stop5070"
  69 + offset="0"
  70 + style="stop-color:#ffffff;stop-opacity:1;" />
  71 + <stop
  72 + style="stop-color:#ffffff;stop-opacity:0.69;"
  73 + offset="0.32894737"
  74 + id="stop5078" />
  75 + <stop
  76 + style="stop-color:#c2c2c2;stop-opacity:0.34;"
  77 + offset="0.65789473"
  78 + id="stop5076" />
  79 + <stop
  80 + id="stop5072"
  81 + offset="1"
  82 + style="stop-color:#ffffff;stop-opacity:0;" />
  83 + </linearGradient>
  84 + <linearGradient
  85 + id="linearGradient2966">
  86 + <stop
  87 + id="stop2968"
  88 + offset="0"
  89 + style="stop-color:#ffd1d1;stop-opacity:1;" />
  90 + <stop
  91 + style="stop-color:#ff1d1d;stop-opacity:1;"
  92 + offset="0.5"
  93 + id="stop3006" />
  94 + <stop
  95 + id="stop2970"
  96 + offset="1"
  97 + style="stop-color:#6f0000;stop-opacity:1;" />
  98 + </linearGradient>
  99 + <linearGradient
  100 + id="linearGradient2974">
  101 + <stop
  102 + id="stop2976"
  103 + offset="0"
  104 + style="stop-color:#c1c1c1;stop-opacity:1;" />
  105 + <stop
  106 + id="stop2978"
  107 + offset="1"
  108 + style="stop-color:#acacac;stop-opacity:1;" />
  109 + </linearGradient>
  110 + <linearGradient
  111 + id="linearGradient2994">
  112 + <stop
  113 + id="stop2996"
  114 + offset="0"
  115 + style="stop-color:#000000;stop-opacity:1;" />
  116 + <stop
  117 + id="stop2998"
  118 + offset="1"
  119 + style="stop-color:#c9c9c9;stop-opacity:1;" />
  120 + </linearGradient>
  121 + <linearGradient
  122 + id="linearGradient9910">
  123 + <stop
  124 + id="stop9912"
  125 + offset="0"
  126 + style="stop-color:#729fcf;stop-opacity:1;" />
  127 + <stop
  128 + style="stop-color:#a5bfda;stop-opacity:1;"
  129 + offset="0.31578946"
  130 + id="stop9918" />
  131 + <stop
  132 + id="stop9914"
  133 + offset="1"
  134 + style="stop-color:#376ca4;stop-opacity:1;" />
  135 + </linearGradient>
  136 + <linearGradient
  137 + id="linearGradient9920">
  138 + <stop
  139 + style="stop-color:#5b90c8;stop-opacity:1;"
  140 + offset="0"
  141 + id="stop9922" />
  142 + <stop
  143 + id="stop9924"
  144 + offset="0.31578946"
  145 + style="stop-color:#8fb0d1;stop-opacity:1;" />
  146 + <stop
  147 + style="stop-color:#34679d;stop-opacity:1;"
  148 + offset="1"
  149 + id="stop9926" />
  150 + </linearGradient>
  151 + <inkscape:perspective
  152 + id="perspective90"
  153 + inkscape:persp3d-origin="24 : 16 : 1"
  154 + inkscape:vp_z="48 : 24 : 1"
  155 + inkscape:vp_y="0 : 1000 : 0"
  156 + inkscape:vp_x="0 : 24 : 1"
  157 + sodipodi:type="inkscape:persp3d" />
  158 + <linearGradient
  159 + id="linearGradient7121">
  160 + <stop
  161 + id="stop7123"
  162 + offset="0"
  163 + style="stop-color:#ffffff;stop-opacity:1;" />
  164 + <stop
  165 + id="stop7125"
  166 + offset="1"
  167 + style="stop-color:#8ae234;stop-opacity:1" />
  168 + </linearGradient>
  169 + <inkscape:perspective
  170 + id="perspective27321"
  171 + inkscape:persp3d-origin="24 : 16 : 1"
  172 + inkscape:vp_z="48 : 24 : 1"
  173 + inkscape:vp_y="0 : 1000 : 0"
  174 + inkscape:vp_x="0 : 24 : 1"
  175 + sodipodi:type="inkscape:persp3d" />
  176 + <linearGradient
  177 + y2="50.939667"
  178 + x2="45.380436"
  179 + y1="45.264122"
  180 + x1="46.834816"
  181 + gradientUnits="userSpaceOnUse"
  182 + id="linearGradient7186"
  183 + xlink:href="#linearGradient2871"
  184 + inkscape:collect="always" />
  185 + <linearGradient
  186 + y2="26.649363"
  187 + x2="53.588623"
  188 + y1="23.667896"
  189 + x1="18.935766"
  190 + gradientUnits="userSpaceOnUse"
  191 + id="linearGradient7184"
  192 + xlink:href="#linearGradient2402"
  193 + inkscape:collect="always" />
  194 + <linearGradient
  195 + y2="50.939667"
  196 + x2="45.380436"
  197 + y1="45.264122"
  198 + x1="46.834816"
  199 + gradientUnits="userSpaceOnUse"
  200 + id="linearGradient7182"
  201 + xlink:href="#linearGradient2871"
  202 + inkscape:collect="always" />
  203 + <linearGradient
  204 + y2="20.60858"
  205 + x2="15.984863"
  206 + y1="36.061237"
  207 + x1="62.513836"
  208 + gradientUnits="userSpaceOnUse"
  209 + id="linearGradient7180"
  210 + xlink:href="#linearGradient2380"
  211 + inkscape:collect="always" />
  212 + <linearGradient
  213 + gradientTransform="matrix(-1,0,0,-1,47.93934,50.02474)"
  214 + y2="23.554308"
  215 + x2="22.374878"
  216 + y1="13.604306"
  217 + x1="13.435029"
  218 + gradientUnits="userSpaceOnUse"
  219 + id="linearGradient7189"
  220 + xlink:href="#linearGradient7179"
  221 + inkscape:collect="always" />
  222 + <linearGradient
  223 + gradientUnits="userSpaceOnUse"
  224 + y2="23.554308"
  225 + x2="22.374878"
  226 + y1="13.604306"
  227 + x1="13.435029"
  228 + id="linearGradient7185"
  229 + xlink:href="#linearGradient7179"
  230 + inkscape:collect="always" />
  231 + <linearGradient
  232 + id="linearGradient1322">
  233 + <stop
  234 + style="stop-color:#729fcf"
  235 + offset="0.0000000"
  236 + id="stop1324" />
  237 + <stop
  238 + style="stop-color:#5187d6;stop-opacity:1.0000000;"
  239 + offset="1.0000000"
  240 + id="stop1326" />
  241 + </linearGradient>
  242 + <linearGradient
  243 + id="linearGradient2316">
  244 + <stop
  245 + id="stop2318"
  246 + offset="0"
  247 + style="stop-color:#000000;stop-opacity:1;" />
  248 + <stop
  249 + id="stop2320"
  250 + offset="1"
  251 + style="stop-color:#ffffff;stop-opacity:0.65979379;" />
  252 + </linearGradient>
  253 + <linearGradient
  254 + id="linearGradient7179"
  255 + inkscape:collect="always">
  256 + <stop
  257 + id="stop7181"
  258 + offset="0"
  259 + style="stop-color:#ffffff;stop-opacity:1;" />
  260 + <stop
  261 + id="stop7183"
  262 + offset="1"
  263 + style="stop-color:#ffffff;stop-opacity:0;" />
  264 + </linearGradient>
  265 + <linearGradient
  266 + y2="26.048164"
  267 + x2="52.854095"
  268 + y1="26.048164"
  269 + x1="5.9649177"
  270 + gradientUnits="userSpaceOnUse"
  271 + id="linearGradient1491"
  272 + xlink:href="#linearGradient2797"
  273 + inkscape:collect="always" />
  274 + <linearGradient
  275 + id="linearGradient2797"
  276 + inkscape:collect="always">
  277 + <stop
  278 + id="stop2799"
  279 + offset="0"
  280 + style="stop-color:#ffffff;stop-opacity:1;" />
  281 + <stop
  282 + id="stop2801"
  283 + offset="1"
  284 + style="stop-color:#ffffff;stop-opacity:0;" />
  285 + </linearGradient>
  286 + <linearGradient
  287 + y2="26.048164"
  288 + x2="52.854095"
  289 + y1="26.048164"
  290 + x1="5.9649177"
  291 + gradientUnits="userSpaceOnUse"
  292 + id="linearGradient1493"
  293 + xlink:href="#linearGradient2797"
  294 + inkscape:collect="always" />
  295 + <linearGradient
  296 + id="linearGradient2402">
  297 + <stop
  298 + id="stop2404"
  299 + offset="0"
  300 + style="stop-color:#729fcf;stop-opacity:1;" />
  301 + <stop
  302 + id="stop2406"
  303 + offset="1"
  304 + style="stop-color:#528ac5;stop-opacity:1;" />
  305 + </linearGradient>
  306 + <linearGradient
  307 + id="linearGradient2871"
  308 + inkscape:collect="always">
  309 + <stop
  310 + id="stop2873"
  311 + offset="0"
  312 + style="stop-color:#3465a4;stop-opacity:1;" />
  313 + <stop
  314 + id="stop2875"
  315 + offset="1"
  316 + style="stop-color:#3465a4;stop-opacity:1" />
  317 + </linearGradient>
  318 + <linearGradient
  319 + gradientTransform="translate(-48.77039,-5.765705)"
  320 + gradientUnits="userSpaceOnUse"
  321 + y2="24.842253"
  322 + x2="37.124462"
  323 + y1="30.748846"
  324 + x1="32.647972"
  325 + id="linearGradient2696"
  326 + xlink:href="#linearGradient2690"
  327 + inkscape:collect="always" />
  328 + <linearGradient
  329 + id="linearGradient2690"
  330 + inkscape:collect="always">
  331 + <stop
  332 + id="stop2692"
  333 + offset="0"
  334 + style="stop-color:#c4d7eb;stop-opacity:1;" />
  335 + <stop
  336 + id="stop2694"
  337 + offset="1"
  338 + style="stop-color:#c4d7eb;stop-opacity:0;" />
  339 + </linearGradient>
  340 + <linearGradient
  341 + gradientTransform="translate(-48.77039,-5.765705)"
  342 + gradientUnits="userSpaceOnUse"
  343 + y2="24.842253"
  344 + x2="37.124462"
  345 + y1="31.455952"
  346 + x1="36.713837"
  347 + id="linearGradient2688"
  348 + xlink:href="#linearGradient2682"
  349 + inkscape:collect="always" />
  350 + <linearGradient
  351 + id="linearGradient2682">
  352 + <stop
  353 + id="stop2684"
  354 + offset="0"
  355 + style="stop-color:#3977c3;stop-opacity:1;" />
  356 + <stop
  357 + id="stop2686"
  358 + offset="1"
  359 + style="stop-color:#89aedc;stop-opacity:0;" />
  360 + </linearGradient>
  361 + <linearGradient
  362 + id="linearGradient2380">
  363 + <stop
  364 + id="stop2382"
  365 + offset="0"
  366 + style="stop-color:#b9cfe7;stop-opacity:1" />
  367 + <stop
  368 + id="stop2384"
  369 + offset="1"
  370 + style="stop-color:#729fcf;stop-opacity:1" />
  371 + </linearGradient>
  372 + <linearGradient
  373 + y2="19.115122"
  374 + x2="15.419417"
  375 + y1="10.612206"
  376 + x1="13.478554"
  377 + gradientTransform="translate(-48.30498,-6.043298)"
  378 + gradientUnits="userSpaceOnUse"
  379 + id="linearGradient1486"
  380 + xlink:href="#linearGradient2831"
  381 + inkscape:collect="always" />
  382 + <linearGradient
  383 + id="linearGradient2831">
  384 + <stop
  385 + id="stop2833"
  386 + offset="0"
  387 + style="stop-color:#3465a4;stop-opacity:1;" />
  388 + <stop
  389 + style="stop-color:#5b86be;stop-opacity:1;"
  390 + offset="0.33333334"
  391 + id="stop2855" />
  392 + <stop
  393 + id="stop2835"
  394 + offset="1"
  395 + style="stop-color:#83a8d8;stop-opacity:0;" />
  396 + </linearGradient>
  397 + <linearGradient
  398 + y2="26.194071"
  399 + x2="37.065414"
  400 + y1="29.729605"
  401 + x1="37.128052"
  402 + gradientTransform="matrix(-1,0,0,-1,-1.24248,40.0817)"
  403 + gradientUnits="userSpaceOnUse"
  404 + id="linearGradient1488"
  405 + xlink:href="#linearGradient2847"
  406 + inkscape:collect="always" />
  407 + <linearGradient
  408 + id="linearGradient2847"
  409 + inkscape:collect="always">
  410 + <stop
  411 + id="stop2849"
  412 + offset="0"
  413 + style="stop-color:#3465a4;stop-opacity:1;" />
  414 + <stop
  415 + id="stop2851"
  416 + offset="1"
  417 + style="stop-color:#3465a4;stop-opacity:0;" />
  418 + </linearGradient>
  419 + <radialGradient
  420 + r="15.644737"
  421 + fy="36.421127"
  422 + fx="24.837126"
  423 + cy="36.421127"
  424 + cx="24.837126"
  425 + gradientTransform="matrix(1,0,0,0.536723,0,16.87306)"
  426 + gradientUnits="userSpaceOnUse"
  427 + id="radialGradient1503"
  428 + xlink:href="#linearGradient8662"
  429 + inkscape:collect="always" />
  430 + <linearGradient
  431 + id="linearGradient8662"
  432 + inkscape:collect="always">
  433 + <stop
  434 + id="stop8664"
  435 + offset="0"
  436 + style="stop-color:#000000;stop-opacity:1;" />
  437 + <stop
  438 + id="stop8666"
  439 + offset="1"
  440 + style="stop-color:#000000;stop-opacity:0;" />
  441 + </linearGradient>
  442 + <linearGradient
  443 + id="linearGradient7916">
  444 + <stop
  445 + id="stop7918"
  446 + offset="0"
  447 + style="stop-color:#ffffff;stop-opacity:1;" />
  448 + <stop
  449 + id="stop7920"
  450 + offset="1.0000000"
  451 + style="stop-color:#ffffff;stop-opacity:0.34020618;" />
  452 + </linearGradient>
  453 + <inkscape:perspective
  454 + id="perspective70"
  455 + inkscape:persp3d-origin="24 : 16 : 1"
  456 + inkscape:vp_z="48 : 24 : 1"
  457 + inkscape:vp_y="0 : 1000 : 0"
  458 + inkscape:vp_x="0 : 24 : 1"
  459 + sodipodi:type="inkscape:persp3d" />
  460 + <linearGradient
  461 + y2="50.939667"
  462 + x2="45.380436"
  463 + y1="45.264122"
  464 + x1="46.834816"
  465 + gradientUnits="userSpaceOnUse"
  466 + id="linearGradient7186-5"
  467 + xlink:href="#linearGradient2871-7"
  468 + inkscape:collect="always" />
  469 + <linearGradient
  470 + y2="26.649363"
  471 + x2="53.588623"
  472 + y1="23.667896"
  473 + x1="18.935766"
  474 + gradientUnits="userSpaceOnUse"
  475 + id="linearGradient7184-5"
  476 + xlink:href="#linearGradient2402-4"
  477 + inkscape:collect="always" />
  478 + <linearGradient
  479 + y2="50.939667"
  480 + x2="45.380436"
  481 + y1="45.264122"
  482 + x1="46.834816"
  483 + gradientUnits="userSpaceOnUse"
  484 + id="linearGradient7182-1"
  485 + xlink:href="#linearGradient2871-7"
  486 + inkscape:collect="always" />
  487 + <linearGradient
  488 + y2="20.60858"
  489 + x2="15.984863"
  490 + y1="36.061237"
  491 + x1="62.513836"
  492 + gradientUnits="userSpaceOnUse"
  493 + id="linearGradient7180-4"
  494 + xlink:href="#linearGradient2380-9"
  495 + inkscape:collect="always" />
  496 + <linearGradient
  497 + gradientTransform="matrix(-1,0,0,-1,47.93934,50.02474)"
  498 + y2="23.554308"
  499 + x2="22.374878"
  500 + y1="13.604306"
  501 + x1="13.435029"
  502 + gradientUnits="userSpaceOnUse"
  503 + id="linearGradient7189-5"
  504 + xlink:href="#linearGradient7179-1"
  505 + inkscape:collect="always" />
  506 + <linearGradient
  507 + gradientUnits="userSpaceOnUse"
  508 + y2="23.554308"
  509 + x2="22.374878"
  510 + y1="13.604306"
  511 + x1="13.435029"
  512 + id="linearGradient7185-1"
  513 + xlink:href="#linearGradient7179-1"
  514 + inkscape:collect="always" />
  515 + <linearGradient
  516 + id="linearGradient1322-5">
  517 + <stop
  518 + style="stop-color:#729fcf"
  519 + offset="0.0000000"
  520 + id="stop1324-3" />
  521 + <stop
  522 + style="stop-color:#5187d6;stop-opacity:1.0000000;"
  523 + offset="1.0000000"
  524 + id="stop1326-9" />
  525 + </linearGradient>
  526 + <linearGradient
  527 + id="linearGradient2316-6">
  528 + <stop
  529 + id="stop2318-0"
  530 + offset="0"
  531 + style="stop-color:#000000;stop-opacity:1;" />
  532 + <stop
  533 + id="stop2320-8"
  534 + offset="1"
  535 + style="stop-color:#ffffff;stop-opacity:0.65979379;" />
  536 + </linearGradient>
  537 + <linearGradient
  538 + id="linearGradient7179-1"
  539 + inkscape:collect="always">
  540 + <stop
  541 + id="stop7181-7"
  542 + offset="0"
  543 + style="stop-color:#ffffff;stop-opacity:1;" />
  544 + <stop
  545 + id="stop7183-0"
  546 + offset="1"
  547 + style="stop-color:#ffffff;stop-opacity:0;" />
  548 + </linearGradient>
  549 + <linearGradient
  550 + y2="26.048164"
  551 + x2="52.854095"
  552 + y1="26.048164"
  553 + x1="5.9649177"
  554 + gradientUnits="userSpaceOnUse"
  555 + id="linearGradient1491-9"
  556 + xlink:href="#linearGradient2797-9"
  557 + inkscape:collect="always" />
  558 + <linearGradient
  559 + id="linearGradient2797-9"
  560 + inkscape:collect="always">
  561 + <stop
  562 + id="stop2799-7"
  563 + offset="0"
  564 + style="stop-color:#ffffff;stop-opacity:1;" />
  565 + <stop
  566 + id="stop2801-4"
  567 + offset="1"
  568 + style="stop-color:#ffffff;stop-opacity:0;" />
  569 + </linearGradient>
  570 + <linearGradient
  571 + y2="26.048164"
  572 + x2="52.854095"
  573 + y1="26.048164"
  574 + x1="5.9649177"
  575 + gradientUnits="userSpaceOnUse"
  576 + id="linearGradient1493-7"
  577 + xlink:href="#linearGradient2797-9"
  578 + inkscape:collect="always" />
  579 + <linearGradient
  580 + id="linearGradient2402-4">
  581 + <stop
  582 + id="stop2404-6"
  583 + offset="0"
  584 + style="stop-color:#729fcf;stop-opacity:1;" />
  585 + <stop
  586 + id="stop2406-3"
  587 + offset="1"
  588 + style="stop-color:#528ac5;stop-opacity:1;" />
  589 + </linearGradient>
  590 + <linearGradient
  591 + id="linearGradient2871-7"
  592 + inkscape:collect="always">
  593 + <stop
  594 + id="stop2873-5"
  595 + offset="0"
  596 + style="stop-color:#3465a4;stop-opacity:1;" />
  597 + <stop
  598 + id="stop2875-6"
  599 + offset="1"
  600 + style="stop-color:#3465a4;stop-opacity:1" />
  601 + </linearGradient>
  602 + <linearGradient
  603 + gradientTransform="translate(-48.77039,-5.765705)"
  604 + gradientUnits="userSpaceOnUse"
  605 + y2="24.842253"
  606 + x2="37.124462"
  607 + y1="30.748846"
  608 + x1="32.647972"
  609 + id="linearGradient2696-9"
  610 + xlink:href="#linearGradient2690-0"
  611 + inkscape:collect="always" />
  612 + <linearGradient
  613 + id="linearGradient2690-0"
  614 + inkscape:collect="always">
  615 + <stop
  616 + id="stop2692-2"
  617 + offset="0"
  618 + style="stop-color:#c4d7eb;stop-opacity:1;" />
  619 + <stop
  620 + id="stop2694-2"
  621 + offset="1"
  622 + style="stop-color:#c4d7eb;stop-opacity:0;" />
  623 + </linearGradient>
  624 + <linearGradient
  625 + gradientTransform="translate(-48.77039,-5.765705)"
  626 + gradientUnits="userSpaceOnUse"
  627 + y2="24.842253"
  628 + x2="37.124462"
  629 + y1="31.455952"
  630 + x1="36.713837"
  631 + id="linearGradient2688-1"
  632 + xlink:href="#linearGradient2682-8"
  633 + inkscape:collect="always" />
  634 + <linearGradient
  635 + id="linearGradient2682-8">
  636 + <stop
  637 + id="stop2684-0"
  638 + offset="0"
  639 + style="stop-color:#3977c3;stop-opacity:1;" />
  640 + <stop
  641 + id="stop2686-8"
  642 + offset="1"
  643 + style="stop-color:#89aedc;stop-opacity:0;" />
  644 + </linearGradient>
  645 + <linearGradient
  646 + id="linearGradient2380-9">
  647 + <stop
  648 + id="stop2382-6"
  649 + offset="0"
  650 + style="stop-color:#b9cfe7;stop-opacity:1" />
  651 + <stop
  652 + id="stop2384-4"
  653 + offset="1"
  654 + style="stop-color:#729fcf;stop-opacity:1" />
  655 + </linearGradient>
  656 + <linearGradient
  657 + y2="19.115122"
  658 + x2="15.419417"
  659 + y1="10.612206"
  660 + x1="13.478554"
  661 + gradientTransform="translate(-48.30498,-6.043298)"
  662 + gradientUnits="userSpaceOnUse"
  663 + id="linearGradient1486-1"
  664 + xlink:href="#linearGradient2831-1"
  665 + inkscape:collect="always" />
  666 + <linearGradient
  667 + id="linearGradient2831-1">
  668 + <stop
  669 + id="stop2833-6"
  670 + offset="0"
  671 + style="stop-color:#3465a4;stop-opacity:1;" />
  672 + <stop
  673 + style="stop-color:#5b86be;stop-opacity:1;"
  674 + offset="0.33333334"
  675 + id="stop2855-6" />
  676 + <stop
  677 + id="stop2835-2"
  678 + offset="1"
  679 + style="stop-color:#83a8d8;stop-opacity:0;" />
  680 + </linearGradient>
  681 + <linearGradient
  682 + y2="26.194071"
  683 + x2="37.065414"
  684 + y1="29.729605"
  685 + x1="37.128052"
  686 + gradientTransform="matrix(-1,0,0,-1,-1.24248,40.0817)"
  687 + gradientUnits="userSpaceOnUse"
  688 + id="linearGradient1488-5"
  689 + xlink:href="#linearGradient2847-4"
  690 + inkscape:collect="always" />
  691 + <linearGradient
  692 + id="linearGradient2847-4"
  693 + inkscape:collect="always">
  694 + <stop
  695 + id="stop2849-0"
  696 + offset="0"
  697 + style="stop-color:#3465a4;stop-opacity:1;" />
  698 + <stop
  699 + id="stop2851-8"
  700 + offset="1"
  701 + style="stop-color:#3465a4;stop-opacity:0;" />
  702 + </linearGradient>
  703 + <radialGradient
  704 + r="15.644737"
  705 + fy="36.421127"
  706 + fx="24.837126"
  707 + cy="36.421127"
  708 + cx="24.837126"
  709 + gradientTransform="matrix(1,0,0,0.536723,0,16.87306)"
  710 + gradientUnits="userSpaceOnUse"
  711 + id="radialGradient1503-0"
  712 + xlink:href="#linearGradient8662-1"
  713 + inkscape:collect="always" />
  714 + <linearGradient
  715 + id="linearGradient8662-1"
  716 + inkscape:collect="always">
  717 + <stop
  718 + id="stop8664-1"
  719 + offset="0"
  720 + style="stop-color:#000000;stop-opacity:1;" />
  721 + <stop
  722 + id="stop8666-7"
  723 + offset="1"
  724 + style="stop-color:#000000;stop-opacity:0;" />
  725 + </linearGradient>
  726 + <linearGradient
  727 + id="linearGradient7916-1">
  728 + <stop
  729 + id="stop7918-7"
  730 + offset="0"
  731 + style="stop-color:#ffffff;stop-opacity:1;" />
  732 + <stop
  733 + id="stop7920-1"
  734 + offset="1.0000000"
  735 + style="stop-color:#ffffff;stop-opacity:0.34020618;" />
  736 + </linearGradient>
  737 + <inkscape:perspective
  738 + id="perspective70-5"
  739 + inkscape:persp3d-origin="24 : 16 : 1"
  740 + inkscape:vp_z="48 : 24 : 1"
  741 + inkscape:vp_y="0 : 1000 : 0"
  742 + inkscape:vp_x="0 : 24 : 1"
  743 + sodipodi:type="inkscape:persp3d" />
  744 + <inkscape:perspective
  745 + id="perspective29237"
  746 + inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
  747 + inkscape:vp_z="1 : 0.5 : 1"
  748 + inkscape:vp_y="0 : 1000 : 0"
  749 + inkscape:vp_x="0 : 0.5 : 1"
  750 + sodipodi:type="inkscape:persp3d" />
  751 + <linearGradient
  752 + inkscape:collect="always"
  753 + id="linearGradient6998-2">
  754 + <stop
  755 + style="stop-color:#000000;stop-opacity:1;"
  756 + offset="0"
  757 + id="stop7000-7" />
  758 + <stop
  759 + style="stop-color:#000000;stop-opacity:0;"
  760 + offset="1"
  761 + id="stop7002-1" />
  762 + </linearGradient>
  763 + <radialGradient
  764 + inkscape:collect="always"
  765 + xlink:href="#linearGradient6998-2"
  766 + id="radialGradient29477"
  767 + gradientUnits="userSpaceOnUse"
  768 + gradientTransform="matrix(1,0,0,0.3222749,0,20.728756)"
  769 + cx="19.688505"
  770 + cy="30.585787"
  771 + fx="19.688505"
  772 + fy="30.585787"
  773 + r="4.6624851" />
  774 + <radialGradient
  775 + inkscape:collect="always"
  776 + xlink:href="#linearGradient6998-2"
  777 + id="radialGradient29479"
  778 + gradientUnits="userSpaceOnUse"
  779 + gradientTransform="matrix(1,0,0,0.3222749,0,20.728756)"
  780 + cx="19.688505"
  781 + cy="30.585787"
  782 + fx="19.688505"
  783 + fy="30.585787"
  784 + r="4.6624851" />
  785 + <linearGradient
  786 + y2="35.739632"
  787 + x2="21.408455"
  788 + y1="36.390400"
  789 + x1="22.686766"
  790 + gradientTransform="matrix(-0.977685,0.210075,0.210075,0.977685,41.80576,-11.11866)"
  791 + gradientUnits="userSpaceOnUse"
  792 + id="linearGradient4374"
  793 + xlink:href="#linearGradient4356"
  794 + inkscape:collect="always" />
  795 + <linearGradient
  796 + y2="36.217758"
  797 + x2="22.626925"
  798 + y1="35.817974"
  799 + x1="20.661695"
  800 + gradientTransform="matrix(0.983375,0.181588,-0.181588,0.983375,-7.072120,-9.824920)"
  801 + gradientUnits="userSpaceOnUse"
  802 + id="linearGradient4372"
  803 + xlink:href="#linearGradient4356"
  804 + inkscape:collect="always" />
  805 + <radialGradient
  806 + gradientUnits="userSpaceOnUse"
  807 + gradientTransform="matrix(1.000000,0.000000,0.000000,0.681917,0.000000,8.233773)"
  808 + r="13.565360"
  809 + fy="19.836468"
  810 + fx="16.214741"
  811 + cy="19.836468"
  812 + cx="16.214741"
  813 + id="radialGradient4350"
  814 + xlink:href="#linearGradient4344"
  815 + inkscape:collect="always" />
  816 + <linearGradient
  817 + gradientTransform="translate(-13.12500,-7.000000)"
  818 + y2="35.803486"
  819 + x2="30.935921"
  820 + y1="29.553486"
  821 + x1="30.935921"
  822 + gradientUnits="userSpaceOnUse"
  823 + id="linearGradient4332"
  824 + xlink:href="#linearGradient3824"
  825 + inkscape:collect="always" />
  826 + <linearGradient
  827 + y2="35.803486"
  828 + x2="30.935921"
  829 + y1="29.553486"
  830 + x1="30.935921"
  831 + gradientTransform="translate(-12.41789,-7.000000)"
  832 + gradientUnits="userSpaceOnUse"
  833 + id="linearGradient4326"
  834 + xlink:href="#linearGradient3824"
  835 + inkscape:collect="always" />
  836 + <linearGradient
  837 + gradientTransform="translate(0.707108,0.000000)"
  838 + y2="35.803486"
  839 + x2="30.935921"
  840 + y1="29.553486"
  841 + x1="30.935921"
  842 + gradientUnits="userSpaceOnUse"
  843 + id="linearGradient4175"
  844 + xlink:href="#linearGradient3824"
  845 + inkscape:collect="always" />
  846 + <radialGradient
  847 + gradientUnits="userSpaceOnUse"
  848 + r="9.1620579"
  849 + fy="17.064077"
  850 + fx="29.344931"
  851 + cy="17.064077"
  852 + cx="29.344931"
  853 + id="radialGradient3806"
  854 + xlink:href="#linearGradient3800"
  855 + inkscape:collect="always" />
  856 + <linearGradient
  857 + id="linearGradient3800">
  858 + <stop
  859 + id="stop3802"
  860 + offset="0.0000000"
  861 + style="stop-color:#f4d9b1;stop-opacity:1.0000000;" />
  862 + <stop
  863 + id="stop3804"
  864 + offset="1.0000000"
  865 + style="stop-color:#df9725;stop-opacity:1.0000000;" />
  866 + </linearGradient>
  867 + <linearGradient
  868 + id="linearGradient3816"
  869 + inkscape:collect="always">
  870 + <stop
  871 + id="stop3818"
  872 + offset="0"
  873 + style="stop-color:#000000;stop-opacity:1;" />
  874 + <stop
  875 + id="stop3820"
  876 + offset="1"
  877 + style="stop-color:#000000;stop-opacity:0;" />
  878 + </linearGradient>
  879 + <linearGradient
  880 + id="linearGradient3824">
  881 + <stop
  882 + id="stop3826"
  883 + offset="0"
  884 + style="stop-color:#ffffff;stop-opacity:1;" />
  885 + <stop
  886 + id="stop3828"
  887 + offset="1.0000000"
  888 + style="stop-color:#c9c9c9;stop-opacity:1.0000000;" />
  889 + </linearGradient>
  890 + <linearGradient
  891 + id="linearGradient4163">
  892 + <stop
  893 + id="stop4165"
  894 + offset="0.0000000"
  895 + style="stop-color:#3b74bc;stop-opacity:1.0000000;" />
  896 + <stop
  897 + id="stop4167"
  898 + offset="1.0000000"
  899 + style="stop-color:#2d5990;stop-opacity:1.0000000;" />
  900 + </linearGradient>
  901 + <linearGradient
  902 + id="linearGradient4338">
  903 + <stop
  904 + style="stop-color:#e9b15e;stop-opacity:1.0000000;"
  905 + offset="0.0000000"
  906 + id="stop4340" />
  907 + <stop
  908 + style="stop-color:#966416;stop-opacity:1.0000000;"
  909 + offset="1.0000000"
  910 + id="stop4342" />
  911 + </linearGradient>
  912 + <linearGradient
  913 + id="linearGradient4344">
  914 + <stop
  915 + id="stop4346"
  916 + offset="0"
  917 + style="stop-color:#727e0a;stop-opacity:1;" />
  918 + <stop
  919 + id="stop4348"
  920 + offset="1.0000000"
  921 + style="stop-color:#5b6508;stop-opacity:1.0000000;" />
  922 + </linearGradient>
  923 + <linearGradient
  924 + id="linearGradient4356"
  925 + inkscape:collect="always">
  926 + <stop
  927 + id="stop4358"
  928 + offset="0"
  929 + style="stop-color:#000000;stop-opacity:1;" />
  930 + <stop
  931 + id="stop4360"
  932 + offset="1"
  933 + style="stop-color:#000000;stop-opacity:0;" />
  934 + </linearGradient>
  935 + <inkscape:perspective
  936 + id="perspective72"
  937 + inkscape:persp3d-origin="24 : 16 : 1"
  938 + inkscape:vp_z="48 : 24 : 1"
  939 + inkscape:vp_y="0 : 1000 : 0"
  940 + inkscape:vp_x="0 : 24 : 1"
  941 + sodipodi:type="inkscape:persp3d" />
  942 + <radialGradient
  943 + inkscape:collect="always"
  944 + xlink:href="#linearGradient3816"
  945 + id="radialGradient4243"
  946 + gradientUnits="userSpaceOnUse"
  947 + cx="31.112698"
  948 + cy="19.008621"
  949 + fx="31.112698"
  950 + fy="19.008621"
  951 + r="8.6620579" />
  952 + <radialGradient
  953 + inkscape:collect="always"
  954 + xlink:href="#linearGradient3800"
  955 + id="radialGradient4251"
  956 + gradientUnits="userSpaceOnUse"
  957 + gradientTransform="matrix(0.787998,0,0,0.787998,6.221198,3.617627)"
  958 + cx="29.344931"
  959 + cy="17.064077"
  960 + fx="29.344931"
  961 + fy="17.064077"
  962 + r="9.1620579" />
  963 + <radialGradient
  964 + inkscape:collect="always"
  965 + xlink:href="#linearGradient3816"
  966 + id="radialGradient4257"
  967 + gradientUnits="userSpaceOnUse"
  968 + cx="31.112698"
  969 + cy="19.008621"
  970 + fx="31.112698"
  971 + fy="19.008621"
  972 + r="8.6620579" />
  973 + <radialGradient
  974 + inkscape:collect="always"
  975 + xlink:href="#linearGradient3816"
  976 + id="radialGradient4261"
  977 + gradientUnits="userSpaceOnUse"
  978 + cx="31.112698"
  979 + cy="19.008621"
  980 + fx="31.112698"
  981 + fy="19.008621"
  982 + r="8.6620579" />
  983 + <radialGradient
  984 + inkscape:collect="always"
  985 + xlink:href="#linearGradient4338"
  986 + id="radialGradient4263"
  987 + gradientUnits="userSpaceOnUse"
  988 + gradientTransform="matrix(0.787998,0,0,0.787998,6.221198,3.617627)"
  989 + cx="29.344931"
  990 + cy="17.064077"
  991 + fx="29.344931"
  992 + fy="17.064077"
  993 + r="9.1620579" />
  994 + <linearGradient
  995 + inkscape:collect="always"
  996 + xlink:href="#linearGradient4356"
  997 + id="linearGradient4272"
  998 + gradientUnits="userSpaceOnUse"
  999 + gradientTransform="matrix(-0.977685,0.210075,0.210075,0.977685,40.096379,991.52674)"
  1000 + x1="22.686766"
  1001 + y1="36.390400"
  1002 + x2="21.408455"
  1003 + y2="35.739632" />
  1004 + <linearGradient
  1005 + inkscape:collect="always"
  1006 + xlink:href="#linearGradient4356"
  1007 + id="linearGradient4275"
  1008 + gradientUnits="userSpaceOnUse"
  1009 + gradientTransform="matrix(0.95236899,-0.304949,0.304949,0.95236899,-24.109161,1001.0625)"
  1010 + x1="20.661695"
  1011 + y1="35.817974"
  1012 + x2="22.626925"
  1013 + y2="36.217758" />
  1014 + <linearGradient
  1015 + inkscape:collect="always"
  1016 + xlink:href="#linearGradient3824"
  1017 + id="linearGradient4278"
  1018 + gradientUnits="userSpaceOnUse"
  1019 + gradientTransform="translate(-14.127271,995.6454)"
  1020 + x1="30.935921"
  1021 + y1="29.553486"
  1022 + x2="30.935921"
  1023 + y2="35.803486" />
  1024 + <radialGradient
  1025 + inkscape:collect="always"
  1026 + xlink:href="#linearGradient4344"
  1027 + id="radialGradient4287"
  1028 + gradientUnits="userSpaceOnUse"
  1029 + gradientTransform="matrix(1,0,0,0.681917,-1.7093807,1010.8792)"
  1030 + cx="16.214741"
  1031 + cy="19.836468"
  1032 + fx="16.214741"
  1033 + fy="19.836468"
  1034 + r="13.565360" />
  1035 + <radialGradient
  1036 + inkscape:collect="always"
  1037 + xlink:href="#linearGradient4338"
  1038 + id="radialGradient4300"
  1039 + gradientUnits="userSpaceOnUse"
  1040 + gradientTransform="matrix(0.787998,0,0,0.787998,6.221198,3.617627)"
  1041 + cx="29.344931"
  1042 + cy="17.064077"
  1043 + fx="29.344931"
  1044 + fy="17.064077"
  1045 + r="9.1620579" />
  1046 + <radialGradient
  1047 + inkscape:collect="always"
  1048 + xlink:href="#linearGradient4163"
  1049 + id="radialGradient4318"
  1050 + gradientUnits="userSpaceOnUse"
  1051 + gradientTransform="matrix(1.297564,0,0,0.884831,-4.2342547,1013.4195)"
  1052 + cx="28.089741"
  1053 + cy="27.203083"
  1054 + fx="28.089741"
  1055 + fy="27.203083"
  1056 + r="13.565360" />
  1057 + <radialGradient
  1058 + inkscape:collect="always"
  1059 + xlink:href="#linearGradient3816"
  1060 + id="radialGradient4321"
  1061 + gradientUnits="userSpaceOnUse"
  1062 + cx="31.112698"
  1063 + cy="19.008621"
  1064 + fx="31.112698"
  1065 + fy="19.008621"
  1066 + r="8.6620579" />
  1067 + <inkscape:perspective
  1068 + id="perspective4984"
  1069 + inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
  1070 + inkscape:vp_z="1 : 0.5 : 1"
  1071 + inkscape:vp_y="0 : 1000 : 0"
  1072 + inkscape:vp_x="0 : 0.5 : 1"
  1073 + sodipodi:type="inkscape:persp3d" />
  1074 + <linearGradient
  1075 + id="linearGradient5048">
  1076 + <stop
  1077 + style="stop-color:black;stop-opacity:0;"
  1078 + offset="0"
  1079 + id="stop5050" />
  1080 + <stop
  1081 + id="stop5056"
  1082 + offset="0.5"
  1083 + style="stop-color:black;stop-opacity:1;" />
  1084 + <stop
  1085 + style="stop-color:black;stop-opacity:0;"
  1086 + offset="1"
  1087 + id="stop5052" />
  1088 + </linearGradient>
  1089 + <linearGradient
  1090 + id="linearGradient259">
  1091 + <stop
  1092 + id="stop260"
  1093 + offset="0.0000000"
  1094 + style="stop-color:#fafafa;stop-opacity:1.0000000;" />
  1095 + <stop
  1096 + id="stop261"
  1097 + offset="1.0000000"
  1098 + style="stop-color:#bbbbbb;stop-opacity:1.0000000;" />
  1099 + </linearGradient>
  1100 + <linearGradient
  1101 + id="linearGradient269">
  1102 + <stop
  1103 + id="stop270"
  1104 + offset="0.0000000"
  1105 + style="stop-color:#a3a3a3;stop-opacity:1.0000000;" />
  1106 + <stop
  1107 + id="stop271"
  1108 + offset="1.0000000"
  1109 + style="stop-color:#4c4c4c;stop-opacity:1.0000000;" />
  1110 + </linearGradient>
  1111 + <linearGradient
  1112 + id="linearGradient15662">
  1113 + <stop
  1114 + id="stop15664"
  1115 + offset="0.0000000"
  1116 + style="stop-color:#ffffff;stop-opacity:1.0000000;" />
  1117 + <stop
  1118 + id="stop15666"
  1119 + offset="1.0000000"
  1120 + style="stop-color:#f8f8f8;stop-opacity:1.0000000;" />
  1121 + </linearGradient>
  1122 + <linearGradient
  1123 + inkscape:collect="always"
  1124 + id="linearGradient5866">
  1125 + <stop
  1126 + style="stop-color:#000000;stop-opacity:1;"
  1127 + offset="0"
  1128 + id="stop5868" />
  1129 + <stop
  1130 + style="stop-color:#000000;stop-opacity:0;"
  1131 + offset="1"
  1132 + id="stop5870" />
  1133 + </linearGradient>
  1134 + <linearGradient
  1135 + id="linearGradient2598">
  1136 + <stop
  1137 + style="stop-color:#859dbc;stop-opacity:1;"
  1138 + offset="0"
  1139 + id="stop2600" />
  1140 + <stop
  1141 + style="stop-color:#547299;stop-opacity:1;"
  1142 + offset="1"
  1143 + id="stop2602" />
  1144 + </linearGradient>
  1145 + <linearGradient
  1146 + inkscape:collect="always"
  1147 + id="linearGradient4404">
  1148 + <stop
  1149 + style="stop-color:#ffffff;stop-opacity:1;"
  1150 + offset="0"
  1151 + id="stop4406" />
  1152 + <stop
  1153 + style="stop-color:#ffffff;stop-opacity:0;"
  1154 + offset="1"
  1155 + id="stop4408" />
  1156 + </linearGradient>
  1157 + <linearGradient
  1158 + id="linearGradient5897">
  1159 + <stop
  1160 + style="stop-color:#000000;stop-opacity:0.0000000;"
  1161 + offset="0.0000000"
  1162 + id="stop5899" />
  1163 + <stop
  1164 + id="stop5905"
  1165 + offset="0.50000000"
  1166 + style="stop-color:#000000;stop-opacity:0.56701028;" />
  1167 + <stop
  1168 + style="stop-color:#000000;stop-opacity:0.0000000;"
  1169 + offset="1.0000000"
  1170 + id="stop5901" />
  1171 + </linearGradient>
  1172 + <linearGradient
  1173 + id="linearGradient2590">
  1174 + <stop
  1175 + style="stop-color:#ffffff;stop-opacity:1;"
  1176 + offset="0"
  1177 + id="stop2592" />
  1178 + <stop
  1179 + style="stop-color:#ffffff;stop-opacity:0;"
  1180 + offset="1"
  1181 + id="stop2594" />
  1182 + </linearGradient>
  1183 + <linearGradient
  1184 + inkscape:collect="always"
  1185 + id="linearGradient2906">
  1186 + <stop
  1187 + style="stop-color:#ffffff;stop-opacity:1;"
  1188 + offset="0"
  1189 + id="stop2908" />
  1190 + <stop
  1191 + style="stop-color:#ffffff;stop-opacity:0;"
  1192 + offset="1"
  1193 + id="stop2910" />
  1194 + </linearGradient>
  1195 + <linearGradient
  1196 + inkscape:collect="always"
  1197 + xlink:href="#linearGradient2896"
  1198 + id="linearGradient2902"
  1199 + x1="14.584077"
  1200 + y1="1.6392649"
  1201 + x2="14.552828"
  1202 + y2="2.4912448"
  1203 + gradientUnits="userSpaceOnUse"
  1204 + gradientTransform="matrix(1,0,0,1.594214,0,-0.790249)" />
  1205 + <linearGradient
  1206 + inkscape:collect="always"
  1207 + id="linearGradient2896">
  1208 + <stop
  1209 + style="stop-color:#000000;stop-opacity:1;"
  1210 + offset="0"
  1211 + id="stop2898" />
  1212 + <stop
  1213 + style="stop-color:#000000;stop-opacity:0;"
  1214 + offset="1"
  1215 + id="stop2900" />
  1216 + </linearGradient>
  1217 + <linearGradient
  1218 + inkscape:collect="always"
  1219 + xlink:href="#linearGradient2896"
  1220 + id="linearGradient5356"
  1221 + gradientUnits="userSpaceOnUse"
  1222 + gradientTransform="matrix(0.35541046,-0.09680687,0.16161446,0.54106498,4.9107799,1029.1036)"
  1223 + x1="14.584077"
  1224 + y1="1.6392649"
  1225 + x2="14.552828"
  1226 + y2="2.4912448" />
  1227 + <linearGradient
  1228 + inkscape:collect="always"
  1229 + xlink:href="#linearGradient2906"
  1230 + id="linearGradient5359"
  1231 + gradientUnits="userSpaceOnUse"
  1232 + gradientTransform="matrix(0.35541046,-0.09680687,0.12011148,0.40211819,4.9170956,1029.1248)"
  1233 + x1="13.354311"
  1234 + y1="1.4866425"
  1235 + x2="14.075844"
  1236 + y2="2.4017651" />
  1237 + <linearGradient
  1238 + inkscape:collect="always"
  1239 + xlink:href="#linearGradient2590"
  1240 + id="linearGradient5362"
  1241 + gradientUnits="userSpaceOnUse"
  1242 + gradientTransform="matrix(0.46898152,-0.12774141,0.12979691,0.43454379,2.9741905,1030.0125)"
  1243 + x1="19.970377"
  1244 + y1="6.1167107"
  1245 + x2="19.970377"
  1246 + y2="2.53125" />
  1247 + <linearGradient
  1248 + inkscape:collect="always"
  1249 + xlink:href="#linearGradient5897"
  1250 + id="linearGradient5365"
  1251 + gradientUnits="userSpaceOnUse"
  1252 + gradientTransform="matrix(0.48606741,0,0,0.75585752,-291.56104,989.60553)"
  1253 + x1="19"
  1254 + y1="9.7738247"
  1255 + x2="19"
  1256 + y2="15.635596" />
  1257 + <linearGradient
  1258 + inkscape:collect="always"
  1259 + xlink:href="#linearGradient4404"
  1260 + id="linearGradient5368"
  1261 + gradientUnits="userSpaceOnUse"
  1262 + gradientTransform="matrix(-0.46898152,0.12774141,0.1380797,0.46227355,19.308685,1025.339)"
  1263 + x1="16.8125"
  1264 + y1="1.875"
  1265 + x2="16.8125"
  1266 + y2="4.71875" />
  1267 + <linearGradient
  1268 + inkscape:collect="always"
  1269 + xlink:href="#linearGradient2598"
  1270 + id="linearGradient5371"
  1271 + gradientUnits="userSpaceOnUse"
  1272 + gradientTransform="matrix(0.46898152,-0.12774141,0.13168827,0.44087584,3.7514528,1029.219)"
  1273 + x1="18.431311"
  1274 + y1="19.119474"
  1275 + x2="18.402472"
  1276 + y2="4.2702327" />
  1277 + <linearGradient
  1278 + inkscape:collect="always"
  1279 + xlink:href="#linearGradient5866"
  1280 + id="linearGradient5374"
  1281 + gradientUnits="userSpaceOnUse"
  1282 + gradientTransform="matrix(0.43511303,-0.11851629,0.12998141,0.43516148,5.1497806,1029.4257)"
  1283 + x1="19.452349"
  1284 + y1="13.174174"
  1285 + x2="19.685436"
  1286 + y2="27.095339" />
  1287 + <radialGradient
  1288 + inkscape:collect="always"
  1289 + xlink:href="#linearGradient15662"
  1290 + id="radialGradient5394"
  1291 + gradientUnits="userSpaceOnUse"
  1292 + gradientTransform="matrix(0.35842521,0,0,0.36658484,-288.74498,994.99084)"
  1293 + cx="8.1435566"
  1294 + cy="7.2678967"
  1295 + fx="8.1435566"
  1296 + fy="7.2678967"
  1297 + r="38.158695" />
  1298 + <radialGradient
  1299 + inkscape:collect="always"
  1300 + xlink:href="#linearGradient259"
  1301 + id="radialGradient5397"
  1302 + gradientUnits="userSpaceOnUse"
  1303 + gradientTransform="matrix(0.353806,0,0,0.37006743,-289.95036,994.73776)"
  1304 + cx="33.966679"
  1305 + cy="35.736916"
  1306 + fx="33.966679"
  1307 + fy="35.736916"
  1308 + r="86.70845" />
  1309 + <radialGradient
  1310 + inkscape:collect="always"
  1311 + xlink:href="#linearGradient269"
  1312 + id="radialGradient5399"
  1313 + gradientUnits="userSpaceOnUse"
  1314 + gradientTransform="matrix(0.35667183,0,0,0.36709384,-288.71505,994.96754)"
  1315 + cx="8.824419"
  1316 + cy="3.7561285"
  1317 + fx="8.824419"
  1318 + fy="3.7561285"
  1319 + r="37.751713" />
  1320 + <radialGradient
  1321 + inkscape:collect="always"
  1322 + xlink:href="#linearGradient4163"
  1323 + id="radialGradient6182"
  1324 + gradientUnits="userSpaceOnUse"
  1325 + gradientTransform="matrix(1.297564,0,0,0.884831,-4.2342547,1013.4195)"
  1326 + cx="28.089741"
  1327 + cy="27.203083"
  1328 + fx="28.089741"
  1329 + fy="27.203083"
  1330 + r="13.565360" />
  1331 + <radialGradient
  1332 + inkscape:collect="always"
  1333 + xlink:href="#linearGradient3816"
  1334 + id="radialGradient6184"
  1335 + gradientUnits="userSpaceOnUse"
  1336 + cx="31.112698"
  1337 + cy="19.008621"
  1338 + fx="31.112698"
  1339 + fy="19.008621"
  1340 + r="8.6620579" />
  1341 + <radialGradient
  1342 + inkscape:collect="always"
  1343 + xlink:href="#linearGradient3800"
  1344 + id="radialGradient6186"
  1345 + gradientUnits="userSpaceOnUse"
  1346 + gradientTransform="matrix(0.787998,0,0,0.787998,6.221198,3.617627)"
  1347 + cx="29.344931"
  1348 + cy="17.064077"
  1349 + fx="29.344931"
  1350 + fy="17.064077"
  1351 + r="9.1620579" />
  1352 + <radialGradient
  1353 + inkscape:collect="always"
  1354 + xlink:href="#linearGradient3816"
  1355 + id="radialGradient6197"
  1356 + gradientUnits="userSpaceOnUse"
  1357 + cx="31.112698"
  1358 + cy="19.008621"
  1359 + fx="31.112698"
  1360 + fy="19.008621"
  1361 + r="8.6620579" />
  1362 + <radialGradient
  1363 + inkscape:collect="always"
  1364 + xlink:href="#linearGradient4163"
  1365 + id="radialGradient6199"
  1366 + gradientUnits="userSpaceOnUse"
  1367 + gradientTransform="matrix(1.297564,0,0,0.884831,-4.2342547,1013.4195)"
  1368 + cx="28.089741"
  1369 + cy="27.203083"
  1370 + fx="28.089741"
  1371 + fy="27.203083"
  1372 + r="13.565360" />
  1373 + <radialGradient
  1374 + inkscape:collect="always"
  1375 + xlink:href="#linearGradient3816"
  1376 + id="radialGradient6201"
  1377 + gradientUnits="userSpaceOnUse"
  1378 + cx="31.112698"
  1379 + cy="19.008621"
  1380 + fx="31.112698"
  1381 + fy="19.008621"
  1382 + r="8.6620579" />
  1383 + <radialGradient
  1384 + inkscape:collect="always"
  1385 + xlink:href="#linearGradient3800"
  1386 + id="radialGradient6203"
  1387 + gradientUnits="userSpaceOnUse"
  1388 + gradientTransform="matrix(0.787998,0,0,0.787998,6.221198,3.617627)"
  1389 + cx="29.344931"
  1390 + cy="17.064077"
  1391 + fx="29.344931"
  1392 + fy="17.064077"
  1393 + r="9.1620579" />
  1394 + <radialGradient
  1395 + inkscape:collect="always"
  1396 + xlink:href="#linearGradient3816"
  1397 + id="radialGradient6242"
  1398 + gradientUnits="userSpaceOnUse"
  1399 + cx="31.112698"
  1400 + cy="19.008621"
  1401 + fx="31.112698"
  1402 + fy="19.008621"
  1403 + r="8.6620579" />
  1404 + <radialGradient
  1405 + inkscape:collect="always"
  1406 + xlink:href="#linearGradient4344"
  1407 + id="radialGradient6244"
  1408 + gradientUnits="userSpaceOnUse"
  1409 + gradientTransform="matrix(1,0,0,0.681917,-1.7093807,1010.8792)"
  1410 + cx="16.214741"
  1411 + cy="19.836468"
  1412 + fx="16.214741"
  1413 + fy="19.836468"
  1414 + r="13.565360" />
  1415 + <radialGradient
  1416 + inkscape:collect="always"
  1417 + xlink:href="#linearGradient3816"
  1418 + id="radialGradient6246"
  1419 + gradientUnits="userSpaceOnUse"
  1420 + cx="31.112698"
  1421 + cy="19.008621"
  1422 + fx="31.112698"
  1423 + fy="19.008621"
  1424 + r="8.6620579" />
  1425 + <radialGradient
  1426 + inkscape:collect="always"
  1427 + xlink:href="#linearGradient4338"
  1428 + id="radialGradient6248"
  1429 + gradientUnits="userSpaceOnUse"
  1430 + gradientTransform="matrix(0.787998,0,0,0.787998,6.221198,3.617627)"
  1431 + cx="29.344931"
  1432 + cy="17.064077"
  1433 + fx="29.344931"
  1434 + fy="17.064077"
  1435 + r="9.1620579" />
  1436 + <linearGradient
  1437 + inkscape:collect="always"
  1438 + xlink:href="#linearGradient3824"
  1439 + id="linearGradient6250"
  1440 + gradientUnits="userSpaceOnUse"
  1441 + gradientTransform="translate(-14.127271,995.6454)"
  1442 + x1="30.935921"
  1443 + y1="29.553486"
  1444 + x2="30.935921"
  1445 + y2="35.803486" />
  1446 + <linearGradient
  1447 + inkscape:collect="always"
  1448 + xlink:href="#linearGradient4356"
  1449 + id="linearGradient6252"
  1450 + gradientUnits="userSpaceOnUse"
  1451 + gradientTransform="matrix(0.95236899,-0.304949,0.304949,0.95236899,-24.109161,1001.0625)"
  1452 + x1="20.661695"
  1453 + y1="35.817974"
  1454 + x2="22.626925"
  1455 + y2="36.217758" />
  1456 + <linearGradient
  1457 + inkscape:collect="always"
  1458 + xlink:href="#linearGradient4356"
  1459 + id="linearGradient6254"
  1460 + gradientUnits="userSpaceOnUse"
  1461 + gradientTransform="matrix(-0.977685,0.210075,0.210075,0.977685,40.096379,991.52674)"
  1462 + x1="22.686766"
  1463 + y1="36.390400"
  1464 + x2="21.408455"
  1465 + y2="35.739632" />
  1466 + <radialGradient
  1467 + inkscape:collect="always"
  1468 + xlink:href="#linearGradient259"
  1469 + id="radialGradient6256"
  1470 + gradientUnits="userSpaceOnUse"
  1471 + gradientTransform="matrix(0.353806,0,0,0.37006743,-289.95036,994.73776)"
  1472 + cx="33.966679"
  1473 + cy="35.736916"
  1474 + fx="33.966679"
  1475 + fy="35.736916"
  1476 + r="86.70845" />
  1477 + <radialGradient
  1478 + inkscape:collect="always"
  1479 + xlink:href="#linearGradient269"
  1480 + id="radialGradient6258"
  1481 + gradientUnits="userSpaceOnUse"
  1482 + gradientTransform="matrix(0.35667183,0,0,0.36709384,-288.71505,994.96754)"
  1483 + cx="8.824419"
  1484 + cy="3.7561285"
  1485 + fx="8.824419"
  1486 + fy="3.7561285"
  1487 + r="37.751713" />
  1488 + <radialGradient
  1489 + inkscape:collect="always"
  1490 + xlink:href="#linearGradient15662"
  1491 + id="radialGradient6260"
  1492 + gradientUnits="userSpaceOnUse"
  1493 + gradientTransform="matrix(0.35842521,0,0,0.36658484,-288.74498,994.99084)"
  1494 + cx="8.1435566"
  1495 + cy="7.2678967"
  1496 + fx="8.1435566"
  1497 + fy="7.2678967"
  1498 + r="38.158695" />
  1499 + <linearGradient
  1500 + inkscape:collect="always"
  1501 + xlink:href="#linearGradient2906"
  1502 + id="linearGradient6262"
  1503 + gradientUnits="userSpaceOnUse"
  1504 + gradientTransform="matrix(0.35541046,-0.09680687,0.12011148,0.40211819,4.9170956,1029.1248)"
  1505 + x1="13.354311"
  1506 + y1="1.4866425"
  1507 + x2="14.075844"
  1508 + y2="2.4017651" />
  1509 + <linearGradient
  1510 + inkscape:collect="always"
  1511 + xlink:href="#linearGradient2896"
  1512 + id="linearGradient6264"
  1513 + gradientUnits="userSpaceOnUse"
  1514 + gradientTransform="matrix(0.35541046,-0.09680687,0.16161446,0.54106498,4.9107799,1029.1036)"
  1515 + x1="14.584077"
  1516 + y1="1.6392649"
  1517 + x2="14.552828"
  1518 + y2="2.4912448" />
  1519 + <radialGradient
  1520 + inkscape:collect="always"
  1521 + xlink:href="#linearGradient4338"
  1522 + id="radialGradient6266"
  1523 + gradientUnits="userSpaceOnUse"
  1524 + gradientTransform="matrix(0.787998,0,0,0.787998,6.221198,3.617627)"
  1525 + cx="29.344931"
  1526 + cy="17.064077"
  1527 + fx="29.344931"
  1528 + fy="17.064077"
  1529 + r="9.1620579" />
  1530 + <radialGradient
  1531 + inkscape:collect="always"
  1532 + xlink:href="#linearGradient4163"
  1533 + id="radialGradient6275"
  1534 + gradientUnits="userSpaceOnUse"
  1535 + gradientTransform="matrix(1.297564,0,0,0.884831,-4.2342547,1013.4195)"
  1536 + cx="28.089741"
  1537 + cy="27.203083"
  1538 + fx="28.089741"
  1539 + fy="27.203083"
  1540 + r="13.565360" />
  1541 + <radialGradient
  1542 + inkscape:collect="always"
  1543 + xlink:href="#linearGradient3816"
  1544 + id="radialGradient6277"
  1545 + gradientUnits="userSpaceOnUse"
  1546 + cx="31.112698"
  1547 + cy="19.008621"
  1548 + fx="31.112698"
  1549 + fy="19.008621"
  1550 + r="8.6620579" />
  1551 + <radialGradient
  1552 + inkscape:collect="always"
  1553 + xlink:href="#linearGradient3800"
  1554 + id="radialGradient6279"
  1555 + gradientUnits="userSpaceOnUse"
  1556 + gradientTransform="matrix(0.787998,0,0,0.787998,6.221198,3.617627)"
  1557 + cx="29.344931"
  1558 + cy="17.064077"
  1559 + fx="29.344931"
  1560 + fy="17.064077"
  1561 + r="9.1620579" />
  1562 + <radialGradient
  1563 + inkscape:collect="always"
  1564 + xlink:href="#linearGradient4163"
  1565 + id="radialGradient6286"
  1566 + gradientUnits="userSpaceOnUse"
  1567 + gradientTransform="matrix(1.297564,0,0,0.884831,-6.8592547,1012.4195)"
  1568 + cx="28.089741"
  1569 + cy="27.203083"
  1570 + fx="28.089741"
  1571 + fy="27.203083"
  1572 + r="13.565360" />
  1573 + <radialGradient
  1574 + inkscape:collect="always"
  1575 + xlink:href="#linearGradient3800"
  1576 + id="radialGradient6300"
  1577 + gradientUnits="userSpaceOnUse"
  1578 + gradientTransform="matrix(0.787998,0,0,0.787998,6.221198,3.617627)"
  1579 + cx="29.344931"
  1580 + cy="17.064077"
  1581 + fx="29.344931"
  1582 + fy="17.064077"
  1583 + r="9.1620579" />
  1584 + </defs>
  1585 + <sodipodi:namedview
  1586 + id="base"
  1587 + pagecolor="#ffffff"
  1588 + bordercolor="#666666"
  1589 + borderopacity="1.0"
  1590 + inkscape:pageopacity="0.0"
  1591 + inkscape:pageshadow="2"
  1592 + inkscape:zoom="15.729167"
  1593 + inkscape:cx="24"
  1594 + inkscape:cy="23.872848"
  1595 + inkscape:document-units="px"
  1596 + inkscape:current-layer="layer1"
  1597 + showgrid="false"
  1598 + inkscape:window-width="1280"
  1599 + inkscape:window-height="975"
  1600 + inkscape:window-x="0"
  1601 + inkscape:window-y="0"
  1602 + inkscape:window-maximized="1" />
  1603 + <metadata
  1604 + id="metadata7">
  1605 + <rdf:RDF>
  1606 + <cc:Work
  1607 + rdf:about="">
  1608 + <dc:format>image/svg+xml</dc:format>
  1609 + <dc:type
  1610 + rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
  1611 + <dc:title></dc:title>
  1612 + </cc:Work>
  1613 + </rdf:RDF>
  1614 + </metadata>
  1615 + <g
  1616 + inkscape:label="Camada 1"
  1617 + inkscape:groupmode="layer"
  1618 + id="layer1"
  1619 + transform="translate(0,-1004.3622)">
  1620 + <g
  1621 + id="g6205"
  1622 + transform="translate(-0.25,-0.625)">
  1623 + <path
  1624 + transform="matrix(1.77551,0,0,0.959183,-39.087601,1014.4169)"
  1625 + sodipodi:type="arc"
  1626 + style="color:#000000;fill:url(#radialGradient6242);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible"
  1627 + id="path4177"
  1628 + sodipodi:cx="31.112698"
  1629 + sodipodi:cy="19.008621"
  1630 + sodipodi:rx="8.6620579"
  1631 + sodipodi:ry="8.6620579"
  1632 + d="m 39.774755,19.008621 c 0,4.783923 -3.878135,8.662058 -8.662057,8.662058 -4.783923,0 -8.662058,-3.878135 -8.662058,-8.662058 0,-4.783922 3.878135,-8.662058 8.662058,-8.662058 4.783922,0 8.662057,3.878136 8.662057,8.662058 z" />
  1633 + <path
  1634 + style="color:#000000;fill:url(#radialGradient6244);fill-opacity:1;fill-rule:evenodd;stroke:#404604;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible"
  1635 + d="m 11.151793,1037.2814 10.606602,0 c 3.005204,0 5.980484,-1.1019 7.071067,-4.2426 1.035639,-2.9825 0.176777,-8.6621 -6.540737,-13.2583 l -12.5511457,0 c -6.717514,4.2427 -7.556991,10.0449 -6.010407,13.4351 1.575595,3.4538 4.24264,4.0658 7.4246207,4.0658 z"
  1636 + id="path2329"
  1637 + sodipodi:nodetypes="cczcczc" />
  1638 + <path
  1639 + sodipodi:nodetypes="cccc"
  1640 + id="path3812"
  1641 + d="m 16.222986,1022.4322 c 0,0 -2.151323,1.6603 -1.965991,3.6605 -2.041226,-1.8008 -2.099873,-5.2515 -2.099873,-5.2515 l 4.065864,1.591 z"
  1642 + style="color:#000000;fill:#9db029;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible" />
  1643 + <path
  1644 + sodipodi:nodetypes="cczcczc"
  1645 + id="path3838"
  1646 + d="m 11.257258,1036.2172 10.31667,0 c 2.639723,0 5.253161,-0.9679 6.211112,-3.7266 0.909689,-2.6198 -0.09472,-7.6086 -5.995279,-11.6459 l -11.524725,0 c -5.9005567,3.7267 -6.8879397,8.8233 -5.5294457,11.8011 1.383978,3.0338 3.726667,3.5714 6.5216677,3.5714 z"
  1647 + style="opacity:0.21518986;color:#000000;fill:none;stroke:#ffffff;stroke-width:0.99999976px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible" />
  1648 + <path
  1649 + style="color:#000000;fill:#9db029;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible"
  1650 + d="m 17.201414,1022.4322 c 0,0 2.151323,1.6603 1.965991,3.6605 2.041226,-1.8008 2.099873,-5.2515 2.099873,-5.2515 l -4.065864,1.591 z"
  1651 + id="path3810"
  1652 + sodipodi:nodetypes="cccc" />
  1653 + <path
  1654 + d="m 39.774755,19.008621 c 0,4.783923 -3.878135,8.662058 -8.662057,8.662058 -4.783923,0 -8.662058,-3.878135 -8.662058,-8.662058 0,-4.783922 3.878135,-8.662058 8.662058,-8.662058 4.783922,0 8.662057,3.878136 8.662057,8.662058 z"
  1655 + sodipodi:ry="8.6620579"
  1656 + sodipodi:rx="8.6620579"
  1657 + sodipodi:cy="19.008621"
  1658 + sodipodi:cx="31.112698"
  1659 + id="path3814"
  1660 + style="color:#000000;fill:url(#radialGradient6246);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible"
  1661 + sodipodi:type="arc"
  1662 + transform="translate(-14.959381,999.1454)" />
  1663 + <g
  1664 + id="g4290">
  1665 + <path
  1666 + transform="translate(-14.834381,995.6454)"
  1667 + d="m 39.774755,19.008621 c 0,4.783923 -3.878135,8.662058 -8.662057,8.662058 -4.783923,0 -8.662058,-3.878135 -8.662058,-8.662058 0,-4.783922 3.878135,-8.662058 8.662058,-8.662058 4.783922,0 8.662057,3.878136 8.662057,8.662058 z"
  1668 + sodipodi:ry="8.6620579"
  1669 + sodipodi:rx="8.6620579"
  1670 + sodipodi:cy="19.008621"
  1671 + sodipodi:cx="31.112698"
  1672 + id="path2327"
  1673 + style="color:#000000;fill:url(#radialGradient6248);fill-opacity:1;fill-rule:evenodd;stroke:#6f4709;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible"
  1674 + sodipodi:type="arc" />
  1675 + <path
  1676 + transform="matrix(0.877095,0,0,0.877095,-11.010454,997.98167)"
  1677 + sodipodi:type="arc"
  1678 + style="opacity:0.12658231;color:#000000;fill:none;stroke:#ffffff;stroke-width:1.14012825px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible"
  1679 + id="path3834"
  1680 + sodipodi:cx="31.112698"
  1681 + sodipodi:cy="19.008621"
  1682 + sodipodi:rx="8.6620579"
  1683 + sodipodi:ry="8.6620579"
  1684 + d="m 39.774755,19.008621 c 0,4.783923 -3.878135,8.662058 -8.662057,8.662058 -4.783923,0 -8.662058,-3.878135 -8.662058,-8.662058 0,-4.783922 3.878135,-8.662058 8.662058,-8.662058 4.783922,0 8.662057,3.878136 8.662057,8.662058 z" />
  1685 + </g>
  1686 + <path
  1687 + style="color:#000000;fill:url(#linearGradient6250);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible"
  1688 + d="m 20.874513,1029.68 4.24264,0 -2.474873,-2.2981 -0.53033,0.7072 -0.530331,-0.5304 -0.707106,2.1213 z"
  1689 + id="path4173" />
  1690 + <path
  1691 + style="opacity:0.22784807;color:#000000;fill:url(#linearGradient6252);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible"
  1692 + d="m 10.187502,1031.9428 c -1.3569797,0.1098 -2.4699596,-0.7834 -2.4699596,-0.7834 -1.1826865,-3.9834 -0.053718,-7.9677 -0.053718,-7.9677 0,0 1.0230233,6.7272 2.5236776,8.7511 z"
  1693 + id="path4368"
  1694 + sodipodi:nodetypes="cccc" />
  1695 + <path
  1696 + sodipodi:nodetypes="cccc"
  1697 + id="path4370"
  1698 + d="m 25.74428,1035.3888 c 1.231251,-0.581 1.80438,-2.0023 1.80438,-2.0023 -0.95912,-4.043 -3.976149,-6.8428 -3.976149,-6.8428 0,0 2.464593,6.3426 2.171769,8.8451 z"
  1699 + style="opacity:0.22784807;color:#000000;fill:url(#linearGradient6254);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible" />
  1700 + <rect
  1701 + transform="matrix(0.96484871,-0.26280595,0.28620224,0.95816923,0,0)"
  1702 + rx="0.42326209"
  1703 + ry="0.40700412"
  1704 + y="996.03387"
  1705 + x="-287.51788"
  1706 + height="14.54507"
  1707 + width="12.846511"
  1708 + id="rect15391"
  1709 + style="color:#000000;fill:url(#radialGradient6256);fill-opacity:1;fill-rule:nonzero;stroke:url(#radialGradient6258);stroke-width:1.00014806;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:block;overflow:visible" />
  1710 + <rect
  1711 + transform="matrix(0.96484871,-0.26280595,0.28620224,0.95816923,0,0)"
  1712 + rx="0.054903328"
  1713 + ry="0.052794438"
  1714 + y="996.38843"
  1715 + x="-287.14862"
  1716 + height="13.824175"
  1717 + width="12.132636"
  1718 + id="rect15660"
  1719 + style="color:#000000;fill:none;stroke:url(#radialGradient6260);stroke-width:0.36121485;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dashoffset:0;marker:none;visibility:visible;display:block;overflow:visible" />
  1720 + <path
  1721 + sodipodi:nodetypes="cc"
  1722 + id="path15672"
  1723 + d="m 9.6371294,1030.1227 3.8428056,12.8652"
  1724 + style="fill:none;stroke:#000000;stroke-width:0.35702735;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:0.01754384;display:inline" />
  1725 + <path
  1726 + sodipodi:nodetypes="cc"
  1727 + id="path15674"
  1728 + d="m 9.9424741,1029.8656 3.8540689,12.903"
  1729 + style="fill:none;stroke:#ffffff;stroke-width:0.36116153;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:0.20467828;display:inline" />
  1730 + <g
  1731 + transform="matrix(0.35541046,-0.09680687,0.10137564,0.33939294,4.9908869,1029.3718)"
  1732 + id="g2188">
  1733 + <rect
  1734 + ry="0.065390877"
  1735 + rx="0.13778631"
  1736 + y="9"
  1737 + x="15.999994"
  1738 + height="1"
  1739 + width="20.000006"
  1740 + id="rect15686"
  1741 + style="color:#000000;fill:#9b9b9b;fill-opacity:0.54970757;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:block;overflow:visible" />
  1742 + <rect
  1743 + ry="0.065390877"
  1744 + rx="0.13778631"
  1745 + y="11"
  1746 + x="15.999994"
  1747 + height="1"
  1748 + width="20.000006"
  1749 + id="rect15688"
  1750 + style="color:#000000;fill:#9b9b9b;fill-opacity:0.54970757;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:block;overflow:visible" />
  1751 + <rect
  1752 + ry="0.065390877"
  1753 + rx="0.13778631"
  1754 + y="13"
  1755 + x="15.999994"
  1756 + height="1"
  1757 + width="20.000006"
  1758 + id="rect15690"
  1759 + style="color:#000000;fill:#9b9b9b;fill-opacity:0.54970757;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:block;overflow:visible" />
  1760 + <rect
  1761 + ry="0.065390877"
  1762 + rx="0.13778631"
  1763 + y="15"
  1764 + x="15.999994"
  1765 + height="1"
  1766 + width="20.000006"
  1767 + id="rect15692"
  1768 + style="color:#000000;fill:#9b9b9b;fill-opacity:0.54970757;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:block;overflow:visible" />
  1769 + <rect
  1770 + ry="0.065390877"
  1771 + rx="0.13778631"
  1772 + y="17"
  1773 + x="15.999994"
  1774 + height="1"
  1775 + width="20.000006"
  1776 + id="rect15694"
  1777 + style="color:#000000;fill:#9b9b9b;fill-opacity:0.54970757;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:block;overflow:visible" />
  1778 + <rect
  1779 + ry="0.065390877"
  1780 + rx="0.13778631"
  1781 + y="19"
  1782 + x="15.999994"
  1783 + height="1"
  1784 + width="20.000006"
  1785 + id="rect15696"
  1786 + style="color:#000000;fill:#9b9b9b;fill-opacity:0.54970757;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:block;overflow:visible" />
  1787 + <rect
  1788 + ry="0.065390877"
  1789 + rx="0.13778631"
  1790 + y="21"
  1791 + x="15.999994"
  1792 + height="1"
  1793 + width="20.000006"
  1794 + id="rect15698"
  1795 + style="color:#000000;fill:#9b9b9b;fill-opacity:0.54970757;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:block;overflow:visible" />
  1796 + <rect
  1797 + ry="0.065390877"
  1798 + rx="0.13778631"
  1799 + y="23"
  1800 + x="15.999994"
  1801 + height="1"
  1802 + width="20.000006"
  1803 + id="rect15700"
  1804 + style="color:#000000;fill:#9b9b9b;fill-opacity:0.54970757;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:block;overflow:visible" />
  1805 + <rect
  1806 + ry="0.065390877"
  1807 + rx="0.062003858"
  1808 + y="25"
  1809 + x="15.999986"
  1810 + height="1"
  1811 + width="9.0000057"
  1812 + id="rect15732"
  1813 + style="color:#000000;fill:#9b9b9b;fill-opacity:0.54970757;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:block;overflow:visible" />
  1814 + <rect
  1815 + ry="0.065390877"
  1816 + rx="0.13778631"
  1817 + y="29"
  1818 + x="15.999986"
  1819 + height="1"
  1820 + width="20.000006"
  1821 + id="rect15736"
  1822 + style="color:#000000;fill:#9b9b9b;fill-opacity:0.54970757;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:block;overflow:visible" />
  1823 + <rect
  1824 + ry="0.065390877"
  1825 + rx="0.13778631"
  1826 + y="31"
  1827 + x="15.999986"
  1828 + height="1"
  1829 + width="20.000006"
  1830 + id="rect15738"
  1831 + style="color:#000000;fill:#9b9b9b;fill-opacity:0.54970757;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:block;overflow:visible" />
  1832 + <rect
  1833 + ry="0.065390877"
  1834 + rx="0.13778631"
  1835 + y="33"
  1836 + x="15.999986"
  1837 + height="1"
  1838 + width="20.000006"
  1839 + id="rect15740"
  1840 + style="color:#000000;fill:#9b9b9b;fill-opacity:0.54970757;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:block;overflow:visible" />
  1841 + <rect
  1842 + ry="0.065390877"
  1843 + rx="0.13778631"
  1844 + y="35"
  1845 + x="15.999986"
  1846 + height="1"
  1847 + width="20.000006"
  1848 + id="rect15742"
  1849 + style="color:#000000;fill:#9b9b9b;fill-opacity:0.54970757;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:block;overflow:visible" />
  1850 + <rect
  1851 + ry="0.065390877"
  1852 + rx="0.096450485"
  1853 + y="37"
  1854 + x="15.999986"
  1855 + height="1"
  1856 + width="14.000014"
  1857 + id="rect15744"
  1858 + style="color:#000000;fill:#9b9b9b;fill-opacity:0.54970757;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:block;overflow:visible" />
  1859 + </g>
  1860 + <path
  1861 + sodipodi:nodetypes="cccc"
  1862 + id="path2894"
  1863 + d="m 10.77767,1029.241 -0.310195,-0.9816 c -0.7572021,0.2062 -0.5578178,0.8619 -0.459453,1.1912 l 0.769647,-0.2096 z"
  1864 + style="opacity:0.48295456;color:#000000;fill:url(#linearGradient6262);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.10533953;marker:none;visibility:visible;display:inline;overflow:visible" />
  1865 + <path
  1866 + style="opacity:0.35795456;color:#000000;fill:url(#linearGradient6264);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.10533953;marker:none;visibility:visible;display:inline;overflow:visible"
  1867 + d="m 10.77767,1029.241 -0.229976,-0.7131 c -0.8149432,0.2286 -0.539672,0.9227 -0.539672,0.9227 l 0.769647,-0.2096 z"
  1868 + id="path2904"
  1869 + sodipodi:nodetypes="cccc" />
  1870 + <path
  1871 + transform="matrix(0.41151985,0,0,0.41151985,-5.6291758,1025.7467)"
  1872 + d="m 39.774755,19.008621 c 0,4.783923 -3.878135,8.662058 -8.662057,8.662058 -4.783923,0 -8.662058,-3.878135 -8.662058,-8.662058 0,-4.783922 3.878135,-8.662058 8.662058,-8.662058 4.783922,0 8.662057,3.878136 8.662057,8.662058 z"
  1873 + sodipodi:ry="8.6620579"
  1874 + sodipodi:rx="8.6620579"
  1875 + sodipodi:cy="19.008621"
  1876 + sodipodi:cx="31.112698"
  1877 + id="path4296"
  1878 + style="color:#000000;fill:url(#radialGradient6266);fill-opacity:1;fill-rule:evenodd;stroke:#6f4709;stroke-width:2.43001652;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible"
  1879 + sodipodi:type="arc" />
  1880 + <path
  1881 + transform="matrix(0.360942,0,0,0.360942,-4.0555539,1026.7081)"
  1882 + sodipodi:type="arc"
  1883 + style="opacity:0.12658231;color:#000000;fill:none;stroke:#ffffff;stroke-width:2.77052832;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible"
  1884 + id="path4298"
  1885 + sodipodi:cx="31.112698"
  1886 + sodipodi:cy="19.008621"
  1887 + sodipodi:rx="8.6620579"
  1888 + sodipodi:ry="8.6620579"
  1889 + d="m 39.774755,19.008621 c 0,4.783923 -3.878135,8.662058 -8.662057,8.662058 -4.783923,0 -8.662058,-3.878135 -8.662058,-8.662058 0,-4.783922 3.878135,-8.662058 8.662058,-8.662058 4.783922,0 8.662057,3.878136 8.662057,8.662058 z" />
  1890 + </g>
  1891 + <path
  1892 + transform="matrix(0.42405721,0,0,0.42405721,8.1654039,1030.3792)"
  1893 + sodipodi:type="arc"
  1894 + style="color:#000000;fill:url(#radialGradient6300);fill-opacity:1;fill-rule:evenodd;stroke:#c17d11;stroke-width:2.35817238;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible"
  1895 + id="path6296"
  1896 + sodipodi:cx="31.112698"
  1897 + sodipodi:cy="19.008621"
  1898 + sodipodi:rx="8.6620579"
  1899 + sodipodi:ry="8.6620579"
  1900 + d="m 39.774755,19.008621 c 0,4.783923 -3.878135,8.662058 -8.662057,8.662058 -4.783923,0 -8.662058,-3.878135 -8.662058,-8.662058 0,-4.783922 3.878135,-8.662058 8.662058,-8.662058 4.783922,0 8.662057,3.878136 8.662057,8.662058 z" />
  1901 + <path
  1902 + d="m 39.774755,19.008621 c 0,4.783923 -3.878135,8.662058 -8.662057,8.662058 -4.783923,0 -8.662058,-3.878135 -8.662058,-8.662058 0,-4.783922 3.878135,-8.662058 8.662058,-8.662058 4.783922,0 8.662057,3.878136 8.662057,8.662058 z"
  1903 + sodipodi:ry="8.6620579"
  1904 + sodipodi:rx="8.6620579"
  1905 + sodipodi:cy="19.008621"
  1906 + sodipodi:cx="31.112698"
  1907 + id="path6298"
  1908 + style="opacity:0.19620254000000001;color:#000000;fill:none;stroke:#ffffff;stroke-width:2.68861682;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible"
  1909 + sodipodi:type="arc"
  1910 + transform="matrix(0.37193846,0,0,0.37193846,9.7869677,1031.3699)" />
  1911 + <path
  1912 + d="m 39.774755,19.008621 c 0,4.783923 -3.878135,8.662058 -8.662057,8.662058 -4.783923,0 -8.662058,-3.878135 -8.662058,-8.662058 0,-4.783922 3.878135,-8.662058 8.662058,-8.662058 4.783922,0 8.662057,3.878136 8.662057,8.662058 z"
  1913 + sodipodi:ry="8.6620579"
  1914 + sodipodi:rx="8.6620579"
  1915 + sodipodi:cy="19.008621"
  1916 + sodipodi:cx="31.112698"
  1917 + id="path4306"
  1918 + style="color:#000000;fill:url(#radialGradient6197);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible"
  1919 + sodipodi:type="arc"
  1920 + transform="matrix(1.77551,0,0,0.583984,-23.12897,1035.6326)" />
  1921 + <path
  1922 + sodipodi:nodetypes="cczcczc"
  1923 + id="path4308"
  1924 + d="m 27.485424,1049.115 10.606602,0 c 3.005204,0 5.980484,-1.1019 7.071067,-4.2426 1.035639,-2.9825 0.176777,-8.6621 -6.540737,-13.2583 l -12.551146,0 c -6.717514,4.2427 -7.556991,10.0449 -6.010407,13.4351 1.575595,3.4538 4.24264,4.0658 7.424621,4.0658 z"
  1925 + style="color:#000000;fill:url(#radialGradient6286);fill-opacity:1;fill-rule:evenodd;stroke:#204a87;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible" />
  1926 + <path
  1927 + style="opacity:0.21518986;color:#000000;fill:none;stroke:#ffffff;stroke-width:0.99999976px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible"
  1928 + d="m 27.414112,1048.0729 10.493447,-0.022 c 2.639723,0 5.253161,-0.9679 6.211112,-3.7266 0.909689,-2.6198 -0.09472,-7.6086 -5.995279,-11.6459 l -11.524725,-0.243 c -5.900557,3.7266 -7.04262,8.8232 -5.662029,12.0441 1.380592,3.221 3.395211,3.5714 6.477474,3.5935 z"
  1929 + id="path4314"
  1930 + sodipodi:nodetypes="cczcczc" />
  1931 + <path
  1932 + transform="translate(1.3742503,1010.979)"
  1933 + sodipodi:type="arc"
  1934 + style="color:#000000;fill:url(#radialGradient6277);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible"
  1935 + id="path4318"
  1936 + sodipodi:cx="31.112698"
  1937 + sodipodi:cy="19.008621"
  1938 + sodipodi:rx="8.6620579"
  1939 + sodipodi:ry="8.6620579"
  1940 + d="m 39.774755,19.008621 c 0,4.783923 -3.878135,8.662058 -8.662057,8.662058 -4.783923,0 -8.662058,-3.878135 -8.662058,-8.662058 0,-4.783922 3.878135,-8.662058 8.662058,-8.662058 4.783922,0 8.662057,3.878136 8.662057,8.662058 z" />
  1941 + <g
  1942 + id="g6288">
  1943 + <path
  1944 + transform="translate(1.4992503,1007.479)"
  1945 + sodipodi:type="arc"
  1946 + style="color:#000000;fill:url(#radialGradient6279);fill-opacity:1;fill-rule:evenodd;stroke:#c17d11;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible"
  1947 + id="path4320"
  1948 + sodipodi:cx="31.112698"
  1949 + sodipodi:cy="19.008621"
  1950 + sodipodi:rx="8.6620579"
  1951 + sodipodi:ry="8.6620579"
  1952 + d="m 39.774755,19.008621 c 0,4.783923 -3.878135,8.662058 -8.662057,8.662058 -4.783923,0 -8.662058,-3.878135 -8.662058,-8.662058 0,-4.783922 3.878135,-8.662058 8.662058,-8.662058 4.783922,0 8.662057,3.878136 8.662057,8.662058 z" />
  1953 + <path
  1954 + d="m 39.774755,19.008621 c 0,4.783923 -3.878135,8.662058 -8.662057,8.662058 -4.783923,0 -8.662058,-3.878135 -8.662058,-8.662058 0,-4.783922 3.878135,-8.662058 8.662058,-8.662058 4.783922,0 8.662057,3.878136 8.662057,8.662058 z"
  1955 + sodipodi:ry="8.6620579"
  1956 + sodipodi:rx="8.6620579"
  1957 + sodipodi:cy="19.008621"
  1958 + sodipodi:cx="31.112698"
  1959 + id="path4322"
  1960 + style="opacity:0.19620254;color:#000000;fill:none;stroke:#ffffff;stroke-width:1.14012825px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible"
  1961 + sodipodi:type="arc"
  1962 + transform="matrix(0.877095,0,0,0.877095,5.3231773,1009.8153)" />
  1963 + </g>
  1964 + </g>
  1965 +</svg>
... ...
plugins/bsc/public/style.css 0 → 100644
... ... @@ -0,0 +1,12 @@
  1 +.controller-profile_editor a.control-panel-bsc-enterprises {background-image: url(images/manage-bsc-enterprises.png)}
  2 +.controller-profile_editor .msie6 a.control-panel-bsc-enterprises {background-image: url(images/manage-bsc-enterprises.gif)}
  3 +
  4 +.controller-profile_editor a.control-panel-transfer-enterprise-ownership {background-image: url(images/transfer-ownership.png)}
  5 +
  6 +.icon-menu-bsc {
  7 + background-image: url(images/manage-bsc-enterprises-icon.png);
  8 +}
  9 +
  10 +#content .token-input-list {
  11 + margin-bottom: 30px;
  12 +}
... ...
plugins/bsc/test/functional/bsc_plugin_environment_controller_test.rb 0 → 100644
... ... @@ -0,0 +1,82 @@
  1 +require File.dirname(__FILE__) + '/../../../../test/test_helper'
  2 +require File.dirname(__FILE__) + '/../../controllers/bsc_plugin_environment_controller'
  3 +require File.dirname(__FILE__) + '/../../../../app/models/uploaded_file'
  4 +
  5 +# Re-raise errors caught by the controller.
  6 +class BscPluginEnvironmentController; def rescue_action(e) raise e end; end
  7 +
  8 +class BscPluginEnvironmentControllerTest < Test::Unit::TestCase
  9 +
  10 + VALID_CNPJ = '94.132.024/0001-48'
  11 +
  12 + def setup
  13 + @controller = BscPluginEnvironmentController.new
  14 + @request = ActionController::TestRequest.new
  15 + @response = ActionController::TestResponse.new
  16 + user_login = create_admin_user(Environment.default)
  17 + login_as(user_login)
  18 + @admin = User[user_login].person
  19 + e = Environment.default
  20 + e.enabled_plugins = ['BscPlugin']
  21 + e.save!
  22 + end
  23 +
  24 + attr_accessor :admin
  25 +
  26 + should 'create a new bsc' do
  27 + assert_difference BscPlugin::Bsc, :count, 1 do
  28 + post :new, :profile_data => {:business_name => 'Sample Bsc', :identifier => 'sample-bsc', :company_name => 'Sample Bsc Ltda.', :cnpj => VALID_CNPJ}
  29 + end
  30 +
  31 + assert_redirected_to :controller => 'profile_editor', :profile => 'sample-bsc'
  32 + end
  33 +
  34 + should 'not create an invalid bsc' do
  35 + assert_difference BscPlugin::Bsc, :count, 0 do
  36 + post :new, :profile_data => {:business_name => 'Sample Bsc', :identifier => 'sample-bsc', :company_name => 'Sample Bsc Ltda.', :cnpj => '29837492304'}
  37 + end
  38 +
  39 + assert_response 200
  40 + end
  41 +
  42 + should 'set the current user as the bsc admin' do
  43 + name = 'Sample Bsc'
  44 + post :new, :profile_data => {:business_name => name, :identifier => 'sample-bsc', :company_name => 'Sample Bsc Ltda.', :cnpj => VALID_CNPJ}
  45 + bsc = BscPlugin::Bsc.find_by_name(name)
  46 + assert_includes bsc.admins, admin
  47 + end
  48 +
  49 + should 'list correct enterprises on search' do
  50 + # Should list if: not validated AND (name matches OR identifier matches) AND not bsc
  51 + e1 = Enterprise.create!(:name => 'Sample Enterprise 1', :identifier => 'bli', :validated => false)
  52 + e2 = Enterprise.create!(:name => 'Bla', :identifier => 'sample-enterprise-6', :validated => false)
  53 + e3 = Enterprise.create!(:name => 'Blo', :identifier => 'blo', :validated => false)
  54 + e4 = BscPlugin::Bsc.create!(:business_name => "Sample Bsc", :identifier => 'sample-bsc', :company_name => 'Sample Bsc Ltda.', :cnpj => VALID_CNPJ, :validated => false)
  55 + e5 = Enterprise.create!(:name => 'Sample Enterprise 5', :identifier => 'sample-enterprise-5')
  56 + e5.validated = true
  57 + e5.save!
  58 +
  59 + get :search_enterprise, :q => 'sampl'
  60 +
  61 + assert_match /#{e1.name}/, @response.body
  62 + assert_match /#{e2.name}/, @response.body
  63 + assert_no_match /#{e3.name}/, @response.body
  64 + assert_no_match /#{e4.name}/, @response.body
  65 + assert_no_match /#{e5.name}/, @response.body
  66 + end
  67 +
  68 + should 'save validations' do
  69 + e1 = fast_create(Enterprise, :validated => false)
  70 + e2 = fast_create(Enterprise, :validated => false)
  71 + e3 = fast_create(Enterprise, :validated => false)
  72 +
  73 + post :save_validations, :q => "#{e1.id},#{e2.id}"
  74 + e1.reload
  75 + e2.reload
  76 + e3.reload
  77 +
  78 + assert e1.validated
  79 + assert e2.validated
  80 + assert !e3.validated
  81 + end
  82 +end
... ...
plugins/bsc/test/functional/bsc_plugin_myprofile_controller_test.rb 0 → 100644
... ... @@ -0,0 +1,112 @@
  1 +require File.dirname(__FILE__) + '/../../../../test/test_helper'
  2 +require File.dirname(__FILE__) + '/../../controllers/bsc_plugin_myprofile_controller'
  3 +require File.dirname(__FILE__) + '/../../../../app/models/uploaded_file'
  4 +
  5 +# Re-raise errors caught by the controller.
  6 +class BscPluginMyprofileController; def rescue_action(e) raise e end; end
  7 +
  8 +class BscPluginMyprofileControllerTest < Test::Unit::TestCase
  9 +
  10 + VALID_CNPJ = '94.132.024/0001-48'
  11 +
  12 + def setup
  13 + @controller = BscPluginMyprofileController.new
  14 + @request = ActionController::TestRequest.new
  15 + @response = ActionController::TestResponse.new
  16 + @bsc = BscPlugin::Bsc.create!({:business_name => 'Sample Bsc', :identifier => 'sample-bsc', :company_name => 'Sample Bsc Ltda.', :cnpj => VALID_CNPJ})
  17 + @admin = create_user('admin').person
  18 + @bsc.add_admin(@admin)
  19 + login_as(@admin.user.login)
  20 + e = Environment.default
  21 + e.enabled_plugins = ['BscPlugin']
  22 + e.save!
  23 + end
  24 +
  25 + attr_accessor :admin, :bsc
  26 +
  27 + should 'list enterprises on search' do
  28 + # Should list if match name
  29 + e1 = Enterprise.create!(:name => 'sample enterprise 1', :identifier => 'sample-enterprise-1')
  30 + # Should be case insensitive
  31 + e2 = Enterprise.create!(:name => 'SaMpLe eNtErPrIsE 2', :identifier => 'sample-enterprise-2')
  32 + # Should not list if don't match name
  33 + e3 = Enterprise.create!(:name => 'blo', :identifier => 'blo')
  34 + # Should not list if is has a bsc
  35 + e4 = Enterprise.create!(:name => 'sample enterprise 4', :identifier => 'sample-enterprise-4', :bsc => bsc)
  36 + # Should not list if is enabled
  37 + e5 = Enterprise.create!(:name => 'sample enterprise 5', :identifier => 'sample-enterprise-5', :enabled => true)
  38 + BscPlugin::AssociateEnterprise.create!(:requestor => admin, :target => e5, :bsc => bsc)
  39 + # Should search by identifier
  40 + e6 = Enterprise.create!(:name => 'Bla', :identifier => 'sample-enterprise-6')
  41 +
  42 + get :search_enterprise, :profile => bsc.identifier, :q => 'sampl'
  43 +
  44 + assert_match /#{e1.name}/, @response.body
  45 + assert_match /#{e2.name}/, @response.body
  46 + assert_no_match /#{e3.name}/, @response.body
  47 + assert_no_match /#{e4.name}/, @response.body
  48 + assert_no_match /#{e5.name}/, @response.body
  49 + assert_no_match /#{bsc.name}/, @response.body
  50 + assert_match /#{e6.name}/, @response.body
  51 + end
  52 +
  53 + should 'save associations' do
  54 + e1 = fast_create(Enterprise, :enabled => false)
  55 + e2 = fast_create(Enterprise, :enabled => false)
  56 +
  57 + post :save_associations, :profile => bsc.identifier, :q => "#{e1.id},#{e2.id}"
  58 + e1.reload
  59 + e2.reload
  60 + assert_equal e1.bsc, bsc
  61 + assert_equal e2.bsc, bsc
  62 +
  63 + post :save_associations, :profile => bsc.identifier, :q => "#{e1.id}"
  64 + e1.reload
  65 + e2.reload
  66 + assert_equal e1.bsc, bsc
  67 + assert_not_equal e2.bsc, bsc
  68 + end
  69 +
  70 + should 'create a task to the enabled enterprise instead of associating it' do
  71 + e = fast_create(Enterprise, :enabled => true)
  72 +
  73 + assert_difference BscPlugin::AssociateEnterprise, :count, 1 do
  74 + post :save_associations, :profile => bsc.identifier, :q => "#{e.id}"
  75 + bsc.reload
  76 + assert_not_includes bsc.enterprises, e
  77 + end
  78 + end
  79 +
  80 + should 'transfer ownership' do
  81 + p1 = create_user('p1').person
  82 + p2 = create_user('p2').person
  83 + p3 = create_user('p3').person
  84 +
  85 + role = Profile::Roles.admin(bsc.environment.id)
  86 +
  87 + bsc.add_admin(p1)
  88 + bsc.add_admin(p2)
  89 +
  90 + post :transfer_ownership, :profile => bsc.identifier, 'q_'+role.key => "#{p3.id}"
  91 +
  92 + assert_response :redirect
  93 +
  94 + assert_not_includes bsc.admins, p1
  95 + assert_not_includes bsc.admins, p2
  96 + assert_includes bsc.admins, p3
  97 + end
  98 +
  99 + should 'create enterprise' do
  100 + assert_difference Enterprise, :count, 1 do
  101 + post :create_enterprise, :profile => bsc.identifier, :create_enterprise => {:name => 'Test Bsc', :identifier => 'test-bsc'}
  102 + end
  103 +
  104 + enterprise = Enterprise.find_by_identifier('test-bsc')
  105 +
  106 + assert_equal true, enterprise.enabled
  107 + assert_equal false, enterprise.validated
  108 + assert_equal enterprise.bsc, bsc
  109 + end
  110 +
  111 +end
  112 +
... ...
plugins/bsc/test/unit/bsc_plugin/associate_enterprise_test.rb 0 → 100644
... ... @@ -0,0 +1,53 @@
  1 +require File.dirname(__FILE__) + '/../../../../../test/test_helper'
  2 +require File.dirname(__FILE__) + '/../../../../../app/models/uploaded_file'
  3 +
  4 +class BscPlugin::AssociateEnterpriseTest < Test::Unit::TestCase
  5 + VALID_CNPJ = '94.132.024/0001-48'
  6 +
  7 + def setup
  8 + @enterprise = fast_create(Enterprise)
  9 + @person = create_user('user').person
  10 + @bsc = BscPlugin::Bsc.create!(:business_name => 'Sample Bsc', :company_name => 'Sample Bsc Ltda.', :identifier => 'sample-bsc', :cnpj => VALID_CNPJ)
  11 + end
  12 +
  13 + attr_accessor :enterprise, :person, :bsc
  14 +
  15 + should 'associate enteprise with bsc after perform' do
  16 + task = BscPlugin::AssociateEnterprise.create!(:requestor => person, :target => enterprise, :bsc => bsc)
  17 + task.perform
  18 + bsc.reload
  19 +
  20 + assert_includes bsc.enterprises, enterprise
  21 + end
  22 +
  23 + should 'notify enterprise when some bsc create the request' do
  24 + enterprise.contact_email = 'enterprise@bsc.org'
  25 + enterprise.save!
  26 + assert_difference ActionMailer::Base.deliveries, :count, 1 do
  27 + BscPlugin::AssociateEnterprise.create!(:requestor => person, :target => enterprise, :bsc => bsc)
  28 + end
  29 + assert_includes ActionMailer::Base.deliveries.last.to, enterprise.contact_email
  30 + end
  31 +
  32 + should 'notify requestor when some enterprise reject the request' do
  33 + person.email = 'person@bsc.org'
  34 + person.save!
  35 + task = BscPlugin::AssociateEnterprise.create!(:requestor => person, :target => enterprise, :bsc => bsc)
  36 + assert_difference ActionMailer::Base.deliveries, :count, 1 do
  37 + task.cancel
  38 + end
  39 + assert_includes ActionMailer::Base.deliveries.last.to, person.contact_email
  40 + end
  41 +
  42 + should 'notify requestor when some enterprise accept the request' do
  43 + person.email = 'person@bsc.org'
  44 + person.save!
  45 + task = BscPlugin::AssociateEnterprise.create!(:requestor => person, :target => enterprise, :bsc => bsc)
  46 + assert_difference ActionMailer::Base.deliveries, :count, 1 do
  47 + task.finish
  48 + end
  49 + assert_includes ActionMailer::Base.deliveries.last.to, person.contact_email
  50 + end
  51 +
  52 +end
  53 +
... ...
plugins/bsc/test/unit/bsc_plugin/bsc_test.rb 0 → 100644
... ... @@ -0,0 +1,86 @@
  1 +require File.dirname(__FILE__) + '/../../../../../test/test_helper'
  2 +require File.dirname(__FILE__) + '/../../../../../app/models/uploaded_file'
  3 +require File.dirname(__FILE__) + '/../../../lib/ext/enterprise'
  4 +
  5 +class BscPlugin::BscTest < Test::Unit::TestCase
  6 + VALID_CNPJ = '94.132.024/0001-48'
  7 +
  8 + should 'validate presence of cnpj' do
  9 + bsc = BscPlugin::Bsc.new()
  10 + bsc.valid?
  11 +
  12 + assert bsc.errors.invalid?(:cnpj)
  13 + end
  14 +
  15 + should 'validate uniqueness of cnpj' do
  16 + bsc1 = BscPlugin::Bsc.create!({:business_name => 'Sample Bsc', :identifier => 'sample-bsc', :company_name => 'Sample Bsc Ltda.', :cnpj => VALID_CNPJ})
  17 + bsc2 = BscPlugin::Bsc.new(:cnpj => VALID_CNPJ)
  18 + bsc2.valid?
  19 + assert bsc2.errors.invalid?(:cnpj)
  20 + end
  21 +
  22 + should 'have many enterprises' do
  23 + e1 = Enterprise.new(:name => 'Enterprise1', :identifier => 'enterprise1')
  24 + e2 = Enterprise.new(:name => 'Enterprise2', :identifier => 'enterprise2')
  25 + bsc = BscPlugin::Bsc.new(:business_name => 'Sample Bsc', :company_name => 'Sample Bsc Ltda.', :identifier => 'sample-bsc', :cnpj => VALID_CNPJ)
  26 + bsc.enterprises << e1
  27 + bsc.enterprises << e2
  28 + bsc.save!
  29 +
  30 + assert_equal e1.bsc, bsc
  31 + assert_equal e2.bsc, bsc
  32 + end
  33 +
  34 + should 'verify already requested enterprises' do
  35 + e1 = fast_create(Enterprise)
  36 + e2 = fast_create(Enterprise)
  37 + bsc = BscPlugin::Bsc.new()
  38 + task = BscPlugin::AssociateEnterprise.new(:target => e1, :bsc => bsc)
  39 + bsc.enterprise_requests.stubs(:pending).returns([task])
  40 +
  41 + assert bsc.already_requested?(e1)
  42 + assert !bsc.already_requested?(e2)
  43 + end
  44 +
  45 + should 'return associated enterprises products' do
  46 + e1 = fast_create(Enterprise)
  47 + e2 = fast_create(Enterprise)
  48 + category = fast_create(ProductCategory)
  49 + bsc = BscPlugin::Bsc.new()
  50 +
  51 + p1 = fast_create(Product, :product_category_id => category.id)
  52 + p2 = fast_create(Product, :product_category_id => category.id)
  53 + p3 = fast_create(Product, :product_category_id => category.id)
  54 +
  55 + e1.products << p1
  56 + e1.products << p2
  57 + e2.products << p3
  58 +
  59 + bsc.enterprises << e1
  60 + bsc.enterprises << e2
  61 +
  62 + assert_includes bsc.products, p1
  63 + assert_includes bsc.products, p2
  64 + assert_includes bsc.products, p3
  65 + end
  66 +
  67 + should 'reload products' do
  68 + e = fast_create(Enterprise)
  69 + category = fast_create(ProductCategory)
  70 + bsc = BscPlugin::Bsc.create!(:business_name => 'Sample Bsc', :company_name => 'Sample Bsc', :identifier => 'sample-bsc', :cnpj => VALID_CNPJ)
  71 + p = fast_create(Product, :product_category_id => category.id)
  72 +
  73 + e.bsc = bsc
  74 + e.save!
  75 + e.products << p
  76 +
  77 + assert_equal [], bsc.products
  78 + assert_equal [p], bsc.products(true)
  79 + end
  80 +
  81 + should 'not be able to create product' do
  82 + bsc = BscPlugin::Bsc.new
  83 + assert !bsc.create_product?
  84 + end
  85 +
  86 +end
... ...
plugins/bsc/test/unit/bsc_plugin/enterprise_test.rb 0 → 100644
... ... @@ -0,0 +1,26 @@
  1 +require File.dirname(__FILE__) + '/../../../../../test/test_helper'
  2 +require File.dirname(__FILE__) + '/../../../../../app/models/uploaded_file'
  3 +require File.dirname(__FILE__) + '/../../../../../app/models/enterprise'
  4 +require File.dirname(__FILE__) + '/../../../lib/ext/enterprise'
  5 +
  6 +class ProductTest < Test::Unit::TestCase
  7 + VALID_CNPJ = '94.132.024/0001-48'
  8 +
  9 + should 'belongs to a bsc' do
  10 + bsc = BscPlugin::Bsc.create!({:business_name => 'Sample Bsc', :identifier => 'sample-bsc', :company_name => 'Sample Bsc Ltda.', :cnpj => VALID_CNPJ})
  11 + enterprise = fast_create(Enterprise, :bsc_id => bsc.id)
  12 +
  13 + assert_equal bsc, enterprise.bsc
  14 + end
  15 +
  16 + should 'return correct enterprises on validated and not validated namedscopes' do
  17 + validated_enterprise = fast_create(Enterprise, :validated => true)
  18 + not_validated_enterprise = fast_create(Enterprise, :validated => false)
  19 +
  20 + assert_includes Enterprise.validated, validated_enterprise
  21 + assert_not_includes Enterprise.validated, not_validated_enterprise
  22 + assert_not_includes Enterprise.not_validated, validated_enterprise
  23 + assert_includes Enterprise.not_validated, not_validated_enterprise
  24 + end
  25 +end
  26 +
... ...
plugins/bsc/test/unit/bsc_plugin/product_test.rb 0 → 100644
... ... @@ -0,0 +1,14 @@
  1 +require File.dirname(__FILE__) + '/../../../../../test/test_helper'
  2 +require File.dirname(__FILE__) + '/../../../../../app/models/uploaded_file'
  3 +
  4 +class ProductTest < Test::Unit::TestCase
  5 + VALID_CNPJ = '94.132.024/0001-48'
  6 +
  7 + should 'return have bsc' do
  8 + bsc = BscPlugin::Bsc.create!({:business_name => 'Sample Bsc', :identifier => 'sample-bsc', :company_name => 'Sample Bsc Ltda.', :cnpj => VALID_CNPJ})
  9 + enterprise = fast_create(Enterprise, :bsc_id => bsc.id)
  10 + product = fast_create(Product, :enterprise_id => enterprise.id)
  11 +
  12 + assert_equal bsc, product.bsc
  13 + end
  14 +end
... ...
plugins/bsc/test/unit/bsc_plugin_test.rb 0 → 100644
... ... @@ -0,0 +1,36 @@
  1 +require File.dirname(__FILE__) + '/../../../../test/test_helper'
  2 +require File.dirname(__FILE__) + '/../../../../app/models/uploaded_file'
  3 +require File.dirname(__FILE__) + '/../../lib/ext/enterprise'
  4 +
  5 +class BscPluginTest < Test::Unit::TestCase
  6 +
  7 + VALID_CNPJ = '94.132.024/0001-48'
  8 +
  9 + should 'add profile controller filter correctly' do
  10 + bsc_plugin = BscPlugin.new
  11 + person = fast_create(Person)
  12 + context = mock()
  13 + context.stubs(:profile).returns(person)
  14 + context.stubs(:params).returns({:profile => person.identifier})
  15 + context.stubs(:user).returns(person)
  16 + context.stubs(:environment).returns(person.environment)
  17 + bsc_plugin.stubs(:context).returns(context)
  18 +
  19 + assert_nil bsc_plugin.profile_controller_filters.first[:block].call
  20 + assert_nil bsc_plugin.content_viewer_controller_filters.first[:block].call
  21 +
  22 + enterprise = fast_create(Enterprise, :validated => false)
  23 + enterprise.bsc = BscPlugin::Bsc.create!({:business_name => 'Sample Bsc', :identifier => 'sample-bsc', :company_name => 'Sample Bsc Ltda.', :cnpj => VALID_CNPJ})
  24 + enterprise.save!
  25 + context.stubs(:profile).returns(enterprise)
  26 + context.stubs(:params).returns({:profile => enterprise.identifier})
  27 + context.stubs(:environment).returns(enterprise.environment)
  28 +
  29 + assert_raise NameError do
  30 + bsc_plugin.profile_controller_filters.first[:block].call
  31 + end
  32 + assert_raise NameError do
  33 + bsc_plugin.content_viewer_controller_filters.first[:block].call
  34 + end
  35 + end
  36 +end
... ...
plugins/bsc/views/bsc_plugin/mailer/admin_notification.html.erb 0 → 100644
... ... @@ -0,0 +1 @@
  1 +<%= _('The management of %{bsc} was transferred to you.') % {:bsc => @bsc.name}%>
... ...
plugins/bsc/views/bsc_plugin_environment/new.html.erb 0 → 100644
... ... @@ -0,0 +1,11 @@
  1 +<%= error_messages_for :bsc %>
  2 +<h1><%= _('BSC registration') %></h1>
  3 +
  4 +<% labelled_form_for :profile_data, @bsc do |f| %>
  5 + <%= render :partial => 'shared/fields', :locals => {:f => f, :profile => @bsc} %>
  6 +
  7 + <% button_bar do %>
  8 + <%= submit_button('save', _('Save')) %>
  9 + <%= button('cancel', _('Cancel'), {:controller => 'admin_panel'}) %>
  10 + <% end %>
  11 +<% end %>
... ...
plugins/bsc/views/bsc_plugin_environment/validate_enterprises.html.erb 0 → 100644
... ... @@ -0,0 +1,31 @@
  1 +<h1><%= _('Validate enterprises') %></h1>
  2 +
  3 +<% form_tag :action => 'save_validations' do %>
  4 + <%= text_field_tag(:q, nil, :id => 'search-enterprises') %>
  5 +
  6 + <% button_bar do %>
  7 + <%= submit_button('save', _('Save'))%>
  8 + <%= button('cancel', _('Cancel'), {:controller => 'admin_panel'})%>
  9 + <% end %>
  10 +<% end %>
  11 +
  12 +<%= javascript_include_tag '/plugins/bsc/jquery_tokeninput/src/jquery.tokeninput.js' %>
  13 +<% stylesheet('/plugins/bsc/jquery_tokeninput/styles/token-input.css') %>
  14 +<% search_url = url_for(:action => 'search_enterprise') %>
  15 +<script type="text/javascript">
  16 + jQuery("#search-enterprises")
  17 + .tokenInput("<%= search_url %>", {
  18 + hintText: <%= _('Type in a search term for enterprise').to_json %>,
  19 + noResultsText: <%= _('No results').to_json %>,
  20 + searchingText: <%= _('Searching...').to_json %>,
  21 + searchDelay: 500,
  22 + backspaceDeleteItem: false
  23 + })
  24 + .focus();
  25 +
  26 + jQuery("#token-input-search-enterprises")
  27 + .live("keydown", function(event){
  28 + if(event.keyCode == "13") return false;
  29 + });
  30 +</script>
  31 +
... ...
plugins/bsc/views/bsc_plugin_myprofile/_similar_enterprises.html.erb 0 → 100644
... ... @@ -0,0 +1,48 @@
  1 +<div id="similar-enterprises" style="display: none; border-bottom: 2px solid #babdb6;">
  2 + <p><b><%= _('Existing enterprises:') %></b></p>
  3 + <p><i style="text-align: center;"><%= _('Were found %{count} enterprises with similar names on the same city, you can decide to associate one of them or create the new enterprise confirming the informations you typed in.') % {:count => content_tag('span', '', :id => 'similar-enterprises-count')} %></i></p>
  4 + <ul id="create-enterprise-similar-enterprises"></ul>
  5 + <% query = bsc.enterprises.map(&:id).join(',') %>
  6 + <script type="text/javascript">
  7 + update_enterprises = function(enterprises){
  8 + var association_url = <%= url_for({:controller => 'bsc_plugin_myprofile', :action => 'save_associations', :profile => bsc.identifier}).to_json %>;
  9 + jQuery('#create-enterprise-similar-enterprises').empty();
  10 + jQuery.each(enterprises, function(index, enterprise){
  11 + var id = enterprise[0]
  12 + var name = enterprise[1]
  13 + var query = <%= query.to_json %>;
  14 + if(query)
  15 + query += ',';
  16 + query += id.toString();
  17 + query = '?q='+query;
  18 + var url = association_url + query;
  19 + jQuery('#create-enterprise-similar-enterprises').append(
  20 + '<li>' + name + ' - <a href="' + url +'">' + <%= _('Associate').to_json %> + '</a></li>'
  21 + );
  22 + });
  23 + if (jQuery(enterprises).length > 0){
  24 + jQuery('#similar-enterprises-count').text(jQuery(enterprises).length.toString());
  25 + jQuery('#similar-enterprises').fadeIn();
  26 + }
  27 + else
  28 + jQuery('#similar-enterprises').fadeOut();
  29 + }
  30 + jQuery('#create_enterprise_name,#create_enterprise_city').change(function() {
  31 + var parameters = {};
  32 + if(jQuery('#create_enterprise_name').length)
  33 + parameters.name = jQuery('#create_enterprise_name').val();
  34 + if(jQuery('#create_enterprise_city').length)
  35 + parameters.city = jQuery('#create_enterprise_city').val();
  36 +
  37 + jQuery.ajax({
  38 + url: <%= url_for({:controller => 'bsc_plugin_myprofile', :action => 'similar_enterprises', :profile => bsc.identifier}).to_json %>,
  39 + dataType: 'json',
  40 + data: parameters,
  41 + success: function(data){ update_enterprises(data); },
  42 + error: function(ajax, stat, errorThrown) {
  43 + alert(stat+': '+errorThrown);
  44 + }
  45 + });
  46 + });
  47 + </script>
  48 +</div>
... ...
plugins/bsc/views/bsc_plugin_myprofile/create_enterprise.html.erb 0 → 100644
... ... @@ -0,0 +1,21 @@
  1 +<%= error_messages_for 'create_enterprise' %>
  2 +
  3 +<h1><%= __('Enterprise registration') %></h1>
  4 +
  5 +<%= required_fields_message %>
  6 +
  7 +<% labelled_form_for(:create_enterprise, @create_enterprise) do |f| %>
  8 +
  9 + <%= required f.text_field 'name', :onchange => "updateUrlField(this, 'create_enterprise_identifier')", :size => 40 %>
  10 + <%= render :partial => 'shared/organization_custom_fields', :locals => { :f => f, :object_name => :create_enterprise, :profile => @create_enterprise } %>
  11 + <p style="border-bottom: 2px solid #babdb6"></p>
  12 + <%= required labelled_form_field(_('Address'), content_tag('code', environment.top_url + "/" + text_field(:create_enterprise, 'identifier', :size => 26))) %>
  13 + <p style="border-bottom: 2px solid #babdb6"></p>
  14 + <%= render :partial => 'similar_enterprises', :locals => {:bsc => profile}%>
  15 +
  16 + <% button_bar do %>
  17 + <%= submit_button('save', _('Save'), :cancel => {:controller => 'profile_editor', :profile => profile.identifier}) %>
  18 + <% end %>
  19 +<% end %>
  20 +
  21 +
... ...
plugins/bsc/views/bsc_plugin_myprofile/manage_associated_enterprises.html.erb 0 → 100644
... ... @@ -0,0 +1,43 @@
  1 +<h1><%= _('Manage associated enterprises') %></h1>
  2 +
  3 +<% if !@pending_enterprises.blank? %>
  4 + <%= _('Associations awaiting approval:') %>
  5 + <ul>
  6 + <% @pending_enterprises.each do |enterprise| %>
  7 + <li><%= enterprise.name %></li>
  8 + <% end %>
  9 + </ul>
  10 +<% end %>
  11 +
  12 +<% form_tag :action => 'save_associations' do %>
  13 + <%= text_field_tag(:q, nil, :id => 'search-enterprises') %>
  14 +
  15 + <%= button('add', _('Add new enterprise'), {:action => 'create_enterprise'}) %>
  16 +
  17 + <% button_bar do %>
  18 + <%= submit_button('save', _('Save'))%>
  19 + <%= button('cancel', _('Cancel'), {:controller => 'profile_editor'})%>
  20 + <% end %>
  21 +
  22 +<% end %>
  23 +<%= javascript_include_tag '/plugins/bsc/jquery_tokeninput/src/jquery.tokeninput.js' %>
  24 +<% stylesheet('/plugins/bsc/jquery_tokeninput/styles/token-input.css') %>
  25 +<% search_url = url_for(:action => 'search_enterprise', :profile => profile.identifier) %>
  26 +<script type="text/javascript">
  27 + jQuery("#search-enterprises")
  28 + .tokenInput("<%= search_url %>", {
  29 + minChars: 3,
  30 + prePopulate: <%= profile.enterprises_to_json %>,
  31 + hintText: <%= _('Type in a search term for enterprise').to_json %>,
  32 + noResultsText: <%= _('No results').to_json %>,
  33 + searchingText: <%= _('Searching...').to_json %>,
  34 + searchDelay: 500,
  35 + backspaceDeleteItem: false
  36 + })
  37 + .focus();
  38 +
  39 + jQuery("#token-input-search-enterprises")
  40 + .live("keydown", function(event){
  41 + if(event.keyCode == "13") return false;
  42 + });
  43 +</script>
... ...
plugins/bsc/views/bsc_plugin_myprofile/transfer_ownership.html.erb 0 → 100644
... ... @@ -0,0 +1,54 @@
  1 +<h1><%= _('Transfer Ownership') %></h1>
  2 +
  3 +<div id='last-admin-message' style="margin-bottom: 20px;">
  4 + <%= _('This option allows you to transfer this enterprise\'s management to another user. This action will remove all the current administrators. Be careful when confirming this procedure.') %>
  5 +</div>
  6 +
  7 +<% if !profile.admins.blank? %>
  8 + <%= _('Current administrators:') %>
  9 + <ul style="list-style-type: none;">
  10 + <% profile.admins.each do |admin| %>
  11 + <li><%= link_to(profile_image(admin, :icon, :style => 'margin-right: 3px;'), admin.url) + link_to(admin.name, admin.url, :style => 'margin-top: -3px;') %></li>
  12 + <% end %>
  13 + </ul>
  14 +<% end %>
  15 +
  16 +<% form_tag do %>
  17 + <% @roles.each do |role|%>
  18 + <%= content_tag('b', _('Administrator:')) %>
  19 + <%= text_field_tag('q_'+role.key, nil, :id => 'search_'+role.key) %>
  20 + <% end %>
  21 +
  22 + <% button_bar do %>
  23 + <%= submit_button('save', _('Save'))%>
  24 + <%= button('cancel', _('Cancel'), {:controller => 'profile_editor'})%>
  25 + <% end %>
  26 +<% end %>
  27 +
  28 +<%= javascript_include_tag '/plugins/bsc/jquery_tokeninput/src/jquery.tokeninput.js' %>
  29 +<% stylesheet('/plugins/bsc/jquery_tokeninput/styles/token-input.css') %>
  30 +
  31 +<% @roles.each do |role| %>
  32 + <% search_url = url_for(:controller => 'profile_members', :action => 'search_user', :role => role.id, :profile => profile.identifier) %>
  33 + <script type="text/javascript">
  34 + jQuery(<%= ('#search_' + role.key).to_json %>)
  35 + .tokenInput("<%= search_url %>", {
  36 + hintText: <%= _('Type in a search term for the new administrator').to_json %>,
  37 + noResultsText: <%= _('No results').to_json %>,
  38 + searchingText: <%= _('Searching...').to_json %>,
  39 + searchDelay: 500,
  40 + backspaceDeleteItem: false,
  41 + preventDuplicates: true,
  42 + tokenLimit: 1,
  43 + queryParam: <%= ('q_'+role.key).to_json %>
  44 + })
  45 + .focus();
  46 +
  47 + jQuery("#token-input-search-enterprises")
  48 + .live("keydown", function(event){
  49 + if(event.keyCode == "13") return false;
  50 + });
  51 + </script>
  52 +<% end %>
  53 +
  54 +
... ...
plugins/bsc/views/profile/_profile_tab.html.erb 0 → 100644
... ... @@ -0,0 +1,6 @@
  1 +<ul>
  2 + <%= content_tag('li', content_tag('b', _('Contact phone: ')) + profile.contact_phone) if !profile.contact_phone.blank? %>
  3 + <%= content_tag('li', content_tag('b', _('Email: ')) + profile.contact_email) if !profile.contact_email.blank? %>
  4 + <%= content_tag('li', content_tag('b', _('Location: ')) + profile.state) if !profile.state.blank? %>
  5 + <%= content_tag('li', content_tag('b', _('Address: ')) + profile.address) if !profile.address.blank? %>
  6 +</ul>
... ...
plugins/bsc/views/profile_editor/bsc_plugin/_bsc.html.erb 0 → 100644
... ... @@ -0,0 +1,2 @@
  1 +<%= render :partial => 'shared/fields', :locals => {:f => f, :profile => profile} %>
  2 +<%= render :partial => 'moderation', :locals => { :profile => profile } %>
... ...
plugins/bsc/views/shared/_fields.html.erb 0 → 100644
... ... @@ -0,0 +1,66 @@
  1 +<!-- This line should be uncommented when bsc is merged with the former plugin -->
  2 +<%# extend FormerPlugin::FieldHelper %>
  3 +
  4 +<fieldset>
  5 + <legend><%= _('Basic information')%></legend>
  6 + <%= required f.text_field(:business_name, :onchange => "updateUrlField(this, 'profile_data_identifier')") %>
  7 + <%= required f.text_field(:company_name) %>
  8 + <%= required f.text_field(:cnpj) %>
  9 + <!-- This line should be uncommented when bsc is merged with the former plugin -->
  10 + <%#= widgets_for_form(f, :bsc_fields) %>
  11 +
  12 + <script type="text/javascript">
  13 + function submit_button(index) {
  14 + return $("profile_data_identifier").form.select("input.submit")[index];
  15 + }
  16 + function warn_value_change() {
  17 + show_warning('bsc-formitem', "identifier-change-confirmation");
  18 + disable_button(submit_button(0));
  19 + }
  20 + function confirm_change() {
  21 + enable_button(submit_button(0));
  22 + hide_warning('identifier-change-confirmation');
  23 + }
  24 + function no_change() {
  25 + $("profile_data_identifier").value = $("old_bsc_identifier").value;
  26 + enable_button(submit_button(0));
  27 + hide_warning('identifier-change-confirmation');
  28 + }
  29 + </script>
  30 +
  31 + <%= hidden_field_tag 'old_bsc_identifier', profile.identifier %>
  32 + <div id="bsc-formitem">
  33 + <%= content_tag('code',
  34 + environment.top_url + '/ ' +
  35 + text_field(:profile_data, :identifier, :onchange => "warn_value_change()", :size => 25)
  36 + ) +
  37 + content_tag('div',
  38 + content_tag('strong', _('WARNING!')) + '&nbsp;' +
  39 + _("You are about to change the address, and this will break external links to this bsc or to posts inside it. Do you really want to change?") +
  40 + content_tag('div',
  41 + button_to_function(:ok, _("Yes"), "confirm_change()") + ' ' +
  42 + button_to_function(:cancel, _('No'), 'no_change()')
  43 + ),
  44 + :id => 'identifier-change-confirmation',
  45 + :class => 'change-confirmation',
  46 + :style => 'display: none;'
  47 + )
  48 + %>
  49 + </div>
  50 +</fieldset>
  51 +
  52 +<fieldset>
  53 + <legend><%= _('Contact')%></legend>
  54 + <%= f.text_field(:contact_email) %>
  55 + <%= f.text_field(:organization_website) %>
  56 + <%= f.text_field(:contact_phone) %>
  57 +</fieldset>
  58 +
  59 +<fieldset>
  60 + <legend><%= _('Location')%></legend>
  61 + <%= f.text_field(:address) %>
  62 + <%= f.text_field(:zip_code) %>
  63 + <%= f.text_field(:city) %>
  64 + <%= f.text_field(:state) %>
  65 + <%= select_country(_('Country'), :profile_data, 'country', {:class => 'type-select'}) %>
  66 +</fieldset>
... ...
plugins/mezuro/lib/mezuro_plugin.rb
... ... @@ -19,7 +19,7 @@ class MezuroPlugin &lt; Noosfero::Plugin
19 19 MezuroPlugin::Project.by_profile(context.profile).with_tab.map do |project|
20 20 { :title => 'Mezuro ' + project.name,
21 21 :id => 'mezuro-project-'+project.identifier,
22   - :content => expanded_template("show.html.erb",{:current_project => project}) }
  22 + :content => lambda { render :partial => 'project_tab', :locals => {:current_project => project} } }
23 23 end
24 24 end
25 25 end
... ...
plugins/mezuro/views/profile/_project_tab.html.erb 0 → 100644
... ... @@ -0,0 +1,81 @@
  1 +<% @project = current_project %>
  2 +<% @total_metrics = @project.total_metrics if @project != nil %>
  3 +<% @statistical_metrics = @project.statistical_metrics if @project != nil %>
  4 +<% @svn_error = @project.svn_error if (@project != nil && @project.svn_error) %>
  5 +
  6 +<h1> <%= @project.name %>'s Info</h1>
  7 +<table id="show_info">
  8 + <tr>
  9 + <td><%= _("Name") %></td>
  10 + <td><%= @project.name %></td>
  11 + </tr>
  12 + <% if (@project.description != nil && @project.description != "" ) %>
  13 + <tr>
  14 + <td><%= _("Description") %></td>
  15 + <td><%= @project.description %></td>
  16 + </tr>
  17 + <% end %>
  18 + <tr>
  19 + <td><%= _("Repository address") %></td>
  20 + <td><%= @project.repository_url %></td>
  21 + </tr>
  22 +</table>
  23 +
  24 +<br />
  25 +
  26 +
  27 +<% if @svn_error %>
  28 + <h3>ERROR</h3>
  29 + <div id="svn_error">
  30 + <%= @svn_error %>
  31 + </div>
  32 + <br />
  33 + <br />
  34 + <p>
  35 + <%= _("Possible causes:") %>
  36 + <ul>
  37 + <li>
  38 + <%= _("Server is down") %>
  39 + </li>
  40 + <li>
  41 + <% _("URL invalid, in this case create another project with the correct URL
  42 + (Sorry for the incovenience, we're working for a better solution)") %>
  43 + </li>
  44 + </ul>
  45 + </p>
  46 +<%else%>
  47 + <h3> <%= _("Metric Results") %> </h3>
  48 + <% if @project.metrics_calculated? %>
  49 + <h3> <% _("Total Metrics") %> </h3>
  50 + <table id="total_metrics">
  51 + <% @total_metrics.each_with_index do |metric, index| %>
  52 + <tr id="tr_<%= metric.name %>" class="d<%= index % 2 %>">
  53 + <td class="metric_name"> <%= metric.name %> </td>
  54 + <td class="metric_value"> <%= metric.value %> </td>
  55 + </tr>
  56 + <% end %>
  57 + </table>
  58 +
  59 + <h3> <%= _("Statistical Metrics") %> </h3>
  60 + <% @statistical_metrics.each_key do |metric_name| %>
  61 + <div id="statistical_metrics">
  62 + <%= "#{metric_name}_average: #{@statistical_metrics[metric_name]["average"]}" %>
  63 + <ul>
  64 + <% @statistical_metrics[metric_name].each do |stat_name, stat_value| %>
  65 + <% if stat_name != "average" %>
  66 + <li>
  67 + <%= "#{metric_name}_#{stat_name}: #{stat_value}" %>
  68 + </li>
  69 + <% end %>
  70 + <% end %>
  71 + </ul>
  72 + </div>
  73 + <% end %>
  74 +
  75 + <% else %>
  76 + <div id="progress_message">
  77 + <%= _("Wait a moment while the metrics are calculated.<br/>
  78 + Reload the page manually in a few moment. ") %>
  79 + </div>
  80 + <% end %>
  81 +<% end %>
... ...
plugins/mezuro/views/show.html.erb
... ... @@ -1,81 +0,0 @@
1   -<% @project = locals[:current_project] %>
2   -<% @total_metrics = @project.total_metrics if @project != nil %>
3   -<% @statistical_metrics = @project.statistical_metrics if @project != nil %>
4   -<% @svn_error = @project.svn_error if (@project != nil && @project.svn_error) %>
5   -
6   -<h1> <%= @project.name %>'s Info</h1>
7   -<table id="show_info">
8   - <tr>
9   - <td><%= _("Name") %></td>
10   - <td><%= @project.name %></td>
11   - </tr>
12   - <% if (@project.description != nil && @project.description != "" ) %>
13   - <tr>
14   - <td><%= _("Description") %></td>
15   - <td><%= @project.description %></td>
16   - </tr>
17   - <% end %>
18   - <tr>
19   - <td><%= _("Repository address") %></td>
20   - <td><%= @project.repository_url %></td>
21   - </tr>
22   -</table>
23   -
24   -<br />
25   -
26   -
27   -<% if @svn_error %>
28   - <h3>ERROR</h3>
29   - <div id="svn_error">
30   - <%= @svn_error %>
31   - </div>
32   - <br />
33   - <br />
34   - <p>
35   - <%= _("Possible causes:") %>
36   - <ul>
37   - <li>
38   - <%= _("Server is down") %>
39   - </li>
40   - <li>
41   - <% _("URL invalid, in this case create another project with the correct URL
42   - (Sorry for the incovenience, we're working for a better solution)") %>
43   - </li>
44   - </ul>
45   - </p>
46   -<%else%>
47   - <h3> <%= _("Metric Results") %> </h3>
48   - <% if @project.metrics_calculated? %>
49   - <h3> <% _("Total Metrics") %> </h3>
50   - <table id="total_metrics">
51   - <% @total_metrics.each_with_index do |metric, index| %>
52   - <tr id="tr_<%= metric.name %>" class="d<%= index % 2 %>">
53   - <td class="metric_name"> <%= metric.name %> </td>
54   - <td class="metric_value"> <%= metric.value %> </td>
55   - </tr>
56   - <% end %>
57   - </table>
58   -
59   - <h3> <%= _("Statistical Metrics") %> </h3>
60   - <% @statistical_metrics.each_key do |metric_name| %>
61   - <div id="statistical_metrics">
62   - <%= "#{metric_name}_average: #{@statistical_metrics[metric_name]["average"]}" %>
63   - <ul>
64   - <% @statistical_metrics[metric_name].each do |stat_name, stat_value| %>
65   - <% if stat_name != "average" %>
66   - <li>
67   - <%= "#{metric_name}_#{stat_name}: #{stat_value}" %>
68   - </li>
69   - <% end %>
70   - <% end %>
71   - </ul>
72   - </div>
73   - <% end %>
74   -
75   - <% else %>
76   - <div id="progress_message">
77   - <%= _("Wait a moment while the metrics are calculated.<br/>
78   - Reload the page manually in a few moment. ") %>
79   - </div>
80   - <% end %>
81   -<% end %>
public/javascripts/jquery.tokeninput.js 0 → 100644
... ... @@ -0,0 +1,793 @@
  1 +/*
  2 + * jQuery Plugin: Tokenizing Autocomplete Text Entry
  3 + * Version 1.5.0
  4 + *
  5 + * Copyright (c) 2009 James Smith (http://loopj.com)
  6 + * Licensed jointly under the GPL and MIT licenses,
  7 + * choose which one suits your project best!
  8 + *
  9 + */
  10 +
  11 +(function ($) {
  12 +// Default settings
  13 +var DEFAULT_SETTINGS = {
  14 + hintText: "Type in a search term",
  15 + noResultsText: "No results",
  16 + searchingText: "Searching...",
  17 + deleteText: "&times;",
  18 + searchDelay: 300,
  19 + minChars: 1,
  20 + tokenLimit: null,
  21 + jsonContainer: null,
  22 + method: "GET",
  23 + contentType: "json",
  24 + queryParam: "q",
  25 + tokenDelimiter: ",",
  26 + preventDuplicates: false,
  27 + prePopulate: null,
  28 + processPrePopulate: false,
  29 + animateDropdown: true,
  30 + onResult: null,
  31 + onAdd: null,
  32 + onDelete: null,
  33 + idPrefix: "token-input-",
  34 + backspaceDeleteItem: true
  35 +};
  36 +
  37 +// Default classes to use when theming
  38 +var DEFAULT_CLASSES = {
  39 + tokenList: "token-input-list",
  40 + token: "token-input-token",
  41 + tokenDelete: "token-input-delete-token",
  42 + selectedToken: "token-input-selected-token",
  43 + highlightedToken: "token-input-highlighted-token",
  44 + dropdown: "token-input-dropdown",
  45 + dropdownItem: "token-input-dropdown-item",
  46 + dropdownItem2: "token-input-dropdown-item2",
  47 + selectedDropdownItem: "token-input-selected-dropdown-item",
  48 + inputToken: "token-input-input-token"
  49 +};
  50 +
  51 +// Input box position "enum"
  52 +var POSITION = {
  53 + BEFORE: 0,
  54 + AFTER: 1,
  55 + END: 2
  56 +};
  57 +
  58 +// Keys "enum"
  59 +var KEY = {
  60 + BACKSPACE: 8,
  61 + TAB: 9,
  62 + ENTER: 13,
  63 + ESCAPE: 27,
  64 + SPACE: 32,
  65 + PAGE_UP: 33,
  66 + PAGE_DOWN: 34,
  67 + END: 35,
  68 + HOME: 36,
  69 + LEFT: 37,
  70 + UP: 38,
  71 + RIGHT: 39,
  72 + DOWN: 40,
  73 + NUMPAD_ENTER: 108,
  74 + COMMA: 188
  75 +};
  76 +
  77 +// Additional public (exposed) methods
  78 +var methods = {
  79 + init: function(url_or_data_or_function, options) {
  80 + var settings = $.extend({}, DEFAULT_SETTINGS, options || {});
  81 +
  82 + return this.each(function () {
  83 + $(this).data("tokenInputObject", new $.TokenList(this, url_or_data_or_function, settings));
  84 + });
  85 + },
  86 + clear: function() {
  87 + this.data("tokenInputObject").clear();
  88 + return this;
  89 + },
  90 + add: function(item) {
  91 + this.data("tokenInputObject").add(item);
  92 + return this;
  93 + },
  94 + remove: function(item) {
  95 + this.data("tokenInputObject").remove(item);
  96 + return this;
  97 + }
  98 +}
  99 +
  100 +// Expose the .tokenInput function to jQuery as a plugin
  101 +$.fn.tokenInput = function (method) {
  102 + // Method calling and initialization logic
  103 + if(methods[method]) {
  104 + return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
  105 + } else {
  106 + return methods.init.apply(this, arguments);
  107 + }
  108 +};
  109 +
  110 +// TokenList class for each input
  111 +$.TokenList = function (input, url_or_data, settings) {
  112 + //
  113 + // Initialization
  114 + //
  115 +
  116 + // Configure the data source
  117 + if(typeof(url_or_data) === "string") {
  118 + // Set the url to query against
  119 + settings.url = url_or_data;
  120 +
  121 + // Make a smart guess about cross-domain if it wasn't explicitly specified
  122 + if(settings.crossDomain === undefined) {
  123 + if(settings.url.indexOf("://") === -1) {
  124 + settings.crossDomain = false;
  125 + } else {
  126 + settings.crossDomain = (location.href.split(/\/+/g)[1] !== settings.url.split(/\/+/g)[1]);
  127 + }
  128 + }
  129 + } else if(typeof(url_or_data) === "object") {
  130 + // Set the local data to search through
  131 + settings.local_data = url_or_data;
  132 + }
  133 +
  134 + // Build class names
  135 + if(settings.classes) {
  136 + // Use custom class names
  137 + settings.classes = $.extend({}, DEFAULT_CLASSES, settings.classes);
  138 + } else if(settings.theme) {
  139 + // Use theme-suffixed default class names
  140 + settings.classes = {};
  141 + $.each(DEFAULT_CLASSES, function(key, value) {
  142 + settings.classes[key] = value + "-" + settings.theme;
  143 + });
  144 + } else {
  145 + settings.classes = DEFAULT_CLASSES;
  146 + }
  147 +
  148 +
  149 + // Save the tokens
  150 + var saved_tokens = [];
  151 +
  152 + // Keep track of the number of tokens in the list
  153 + var token_count = 0;
  154 +
  155 + // Basic cache to save on db hits
  156 + var cache = new $.TokenList.Cache();
  157 +
  158 + // Keep track of the timeout, old vals
  159 + var timeout;
  160 + var input_val;
  161 +
  162 + // Create a new text input an attach keyup events
  163 + var input_box = $("<input type=\"text\" autocomplete=\"off\">")
  164 + .css({
  165 + outline: "none"
  166 + })
  167 + .attr("id", settings.idPrefix + input.id)
  168 + .focus(function () {
  169 + if (settings.tokenLimit === null || settings.tokenLimit !== token_count) {
  170 + show_dropdown_hint();
  171 + }
  172 + })
  173 + .blur(function () {
  174 + hide_dropdown();
  175 + $(this).val("");
  176 + })
  177 + .bind("keyup keydown blur update", resize_input)
  178 + .keydown(function (event) {
  179 + var previous_token;
  180 + var next_token;
  181 +
  182 + switch(event.keyCode) {
  183 + case KEY.LEFT:
  184 + case KEY.RIGHT:
  185 + case KEY.UP:
  186 + case KEY.DOWN:
  187 + if(!$(this).val()) {
  188 + previous_token = input_token.prev();
  189 + next_token = input_token.next();
  190 +
  191 + if((previous_token.length && previous_token.get(0) === selected_token) || (next_token.length && next_token.get(0) === selected_token)) {
  192 + // Check if there is a previous/next token and it is selected
  193 + if(event.keyCode === KEY.LEFT || event.keyCode === KEY.UP) {
  194 + deselect_token($(selected_token), POSITION.BEFORE);
  195 + } else {
  196 + deselect_token($(selected_token), POSITION.AFTER);
  197 + }
  198 + } else if((event.keyCode === KEY.LEFT || event.keyCode === KEY.UP) && previous_token.length) {
  199 + // We are moving left, select the previous token if it exists
  200 + select_token($(previous_token.get(0)));
  201 + } else if((event.keyCode === KEY.RIGHT || event.keyCode === KEY.DOWN) && next_token.length) {
  202 + // We are moving right, select the next token if it exists
  203 + select_token($(next_token.get(0)));
  204 + }
  205 + } else {
  206 + var dropdown_item = null;
  207 +
  208 + if(event.keyCode === KEY.DOWN || event.keyCode === KEY.RIGHT) {
  209 + dropdown_item = $(selected_dropdown_item).next();
  210 + } else {
  211 + dropdown_item = $(selected_dropdown_item).prev();
  212 + }
  213 +
  214 + if(dropdown_item.length) {
  215 + select_dropdown_item(dropdown_item);
  216 + }
  217 + return false;
  218 + }
  219 + break;
  220 +
  221 + case KEY.BACKSPACE:
  222 + previous_token = input_token.prev();
  223 + if(!$(this).val().length && settings.backspaceDeleteItem) {
  224 + if(selected_token) {
  225 + delete_token($(selected_token));
  226 + } else if(previous_token.length) {
  227 + select_token($(previous_token.get(0)));
  228 + }
  229 +
  230 + return false;
  231 + } else if($(this).val().length === 1) {
  232 + hide_dropdown();
  233 + } else {
  234 + // set a timeout just long enough to let this function finish.
  235 + setTimeout(function(){do_search();}, 5);
  236 + }
  237 + break;
  238 +
  239 + case KEY.TAB:
  240 + case KEY.ENTER:
  241 + case KEY.NUMPAD_ENTER:
  242 + case KEY.COMMA:
  243 + if(selected_dropdown_item) {
  244 + add_token($(selected_dropdown_item).data("tokeninput"));
  245 + return false;
  246 + }
  247 + break;
  248 +
  249 + case KEY.ESCAPE:
  250 + hide_dropdown();
  251 + return true;
  252 +
  253 + default:
  254 + if(String.fromCharCode(event.which)) {
  255 + // set a timeout just long enough to let this function finish.
  256 + setTimeout(function(){do_search();}, 5);
  257 + }
  258 + break;
  259 + }
  260 + });
  261 +
  262 + // Keep a reference to the original input box
  263 + var hidden_input = $(input)
  264 + .hide()
  265 + .val("")
  266 + .focus(function () {
  267 + input_box.focus();
  268 + })
  269 + .blur(function () {
  270 + input_box.blur();
  271 + });
  272 +
  273 + // Keep a reference to the selected token and dropdown item
  274 + var selected_token = null;
  275 + var selected_token_index = 0;
  276 + var selected_dropdown_item = null;
  277 +
  278 + // The list to store the token items in
  279 + var token_list = $("<ul />")
  280 + .addClass(settings.classes.tokenList)
  281 + .click(function (event) {
  282 + var li = $(event.target).closest("li");
  283 + if(li && li.get(0) && $.data(li.get(0), "tokeninput")) {
  284 + toggle_select_token(li);
  285 + } else {
  286 + // Deselect selected token
  287 + if(selected_token) {
  288 + deselect_token($(selected_token), POSITION.END);
  289 + }
  290 +
  291 + // Focus input box
  292 + input_box.focus();
  293 + }
  294 + })
  295 + .mouseover(function (event) {
  296 + var li = $(event.target).closest("li");
  297 + if(li && selected_token !== this) {
  298 + li.addClass(settings.classes.highlightedToken);
  299 + }
  300 + })
  301 + .mouseout(function (event) {
  302 + var li = $(event.target).closest("li");
  303 + if(li && selected_token !== this) {
  304 + li.removeClass(settings.classes.highlightedToken);
  305 + }
  306 + })
  307 + .insertBefore(hidden_input);
  308 +
  309 + // The token holding the input box
  310 + var input_token = $("<li />")
  311 + .addClass(settings.classes.inputToken)
  312 + .appendTo(token_list)
  313 + .append(input_box);
  314 +
  315 + // The list to store the dropdown items in
  316 + var dropdown = $("<div>")
  317 + .addClass(settings.classes.dropdown)
  318 + .appendTo("body")
  319 + .hide();
  320 +
  321 + // Magic element to help us resize the text input
  322 + var input_resizer = $("<tester/>")
  323 + .insertAfter(input_box)
  324 + .css({
  325 + position: "absolute",
  326 + top: -9999,
  327 + left: -9999,
  328 + width: "auto",
  329 + fontSize: input_box.css("fontSize"),
  330 + fontFamily: input_box.css("fontFamily"),
  331 + fontWeight: input_box.css("fontWeight"),
  332 + letterSpacing: input_box.css("letterSpacing"),
  333 + whiteSpace: "nowrap"
  334 + });
  335 +
  336 + // Pre-populate list if items exist
  337 + hidden_input.val("");
  338 + var li_data = settings.prePopulate || hidden_input.data("pre");
  339 + if(settings.processPrePopulate && $.isFunction(settings.onResult)) {
  340 + li_data = settings.onResult.call(hidden_input, li_data);
  341 + }
  342 + if(li_data && li_data.length) {
  343 + $.each(li_data, function (index, value) {
  344 + insert_token(value);
  345 + checkTokenLimit();
  346 + });
  347 + }
  348 +
  349 +
  350 + //
  351 + // Public functions
  352 + //
  353 +
  354 + this.clear = function() {
  355 + token_list.children("li").each(function() {
  356 + if ($(this).children("input").length === 0) {
  357 + delete_token($(this));
  358 + }
  359 + });
  360 + }
  361 +
  362 + this.add = function(item) {
  363 + add_token(item);
  364 + }
  365 +
  366 + this.remove = function(item) {
  367 + token_list.children("li").each(function() {
  368 + if ($(this).children("input").length === 0) {
  369 + var currToken = $(this).data("tokeninput");
  370 + var match = true;
  371 + for (var prop in item) {
  372 + if (item[prop] !== currToken[prop]) {
  373 + match = false;
  374 + break;
  375 + }
  376 + }
  377 + if (match) {
  378 + delete_token($(this));
  379 + }
  380 + }
  381 + });
  382 + }
  383 +
  384 + //
  385 + // Private functions
  386 + //
  387 +
  388 + function checkTokenLimit() {
  389 + if(settings.tokenLimit !== null && token_count >= settings.tokenLimit) {
  390 + input_box.hide();
  391 + hide_dropdown();
  392 + return;
  393 + } else {
  394 + input_box.focus();
  395 + }
  396 + }
  397 +
  398 + function resize_input() {
  399 + if(input_val === (input_val = input_box.val())) {return;}
  400 +
  401 + // Enter new content into resizer and resize input accordingly
  402 + var escaped = input_val.replace(/&/g, '&amp;').replace(/\s/g,' ').replace(/</g, '&lt;').replace(/>/g, '&gt;');
  403 + input_resizer.html(escaped);
  404 + input_box.width(input_resizer.width() + 30);
  405 + }
  406 +
  407 + function is_printable_character(keycode) {
  408 + return ((keycode >= 48 && keycode <= 90) || // 0-1a-z
  409 + (keycode >= 96 && keycode <= 111) || // numpad 0-9 + - / * .
  410 + (keycode >= 186 && keycode <= 192) || // ; = , - . / ^
  411 + (keycode >= 219 && keycode <= 222)); // ( \ ) '
  412 + }
  413 +
  414 + // Inner function to a token to the list
  415 + function insert_token(item) {
  416 + var this_token = $("<li><p>"+ item.name +"</p></li>")
  417 + .addClass(settings.classes.token)
  418 + .insertBefore(input_token);
  419 +
  420 + // The 'delete token' button
  421 + $("<span>" + settings.deleteText + "</span>")
  422 + .addClass(settings.classes.tokenDelete)
  423 + .appendTo(this_token)
  424 + .click(function () {
  425 + delete_token($(this).parent());
  426 + return false;
  427 + });
  428 +
  429 + // Store data on the token
  430 + var token_data = {"id": item.id, "name": item.name};
  431 + $.data(this_token.get(0), "tokeninput", item);
  432 +
  433 + // Save this token for duplicate checking
  434 + saved_tokens = saved_tokens.slice(0,selected_token_index).concat([token_data]).concat(saved_tokens.slice(selected_token_index));
  435 + selected_token_index++;
  436 +
  437 + // Update the hidden input
  438 + var token_ids = $.map(saved_tokens, function (el) {
  439 + return el.id;
  440 + });
  441 + hidden_input.val(token_ids.join(settings.tokenDelimiter));
  442 +
  443 + token_count += 1;
  444 +
  445 + return this_token;
  446 + }
  447 +
  448 + // Add a token to the token list based on user input
  449 + function add_token (item) {
  450 + var callback = settings.onAdd;
  451 +
  452 + // See if the token already exists and select it if we don't want duplicates
  453 + if(token_count > 0 && settings.preventDuplicates) {
  454 + var found_existing_token = null;
  455 + token_list.children().each(function () {
  456 + var existing_token = $(this);
  457 + var existing_data = $.data(existing_token.get(0), "tokeninput");
  458 + if(existing_data && existing_data.id === item.id) {
  459 + found_existing_token = existing_token;
  460 + return false;
  461 + }
  462 + });
  463 +
  464 + if(found_existing_token) {
  465 + select_token(found_existing_token);
  466 + input_token.insertAfter(found_existing_token);
  467 + input_box.focus();
  468 + return;
  469 + }
  470 + }
  471 +
  472 + // Insert the new tokens
  473 + insert_token(item);
  474 + checkTokenLimit();
  475 +
  476 + // Clear input box
  477 + input_box.val("");
  478 +
  479 + // Don't show the help dropdown, they've got the idea
  480 + hide_dropdown();
  481 +
  482 + // Execute the onAdd callback if defined
  483 + if($.isFunction(callback)) {
  484 + callback.call(hidden_input,item);
  485 + }
  486 + }
  487 +
  488 + // Select a token in the token list
  489 + function select_token (token) {
  490 + token.addClass(settings.classes.selectedToken);
  491 + selected_token = token.get(0);
  492 +
  493 + // Hide input box
  494 + input_box.val("");
  495 +
  496 + // Hide dropdown if it is visible (eg if we clicked to select token)
  497 + hide_dropdown();
  498 + }
  499 +
  500 + // Deselect a token in the token list
  501 + function deselect_token (token, position) {
  502 + token.removeClass(settings.classes.selectedToken);
  503 + selected_token = null;
  504 +
  505 + if(position === POSITION.BEFORE) {
  506 + input_token.insertBefore(token);
  507 + selected_token_index--;
  508 + } else if(position === POSITION.AFTER) {
  509 + input_token.insertAfter(token);
  510 + selected_token_index++;
  511 + } else {
  512 + input_token.appendTo(token_list);
  513 + selected_token_index = token_count;
  514 + }
  515 +
  516 + // Show the input box and give it focus again
  517 + input_box.focus();
  518 + }
  519 +
  520 + // Toggle selection of a token in the token list
  521 + function toggle_select_token(token) {
  522 + var previous_selected_token = selected_token;
  523 +
  524 + if(selected_token) {
  525 + deselect_token($(selected_token), POSITION.END);
  526 + }
  527 +
  528 + if(previous_selected_token === token.get(0)) {
  529 + deselect_token(token, POSITION.END);
  530 + } else {
  531 + select_token(token);
  532 + }
  533 + }
  534 +
  535 + // Delete a token from the token list
  536 + function delete_token (token) {
  537 + // Remove the id from the saved list
  538 + var token_data = $.data(token.get(0), "tokeninput");
  539 + var callback = settings.onDelete;
  540 +
  541 + var index = token.prevAll().length;
  542 + if(index > selected_token_index) index--;
  543 +
  544 + // Delete the token
  545 + token.remove();
  546 + selected_token = null;
  547 +
  548 + // Show the input box and give it focus again
  549 + input_box.focus();
  550 +
  551 + // Remove this token from the saved list
  552 + saved_tokens = saved_tokens.slice(0,index).concat(saved_tokens.slice(index+1));
  553 + if(index < selected_token_index) selected_token_index--;
  554 +
  555 + // Update the hidden input
  556 + var token_ids = $.map(saved_tokens, function (el) {
  557 + return el.id;
  558 + });
  559 + hidden_input.val(token_ids.join(settings.tokenDelimiter));
  560 +
  561 + token_count -= 1;
  562 +
  563 + if(settings.tokenLimit !== null) {
  564 + input_box
  565 + .show()
  566 + .val("")
  567 + .focus();
  568 + }
  569 +
  570 + // Execute the onDelete callback if defined
  571 + if($.isFunction(callback)) {
  572 + callback.call(hidden_input,token_data);
  573 + }
  574 + }
  575 +
  576 + // Hide and clear the results dropdown
  577 + function hide_dropdown () {
  578 + dropdown.hide().empty();
  579 + selected_dropdown_item = null;
  580 + }
  581 +
  582 + function show_dropdown() {
  583 + dropdown
  584 + .css({
  585 + position: "absolute",
  586 + top: $(token_list).offset().top + $(token_list).outerHeight(),
  587 + left: $(token_list).offset().left,
  588 + zindex: 999
  589 + })
  590 + .show();
  591 + }
  592 +
  593 + function show_dropdown_searching () {
  594 + if(settings.searchingText) {
  595 + dropdown.html("<p>"+settings.searchingText+"</p>");
  596 + show_dropdown();
  597 + }
  598 + }
  599 +
  600 + function show_dropdown_hint () {
  601 + if(settings.hintText) {
  602 + dropdown.html("<p>"+settings.hintText+"</p>");
  603 + show_dropdown();
  604 + }
  605 + }
  606 +
  607 + // Highlight the query part of the search term
  608 + function highlight_term(value, term) {
  609 + return value.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + term + ")(?![^<>]*>)(?![^&;]+;)", "gi"), "<b>$1</b>");
  610 + }
  611 +
  612 + // Populate the results dropdown with some results
  613 + function populate_dropdown (query, results) {
  614 + if(results && results.length) {
  615 + dropdown.empty();
  616 + var dropdown_ul = $("<ul>")
  617 + .appendTo(dropdown)
  618 + .mouseover(function (event) {
  619 + select_dropdown_item($(event.target).closest("li"));
  620 + })
  621 + .mousedown(function (event) {
  622 + add_token($(event.target).closest("li").data("tokeninput"));
  623 + return false;
  624 + })
  625 + .hide();
  626 +
  627 + $.each(results, function(index, value) {
  628 + var this_li = $("<li>" + highlight_term(value.name, query) + "</li>")
  629 + .appendTo(dropdown_ul);
  630 +
  631 + if(index % 2) {
  632 + this_li.addClass(settings.classes.dropdownItem);
  633 + } else {
  634 + this_li.addClass(settings.classes.dropdownItem2);
  635 + }
  636 +
  637 + if(index === 0) {
  638 + select_dropdown_item(this_li);
  639 + }
  640 +
  641 + $.data(this_li.get(0), "tokeninput", value);
  642 + });
  643 +
  644 + show_dropdown();
  645 +
  646 + if(settings.animateDropdown) {
  647 + dropdown_ul.slideDown("fast");
  648 + } else {
  649 + dropdown_ul.show();
  650 + }
  651 + } else {
  652 + if(settings.noResultsText) {
  653 + dropdown.html("<p>"+settings.noResultsText+"</p>");
  654 + show_dropdown();
  655 + }
  656 + }
  657 + }
  658 +
  659 + // Highlight an item in the results dropdown
  660 + function select_dropdown_item (item) {
  661 + if(item) {
  662 + if(selected_dropdown_item) {
  663 + deselect_dropdown_item($(selected_dropdown_item));
  664 + }
  665 +
  666 + item.addClass(settings.classes.selectedDropdownItem);
  667 + selected_dropdown_item = item.get(0);
  668 + }
  669 + }
  670 +
  671 + // Remove highlighting from an item in the results dropdown
  672 + function deselect_dropdown_item (item) {
  673 + item.removeClass(settings.classes.selectedDropdownItem);
  674 + selected_dropdown_item = null;
  675 + }
  676 +
  677 + // Do a search and show the "searching" dropdown if the input is longer
  678 + // than settings.minChars
  679 + function do_search() {
  680 + var query = input_box.val().toLowerCase();
  681 +
  682 + if(query && query.length) {
  683 + if(selected_token) {
  684 + deselect_token($(selected_token), POSITION.AFTER);
  685 + }
  686 +
  687 + if(query.length >= settings.minChars) {
  688 + show_dropdown_searching();
  689 + clearTimeout(timeout);
  690 +
  691 + timeout = setTimeout(function(){
  692 + run_search(query);
  693 + }, settings.searchDelay);
  694 + } else {
  695 + hide_dropdown();
  696 + }
  697 + }
  698 + }
  699 +
  700 + // Do the actual search
  701 + function run_search(query) {
  702 + var cached_results = cache.get(query);
  703 + if(cached_results) {
  704 + populate_dropdown(query, cached_results);
  705 + } else {
  706 + // Are we doing an ajax search or local data search?
  707 + if(settings.url) {
  708 + // Extract exisiting get params
  709 + var ajax_params = {};
  710 + ajax_params.data = {};
  711 + if(settings.url.indexOf("?") > -1) {
  712 + var parts = settings.url.split("?");
  713 + ajax_params.url = parts[0];
  714 +
  715 + var param_array = parts[1].split("&");
  716 + $.each(param_array, function (index, value) {
  717 + var kv = value.split("=");
  718 + ajax_params.data[kv[0]] = kv[1];
  719 + });
  720 + } else {
  721 + ajax_params.url = settings.url;
  722 + }
  723 +
  724 + // Prepare the request
  725 + ajax_params.data[settings.queryParam] = query;
  726 + ajax_params.type = settings.method;
  727 + ajax_params.dataType = settings.contentType;
  728 + if(settings.crossDomain) {
  729 + ajax_params.dataType = "jsonp";
  730 + }
  731 +
  732 + // Attach the success callback
  733 + ajax_params.success = function(results) {
  734 + if($.isFunction(settings.onResult)) {
  735 + results = settings.onResult.call(hidden_input, results);
  736 + }
  737 + cache.add(query, settings.jsonContainer ? results[settings.jsonContainer] : results);
  738 +
  739 + // only populate the dropdown if the results are associated with the active search query
  740 + if(input_box.val().toLowerCase() === query) {
  741 + populate_dropdown(query, settings.jsonContainer ? results[settings.jsonContainer] : results);
  742 + }
  743 + };
  744 +
  745 + // Make the request
  746 + $.ajax(ajax_params);
  747 + } else if(settings.local_data) {
  748 + // Do the search through local data
  749 + var results = $.grep(settings.local_data, function (row) {
  750 + return row.name.toLowerCase().indexOf(query.toLowerCase()) > -1;
  751 + });
  752 +
  753 + if($.isFunction(settings.onResult)) {
  754 + results = settings.onResult.call(hidden_input, results);
  755 + }
  756 + cache.add(query, results);
  757 + populate_dropdown(query, results);
  758 + }
  759 + }
  760 + }
  761 +};
  762 +
  763 +// Really basic cache for the results
  764 +$.TokenList.Cache = function (options) {
  765 + var settings = $.extend({
  766 + max_size: 500
  767 + }, options);
  768 +
  769 + var data = {};
  770 + var size = 0;
  771 +
  772 + var flush = function () {
  773 + data = {};
  774 + size = 0;
  775 + };
  776 +
  777 + this.add = function (query, results) {
  778 + if(size > settings.max_size) {
  779 + flush();
  780 + }
  781 +
  782 + if(!data[query]) {
  783 + size += 1;
  784 + }
  785 +
  786 + data[query] = results;
  787 + };
  788 +
  789 + this.get = function (query) {
  790 + return data[query];
  791 + };
  792 +};
  793 +}(jQuery));
... ...
public/stylesheets/token-input-facebook.css 0 → 100644
... ... @@ -0,0 +1,122 @@
  1 +/* Example tokeninput style #2: Facebook style */
  2 +ul.token-input-list-facebook {
  3 + overflow: hidden;
  4 + height: auto !important;
  5 + height: 1%;
  6 + width: 400px;
  7 + border: 1px solid #8496ba;
  8 + cursor: text;
  9 + font-size: 12px;
  10 + font-family: Verdana;
  11 + min-height: 1px;
  12 + z-index: 999;
  13 + margin: 0;
  14 + padding: 0;
  15 + background-color: #fff;
  16 + list-style-type: none;
  17 + clear: left;
  18 +}
  19 +
  20 +ul.token-input-list-facebook li input {
  21 + border: 0;
  22 + width: 100px;
  23 + padding: 3px 8px;
  24 + background-color: white;
  25 + margin: 2px 0;
  26 + -webkit-appearance: caret;
  27 +}
  28 +
  29 +li.token-input-token-facebook {
  30 + overflow: hidden;
  31 + height: auto !important;
  32 + height: 15px;
  33 + margin: 3px;
  34 + padding: 1px 3px;
  35 + background-color: #eff2f7;
  36 + color: #000;
  37 + cursor: default;
  38 + border: 1px solid #ccd5e4;
  39 + font-size: 11px;
  40 + border-radius: 5px;
  41 + -moz-border-radius: 5px;
  42 + -webkit-border-radius: 5px;
  43 + float: left;
  44 + white-space: nowrap;
  45 +}
  46 +
  47 +li.token-input-token-facebook p {
  48 + display: inline;
  49 + padding: 0;
  50 + margin: 0;
  51 +}
  52 +
  53 +li.token-input-token-facebook span {
  54 + color: #a6b3cf;
  55 + margin-left: 5px;
  56 + font-weight: bold;
  57 + cursor: pointer;
  58 +}
  59 +
  60 +li.token-input-selected-token-facebook {
  61 + background-color: #5670a6;
  62 + border: 1px solid #3b5998;
  63 + color: #fff;
  64 +}
  65 +
  66 +li.token-input-input-token-facebook {
  67 + float: left;
  68 + margin: 0;
  69 + padding: 0;
  70 + list-style-type: none;
  71 +}
  72 +
  73 +div.token-input-dropdown-facebook {
  74 + position: absolute;
  75 + width: 400px;
  76 + background-color: #fff;
  77 + overflow: hidden;
  78 + border-left: 1px solid #ccc;
  79 + border-right: 1px solid #ccc;
  80 + border-bottom: 1px solid #ccc;
  81 + cursor: default;
  82 + font-size: 11px;
  83 + font-family: Verdana;
  84 + z-index: 1;
  85 +}
  86 +
  87 +div.token-input-dropdown-facebook p {
  88 + margin: 0;
  89 + padding: 5px;
  90 + font-weight: bold;
  91 + color: #777;
  92 +}
  93 +
  94 +div.token-input-dropdown-facebook ul {
  95 + margin: 0;
  96 + padding: 0;
  97 +}
  98 +
  99 +div.token-input-dropdown-facebook ul li {
  100 + background-color: #fff;
  101 + padding: 3px;
  102 + margin: 0;
  103 + list-style-type: none;
  104 +}
  105 +
  106 +div.token-input-dropdown-facebook ul li.token-input-dropdown-item-facebook {
  107 + background-color: #fff;
  108 +}
  109 +
  110 +div.token-input-dropdown-facebook ul li.token-input-dropdown-item2-facebook {
  111 + background-color: #fff;
  112 +}
  113 +
  114 +div.token-input-dropdown-facebook ul li em {
  115 + font-weight: bold;
  116 + font-style: normal;
  117 +}
  118 +
  119 +div.token-input-dropdown-facebook ul li.token-input-selected-dropdown-item-facebook {
  120 + background-color: #3b5998;
  121 + color: #fff;
  122 +}
0 123 \ No newline at end of file
... ...
public/stylesheets/token-input-mac.css 0 → 100644
... ... @@ -0,0 +1,204 @@
  1 +/* Example tokeninput style #2: Mac Style */
  2 +fieldset.token-input-mac {
  3 + position: relative;
  4 + padding: 0;
  5 + margin: 5px 0;
  6 + background: #fff;
  7 + width: 400px;
  8 + border: 1px solid #A4BDEC;
  9 + border-radius: 10px;
  10 + -moz-border-radius: 10px;
  11 + -webkit-border-radius: 10px;
  12 +}
  13 +
  14 +fieldset.token-input-mac.token-input-dropdown-mac {
  15 + border-radius: 10px 10px 0 0;
  16 + -moz-border-radius: 10px 10px 0 0;
  17 + -webkit-border-radius: 10px 10px 0 0;
  18 + box-shadow: 0 5px 20px 0 rgba(0,0,0,0.25);
  19 + -moz-box-shadow: 0 5px 20px 0 rgba(0,0,0,0.25);
  20 + -webkit-box-shadow: 0 5px 20px 0 rgba(0,0,0,0.25);
  21 +}
  22 +
  23 +ul.token-input-list-mac {
  24 + overflow: hidden;
  25 + height: auto !important;
  26 + height: 1%;
  27 + cursor: text;
  28 + font-size: 12px;
  29 + font-family: Verdana;
  30 + min-height: 1px;
  31 + z-index: 999;
  32 + margin: 0;
  33 + padding: 3px;
  34 + background: transparent;
  35 +}
  36 +
  37 +ul.token-input-list-mac.error {
  38 + border: 1px solid #C52020;
  39 +}
  40 +
  41 +ul.token-input-list-mac li {
  42 + list-style-type: none;
  43 +}
  44 +
  45 +li.token-input-token-mac p {
  46 + display: inline;
  47 + padding: 0;
  48 + margin: 0;
  49 +}
  50 +
  51 +li.token-input-token-mac span {
  52 + color: #a6b3cf;
  53 + margin-left: 5px;
  54 + font-weight: bold;
  55 + cursor: pointer;
  56 +}
  57 +
  58 +/* TOKENS */
  59 +
  60 +li.token-input-token-mac {
  61 + font-family: "Lucida Grande", Arial, serif;
  62 + font-size: 9pt;
  63 + line-height: 12pt;
  64 + overflow: hidden;
  65 + height: 16px;
  66 + margin: 3px;
  67 + padding: 0 10px;
  68 + background: none;
  69 + background-color: #dee7f8;
  70 + color: #000;
  71 + cursor: default;
  72 + border: 1px solid #a4bdec;
  73 + border-radius: 15px;
  74 + -moz-border-radius: 15px;
  75 + -webkit-border-radius: 15px;
  76 + float: left;
  77 +}
  78 +
  79 +li.token-input-highlighted-token-mac {
  80 + background-color: #bbcef1;
  81 + border: 1px solid #598bec;
  82 + color: #000;
  83 +}
  84 +
  85 +li.token-input-selected-token-mac {
  86 + background-color: #598bec;
  87 + border: 1px solid transparent;
  88 + color: #fff;
  89 +}
  90 +
  91 +li.token-input-highlighted-token-mac span.token-input-delete-token-mac {
  92 + color: #000;
  93 +}
  94 +
  95 +li.token-input-selected-token-mac span.token-input-delete-token-mac {
  96 + color: #fff;
  97 +}
  98 +
  99 +li.token-input-input-token-mac {
  100 + border: none;
  101 + background: transparent;
  102 + float: left;
  103 + padding: 0;
  104 + margin: 0;
  105 +}
  106 +
  107 +li.token-input-input-token-mac input {
  108 + border: 0;
  109 + width: 100px;
  110 + padding: 3px;
  111 + background-color: transparent;
  112 + margin: 0;
  113 +}
  114 +
  115 +div.token-input-dropdown-mac {
  116 + position: absolute;
  117 + border: 1px solid #A4BDEC;
  118 + border-top: none;
  119 + left: -1px;
  120 + right: -1px;
  121 + background-color: #fff;
  122 + overflow: hidden;
  123 + cursor: default;
  124 + font-size: 10pt;
  125 + font-family: "Lucida Grande", Arial, serif;
  126 + padding: 5px;
  127 + border-radius: 0 0 10px 10px;
  128 + -moz-border-radius: 0 0 10px 10px;
  129 + -webkit-border-radius: 0 0 10px 10px;
  130 + box-shadow: 0 5px 20px 0 rgba(0,0,0,0.25);
  131 + -moz-box-shadow: 0 5px 20px 0 rgba(0,0,0,0.25);
  132 + -webkit-box-shadow: 0 5px 20px 0 rgba(0,0,0,0.25);
  133 + clip:rect(0px, 1000px, 1000px, -10px);
  134 +}
  135 +
  136 +div.token-input-dropdown-mac p {
  137 + font-size: 8pt;
  138 + margin: 0;
  139 + padding: 0 5px;
  140 + font-style: italic;
  141 + color: #aaa;
  142 +}
  143 +
  144 +div.token-input-dropdown-mac h3.token-input-dropdown-category-mac {
  145 + font-family: "Lucida Grande", Arial, serif;
  146 + font-size: 10pt;
  147 + font-weight: bold;
  148 + border: none;
  149 + padding: 0 5px;
  150 + margin: 0;
  151 +}
  152 +
  153 +div.token-input-dropdown-mac ul {
  154 + margin: 0;
  155 + padding: 0;
  156 +}
  157 +
  158 +div.token-input-dropdown-mac ul li {
  159 + list-style-type: none;
  160 + cursor: pointer;
  161 + background: none;
  162 + background-color: #fff;
  163 + margin: 0;
  164 + padding: 0 0 0 25px;
  165 +}
  166 +
  167 +div.token-input-dropdown-mac ul li.token-input-dropdown-item-mac {
  168 + background-color: #fff;
  169 +}
  170 +
  171 +div.token-input-dropdown-mac ul li.token-input-dropdown-item-mac.odd {
  172 + background-color: #ECF4F9;
  173 + border-radius: 15px;
  174 + -moz-border-radius: 15px;
  175 + -webkit-border-radius: 15px;
  176 +}
  177 +
  178 +div.token-input-dropdown-mac ul li.token-input-dropdown-item-mac span.token-input-dropdown-item-description-mac {
  179 + float: right;
  180 + font-size: 8pt;
  181 + font-style: italic;
  182 + padding: 0 10px 0 0;
  183 + color: #999;
  184 +}
  185 +
  186 +div.token-input-dropdown-mac ul li strong {
  187 + font-weight: bold;
  188 + text-decoration: underline;
  189 + font-style: none;
  190 +}
  191 +
  192 +div.token-input-dropdown-mac ul li.token-input-selected-dropdown-item-mac,
  193 +div.token-input-dropdown-mac ul li.token-input-selected-dropdown-item-mac.odd {
  194 + background-color: #598bec;
  195 + color: #fff;
  196 + border-radius: 15px;
  197 + -moz-border-radius: 15px;
  198 + -webkit-border-radius: 15px;
  199 +}
  200 +
  201 +div.token-input-dropdown-mac ul li.token-input-selected-dropdown-item-mac span.token-input-dropdown-item-description-mac,
  202 +div.token-input-dropdown-mac ul li.token-input-selected-dropdown-item-mac.odd span.token-input-dropdown-item-description-mac {
  203 + color: #fff;
  204 +}
... ...
public/stylesheets/token-input.css 0 → 100644
... ... @@ -0,0 +1,113 @@
  1 +/* Example tokeninput style #1: Token vertical list*/
  2 +ul.token-input-list {
  3 + overflow: hidden;
  4 + height: auto !important;
  5 + height: 1%;
  6 + width: 497px;
  7 + border: 1px solid #999;
  8 + cursor: text;
  9 + font-size: 12px;
  10 + font-family: Verdana;
  11 + z-index: 999;
  12 + margin: 0;
  13 + padding: 0;
  14 + background-color: #fff;
  15 + list-style-type: none;
  16 + clear: left;
  17 +}
  18 +
  19 +ul.token-input-list li {
  20 + list-style-type: none;
  21 +}
  22 +
  23 +ul.token-input-list li input {
  24 + border: 0;
  25 + width: 350px;
  26 + padding: 3px 8px;
  27 + background-color: white;
  28 + -webkit-appearance: caret;
  29 +}
  30 +
  31 +li.token-input-token {
  32 + overflow: hidden;
  33 + height: auto !important;
  34 + height: 1%;
  35 + margin: 3px;
  36 + padding: 3px 5px;
  37 + background-color: #d0efa0;
  38 + color: #000;
  39 + font-weight: bold;
  40 + cursor: default;
  41 + display: block;
  42 +}
  43 +
  44 +li.token-input-token p {
  45 + float: left;
  46 + padding: 0;
  47 + margin: 0;
  48 +}
  49 +
  50 +li.token-input-token span {
  51 + float: right;
  52 + color: #777;
  53 + cursor: pointer;
  54 +}
  55 +
  56 +li.token-input-selected-token {
  57 + background-color: #08844e;
  58 + color: #fff;
  59 +}
  60 +
  61 +li.token-input-selected-token span {
  62 + color: #bbb;
  63 +}
  64 +
  65 +div.token-input-dropdown {
  66 + position: absolute;
  67 + width: 497px;
  68 + background-color: #fff;
  69 + overflow: hidden;
  70 + border-left: 1px solid #ccc;
  71 + border-right: 1px solid #ccc;
  72 + border-bottom: 1px solid #ccc;
  73 + cursor: default;
  74 + font-size: 12px;
  75 + font-family: Verdana;
  76 + z-index: 1;
  77 +}
  78 +
  79 +div.token-input-dropdown p {
  80 + margin: 0;
  81 + padding: 5px;
  82 + font-weight: bold;
  83 + color: #777;
  84 +}
  85 +
  86 +div.token-input-dropdown ul {
  87 + margin: 0;
  88 + padding: 0;
  89 +}
  90 +
  91 +div.token-input-dropdown ul li {
  92 + background-color: #fff;
  93 + padding: 3px;
  94 + list-style-type: none;
  95 +}
  96 +
  97 +div.token-input-dropdown ul li.token-input-dropdown-item {
  98 + background-color: #fafafa;
  99 +}
  100 +
  101 +div.token-input-dropdown ul li.token-input-dropdown-item2 {
  102 + background-color: #fff;
  103 +}
  104 +
  105 +div.token-input-dropdown ul li em {
  106 + font-weight: bold;
  107 + font-style: normal;
  108 +}
  109 +
  110 +div.token-input-dropdown ul li.token-input-selected-dropdown-item {
  111 + background-color: #d0efa0;
  112 +}
  113 +
... ...
script/sample-profiles
... ... @@ -95,6 +95,7 @@ save guest do
95 95 communities.rand.add_member(guest.person)
96 96 end
97 97 end
  98 +User.all(:conditions => ['login NOT LIKE "%%_template"']).each(&:activate)
98 99 done
99 100  
100 101 people = $environment.people
... ...
test/functional/account_controller_test.rb
... ... @@ -667,17 +667,21 @@ class AccountControllerTest &lt; Test::Unit::TestCase
667 667 end
668 668  
669 669 should 'merge user data with extra stuff from plugins' do
670   - plugin1 = mock()
671   - plugin1.stubs(:user_data_extras).returns({ :foo => 'bar' })
672   -
673   - plugin2 = mock()
674   - plugin2.stubs(:user_data_extras).returns({ :test => 5 })
  670 + class Plugin1 < Noosfero::Plugin
  671 + def user_data_extras
  672 + {:foo => 'bar'}
  673 + end
  674 + end
675 675  
676   - enabled_plugins = [plugin1, plugin2]
  676 + class Plugin2 < Noosfero::Plugin
  677 + def user_data_extras
  678 + {:test => 5}
  679 + end
  680 + end
677 681  
678   - plugins = mock()
679   - plugins.stubs(:enabled_plugins).returns(enabled_plugins)
680   - Noosfero::Plugin::Manager.stubs(:new).returns(plugins)
  682 + e = User.find_by_login('ze').environment
  683 + e.enable_plugin(Plugin1.name)
  684 + e.enable_plugin(Plugin2.name)
681 685  
682 686 login_as 'ze'
683 687  
... ...
test/functional/admin_panel_controller_test.rb
... ... @@ -342,4 +342,20 @@ class AdminPanelControllerTest &lt; Test::Unit::TestCase
342 342 assert_equal 3, Environment.default.news_amount_by_folder
343 343 end
344 344  
  345 + should 'display plugins links' do
  346 + plugin1_link = {:title => 'Plugin1 link', :url => 'plugin1.com'}
  347 + plugin2_link = {:title => 'Plugin2 link', :url => 'plugin2.com'}
  348 + links = [plugin1_link, plugin2_link]
  349 + plugins = mock()
  350 + plugins.stubs(:map).with(:admin_panel_links).returns(links)
  351 + plugins.stubs(:enabled_plugins).returns([])
  352 + plugins.stubs(:map).with(:body_beginning).returns([])
  353 + Noosfero::Plugin::Manager.stubs(:new).returns(plugins)
  354 +
  355 + get :index
  356 +
  357 + assert_tag :tag => 'a', :content => /#{plugin1_link[:title]}/, :attributes => {:href => /#{plugin1_link[:url]}/}
  358 + assert_tag :tag => 'a', :content => /#{plugin2_link[:title]}/, :attributes => {:href => /#{plugin2_link[:url]}/}
  359 + end
  360 +
345 361 end
... ...
test/functional/application_controller_test.rb
... ... @@ -442,28 +442,23 @@ class ApplicationControllerTest &lt; Test::Unit::TestCase
442 442 end
443 443  
444 444 should 'include stylesheets supplied by plugins' do
445   - plugin1 = mock()
446   - plugin1.stubs(:stylesheet?).returns(true)
447   - plugin1.stubs(:js_files).returns([])
448   - plugin1_class = mock()
  445 + class Plugin1 < Noosfero::Plugin
  446 + def stylesheet?
  447 + true
  448 + end
  449 + end
449 450 plugin1_path = '/plugin1/style.css'
450   - plugin1_class.stubs(:public_path).with('style.css').returns(plugin1_path)
451   - plugin1.stubs(:class).returns(plugin1_class)
452 451  
453   - plugin2 = mock()
454   - plugin2.stubs(:stylesheet?).returns(true)
455   - plugin2.stubs(:js_files).returns([])
456   - plugin2_class = mock()
  452 + class Plugin2 < Noosfero::Plugin
  453 + def stylesheet?
  454 + true
  455 + end
  456 + end
457 457 plugin2_path = '/plugin2/style.css'
458   - plugin2_class.stubs(:public_path).with('style.css').returns(plugin2_path)
459   - plugin2.stubs(:class).returns(plugin2_class)
460   -
461   - enabled_plugins = [plugin1, plugin2]
462 458  
463   - plugins = mock()
464   - plugins.stubs(:map).with(:body_beginning).returns([])
465   - plugins.stubs(:enabled_plugins).returns(enabled_plugins)
466   - Noosfero::Plugin::Manager.stubs(:new).returns(plugins)
  459 + environment = Environment.default
  460 + environment.enable_plugin(Plugin1.name)
  461 + environment.enable_plugin(Plugin2.name)
467 462  
468 463 get :index
469 464  
... ... @@ -472,33 +467,29 @@ class ApplicationControllerTest &lt; Test::Unit::TestCase
472 467 end
473 468  
474 469 should 'include javascripts supplied by plugins' do
  470 + class Plugin1 < Noosfero::Plugin
  471 + def js_files
  472 + ['js1.js']
  473 + end
  474 + end
  475 +
475 476 js1 = 'js1.js'
476   - plugin1 = mock()
477   - plugin1.stubs(:stylesheet?).returns(false)
478   - plugin1.stubs(:js_files).returns([js1])
479   - plugin1_class = mock()
480 477 plugin1_path = '/plugin1/'+js1
481   - plugin1_class.stubs(:public_path).with(js1).returns(plugin1_path)
482   - plugin1.stubs(:class).returns(plugin1_class)
  478 +
  479 + class Plugin2 < Noosfero::Plugin
  480 + def js_files
  481 + ['js2.js', 'js3.js']
  482 + end
  483 + end
483 484  
484 485 js2 = 'js2.js'
485 486 js3 = 'js3.js'
486   - plugin2 = mock()
487   - plugin2.stubs(:stylesheet?).returns(false)
488   - plugin2.stubs(:js_files).returns([js2, js3])
489   - plugin2_class = mock()
490 487 plugin2_path2 = '/plugin2/'+js2
491 488 plugin2_path3 = '/plugin2/'+js3
492   - plugin2_class.stubs(:public_path).with(js2).returns(plugin2_path2)
493   - plugin2_class.stubs(:public_path).with(js3).returns(plugin2_path3)
494   - plugin2.stubs(:class).returns(plugin2_class)
495 489  
496   - enabled_plugins = [plugin1, plugin2]
497   -
498   - plugins = mock()
499   - plugins.stubs(:map).with(:body_beginning).returns([])
500   - plugins.stubs(:enabled_plugins).returns(enabled_plugins)
501   - Noosfero::Plugin::Manager.stubs(:new).returns(plugins)
  490 + environment = Environment.default
  491 + environment.enable_plugin(Plugin1.name)
  492 + environment.enable_plugin(Plugin2.name)
502 493  
503 494 get :index
504 495  
... ...
test/functional/catalog_controller_test.rb
... ... @@ -94,23 +94,27 @@ class CatalogControllerTest &lt; Test::Unit::TestCase
94 94 end
95 95  
96 96 should 'include extra content supplied by plugins on catalog item extras' do
  97 + class Plugin1 < Noosfero::Plugin
  98 + def catalog_item_extras(product)
  99 + lambda {"<span id='plugin1'>This is Plugin1 speaking!</span>"}
  100 + end
  101 + end
  102 +
  103 + class Plugin2 < Noosfero::Plugin
  104 + def catalog_item_extras(product)
  105 + lambda {"<span id='plugin2'>This is Plugin2 speaking!</span>"}
  106 + end
  107 + end
  108 +
97 109 product = fast_create(Product, :enterprise_id => @enterprise.id)
98   - plugin1_local_variable = "Plugin1"
99   - plugin1_content = lambda {"<span id='plugin1'>This is #{plugin1_local_variable} speaking!</span>"}
100   - plugin2_local_variable = "Plugin2"
101   - plugin2_content = lambda {"<span id='plugin2'>This is #{plugin2_local_variable} speaking!</span>"}
102   - contents = [plugin1_content, plugin2_content]
103   -
104   - plugins = mock()
105   - plugins.stubs(:enabled_plugins).returns([])
106   - plugins.stubs(:map).with(:body_beginning).returns([])
107   - plugins.stubs(:map).with(:catalog_item_extras, product).returns(contents)
108   - Noosfero::Plugin::Manager.stubs(:new).returns(plugins)
  110 + environment = Environment.default
  111 + environment.enable_plugin(Plugin1.name)
  112 + environment.enable_plugin(Plugin2.name)
109 113  
110 114 get :index, :profile => @enterprise.identifier
111 115  
112   - assert_tag :tag => 'span', :content => 'This is ' + plugin1_local_variable + ' speaking!', :attributes => {:id => 'plugin1'}
113   - assert_tag :tag => 'span', :content => 'This is ' + plugin2_local_variable + ' speaking!', :attributes => {:id => 'plugin2'}
  116 + assert_tag :tag => 'span', :content => 'This is Plugin1 speaking!', :attributes => {:id => 'plugin1'}
  117 + assert_tag :tag => 'span', :content => 'This is Plugin2 speaking!', :attributes => {:id => 'plugin2'}
114 118 end
115 119  
116 120 end
... ...
test/functional/enterprise_registration_controller_test.rb
... ... @@ -179,5 +179,4 @@ all_fixtures
179 179 get :index
180 180 assert_equal assigns(:create_enterprise).target, environment
181 181 end
182   -
183 182 end
... ...
test/functional/manage_products_controller_test.rb
... ... @@ -455,4 +455,16 @@ class ManageProductsControllerTest &lt; Test::Unit::TestCase
455 455 assert_tag :tag => 'span', :content => 'This is ' + plugin1_local_variable + ' speaking!', :attributes => {:id => 'plugin1'}
456 456 assert_tag :tag => 'span', :content => 'This is ' + plugin2_local_variable + ' speaking!', :attributes => {:id => 'plugin2'}
457 457 end
  458 +
  459 + should 'not allow product creation for profiles that can\'t do it' do
  460 + class SpecialEnterprise < Enterprise
  461 + def create_product?
  462 + false
  463 + end
  464 + end
  465 + enterprise = SpecialEnterprise.create!(:identifier => 'special-enterprise', :name => 'Special Enterprise')
  466 + get 'new', :profile => enterprise.identifier
  467 + assert_response 403
  468 + end
  469 +
458 470 end
... ...
test/functional/profile_controller_test.rb
... ... @@ -1163,19 +1163,31 @@ class ProfileControllerTest &lt; Test::Unit::TestCase
1163 1163 end
1164 1164  
1165 1165 should 'display plugins tabs' do
1166   - plugin1_tab = {:title => 'Plugin1 tab', :id => 'plugin1_tab', :content => 'Content from plugin1.'}
1167   - plugin2_tab = {:title => 'Plugin2 tab', :id => 'plugin2_tab', :content => 'Content from plugin2.'}
1168   - tabs = [plugin1_tab, plugin2_tab]
1169   - plugins = mock()
1170   - plugins.stubs(:map).with(:profile_tabs).returns(tabs)
1171   - plugins.stubs(:enabled_plugins).returns([])
1172   - plugins.stubs(:map).with(:body_beginning).returns([])
1173   - Noosfero::Plugin::Manager.stubs(:new).returns(plugins)
  1166 + class Plugin1 < Noosfero::Plugin
  1167 + def profile_tabs
  1168 + {:title => 'Plugin1 tab', :id => 'plugin1_tab', :content => lambda { 'Content from plugin1.' }}
  1169 + end
  1170 + end
  1171 +
  1172 + class Plugin2 < Noosfero::Plugin
  1173 + def profile_tabs
  1174 + {:title => 'Plugin2 tab', :id => 'plugin2_tab', :content => lambda { 'Content from plugin2.' }}
  1175 + end
  1176 + end
  1177 +
  1178 + e = profile.environment
  1179 + e.enable_plugin(Plugin1.name)
  1180 + e.enable_plugin(Plugin2.name)
1174 1181  
1175 1182 get :index, :profile => profile.identifier
1176 1183  
1177   - assert_tag :tag => 'a', :content => /#{plugin1_tab[:title]}/, :attributes => {:href => /#{plugin1_tab[:id]}/}
1178   - assert_tag :tag => 'div', :content => /#{plugin1_tab[:content]}/, :attributes => {:id => /#{plugin1_tab[:id]}/}
  1184 + plugin1 = Plugin1.new
  1185 + plugin2 = Plugin2.new
  1186 +
  1187 + assert_tag :tag => 'a', :content => /#{plugin1.profile_tabs[:title]}/, :attributes => {:href => /#{plugin1.profile_tabs[:id]}/}
  1188 + assert_tag :tag => 'div', :content => /#{instance_eval(&plugin1.profile_tabs[:content])}/, :attributes => {:id => /#{plugin1.profile_tabs[:id]}/}
  1189 + assert_tag :tag => 'a', :content => /#{plugin2.profile_tabs[:title]}/, :attributes => {:href => /#{plugin2.profile_tabs[:id]}/}
  1190 + assert_tag :tag => 'div', :content => /#{instance_eval(&plugin2.profile_tabs[:content])}/, :attributes => {:id => /#{plugin2.profile_tabs[:id]}/}
1179 1191 end
1180 1192  
1181 1193 should 'redirect to profile page when try to request join_not_logged via GET method' do
... ...
test/functional/profile_members_controller_test.rb
... ... @@ -233,59 +233,87 @@ class ProfileMembersControllerTest &lt; Test::Unit::TestCase
233 233 assert_not_includes com.members, u
234 234 end
235 235  
236   - should 'find users' do
237   - ent = fast_create(Enterprise, :name => 'Test Ent', :identifier => 'test_ent')
238   - user = create_user_full('test_user').person
239   - person = create_user_with_permission('ent_user', 'manage_memberships', ent)
240   - login_as :ent_user
241   -
242   - get :find_users, :profile => ent.identifier, :query => 'test*', :scope => 'all_users'
243   -
244   - assert_includes assigns(:users_found), user
245   - end
246   -
247   - should 'not display members when finding users in all_users scope' do
248   - ent = fast_create(Enterprise, :name => 'Test Ent', :identifier => 'test_ent')
249   - user = create_user_full('test_user').person
250   -
251   - person = create_user_with_permission('ent_user', 'manage_memberships', ent)
252   - login_as :ent_user
253   -
254   - get :find_users, :profile => ent.identifier, :query => '*user', :scope => 'all_users'
255   -
256   - assert_tag :tag => 'a', :content => /#{user.name}/
257   - assert_no_tag :tag => 'a', :content => /#{person.name}/
258   - end
259   -
260   - should 'not display admins when finding users in new_admins scope' do
261   - ent = fast_create(Enterprise, :name => 'Test Ent', :identifier => 'test_ent')
262   -
263   - person = create_user('admin_user').person
264   - ent.add_admin(person)
265   -
266   - user = create_user_full('test_user').person
267   - ent.add_member(user).finish
268   -
269   - login_as :admin_user
270   -
271   - get :find_users, :profile => ent.identifier, :query => '*user', :scope => 'new_admins'
  236 + should 'list users on search by role' do
  237 + e = Enterprise.create!(:name => 'Sample Enterprise', :identifier => 'sample-enterprise')
  238 + user = create_user_with_permission('test_user', 'manage_memberships', e)
  239 + login_as :test_user
272 240  
273   - assert_tag :tag => 'a', :content => /#{user.name}/
274   - assert_no_tag :tag => 'a', :content => /#{person.name}/
  241 + # Should list if match name
  242 + p1 = create_user('person_1').person
  243 + p2 = create_user('person_2').person
  244 + # Should not list if don't match name
  245 + p3 = create_user('blo').person
  246 + r1 = Profile::Roles.organization_member_roles(e.environment.id).first
  247 + r2 = Profile::Roles.organization_member_roles(e.environment.id).last
  248 +
  249 + p4 = create_user('person_4').person
  250 + e.affiliate(p4, r1)
  251 + p5 = create_user('person_5').person
  252 + e.affiliate(p5, r2)
  253 +
  254 + # Should be case insensitive
  255 + p6 = create_user('PeRsOn_2').person
  256 + # Should list if match identifier
  257 + p7 = create_user('person_7').person
  258 + p7.name = 'Bli'
  259 + p7.save!
  260 +
  261 + get :search_user, :profile => e.identifier, 'q_'+r1.key => 'per', :role => r1.id
  262 + assert_match /#{p1.name}/, @response.body
  263 + assert_match /#{p2.name}/, @response.body
  264 + assert_no_match /#{p3.name}/, @response.body
  265 + assert_no_match /#{p4.name}/, @response.body
  266 + assert_match /#{p5.name}/, @response.body
  267 + assert_match /#{p6.name}/, @response.body
  268 + assert_match /#{p7.name}/, @response.body
  269 +
  270 + get :search_user, :profile => e.identifier, 'q_'+r2.key => 'per', :role => r2.id
  271 + assert_match /#{p1.name}/, @response.body
  272 + assert_match /#{p2.name}/, @response.body
  273 + assert_no_match /#{p3.name}/, @response.body
  274 + assert_match /#{p4.name}/, @response.body
  275 + assert_no_match /#{p5.name}/, @response.body
  276 + assert_match /#{p6.name}/, @response.body
  277 + assert_match /#{p7.name}/, @response.body
275 278 end
276 279  
277   - should 'return users with <query> as a prefix' do
278   - daniel = create_user_full('daniel').person
279   - daniela = create_user_full('daniela').person
280   -
281   - ent = fast_create(Enterprise, :name => 'Test Ent', :identifier => 'test_ent')
282   - person = create_user_with_permission('test_user', 'manage_memberships', ent)
  280 + should 'save associations' do
  281 + e = Enterprise.create!(:name => 'Sample Enterprise', :identifier => 'sample-enterprise')
  282 + user = create_user_with_permission('test_user', 'manage_memberships', e)
283 283 login_as :test_user
284 284  
285   - get :find_users, :profile => ent.identifier, :query => 'daniel', :scope => 'all_users'
286   -
287   - assert_includes assigns(:users_found), daniel
288   - assert_includes assigns(:users_found), daniela
  285 + p1 = create_user('person-1').person
  286 + p2 = create_user('person-2').person
  287 + p3 = create_user('person-3').person
  288 + roles = Profile::Roles.organization_member_roles(e.environment.id)
  289 + r1 = roles.first
  290 + r2 = roles.last
  291 + roles.delete(r1)
  292 + roles.delete(r2)
  293 +
  294 + roles_params = roles.inject({}) { |result, role| result.merge({'q_'+role.key => ''})}
  295 +
  296 + post :save_associations,
  297 + {:profile => e.identifier,
  298 + 'q_'+r1.key => "#{p1.id},#{p2.id},#{user.id}",
  299 + 'q_'+r2.key => "#{p2.id},#{p3.id}"}.merge(roles_params)
  300 + assert_includes e.members_by_role(r1), p1
  301 + assert_includes e.members_by_role(r1), p2
  302 + assert_not_includes e.members_by_role(r1), p3
  303 + assert_not_includes e.members_by_role(r2), p1
  304 + assert_includes e.members_by_role(r2), p2
  305 + assert_includes e.members_by_role(r2), p3
  306 +
  307 + post :save_associations,
  308 + {:profile => e.identifier,
  309 + 'q_'+r1.key => "#{p2.id},#{p3.id},#{user.id}",
  310 + 'q_'+r2.key => "#{p1.id},#{p2.id}"}.merge(roles_params)
  311 + assert_not_includes e.members_by_role(r1), p1
  312 + assert_includes e.members_by_role(r1), p2
  313 + assert_includes e.members_by_role(r1), p3
  314 + assert_includes e.members_by_role(r2), p1
  315 + assert_includes e.members_by_role(r2), p2
  316 + assert_not_includes e.members_by_role(r2), p3
289 317 end
290 318  
291 319 should 'ignore roles with id zero' do
... ...
test/functional/search_controller_test.rb
... ... @@ -290,24 +290,53 @@ class SearchControllerTest &lt; Test::Unit::TestCase
290 290 end
291 291  
292 292 should 'include extra content supplied by plugins on product asset' do
  293 + class Plugin1 < Noosfero::Plugin
  294 + def asset_product_extras(product, enterprise)
  295 + lambda {"<span id='plugin1'>This is Plugin1 speaking!</span>"}
  296 + end
  297 + end
  298 +
  299 + class Plugin2 < Noosfero::Plugin
  300 + def asset_product_extras(product, enterprise)
  301 + lambda {"<span id='plugin2'>This is Plugin2 speaking!</span>"}
  302 + end
  303 + end
  304 +
293 305 enterprise = fast_create(Enterprise)
294 306 product = fast_create(Product, :enterprise_id => enterprise.id)
295   - plugin1_local_variable = "Plugin1"
296   - plugin1_content = lambda {"<span id='plugin1'>This is #{plugin1_local_variable} speaking!</span>"}
297   - plugin2_local_variable = "Plugin2"
298   - plugin2_content = lambda {"<span id='plugin2'>This is #{plugin2_local_variable} speaking!</span>"}
299   - contents = [plugin1_content, plugin2_content]
300   -
301   - plugins = mock()
302   - plugins.stubs(:enabled_plugins).returns([])
303   - plugins.stubs(:map).with(:body_beginning).returns([])
304   - plugins.stubs(:map).with(:asset_product_extras, product, enterprise).returns(contents)
305   - Noosfero::Plugin::Manager.stubs(:new).returns(plugins)
  307 +
  308 + e = Environment.default
  309 + e.enable_plugin(Plugin1.name)
  310 + e.enable_plugin(Plugin2.name)
  311 +
  312 + get :assets, :asset => 'products'
  313 +
  314 + assert_tag :tag => 'span', :content => 'This is Plugin1 speaking!', :attributes => {:id => 'plugin1'}
  315 + assert_tag :tag => 'span', :content => 'This is Plugin2 speaking!', :attributes => {:id => 'plugin2'}
  316 + end
  317 +
  318 + should 'include extra properties of the product supplied by plugins' do
  319 + class Plugin1 < Noosfero::Plugin
  320 + def asset_product_properties(product)
  321 + return { :name => _('Property1'), :content => lambda { link_to(product.name, '/plugin1') } }
  322 + end
  323 + end
  324 + class Plugin2 < Noosfero::Plugin
  325 + def asset_product_properties(product)
  326 + return { :name => _('Property2'), :content => lambda { link_to(product.name, '/plugin2') } }
  327 + end
  328 + end
  329 + enterprise = fast_create(Enterprise)
  330 + product = fast_create(Product, :enterprise_id => enterprise.id)
  331 +
  332 + environment = Environment.default
  333 + environment.enable_plugin(Plugin1.name)
  334 + environment.enable_plugin(Plugin2.name)
306 335  
307 336 get :assets, :asset => 'products'
308 337  
309   - assert_tag :tag => 'span', :content => 'This is ' + plugin1_local_variable + ' speaking!', :attributes => {:id => 'plugin1'}
310   - assert_tag :tag => 'span', :content => 'This is ' + plugin2_local_variable + ' speaking!', :attributes => {:id => 'plugin2'}
  338 + assert_tag :tag => 'li', :content => /Property1/, :child => {:tag => 'a', :attributes => {:href => '/plugin1'}, :content => product.name}
  339 + assert_tag :tag => 'li', :content => /Property2/, :child => {:tag => 'a', :attributes => {:href => '/plugin2'}, :content => product.name}
311 340 end
312 341  
313 342 should 'paginate enterprise listing' do
... ...
test/unit/application_helper_test.rb
... ... @@ -18,18 +18,6 @@ class ApplicationHelperTest &lt; Test::Unit::TestCase
18 18  
19 19 File.expects(:exists?).with(p1+"test/_integer.rhtml").returns(true)
20 20  
21   - assert_equal 'integer', partial_for_class(Integer)
22   - end
23   -
24   -
25   - should 'calculate correctly partial for models recursively' do
26   - p1 = 'path1/'
27   - p2 = 'path2/'
28   - @controller = mock()
29   - @controller.stubs(:view_paths).returns([p1,p2])
30   -
31   - self.stubs(:params).returns({:controller => 'test'})
32   -
33 21 File.expects(:exists?).with(p1+"test/_float.rhtml").returns(false)
34 22 File.expects(:exists?).with(p1+"test/_float.html.erb").returns(false)
35 23 File.expects(:exists?).with(p2+"test/_float.rhtml").returns(false)
... ... @@ -40,22 +28,13 @@ class ApplicationHelperTest &lt; Test::Unit::TestCase
40 28 File.expects(:exists?).with(p1+"test/_numeric.html.erb").returns(false)
41 29 File.expects(:exists?).with(p2+"test/_numeric.rhtml").returns(true)
42 30  
43   - assert_equal 'numeric', partial_for_class(Float)
44   - end
45   -
46   - should 'raise error when partial is missing' do
47   - p1 = 'path1/'
48   - p2 = 'path2/'
49   - @controller = mock()
50   - @controller.stubs(:view_paths).returns([p1,p2])
51   -
52   - self.stubs(:params).returns({:controller => 'test'})
53   -
54 31 File.expects(:exists?).with(p1+"test/_object.rhtml").returns(false)
55 32 File.expects(:exists?).with(p1+"test/_object.html.erb").returns(false)
56 33 File.expects(:exists?).with(p2+"test/_object.rhtml").returns(false)
57 34 File.expects(:exists?).with(p2+"test/_object.html.erb").returns(false)
58 35  
  36 + assert_equal 'integer', partial_for_class(Integer)
  37 + assert_equal 'numeric', partial_for_class(Float)
59 38 assert_raises ArgumentError do
60 39 partial_for_class(Object)
61 40 end
... ... @@ -74,6 +53,15 @@ class ApplicationHelperTest &lt; Test::Unit::TestCase
74 53 assert_equal 'test/application_helper_test/school/project', partial_for_class(School::Project)
75 54 end
76 55  
  56 + should 'look for superclasses on view_for_profile actions' do
  57 + File.expects(:exists?).with("#{RAILS_ROOT}/app/views/blocks/profile_info_actions/float.rhtml").returns(false)
  58 + File.expects(:exists?).with("#{RAILS_ROOT}/app/views/blocks/profile_info_actions/float.html.erb").returns(false)
  59 + File.expects(:exists?).with("#{RAILS_ROOT}/app/views/blocks/profile_info_actions/numeric.rhtml").returns(false)
  60 + File.expects(:exists?).with("#{RAILS_ROOT}/app/views/blocks/profile_info_actions/numeric.html.erb").returns(true)
  61 +
  62 + assert_equal 'blocks/profile_info_actions/numeric.html.erb', view_for_profile_actions(Float)
  63 + end
  64 +
77 65 should 'give error when there is no partial for class' do
78 66 assert_raises ArgumentError do
79 67 partial_for_class(nil)
... ...
test/unit/enterprise_test.rb
... ... @@ -350,6 +350,20 @@ class EnterpriseTest &lt; Test::Unit::TestCase
350 350 assert_equal false, Enterprise['test_ent'].enabled?
351 351 end
352 352  
  353 + should 'enterprise is validated according to feature enterprises_are_validated_when_created' do
  354 + e = Environment.default
  355 +
  356 + e.enable('enterprises_are_validated_when_created')
  357 + e.save
  358 + enterprise = Enterprise.create(:name => 'test enteprise', :identifier => 'test_ent1')
  359 + assert enterprise.validated
  360 +
  361 + e.disable('enterprises_are_validated_when_created')
  362 + e.save
  363 + enterprise = Enterprise.create(:name => 'test enteprise', :identifier => 'test_ent2')
  364 + assert !enterprise.validated
  365 + end
  366 +
353 367 should 'have inactive_template when creating enterprise and feature is enabled' do
354 368 inactive_template = fast_create(Enterprise, :name => 'inactive enteprise template', :identifier => 'inactive_enterprise_template')
355 369 inactive_template.boxes.destroy_all
... ...
test/unit/environment_test.rb
... ... @@ -1183,4 +1183,17 @@ class EnvironmentTest &lt; Test::Unit::TestCase
1183 1183 assert_equal env.settings[:string_key], 'new value'
1184 1184 end
1185 1185  
  1186 + should 'be able to enable or disable a plugin' do
  1187 + environment = Environment.default
  1188 + plugin = 'Plugin'
  1189 +
  1190 + environment.enable_plugin(plugin)
  1191 + environment.reload
  1192 + assert_includes environment.enabled_plugins, plugin
  1193 +
  1194 + environment.disable_plugin(plugin)
  1195 + environment.reload
  1196 + assert_not_includes environment.enabled_plugins, plugin
  1197 + end
  1198 +
1186 1199 end
... ...
test/unit/organization_test.rb
... ... @@ -386,4 +386,26 @@ class OrganizationTest &lt; Test::Unit::TestCase
386 386 assert_includes Organization.more_active, profile
387 387 end
388 388  
  389 + should 'validates format of cnpj' do
  390 + organization = Organization.new(:cnpj => '239-234.234')
  391 + organization.valid?
  392 + assert organization.errors.invalid?(:cnpj)
  393 +
  394 + organization.cnpj = '94.132.024/0001-48'
  395 + organization.valid?
  396 + assert !organization.errors.invalid?(:cnpj)
  397 + end
  398 +
  399 + should 'return members by role in a json format' do
  400 + organization = fast_create(Organization)
  401 + p1 = create_user('person-1').person
  402 + p2 = create_user('person-2').person
  403 + role = Profile::Roles.organization_member_roles(organization.environment.id).last
  404 +
  405 + organization.affiliate(p1, role)
  406 + organization.affiliate(p2, role)
  407 +
  408 + assert_match [{:id => p1.id, :name => p1.name}, {:id => p2.id, :name => p2.name}].to_json, organization.members_by_role_to_json(role)
  409 + end
  410 +
389 411 end
... ...
test/unit/profile_test.rb
... ... @@ -1726,6 +1726,20 @@ class ProfileTest &lt; Test::Unit::TestCase
1726 1726 assert_not_includes env.profiles.without_image, with_image
1727 1727 end
1728 1728  
  1729 + should 'return enterprises subclasses too on namedscope enterprises' do
  1730 + class EnterpriseSubclass < Enterprise; end
  1731 + child = EnterpriseSubclass.create!(:identifier => 'child', :name => 'Child')
  1732 +
  1733 + assert_includes Profile.enterprises, child
  1734 + end
  1735 +
  1736 + should 'return communities subclasses too on namedscope communities' do
  1737 + class CommunitySubclass < Community; end
  1738 + child = CommunitySubclass.create!(:identifier => 'child', :name => 'Child')
  1739 +
  1740 + assert_includes Profile.communities, child
  1741 + end
  1742 +
1729 1743 private
1730 1744  
1731 1745 def assert_invalid_identifier(id)
... ...
vendor/plugins/validates_as_cnpj/LEIAME 0 → 100755
... ... @@ -0,0 +1,13 @@
  1 +Validacao de CNPJ
  2 +=================
  3 +
  4 +Plugin para validacao do formato e dos digitos verificadores de um CNPJ.
  5 +
  6 +Uso:
  7 + Adicione ao modelo:
  8 + validates_as_cnpj :nome_do_campo
  9 +
  10 +Exemplo:
  11 + class Empresa < ActiveRecord::Base
  12 + validates_as_cnpj :cnpj
  13 + end
... ...
vendor/plugins/validates_as_cnpj/init.rb 0 → 100755
... ... @@ -0,0 +1,17 @@
  1 +# init.rb - initialize the plugin
  2 +#
  3 +# Copyright (c) 2006 O.S. Systems
  4 +#
  5 +# Authors: André Ribeiro Camargo <andre@boaideia.inf.br>,
  6 +# Luis Gustavo S. Barreto <gustavo@ossystems.com.br>
  7 +#
  8 +# This program is free software; you can redistribute it and/or modify
  9 +# it under the terms of the GNU General Public License as published by
  10 +# the Free Software Foundation; either version 2 of the License, or
  11 +# (at your option) any later version.
  12 +#
  13 +# This program is distributed in the hope that it will be useful, but
  14 +# WITHOUT ANY WARRANTY; without even the implied warranty of
  15 +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  16 +# General Public License for more details.
  17 +require 'validates_as_cnpj'
... ...
vendor/plugins/validates_as_cnpj/lib/validates_as_cnpj.rb 0 → 100755
... ... @@ -0,0 +1,78 @@
  1 +# validates_as_cnpj.rb - implement the validation of cnpj
  2 +#
  3 +# Copyright (c) 2006 O.S. Systems
  4 +#
  5 +# Authors: André Ribeiro Camargo <andre@boaideia.inf.br>,
  6 +# Luis Gustavo S. Barreto <gustavo@ossystems.com.br>
  7 +#
  8 +# This program is free software; you can redistribute it and/or modify
  9 +# it under the terms of the GNU General Public License as published by
  10 +# the Free Software Foundation; either version 2 of the License, or
  11 +# (at your option) any later version.
  12 +#
  13 +# This program is distributed in the hope that it will be useful, but
  14 +# WITHOUT ANY WARRANTY; without even the implied warranty of
  15 +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  16 +# General Public License for more details.
  17 +module ValidaCNPJ
  18 + def self.valida_cnpj(cnpj = nil)
  19 + return nil if cnpj.nil?
  20 +
  21 + nulos = %w{11111111111111
  22 + 22222222222222
  23 + 33333333333333
  24 + 44444444444444
  25 + 55555555555555
  26 + 66666666666666
  27 + 77777777777777
  28 + 88888888888888
  29 + 99999999999999
  30 + 00000000000000}
  31 +
  32 + valor = cnpj.scan(/[0-9]/).collect{|x| x.to_i}
  33 +
  34 + fatores = [5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2]
  35 +
  36 + if valor.length == 14 and not nulos.member?(valor.to_s)
  37 + soma = 0
  38 + 0.upto(11) do |i|
  39 + soma += valor[i] * fatores[i]
  40 + end
  41 +
  42 + resto = soma % 11
  43 + dv1 = resto < 2 ? 0 : 11 - resto
  44 +
  45 + if dv1 == valor[12]
  46 + soma = 0
  47 + 0.upto(12) do |i|
  48 + soma += valor[i] * (i == 0 ? 6 : fatores[i-1])
  49 + end
  50 +
  51 + resto = soma % 11
  52 + dv2 = resto < 2 ? 0 : 11 - resto
  53 +
  54 + return true if dv2 == valor[13]
  55 + end
  56 + end
  57 + return nil
  58 + end
  59 +end
  60 +
  61 +module ActiveRecord
  62 + module Validations
  63 + module ClassMethods
  64 + def validates_as_cnpj(*attr_names)
  65 + configuration = { :message => "%{fn} is invalid" }
  66 + configuration.update(attr_names.pop) if attr_names.last.is_a?(Hash)
  67 +
  68 + validates_each(attr_names, configuration) do |record, attr_name, value|
  69 + next if value.blank?
  70 +
  71 + unless ValidaCNPJ::valida_cnpj(value)
  72 + record.errors.add(attr_name, configuration[:message])
  73 + end
  74 + end
  75 + end
  76 + end
  77 + end
  78 +end
... ...