Hello community, here is the log from the commit of package webyast-users-ui for openSUSE:Factory checked in at Wed May 4 10:27:30 CEST 2011.
-------- --- webyast-users-ui/webyast-users-ui.changes 2010-08-30 12:43:11.000000000 +0200 +++ /mounts/work_src_done/STABLE/webyast-users-ui/webyast-users-ui.changes 2011-04-14 09:18:45.000000000 +0200 @@ -1,0 +2,23 @@ +Tue Apr 12 14:43:13 UTC 2011 - [email protected] + +- new caching +- 0.2.11 + +------------------------------------------------------------------- +Thu Mar 24 11:33:13 UTC 2011 - [email protected] + +- wrong dependencies in webyast-user-ui, users module should pre require webyast-base-ui >= 0.2.0 ([yast-internal] Fwd: [studio-feedback] [Feedback] Bug on my appliance: SLES 11 sp1 JeOS-fsDeployed...) +- 0.2.10 +------------------------------------------------------------------- +Fri Nov 26 10:17:07 CET 2010 - [email protected] + +- accept system users (bnc#638476) +- 0.2.9 + +------------------------------------------------------------------- +Fri Nov 26 09:57:37 CET 2010 - [email protected] + +- untranslated text (bnc#603782) +- 0.2.8 + +------------------------------------------------------------------- calling whatdependson for head-i586 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ webyast-users-ui.spec ++++++ --- /var/tmp/diff_new_pack.sPxvIV/_old 2011-05-04 10:23:15.000000000 +0200 +++ /var/tmp/diff_new_pack.sPxvIV/_new 2011-05-04 10:23:15.000000000 +0200 @@ -23,19 +23,19 @@ Provides: yast2-webclient-users = %{version} Obsoletes: yast2-webclient-users < %{version} # updated jQuery quicksearch plugin -PreReq: yast2-webclient >= 0.1.17 +PreReq: webyast-base-ui >= 0.2.0 PreReq: webyast-users-ws >= 0.1.6 License: GPLv2 Group: Productivity/Networking/Web/Utilities Url: http://en.opensuse.org/Portal:WebYaST AutoReqProv: on -Version: 0.2.7 +Version: 0.2.11 Release: 1 Summary: WebYaST - users management UI Source: www.tar.bz2 BuildRoot: %{_tmppath}/%{name}-%{version}-build BuildArch: noarch -BuildRequires: rubygem-mocha rubygem-test-unit rubygem-webyast-rake-tasks webyast-base-ui-testsuite +BuildRequires: rubygem-mocha rubygem-test-unit rubygem-webyast-rake-tasks webyast-base-ui webyast-base-ui-testsuite BuildRequires: tidy # ++++++ www.tar.bz2 ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/www/app/controllers/groups_controller.rb new/www/app/controllers/groups_controller.rb --- old/www/app/controllers/groups_controller.rb 2010-05-28 09:52:16.000000000 +0200 +++ new/www/app/controllers/groups_controller.rb 2011-01-19 10:39:15.000000000 +0100 @@ -139,9 +139,12 @@ group.members_string = group.members.join(",") end @all_users_string = "" + @all_sys_users_string = "" @users = [] + @sys_users = [] if @permissions[:usersget] == true @users = User.find(:all, :params => { :attributes => "uid"}) + @sys_users = User.find( :all, :params=> { "attributes"=>"cn,uidNumber,uid", "type"=>"system", "index"=>["s", "uid"]} ) end @users.each do |user| if @all_users_string.blank? @@ -151,6 +154,14 @@ end end + @sys_users.each do |user| + if @all_sys_users_string.blank? + @all_sys_users_string = user.uid + else + @all_sys_users_string += ",#{user.uid}" + end + end + rescue ActiveResource::ResourceNotFound => e flash[:error] = _("Cannot read groups list.") return diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/www/app/controllers/users_controller.rb new/www/app/controllers/users_controller.rb --- old/www/app/controllers/users_controller.rb 2010-08-04 16:42:28.000000000 +0200 +++ new/www/app/controllers/users_controller.rb 2011-04-12 11:29:23.000000000 +0200 @@ -66,7 +66,14 @@ return roles end - +def all_users + all_users_list = [] + all_users = User.find :all + all_users.each do |user| + all_users_list.push(user.uid) + end + all_users_list.join(",") +end public def initialize end @@ -166,6 +173,9 @@ all_roles.push(role.name) end @all_roles_string = all_roles.join(",") + + @all_users_string = all_users + @groups = [] if @permissions[:groupsget] == true @groups = Group.find :all @@ -251,6 +261,7 @@ :type => "local" ) @user.grp_string = dummy.grp_string + @all_users_string = all_users response = true begin @@ -298,18 +309,14 @@ save_roles(@user.id,params["user"]["roles_string"]) end - response = true begin - response = @user.save - rescue ActiveResource::ClientError => e - flash[:error] = YaST::ServiceResource.error(e) - response = false - end - if response - flash[:notice] = _("User <i>%s</i> was successfully updated.") % @user.uid + if @user.save + flash[:notice] = _("User <i>%s</i> was successfully updated.") % @user.uid + redirect_to :action => "index" + end + rescue ActiveResource::ClientError => e + flash[:error] = YaST::ServiceResource.error(e) redirect_to :action => "index" - else - render :action => "edit" end end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/www/app/views/groups/index.html.erb new/www/app/views/groups/index.html.erb --- old/www/app/views/groups/index.html.erb 2010-08-25 12:06:17.000000000 +0200 +++ new/www/app/views/groups/index.html.erb 2011-04-12 13:05:56.000000000 +0200 @@ -1,4 +1,4 @@ -<!-- +<!-- RORSCAN_ICF # Copyright (c) 2009-2010 Novell, Inc. # # All Rights Reserved. @@ -21,7 +21,7 @@ <% content_for :head do %> <% if JSMIN == true %> - <%= javascript_include_tag "users-min.js"-%> + <%= javascript_include_tag "min/users-min.js"-%> <% else %> <%= javascript_include_tag "jquery.quicksearch.js"-%> <%= javascript_include_tag "select_dialog.js" %> @@ -53,6 +53,9 @@ </style> <% javascript_tag do %> + var AUTH_TOKEN = 'authenticity_token=' + encodeURIComponent("<%= escape_javascript form_authenticity_token %>"); + startNotifier({'module':'groups', 'AUTH_TOKEN':AUTH_TOKEN}, 1000, 11000); + jQuery.expr[':'].Contains = function(a, i, m) { return jQuery(a).text().toUpperCase().indexOf(m[3].toUpperCase()) >= 0; }; @@ -65,10 +68,12 @@ unselected_title : <%= jss _('Available Members') %>, tooltip : <%= jss _('Click user names to select/unselect members') %>, loadItems : function (dialogId) { - return $('#form_'+dialogId+' .members-string')[0].value.split(",") + var members = $('#form_'+dialogId+' .members-string')[0].value.split(","); + this.system_users = arrays_complement($('#form_'+dialogId+' .members-string')[0].value.split(","), $("#all_users_string")[0].value.split(",")); + return members; }, storeItems : function (dialogId, items) { - $('#form_'+dialogId+' .members-string')[0].value = items.join(","); + $('#form_'+dialogId+' .members-string')[0].value = this.system_users.concat(items).join(","); }, allItems : function (dialogId) { return $('#all_users_string')[0].value.split(",") @@ -102,7 +107,7 @@ <% end %> <% end %> -<div class='plugin-icon'><img alt="yast-groups" src='/icons/yast-groups.png' width="48px" height="48px"><%=_("Groups")%></div> +<div class='plugin-icon'><img alt="yast-groups" src='/icons/yast-groups.png' width="48px" height="48px"><%=_("Groups")%><span id="questionMark">?</span></div> <div class="plugin-content"> <div id="search-userbar"> @@ -122,7 +127,7 @@ <div id="link-container"> <div id="action_links" class="action_links"> <% if @permissions[:groupadd] %> - <%=link_to image_tag("/icons/yast-groups_16.png", :class=>"icons") + _("Add New Group"), :action => :new %> + <%=link_to image_tag("/icons/yast-groups_16.png", :class=>"icons") + _("New Group"), :action => :new %> <label>|</label> <% end %> <%=link_to image_tag("/icons/yast-users_16.png", :class=>"icons") + _("Manage Users"), "controller" => "users" %> @@ -198,6 +203,7 @@ </div> </div> <div><input type="hidden" id="all_users_string" value="<%= @all_users_string %>" /></div> + <div><input type="hidden" id="system_users_string" value="<%= @all_sys_users_string %>" /></div> <div class="nav-buttons"> <%= form_back_button -%> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/www/app/views/groups/new.html.erb new/www/app/views/groups/new.html.erb --- old/www/app/views/groups/new.html.erb 2010-08-25 12:06:17.000000000 +0200 +++ new/www/app/views/groups/new.html.erb 2011-04-12 11:29:23.000000000 +0200 @@ -20,7 +20,7 @@ --> <% if JSMIN == true %> - <%= javascript_include_tag "users-min.js"-%> + <%= javascript_include_tag "min/users-min.js"-%> <% else %> <%= javascript_include_tag "users.js" %> <%= javascript_include_tag "select_dialog.js" %> @@ -88,7 +88,7 @@ <% disabled = ! ((@permissions[:groupadd] && @adding) || (@permissions[:groupmodify] && !@adding)) %> <div class='plugin-icon'><img alt="yast-groups" src='/icons/yast-groups.png' alt="groups module"/> - <%=_("Groups") + header_spacer %> + <%=_("Groups") + header_spacer %><span id="questionMark">?</span> <%= _("Add new group") %> </div> @@ -136,4 +136,5 @@ <% end %> <div><input type="hidden" id="all_users_string" value="<%= @all_users_string %>" /></div> + <div><input type="hidden" id="system_users_string" value="<%= @all_sys_users_string %>" /></div> </div> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/www/app/views/users/_user_form.erb new/www/app/views/users/_user_form.erb --- old/www/app/views/users/_user_form.erb 2010-08-17 13:53:02.000000000 +0200 +++ new/www/app/views/users/_user_form.erb 2011-04-12 11:29:23.000000000 +0200 @@ -32,8 +32,10 @@ <tr><td> <div class="label"><%=_("Login Name")%></div> - </td><td colspan=2> - <%= f.text_field :uid, :disabled => disabled, :onblur => "$('#form_"+ (new ? "" : user.uid) +"').validate().element('#user_uid');", :class => "required" %> + </td><td> + <%= f.text_field :uid, :disabled => disabled, :onblur => "$('#form_"+ (new ? "" : user.uid) +"').validate().element('#user_uid');", :onkeyup => "user_exists_validation(this);", :class => "required" %> + </td><td> + <label id="user_name-error" class="error" style="display:none"><%= _('User already exists.') %></label> <%= f.hidden_field :id %> </td></tr> @@ -72,7 +74,7 @@ <% end %> </td> <td> - <label id="groups-error" class="error">error</label> + <label id="groups-error" class="error"></label> </td> </tr> <tr> @@ -91,7 +93,7 @@ <% end %> </td> <td> - <label id="def-group-error" class="error">error</label> + <label id="def-group-error" class="error"></label> </td> </tr> </table> @@ -135,7 +137,7 @@ %> </td> <td> - <label id="roles-error" class="error">error</label> + <label id="roles-error" class="error"></label> </td> </tr> </table> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/www/app/views/users/index.html.erb new/www/app/views/users/index.html.erb --- old/www/app/views/users/index.html.erb 2010-08-25 12:06:17.000000000 +0200 +++ new/www/app/views/users/index.html.erb 2011-04-12 13:05:56.000000000 +0200 @@ -21,10 +21,11 @@ <% content_for :head do %> <% if JSMIN == true %> - <%= javascript_include_tag "users-min.js"-%> + <%= javascript_include_tag "/min/users-min.js"-%> + <%= javascript_include_tag "select_dialog.js" %> <% else %> - <%= javascript_include_tag "jquery.quicksearch.js"-%> <%= javascript_include_tag "select_dialog.js" %> + <%= javascript_include_tag "jquery.quicksearch.js"-%> <%= javascript_include_tag "users.js" %> <% end %> @@ -59,6 +60,9 @@ </style> <% javascript_tag do %> + var AUTH_TOKEN = 'authenticity_token=' + encodeURIComponent("<%= escape_javascript form_authenticity_token %>"); + startNotifier({'module':'users', 'AUTH_TOKEN':AUTH_TOKEN}, 1000, 11000); + jQuery.expr[':'].Contains = function(a, i, m) { return jQuery(a).text().toUpperCase().indexOf(m[3].toUpperCase()) >= 0; }; @@ -185,7 +189,7 @@ <% end %> <% end %> -<div class='plugin-icon'><img alt="yast-users" src='/icons/yast-users.png'/><%=_("Users")%></div> +<div class='plugin-icon'><img alt="yast-users" src='/icons/yast-users.png'/><%=_("Users")%><span id="questionMark">?</span></div> <div class="plugin-content"> <div id="search-userbar"> @@ -205,7 +209,7 @@ <div id="link-container"> <div id="action_links" class="action_links"> <% if @permissions[:useradd] %> - <%=link_to image_tag("/icons/yast-users.png", :class=>"icons") + _("Add New User"), :action => :new %> + <%=link_to image_tag("/icons/yast-users.png", :class=>"icons") + _("New User"), :action => :new %> <label>|</label> <% end %> <%=link_to image_tag("/icons/yast-groups.png", :class=>"icons") + _("Manage Groups"), :controller => "groups" %> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/www/app/views/users/new.html.erb new/www/app/views/users/new.html.erb --- old/www/app/views/users/new.html.erb 2010-08-25 12:06:17.000000000 +0200 +++ new/www/app/views/users/new.html.erb 2011-04-12 11:29:23.000000000 +0200 @@ -20,7 +20,7 @@ --> <% content_for :head do %> <% if JSMIN == true %> - <%= javascript_include_tag "users-min"-%> + <%= javascript_include_tag "min/users-min" -%> <% else %> <%= javascript_include_tag "users.js" %> <%= javascript_include_tag "select_dialog.js" %> @@ -69,7 +69,6 @@ </style> <script language='javascript'> - function select_groups_dialog() { var open_dialog = select_many_dialog({ kind : 'groups', @@ -126,7 +125,6 @@ }; $(document).ready(function(){ - select_groups_open = select_groups_dialog(); select_default_group_open = select_default_group_dialog(); select_roles_open = select_roles_dialog(); @@ -213,4 +211,5 @@ <% end %> <div><input type="hidden" id="all_grps_string" value="<%= @all_grps_string %>" /></div> <div><input type="hidden" id="all_roles_string" value="<%= @all_roles_string %>" /></div> + <div><input type="hidden" id="all_users_string" value="<%= @all_users_string %>" /></div> </div> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/www/lib/tasks/jsmin.rake new/www/lib/tasks/jsmin.rake --- old/www/lib/tasks/jsmin.rake 2010-08-23 14:32:04.000000000 +0200 +++ new/www/lib/tasks/jsmin.rake 2011-04-12 11:29:23.000000000 +0200 @@ -30,16 +30,17 @@ end namespace :js do - javascripts = ['select_dialog.js', 'excanvas.js'] + javascripts = ['select_dialog.js', 'jquery.quicksearch.js', 'excanvas.js', 'users.js'] Dir.chdir(File.join(RAILS_ROOT, 'public', 'javascripts')) do javascripts.map! {|f| File.join(Dir.pwd, f)} #users.js stored in the plugin folder!!! - javascripts.push(File.join(File.dirname(__FILE__), '/../../public/javascripts/users.js')) + #javascripts.push(File.join(File.dirname(__FILE__), '/../../public/javascripts/users.js')) file 'users-min.js' => javascripts do | f | - output_file = File.join(File.dirname(__FILE__), '/../../public/javascripts/') + f.name - minify(f.prerequisites, output_file) + $dir = File.join(File.dirname(__FILE__), '/../../public/javascripts/min/') + mkpath($dir); + minify(f.prerequisites, $dir + f.name) end end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/www/public/javascripts/users.js new/www/public/javascripts/users.js --- old/www/public/javascripts/users.js 2010-08-17 13:53:02.000000000 +0200 +++ new/www/public/javascripts/users.js 1970-01-01 01:00:00.000000000 +0100 @@ -1,203 +0,0 @@ -/* -# Copyright (c) 2009-2010 Novell, Inc. -# -# All Rights Reserved. -# -# This program is free software; you can redistribute it and/or modify it -# under the terms of version 2 of the GNU General Public License -# as published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, contact Novell, Inc. -# -# To contact Novell about this file by physical or electronic mail, -# you may find current contact information at www.novell.com -*/ - -// using replace instead of trim() see bnc#580561 -function _trim(word){ - return word.replace(/^\s*|\s*$/g,''); -} - -function _getElementsByClassName(node, classname) { - if(!node) node = document.getElementsByTagName("body")[0]; - var a = []; - var re = new RegExp('\\b' + classname + '\\b'); - var els = node.getElementsByTagName("*"); - for(var i=0,j=els.length; i<j; i++) - if(re.test(els[i].className))a.push(els[i]); - return a; -} - - - - // onsubmit handler - function form_handler(sid, message) { - if ($('#form_' + sid).valid()) - { -// disable_forms(); -// $('#progress_' + sid).show(); -// blockForm('form_'+sid, message); - - return true; - } - else - { - return false; - } - } - -// delete button handler -function delete_handler(which, progress, message){ - if (which.childElementCount == 2 && which.children[0].firstChild.textContent == "Delete"){ - which.childNodes[0].onclick="return false;"; - which.childNodes[0].href=""; - - disableFormOnSubmit(message); - } -} - -function members_validation(which){ - var mygroups = []; - if (_trim(which.value).length>0) mygroups = which.value.split(","); - var allgroups = $("#all_users_string")[0].value.split(","); - errmsg=""; - for (i=0;i<mygroups.length;i++){ - var found=false; - for(a=0;a<allgroups.length;a++){ - if (allgroups[a]==_trim(mygroups[i])) found=true; - } - if (!found){ - errmsg = mygroups[i]+" "+"is not valid user!" ; - } - } - _getElementsByClassName(which.parentNode.parentNode, 'error')[0].innerHTML = errmsg; - _getElementsByClassName(which.parentNode.parentNode, 'error')[0].style.display= (errmsg.length==0) ? "none" : "block"; - return (errmsg.length==0); -} - - -function set_tab_focus(tab){ - $("#accordion").accordion('activate',$("#tab_"+tab).children("legend")); -} - - -function findById(where, id){ - var node=null; - for(var i=0;i<where.length;i++){ - if (where[i].id==id) node=where[i]; - } - return node; -} - - -function groups_validation(which){ - var mygroups = _trim(findById(which.parentNode.getElementsByTagName('input'), "user_grp_string").value); - if (mygroups.length>0) mygroups = mygroups.split(","); - var allgroups = $("#all_grps_string")[0].value.split(","); - errmsg=""; - for (i=0;i<mygroups.length;i++){ - var found=false; - for(a=0;a<allgroups.length;a++){ - if (allgroups[a]==_trim(mygroups[i])) found=true; - } - if (!found){ - errmsg = mygroups[i]+" "+"is not valid group!" ; - } - } - set_tab_focus("groups") - var error = findById(which.parentNode.parentNode.parentNode.getElementsByTagName('label'), "groups-error"); - error.innerHTML = errmsg; - error.style.display= (errmsg.length==0) ? "none" : "block"; - return (errmsg.length==0); -} - -function def_group_validation(which){ - var mygroup = _trim(findById(which.parentNode.getElementsByTagName('input'), "user_groupname").value); - var allgroups = $("#all_grps_string")[0].value.split(","); - errmsg=""; - - if (mygroup.length>0){ - var found=false; - for(a=0;a<allgroups.length;a++){ - if (allgroups[a]==_trim(mygroup)) found=true; - } - if (!found){ - errmsg = mygroup+" "+"is not valid group!" ; - } - } - - set_tab_focus("groups") - var error = findById(which.parentNode.parentNode.parentNode.getElementsByTagName('label'), "def-group-error"); - error.innerHTML = errmsg; - error.style.display= (errmsg.length==0) ? "none" : "block"; - return (errmsg.length==0); -} - -function roles_validation(which){ - var myroles = _trim(findById(which.parentNode.getElementsByTagName('input'), "user_roles_string").value); - if (myroles.length>0) myroles = myroles.split(","); - var allroles = $("#all_roles_string")[0].value.split(","); - errmsg=""; - for (i=0;i<myroles.length;i++){ - var found=false; - for(a=0;a<allroles.length;a++){ - if (allroles[a]==_trim(myroles[i])) found=true; - } - if (!found){ - errmsg = myroles[i]+" "+"is not valid role!" ; - } - } - set_tab_focus("roles") - var error = findById(which.parentNode.parentNode.parentNode.getElementsByTagName('label'), "roles-error"); - error.innerHTML = errmsg; - error.style.display= (errmsg.length==0) ? "none" : "block"; - return (errmsg.length==0); -} - -function user_validation(which, username){ - var valid = true; - var form = '#form_'+username; - if (valid && ($(form).validate().element(form+' #user_uid')==false || $(form).validate().element(form+' #user_user_password')==false || $(form).validate().element(form+' #user_user_password2')==false)){ - $(".tabs_"+username).tabs('select',"#tab_login_"+username); - valid = false; - } - if (valid && (groups_validation($(form+' #user_grp_string')[0])==false || def_group_validation($(form+' #user_groupname')[0])==false)){ - $(".tabs_"+username).tabs('select',"#tab_groups_"+username); - valid = false; - } - if (valid && $(form).validate().element(form+' #user_uid_number')==false){ - $(".tabs_"+username).tabs('select',"#tab_advanced_"+username); - valid = false; - } - - return valid; - -} - - -function propose_home(which){ - var login = findById(which.parentNode.getElementsByTagName('input'), "user_uid").value; - var home = findById(which.parentNode.getElementsByTagName('input'), "user_home_directory").value; - - home = "/home/"+login; - - if (login.length>0) findById(which.parentNode.getElementsByTagName('input'), "user_home_directory").value = home; -} - -function propose_login(which){ - var fullname = findById(which.parentNode.getElementsByTagName('input'), "user_cn").value; - var login = findById(which.parentNode.getElementsByTagName('input'), "user_uid").value; - - if (login.length==0){ - login = fullname.replace(/\s/g, '').toLowerCase(); - findById(which.parentNode.getElementsByTagName('input'), "user_uid").value = login; - propose_home(which.parentNode.parentNode.parentNode); - } -} - diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/www/test/functional/groups_controller_test.rb new/www/test/functional/groups_controller_test.rb --- old/www/test/functional/groups_controller_test.rb 2010-08-02 09:15:09.000000000 +0200 +++ new/www/test/functional/groups_controller_test.rb 2011-01-19 10:39:15.000000000 +0100 @@ -47,6 +47,7 @@ mock.delete "/groups/users.xml", header, nil, 200 mock.put "/groups/users.xml", header, nil, 200 mock.get "/users.xml?attributes=uid", header, response_users, 200 + mock.get "/users.xml?attributes=cn,uidNumber,id&index=s,uid", header, nil, 200 end end ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Remember to have fun... -- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
