Donnerstag, 28. November 2013

Java - jar Datei starten inkl. Log Datei

Anbei ein kleines Bash Script, mit dem meine JAR Datei starten kann und gleichzeitg auch alle Ausgaben in eine Log-Datei geschrieben werden.


#!/bin/bash
DATE=`date +%Y%m%e_%H%M`
LOGDIR="logs"
BCKFILE="log_"$DATE".txt"
 
if [ ! -d $LOGDIR ]
then
  mkdir $LOGDIR
fi
if [ -f log.txt ]
then
  cp -v log.txt $LOGDIR"/"$BCKFILE
fi
 
java -jar xyz.jar 2 > &1 > log.txt &

Freitag, 1. November 2013

CAS (Central Authentication Service) mit Spring Security - Teil 3

Beispiel Klasse: /src/java/cas/MyUserDetails.java


 package de.test.cas;  
 import java.io.Serializable;  
 import java.util.Collection;  
 import java.util.HashSet;  
 import java.util.Set;  
 import javax.persistence.EntityManager;  
 import org.apache.log4j.Logger;  
 import org.springframework.security.core.GrantedAuthority;  
 import org.springframework.security.core.authority.SimpleGrantedAuthority;  
 import org.springframework.security.core.userdetails.UserDetails;  
 /*  
  *   
  * Assign all authenticated users ROLE_AUTHENTICATED  
  *   
  */  
 public class MyUserDetails implements Serializable, UserDetails {  
      private static final long serialVersionUID = 1L;  
      private final String username;  
      private final Set<Long> permissionsForUsers;  
      static final Logger logger = Logger.getLogger(MyUserDetails.class);  
      private final Collection<GrantedAuthority> authorities;  
      public MyUserDetails(Collection<GrantedAuthority> authorities, String username, Set<Long> permissionsForUsers) {  
           this.username=username;  
           this.authorities = authorities;  
           this.permissionsForUsers = permissionsForUsers;  
      }  
      @Override  
      public String toString() {  
           return this.username;  
      }  
      public Set<Long> getPermissionsForUsers() {  
           return permissionsForUsers;  
      }  
      @Override  
      public Collection<GrantedAuthority> getAuthorities() {  
           return authorities;  
      }  
      @Override  
      public String getPassword() {  
           return null;  
      }  
      @Override  
      public String getUsername() {  
           return username;  
      }  
      @Override  
      public boolean isAccountNonExpired() {  
           return true;  
      }  
      @Override  
      public boolean isAccountNonLocked() {  
           return true;  
      }  
      @Override  
      public boolean isCredentialsNonExpired() {  
           return true;  
      }  
      @Override  
      public boolean isEnabled() {  
           return true;  
      }  
 }  


Beispiel Klasse: /src/java/cas/MyUserService.java


 package de.test.cas;  
 import java.math.BigDecimal;  
 import java.util.HashSet;  
 import java.util.List;  
 import java.util.Set;  
 import javax.persistence.EntityManager;  
 import javax.persistence.NoResultException;  
 import javax.persistence.PersistenceContext;  
 import javax.persistence.Query;  
 import javax.persistence.criteria.CriteriaBuilder;  
 import javax.persistence.criteria.CriteriaQuery;  
 import javax.persistence.criteria.Root;  
 import org.apache.log4j.Logger;  
 import org.springframework.dao.DataAccessException;  
 import org.springframework.security.core.GrantedAuthority;  
 import org.springframework.security.core.authority.SimpleGrantedAuthority;  
 import org.springframework.security.core.userdetails.UserDetails;  
 import org.springframework.security.core.userdetails.UserDetailsService;  
 import org.springframework.security.core.userdetails.UsernameNotFoundException;  
 import de.test.db.domain.Assistant;  
 import de.test.db.domain.Transformable;  
 import de.test.db.domain.User;  
 public class MyUserService implements UserDetailsService {  
      private List<String> predefinedAdminAccounts = null;  
      static final Logger logger = Logger.getLogger(UserDetailsService.class);  
      private EntityManager entityManager = null;  
      public EntityManager getEntityManager() {  
           return entityManager;  
      }  
      @PersistenceContext  
      public void setEntityManager(EntityManager entityManager) {  
           this.entityManager = entityManager;  
      }  
      public List<String> getPredefinedAdminAccounts() {  
           return predefinedAdminAccounts;  
      }  
      public void setPredefinedAdminAccounts(List<String> predefinedAdminAccounts) {  
           this.predefinedAdminAccounts = predefinedAdminAccounts;  
      }  
      @Override  
      public UserDetails loadUserByUsername(String username)  
                throws UsernameNotFoundException, DataAccessException, NoResultException {  
           logger.info("!!! loadUserByUsername !!!");  
           Set<GrantedAuthority> authorities = new HashSet<GrantedAuthority>();   
           Set<Long> permissionsForUsers = new HashSet<Long>();  
           if(predefinedAdminAccounts.contains(username)) {  
                authorities.add(new SimpleGrantedAuthority("ROLE_ADMIN"));  
           } else {  
                CriteriaBuilder cb = entityManager.getCriteriaBuilder();  
                CriteriaQuery<User> uq = cb.createQuery(User.class);  
                Root<User> ur = uq.from(User.class);  
                uq.select(ur).where(cb.equal(ur.get("accountName"), username));  
                List<User> uresult = entityManager.createQuery(uq).getResultList();  
                User user = null;  
                if(!uresult.isEmpty()) {  
                     user = uresult.get(0);  
                }  
                if(user != null) {  
                     permissionsForUsers.add(user.getId());  
                     logger.info(user.getAccountName() + " " + user.getId());  
                     authorities.add(new SimpleGrantedAuthority("ROLE_USER"));  
                }  
                CriteriaQuery<Assistant> aq = cb.createQuery(Assistant.class);  
                Root<Assistant> ar = aq.from(Assistant.class);  
                aq.select(ar).where(cb.equal(ar.get("accountName"), username));  
                List<Assistant> aresult = entityManager.createQuery(aq).getResultList();  
                Assistant assistant = null;  
                if(!aresult.isEmpty()) {  
                     assistant = aresult.get(0);  
                }  
                if(assistant != null) {  
                     authorities.add(new SimpleGrantedAuthority("ROLE_ASSISTANT"));  
                     Query queryForPrincipals = getEntityManager().createNativeQuery("select userId from USERS_ASSISTANTS where assistantId=:assistantId");  
                     queryForPrincipals.setParameter("assistantId", assistant.getId());  
                     List<BigDecimal> ids = queryForPrincipals.getResultList();  
                     for(BigDecimal b : ids)  
                          permissionsForUsers.add(b.longValue());  
                }  
           }  
           return      new MyUserDetails(authorities, username, permissionsForUsers);  
      }  
      private <T extends Transformable<Long>> T getPrincipal(Class<T> c, String username) {  
           CriteriaBuilder cb = entityManager.getCriteriaBuilder();  
           CriteriaQuery<T> cq = cb.createQuery(c);  
           Root<T> r = cq.from(c);  
           cq.select(r).where(cb.equal(r.get("accountName"), username));  
           List<T> result = entityManager.createQuery(cq).getResultList();  
           if(!result.isEmpty()) {  
                return result.get(0);  
           }  
           else  
                return null;  
      }  
 }  

Freitag, 30. August 2013

CAS (Central Authentication Service) mit Spring Security - Teil 2

Konfiguration der spring/applicationContextSecurityCas.xml

<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:security="http://www.springframework.org/schema/security"
 xmlns:sec="http://www.springframework.org/security/tags"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns:util="http://www.springframework.org/schema/util"
 xsi:schemaLocation="http://www.springframework.org/schema/beans
  http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
  http://www.springframework.org/schema/security
  http://www.springframework.org/schema/security/spring-security-3.1.xsd
  http://www.springframework.org/schema/util
  http://www.springframework.org/schema/util/spring-util-2.5.xsd">

 <description>
  This is the main configuration for the security with cas.
 </description>
 
  <!-- Variablen als key/value-Paare in einer Properties-Datei ablegen und dann 
in den Context-Dateien auslesen -->
 <bean id="placeholderConfig" 
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
  <property name="locations">
  <list>
   <value>/WEB-INF/environment.properties</value>
   <value>/WEB-INF/jdbc.properties</value>
  </list>
  </property>
  <property name="ignoreResourceNotFound" value="false" />
  <property name="ignoreUnresolvablePlaceholders" value="false" />
  <property name="searchSystemEnvironment" value="false" />
 </bean>
  
 
 <security:global-method-security pre-post-annotations="enabled" /> 

 <!-- ======================== Security Filter Chain ======================= -->
 <bean id="springSecurityFilterChain"
  class="org.springframework.security.web.FilterChainProxy">
  <security:filter-chain-map path-type="ant">
   <security:filter-chain pattern="/j_spring_security_logout" 
filters="logoutFilter,etf,filterSecurityInterceptor" />
   <security:filter-chain pattern="/**" filters="
    securityContextPersistentFilter, 
    anonymousAuthenticationFilter, 
    
    casAuthenticationFilter, 
    logoutFilter,
    exceptionTranslationFilterCAS, 
    filterSecurityInterceptor"
   />
 
  </security:filter-chain-map>
 </bean>
 
 <!-- Filter to store the Authentication object in the HTTP Session -->   
 <bean id="securityContextPersistentFilter" 
class="org.springframework.security.web.context.SecurityContextPersistenceFilter">
  <property name="securityContextRepository" ref="securityContextRepository" />
 </bean>
 <bean id="securityContextRepository" 
class="org.springframework.security.web.context.HttpSessionSecurityContextRepository" />

 <!-- anonymousAuthenticationFilter -->
 <bean id="anonymousAuthenticationFilter" 
class="org.springframework.security.web.authentication.AnonymousAuthenticationFilter">
  <property name="key" value="foobar"/>
  <property name="userAttribute" value="anonymousUser, ROLE_ANONYMOUS"/>
 </bean>
 
 <!-- casAuthenticationFilter -->
 <bean id="casAuthenticationFilter" 
class="org.springframework.security.cas.web.CasAuthenticationFilter">
  <property name="authenticationManager" ref="authenticationManager"/>
        <property name="authenticationFailureHandler">
            <bean 
class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
                <property name="defaultFailureUrl" value="/casfailed"/>
            </bean>
        </property>
  <property name="authenticationSuccessHandler">
   <bean 
class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler">
    <property name="defaultTargetUrl" value="/"/>
   </bean>
  </property>
 </bean>
    
   <!-- casAuthenticationEntryPoint  -->
   <bean id="casAuthenticationEntryPoint" 
class="org.springframework.security.cas.web.CasAuthenticationEntryPoint">
    <!--
    <property name="loginUrl" value="https://sso.your.server.de"/>
    -->
    <property name="loginUrl" value="${sso.host}"/>
    <property name="serviceProperties" ref="casServiceProperties"/>
   </bean>
   
 <!-- exceptionTranslationFilterCAS -->
 <bean id="exceptionTranslationFilterCAS" 
class="org.springframework.security.web.access.ExceptionTranslationFilter">
  <property name="authenticationEntryPoint" ref="casAuthenticationEntryPoint"/>
  <!--
  <property name="accessDeniedHandler" ref="accessDeniedHandler"/>
  -->
 </bean>
 
 <!-- logoutFilter: this filter handles the logout.It should be placed at the 
beginning of the filter chain so a click on the logout link (or button) will not
   go through the rest of the chain -->
    <bean id="logoutFilter" 
class="org.springframework.security.web.authentication.logout.LogoutFilter">
        <!-- 
  <constructor-arg value="/"/>  
  Logout wird noch nicht richtig durchgeführt, 
alternativ https://sso.your.server.de/logout verwenden
  -->  
        <constructor-arg value="/logout"/> 
        <constructor-arg>
            <list>
                <bean 
class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler"/>
            </list>
        </constructor-arg>
    </bean>
    
     <bean id="etf" class="org.springframework.security.web.access.ExceptionTranslationFilter">
        <property name="authenticationEntryPoint" ref="preAuthEntryPoint"/>
    </bean>   

 <bean id="preAuthEntryPoint" 
class="org.springframework.security.web.authentication.Http403ForbiddenEntryPoint" />

    <bean id="servletContext" 
class="org.springframework.web.context.support.ServletContextFactoryBean"/>

 <!-- Authentication Manager 
 Benutzer gegenüber mehreren Quellen zur Identitätsverwaltung authentifizieren.
 Dies ermöglicht es Spring Security, mehrere Authentifizierungsmechanismen für 
        eine einzelne Anwendung zu unterstützen.
 -->
 <bean id="authenticationManager"
  class="org.springframework.security.authentication.ProviderManager">
  <property name="providers">
   <list>
    <ref local="casAuthenticationProvider"/>
    <!--
    <ref local="authenticationProvider"/>
    <ref local="daoAuthenticationProvider"/>
    -->
    <ref local="anonymousAuthenticationProvider"/>
   </list>
  </property>
 </bean>

 <bean id="dataSource" 
class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
  <property name="driverClassName" value="${jdbc.driverClassName}"></property>
  <property name="url" value="${jdbc.databaseurl}"></property>
  <property name="username" value="${jdbc.username}"></property>
  <property name="password" value="${jdbc.password}"></property>
 </bean>
   
 <util:list id="predefinedAdminAccounts" list-class="java.util.ArrayList" 
value-type="java.lang.String">
   <value>adminuser1</value>
   <value>adminuser2</value>
 </util:list>
   
 <bean id="myUserService" class="de.shemel.cas.MyUserService">
  <property name="dataSource" ref="dataSource"/>
  <property name="predefinedAdminAccounts" ref="predefinedAdminAccounts"/>
 </bean>
   
 <bean id="casAuthenticationProvider" 
class="org.springframework.security.cas.authentication.CasAuthenticationProvider">
  <property name="userDetailsService" ref="myUserService" />
  <property name="serviceProperties" ref="casServiceProperties"/>
  <property name="ticketValidator">
   <bean 
class="org.jasig.cas.client.validation.Cas20ServiceTicketValidator">
    <constructor-arg index="0" value="${sso.host}/" />
    <property name="proxyGrantingTicketStorage">
     <bean 
class="org.jasig.cas.client.proxy.ProxyGrantingTicketStorageImpl"/>
    </property>
   </bean>
  </property>
  <property name="key" value="tudCasAuthProviderId"/>
 </bean>

 <!-- which service (application) am I authenticating -->
 <bean id="casServiceProperties" class="org.springframework.security.cas.ServiceProperties">
  <!-- 
  <property name="service" 
value="https://your.domain.de/admin/j_spring_cas_security_check"/>
  -->
  <property name="service" value="${host}/admin/j_spring_cas_security_check"/>
  <property name="sendRenew" value="false"/>
 </bean>
 
 <!-- Authentication anonymousAuthenticationProvider -->
 <bean id="anonymousAuthenticationProvider" 
class="org.springframework.security.authentication.AnonymousAuthenticationProvider">
  <property name="key" value="foobar"/>
 </bean>
   
 <bean id="accessDecisionManager" 
class="org.springframework.security.access.vote.AffirmativeBased">
 <property name="allowIfAllAbstainDecisions" value="false"/>
 <property name="decisionVoters">
  <list>
  <bean class="org.springframework.security.access.vote.RoleHierarchyVoter">
     <constructor-arg>
      <bean 
class="org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl">
    <property name="hierarchy">
     <value>
      ROLE_ADMIN &gt; ROLE_USER
      ROLE_EMPLOYEE &gt; ROLE_USER
      ROLE_USER &gt; ROLE_ANONYMOUS
     </value>
    </property>
    </bean>
   </constructor-arg>
  </bean>
 <bean class="org.springframework.security.access.vote.RoleVoter"/>
 <bean class="org.springframework.security.access.vote.AuthenticatedVoter"/>
   </list>
  </property>
 </bean>

 <security:filter-security-metadata-source id="securityMetadataSource">
  <security:intercept-url pattern="/**" method="POST"  
access="ROLE_ADMIN, ROLE_USER"/>
  <security:intercept-url pattern="/**" method="GET"  
access="ROLE_ADMIN, ROLE_USER"/>
  <security:intercept-url pattern="/**" method="PUT"  
access="ROLE_ADMIN, ROLE_USER"/>
  <security:intercept-url pattern="/**" method="DELETE"          
access="ROLE_ADMIN, ROLE_USER"/>
  <security:intercept-url pattern="/**"     
access="ROLE_ADMIN, ROLE_USER" />  
  <security:intercept-url pattern="/casfailed"    
access="ROLE_ANONYMOUS" />
  <security:intercept-url pattern="/logout"    
access="ROLE_ANONYMOUS"/>
  <security:intercept-url pattern="/info"    
access="ROLE_ADMIN, ROLE_USER"/>
 </security:filter-security-metadata-source>
 
 <!--=============== Absicherung Webschicht=========================-->
 <!--Filter für die Rechtevergabe auf der Webschicht --> 
 <bean id="filterSecurityInterceptor" 
class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor">
  <property name="authenticationManager" ref="authenticationManager"/>
  <property name="accessDecisionManager" ref="accessDecisionManager"/>
  <property name="securityMetadataSource" ref="securityMetadataSource"/>
 </bean>

</beans>*/
environment.properties
host=http://localhost:8080
#host=your.domain.de
sso.host=https://sso.your.server.de

jdbc.properties
jdbc.driverClassName=com.microsoft.sqlserver.jdbc.SQLServerDriver
jdbc.databaseurl=jdbc:sqlserver://your.sql.server.de;instanceName=test;databaseName=test-app
jdbc.username=user
jdbc.password=pw123

In Teil III folgt die Erstellung einer eigenen Java-Klasse für SpringSecurity und CAS (de.shemel.cas.MyUserService) !

Freitag, 9. August 2013

CAS (Central Authentication Service) mit Spring Security - Teil 1

Für eine Authentifikation mit CAS wird ein Centraler Authenticate Server benötigt. Java Servlets übernehmen den Anmelde- und Authentifizierungs-Prozess. In diesem kleinen Beispiel wird die Clientseitige Anbindung an den CAS-Server mit Hilfe von Hibernate und SpringSecurity beschrieben.

Ablauf der Benutzeranmeldung 

Login URL
Bei der Anmeldung wird der Benutzers automatisch auf die Login URL des CAS-Servers weitergeleitet. Hier findet die eigentliche Authentifizierung statt (Benutzername und Passwort). Bei Erfolg, bekommt der Benutzer ein gültiges Ticket.

Validation URL
Mit dem Ticket wird der Benutzer wieder zu der eigentlichen Web-Anwendung zurück geleitet. Das Ticket wird validiert (CAS-Server prüft, ob das Ticket bereits in seiner Datenbank vorhanden ist), der Zugriff auf die Anwendung wird freigegeben.

Logout URL
Die Logout URL ist optional und macht ein Ticket ungültig.

Einrichten von CAS mit Hilfe von Spring Security


Herunterladen der richtigen Libraries unter: http://downloads.jasig.org/cas-clients/?C=M;O=D

Vorbereiten der web.xml
 <context-param>  
      <param-name>contextConfigLocation</param-name>  
      <param-value>  
           /WEB-INF/spring/root-context.xml /WEB-INF/spring/applicationContextSecurityCas.xml  
      </param-value>   
 </context-param>  
...
 <!-- CAS -->  
 <!-- ****************************************************************************************************************************** -->  
 <!-- ProxyTicketReceptor -->       
 <!-- -->  
 <servlet>  
  <servlet-name>ProxyTicketReceptor</servlet-name>  
  <servlet-class>  
      edu.yale.its.tp.cas.proxy.ProxyTicketReceptor  
  </servlet-class>  
 </servlet>  
 <servlet-mapping>  
  <servlet-name>ProxyTicketReceptor</servlet-name>  
  <url-pattern>/CasProxyServlet</url-pattern>  
 </servlet-mapping>   
 <filter>  
   <filter-name>CAS Single Sign Out Filter</filter-name>  
   <filter-class>org.jasig.cas.client.session.SingleSignOutFilter</filter-class>  
 </filter>  
 <filter>  
           <filter-name>springSecurityFilterChain</filter-name>  
           <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>  
 </filter>  
 <filter-mapping>  
   <filter-name>CAS Single Sign Out Filter</filter-name>  
   <url-pattern>/*</url-pattern>  
 </filter-mapping>  
 <filter-mapping>  
      <filter-name>springSecurityFilterChain</filter-name>  
      <url-pattern>/*</url-pattern>  
 </filter-mapping>  
 <!-- Default to 60 minute session timeouts -->  
 <session-config>   
      <session-timeout>60</session-timeout>   
 </session-config>  
 <!-- 403 is what the CAS Validation Filter will throw if it has a problem with the ticket -->  
 <error-page>  
      <error-code>403</error-code>  
      <location>/casfailed.jsp</location>  
 </error-page>  
 <!-- ****************************************************************************************************************************** -->  



In Teil II folgt die Konfiguration der spring/applicationContextSecurityCas.xml !

Freitag, 2. August 2013

Jenkins - Deploy Tomcat 7 (fails)

Bei der Umstellung von Apache Tomcat 6 auf die Version 7, kann zu Problemen beim Deploy von war-Files kommen.

BUILD FAILED
java.io.IOException: Server returned HTTP response code: 403 
for URL: http://localhost:8080/manager/list
 at sun.net.www.protocol.http.HttpURLConnection.getInputStream
...

Der Grund dafür ist, dass bei der Version 7 sich einige URL´s und Rollen für den Text-Zugriff auf die Tomcat Manager Apllication geändert haben.

Angepasste URLs



The Manager application has been re-structured for Tomcat 7 onwards and some of URLs have changed. All URLs used to access the Manager application should now start with one of the following options:
  • /manager/html for the HTML GUI
  • /manager/text for the text interface
  • /manager/jmxproxy for the JMX proxy
  • /manager/status for the status pages
Note that the URL for the text interface has changed from "/manager" to "/manager/text".


Angepasste Rollen


Note that for Tomcat 7 onwards, the roles required to use the manager application were changed from the single manager role to the following four roles. You will need to assign the role(s) required for the functionality you wish to access.

  • manager-gui: allows access to the HTML GUI and the status pages
  • manager-script: allows access to the text interface and the status pages
  • manager-jmx: allows access to the JMX proxy and the status pages
  • manager-status: allows access to the status pages only

Donnerstag, 1. August 2013

Kommunikation mit Gesprächspartnern

Kommunikation mit Kollegen, Führungskräften und Kunden spielt in fast allen Berufen eine wichtige Rolle. Die Wahl der richtigen Kommunikation kann in verschiedenen Situationen eine wirkliche Herausforderung sein. Mangelnde oder schlechte Kommunikation kann eine Ursache für Zeitmangel sein. Durch die richtige Kommunikation können Sie Ihr Selbstmanagement und den Umgang mit schwierigen Gesprächspartnern verbessern.


4 Seiten einer Nachricht

Kommunikation läuft immer zwischen einem Sender und Empfänger ab. Es muss ständig zwischen beiden „Sprachen“ übersetzt und zurück übersetzt werden. Sehr häufig kommt es bei der Kommunikation (durch eine falsche Übersetzung) zu Missverständnissen. Diese Missverständnisse können dann zu einer Auseinandersetzung führen, was evtl. in einem Streitgespräch enden kann. Streitgespräche können auch dann entstehen, wenn z.B. Menschen mit unterschiedlichen Sprachstielen kommunizieren.

Das Kommunikationsquadrat ist das bekannteste Modell von Friedemann Schulz von Thun. Dieses Modell ist auch bekannt als das "Vier-Ohren-Modell".



Wenn Sie etwas von sich geben, sind Sie auf vierfache Weise wirksam. Jede Ihrer Äußerungen enthält gleichzeitig vier Botschaften:
  • Eine Sachinformation, worüber Sie informieren.
  • Eine Selbstkundgabe, was Sie von sich zu erkennen geben.
  • Einen Beziehungshinweis, was Sie von dem Gegenüber halten und wie Sie zu ihm stehen.
  • Einen Appell, was Sie bei dem Gegenüber erreichen möchten.


Weitere Informationen zum Thema "Kommunikation" finden Sie in meinem Buch
Zeit- und Selbstmanagement im Beruf - Lernen Sie, Ihren Tag in nur 30 Minuten effektiv zu organisieren


Donnerstag, 18. Juli 2013

Virtueller Linux Server incl. Port Forwarding

Mit Hilfe dieses Beitrages ist es möglich auf einem Windows Rechner (durch einen virtuellen Rechner) auf Services eines Ubuntu Server zuzugreifen.

Aufsetzen von VMware inkl. Port-Forwarding:

Herunterladen von Ubuntu Server: http://www.ubuntu.com/download/server

Installation von VMware Player: http://www.chip.de/downloads/VMware-Player_12994646.html



Per Default sollte der openssh-sever installiert werden, damit man sich auch per SSH (z.B. Putty) auf dem virtuellen Server verbinden kann.

Möchte man nicht nur vom Lokalen-PC per SSH auf die virtuelle Maschine zugreifen, muss ein Port Forwarding für die IP Adresse des virtuellen Servers eingerichtet werden.
Dies ist mit dem "Virtual Network Editor" (vmnetcfg.exe) möglich. Eine Installationsanaleitung findet sich unter:
http://alexduan.com/2012/10/15/vmware-player-5-0-network-editor/

A
nschließend kann unter VMnet8 (virtuelle Netzwerkkarte) ein Port Forwarding für die installierten Services auf dem virtuellen Server (192.168.110.129) eingetragen werden. In diesem Beispiel z.B. SSH, Tomcat, nodeJS usw.


Nach dem Klick auf "OK" und "Apply" ist es jetzt möglich über die IP-Adresse des Rechners auf die Services des virtuelles Servers zuzugreifen :-)


Weitere Informationen und Beispiele finden sich hier:

Montag, 8. Juli 2013

Nutzen Sie das Parkinsonsche Gesetz

Das Pareto-Prinzip ist vielen mittlerweile bekannt, aber haben Sie schon mal etwas vom „Parkinson´sche Gesetz“ gehört?

Das Gesetz, welches nach Cyril Northcote Parkinson benannt wurde, beschreibt folgendes:

„Work expands so as to fill the time available for its completion.” (The Economist Nr. 5856 vom 19. November 1955 (Bd. 177 S. 635–637))

„Arbeit dehnt sich genau in dem Maße aus, wie Zeit für die Erledigung von Aufgaben zur Verfügung steht – und nicht in dem Maße, wie komplex die Aufgaben tatsächlich sind.“


Benötigen Sie für das Erledigen einer Aufgabe in der Regel 20 Minuten, aber es stehen Ihnen 50 Minuten zur Verfügung, dann werden Sie aller Wahrscheinlichkeit nach genau auch diese 50 Minuten für diese Aufgabe brauchen. Sollten Sie aber wie üblich nur 20 Minuten Zeit haben, so werden Sie in der Regel auch nach 20 Minuten fertig sein.


Kurz und knapp der Unterschied zwischen Pareto und dem Parkinsonschen Gesetz:

Pareto-Prinzip
Reduzieren Sie Ihre Aufgaben auf das Wesentliche mit Hilfe der 80-zu-20-Regel.

Parkinsonsche Gesetz
Verkürzen Sie Ihre Arbeitszeit, damit Sie Aufgaben auf das Wesentliche beschränken können.


Versuchen Sie das Parkinsonsche Gesetz zum Beispiel bei Routineaufgaben anzuwenden, bei denen Sie wissen, wie lange Sie für das Bewältigen der Aufgabe benötigen.

Weiterführende Literatur zum Parkinsonschen Gesetz: 
Parkinsons Gesetz und andere Untersuchungen über die Verwaltung

Samstag, 29. Juni 2013

SQLite - Import CSV File - existing or new table

Für mobile Webanwendungen oder Android Applikationen werden in der Regel SQLite Datenbanken verwendet. SQLite unterstützt dabei einen Großteil der im SQL-92-Standard festgelegten SQL-Sprachbefehle.

Weitere Informationen zu SQLite und Downloadmöglichkeit findet Sie hier:
http://www.sqlite.org/download.html

Öffnen der Datenbank mit Hilfe der SQLite command-line shell
attach "my.db" as db1;

Mit dem Kommando ".databases", sollte die soeben hinzugefügte Datei jetzt gelistet werden.








In eine vorhandene Tabelle sollen Daten aus eine CSV Datei importiert werden

Die vorhanden Datenbank hat folgende Struktur:
sqlite> select * from schueler;
1;Max;Mustermann;210;2011
2;Paul;Mustermann;211;2011

Folgende Daten befinden sich in der CSV Datei:
sqlite> select * from schueler;
3;Max;Mustermann;110;2012
4;Paul;Mustermann;111;2012

Da die Datenstruktur übereinstimmt, können die Daten mit dem folgenden Befehl direkt importiert werden:
sqlite> select * from schueler;
sqlite> .separator ';'
sqlite> .import schueler.csv schueler

Hinweis: Sollte es Probleme mit Umlauten geben, muss die CSV Datei im UTF8 Format gespeichert werden. Dies geht zum Beispiel mit Notepad++ - Kodierung - Konvertiere zu UTF8.

In eine leere bzw. neue Datenbank CSV Dateien importieren und dabei die Tabellen anlegen

Dies geht zum Beispiel mit dem Programm SQLite Database Browser (http://sourceforge.net/projects/sqlitebrowser/).




Aufbau der CSV Datei:
_id;jahr;vorname;nachname;zeit
20115248;2011;Erik;Test-Muster;00:04:10
20115152;2011;Jan;Test-Muster;00:04:17
20115153;2011;Tim;Test-Muster;00:04:21

Damit die Daten inkl. der Spaltenstruktur importiert werden können, muss das richtige Trennzeichen (separator) und "Extract field names from first line" ausgewählt werden.






Nach dem erfolgreichen Import der Daten sollte unter dem Menüpunkt "Modify Table" noch die richtigen Datentypen für die einzelnen Spalten angepasst werden!

Weiterführende Literatur zu SQLite: 
The Definitive Guide to SQLite (The Expert's Voice in Open Source)

Montag, 24. Juni 2013

Certified ScrumMaster - Ablauf des Online-Examen

Da ich vor kurzem den Certified ScrumMaster erfolgreich absolviert habe, möchte ich den Ablauf der Online-Prüfung näher beschreiben.

Im Januar 2012 stellte die Scrum Alliance eine neue Version des Zertifizierungsprogramms für den ScrumMaster vor (Online-Examen). Damit man an diesem Test teilnehmen kann, muss man vorab an einer Certified ScrumMaster Schulung teilgenommen haben (zum Beispiel bei der wibas GmbH). Anschließend wird man für das Online-Examen bei der Scrum Alliance (www.scrumalliance.org) angemeldet.

Nun hat man innerhalb von 90 Tagen nach dem Kurs zwei Versuche um das Examens zu bestehen. Sollte ein bestehen in diesem Zeitraum nicht klappen, muss man für jeden weiteren Versuch 25 $ bezahlen.

Das Online-Examen beinhaltet 35 multiple-choice Fragen ohne Zeitbegrenzung, von denen man 24 oder mehr korrekt beantworten muss.

Beispielfragen für das Online-Examen
  • Welche Herangehensweise an die Architektur empfehlen die Prinzipien hinter dem Agilen Manifest? - Antwort: Architektur entwickelt sich.
  • Wann sollte das Release Burndown Chart aktualisiert werden? - Antwort: Nach jedem Sprint.
  • Wie werden Teams während eines Sprints geführt? - Antwort: Durch ihr kollektives Wissen und ihre Erfahrung.
  • Was ist ein HAUPTZWECK eines Sprint Backlogs? - Antwort: Für das Team: sich während des Sprints selbst zu steuern.
  • Was ist eine zielführende Technik für den ScrumMaster, um eine Kommunikation zwischen dem Team und dem Product Owner zu ermöglichen? - Antwort: Alle diese Antworten (Den Product Owner über die während der Sprints angewandten Technologien unterrichten. ; Das Team unterrichten, sich im Hinblick auf die geschäftlichen Anforderungen und Ziele auszudrücken. ; Gemeinsame Besprechungen moderieren.)

Nach dem erfolgreichen Bestehen des Online-Examens kann das CSM-Zertifikat alle zwei Jahre erneuert werden.

Zur Vorbereitung empfehle ich folgende Literatur: Scrum - Agiles Projektmanagement erfolgreich einsetzen

Samstag, 15. Juni 2013

Taskplaner Vorlage für Ihr Zeitmanagement

Im Arbeitsalltag sind Taskplaner auf Papier nach wie vor eine effektive Hilfe für das Zeitmanagement. Man hat sofort einen Überblick über die anstehenden Aufgaben und kann schnell Änderungen vornehmen, Einträge verbinden und gruppieren.
Zusätzlich ist Platz für Termine und für die Auflistung von Zeitdieben vorhanden.

Seien Sie effizient und wenden Sie die Methoden aus meinem Buch
Zeit- und Selbstmanagement im Beruf - Lernen Sie, Ihren Tag in nur 30 Minuten effektiv zu organisieren
mit Hilfe des nachfolgenden Taskplaner an.



Dienstag, 28. Mai 2013

Eigenen IRC Server aufsetzen

In kleineren Softwareentwickler-Teams ist ein schneller Austausch von Informationen, Code-Snippets oder auch Passwörtern wichtig.
Möchte man diese Kommunikation nicht über einen externen Anbieter wie z.B. Skype oder ICQ laufen lassen, bietet sich als schlanke und schnelle Lösung ein eigener IRC (Internet Relay Chat) Server an.

Die Beschreibung der Installation erfolgt als Beispiel auf einem Ubuntu Linux System incl. SSL Verschlüsselung. Als IRC-Server wird UnrealIRCd (http://unrealircd.com) verwendet.

Aktuelle Version herunterladen und anschließend entpacken
wget http://www.unrealircd.com/downloads/Unreal3.2.10.1.tar.gz  
tar xfz Unreal3.2.10.1.tar.gz  

Die Dateien befinden sich jetzt unter ~/Unreal3.2.10.1

Starten der Konfiguration und kompilieren des Quellcodes von UnrealIRCd
./Config


Anschließend startet ein wirklicher Konfigurations-Marathon :-)

Jeder Wert muss durch bestätigen mit der ENTER-Taste bestätigt werden.






Hier muss jetzt der Pfad zu den eben entpackten Dateien noch mal angegeben werden. Stimmt das angezeigte Verzeichnis, dann einfach mit bestätigen.
What directory are all the server configuration files in?
[/home/shemel/Unreal3.2.10.1] ->

What is the path to the ircd binary including the name of the binary?
[/home/shemel/Unreal3.2.10.1/src/ircd] ->

Diesen default-Wert bestätigen!
What should the default permissions for your configuration files be? (Set this to 0 to disable)
It is strongly recommended that you use 0600 to prevent unwanted reading of the file
[0600] ->

Für den SSL-Support des IRC-Server hier bitte YES eintragen!
Do you want to support SSL (Secure Sockets Layer) connections?
[No] -> YES
Leer lassen, wenn man nicht weiß wo OpenSSL auf dem System liegt!
If you know the path to OpenSSL on your system, enter it here. If not
leave this blank (in most cases it will be detected automatically).
[] ->
Die restlichen Abfragen können bestätigt werden.
Do you want to enable IPv6 support?
[No] ->

Do you want to enable ziplinks support?
[No] ->

Do you want to enable remote includes?
This allows stuff like this in your configuration file:
include "http://www.somesite.org/files/opers.conf";
[No] ->

Do you want to enable prefixes for chanadmin and chanowner?
This will give +a the & prefix and ~ for +q (just like +o is @)
Supported by the major clients (mIRC, xchat, epic, eggdrop, Klient,
PJIRC, irssi, CGI:IRC, etc.)
This feature should be enabled/disabled network-wide.
[Yes] ->

What listen() backlog value do you wish to use?  Some older servers
have problems with more than 5, others work fine with many more.
[5] ->

What listen() backlog value do you wish to use?  Some older servers
have problems with more than 5, others work fine with many more.
[5] ->

How far back do you want to keep the nickname history?
[2000] ->


What is the maximum sendq length you wish to have?
[3000000] ->

How many buffer pools would you like?
This number will be multiplied by MAXSENDQLENGTH.
[18] ->

How many file descriptors (or sockets) can the IRCd use?
[1024] ->

Would you like to pass any custom parameters to configure?
See  `./configure --help' and write them here:
[] ->

Ist kein Openssl installiert, erscheint folgende Meldung:
checking for openssl... not found

Apparently you do not have both the openssl binary and openssl development libraries installed.
You have two options:
a) Install the needed binaries and libraries
   and run ./Config
OR
b) If you don't need SSL...
   Run ./Config and say 'no' when asked about SSL
   (or pass --disable-ssl to ./configure)
Eine Anleitung zum Installieren von SSL finden Sie z.B. hier: http://www.postfix-howto.de/installation/openssl.htm

Wurden die Einstellungen wie gewünscht vorgenommen, erfolgt anschließend die Kompilierung des UnrealIRCd. Mit dem Befehlt "make".
Sollten bei der Kompilierung Fehler auftreten, dann muss gegebenenfalls die ./Config noch mal angepasst werden.
 __________________________________________________
| Compile is now complete.                         |
| You should now read the documentation and learn  |
| how to configure your IRCd.                      |
|                                                  |
| If you really like UnrealIRCd, and would like to |
| make a donation, please read the Donation file in|
| this archive. :)                                 |
|                                                  |
| Thanks for using Unreal IRCd! If you are in need |
| for any kind of help regarding the IRCd please   |
| read the Unreal.nfo file.                        |
|__________________________________________________|
Die Kompilierung wurde erfolgreich beendet.

Vor dem Starten des Servers, müssen an der Einstellungsdatei unrealircd.conf noch einige wichtige Einstellungen vorgenommen werden!!! Für den Einstieg ist die Beispieldatei von irc-guide.de sehr gut: http://irc-guide.de/wiki/Main/UnrealIRCdBeispielkonfigurationsdatei

Folgende Anpassungen habe ich an der Beispieldatei vorgenommen:

me {
        name "www.deinserver.de";
        info "IRC - Server von DEINNAME";
        numeric 1;
};

admin {
        "Sebastian Hemel";
        "BENUTZERNAME";
        "deine@mail.de";
};

/* Passworded allow line 
 * Nur Benutzer von einer bestimmten IP-Range und Hostnamen zulassen
 * zusätzlich muss ein Passwort eingegeben werden.
*/
allow {
        ip             *@130.83.*.*;            # Besucher von dieser IP ...
        hostname       *@*.t-online.de;         # ... bzw diesem Host  ...
        class           clients;
        password "xxxxxxxxxxxxxxx";             # ... brauchen ein Passwort zum Verbinden ...
        maxperip 2;                             # ... und dürfen im Gegensatz zu allen anderen ...
                                                # ... nur einmal pro IP/Host verbinden!
};

allow channel {
        channel "#team-chat";
        channel "#raum1";
        channel "#raum2";
};

set {
        auto-join "#team-chat";
};

oper shemel {
 ...
};

/* Server linken. Wenn das nicht gewünscht ist, dann diese Zeilen
 * auskommentieren oder löschen! */
/*
 * listen               123.45.67.8:7001        // Auf Port 7001...
 * {
 *      options
 *      {
 *              serversonly;            // Nur Server, keine Clients.
 *      };
 * };
 */

 /*
  * link hub.mynet.com {
  * ...
  */

 /*
  * tld {
  * ..
  */ 

deny channel {
   channel "*";
   reason "Wir unterstützen keine frei waehlbaren Channels";
}

/* Network configuration */
set {
        network-name            "IRC";
        default-server          "deinserver.de";
        services-server         "deinserver.de";
        stats-server            "deinserver.de";
        help-channel            "#help";
        hiddenhost-prefix       "hrz";
        /* prefix-quit          "no"; */
  
...

        /* Richtiges SSL-Zertifikat hinterlegen!*/
  ssl {
                /* certificate server.crt.pem; */
                certificate server_cert-xyz.pem;
                /* key server.key.pem; */
                key server.priv;
                /* trusted-ca-file class3.crt; */
                trusted-ca-file rootcert.crt;
        };
};


Folgende "Welcome" Dateien können noch erstellt werden:
vi motd.conf
vi rules.conf
Mit den beiden Dateien kann man angeben welche Regeln auf dem IRC-Server gelten und verbindlich sind. Bekannt ist dies auch als "Message of the Day". Ein Generator für schöne Logos im ASCII Format findet sich hier: http://patorjk.com/software/taag

Jetzt lässt sich der IRC Server mit dem folgenden Befehl starten
./unreal start

Starting UnrealIRCd
 _   _                      _ ___________  _____     _
| | | |                    | |_   _| ___ \/  __ \   | |
| | | |_ __  _ __ ___  __ _| | | | | |_/ /| /  \/ __| |
| | | | '_ \| '__/ _ \/ _` | | | | |    / | |    / _` |
| |_| | | | | | |  __/ (_| | |_| |_| |\ \ | \__/\ (_| |
 \___/|_| |_|_|  \___|\__,_|_|\___/\_| \_| \____/\__,_|
                           v3.2.10.1
                     using TRE 0.8.0 (BSD)
                     using OpenSSL 1.0.1e
                     using zlib 1.2.3.3

* Loading IRCd configuration ..
* Configuration loaded without any problems ..
* Loading tunefile..
* Initializing SSL.
* Dynamic configuration initialized .. booting IRCd.
---------------------------------------------------------------------


Glückwunsch zum eigenen IRC Server!
Passende Clients sind z.B. Mirand IM oder auch der Opera Browser.

Programmier-Beispiele in Python um IRC-Services anzusprechen, findet man hier:
Raspberry Pi: Einstieg und User Guide (mitp Professional)

Dienstag, 14. Mai 2013

MS-SQL Tricks

Eine kleine Auflistung von MS-SQL Tricks, die fast täglich zur Anwendung kommen.

Alle Tabellen einer Datenbank löschen:
 Exec sp_MSforeachtable  
  @command1 = "DROP TABLE ? PRINT '? dropped'",  
  @whereand = "and uid = (SELECT schema_id FROM sys.schemas WHERE name = 'dbo') ";  

Informationen über eine Tabelle ausgeben:
 sp_spaceused [TABELLENNAME]  
Gibt die Anzahl der Zeilen sowie den zugeordneten und verwendeten Speicherplatz für eine bestimmte Tabelle, eine indizierte Sicht oder eine Service Broker-Warteschlange in der aktuellen Datenbank bzw. den zugeordneten und verwendeten Speicherplatz für die gesamte Datenbank an.  

Überprüfen ob man Zugang zu der DB hat, kann man recht schnell mit einer Telnet-Verbindung:
 telnet sqlserver.name.de [PORT]  

Backup/Dump der Datenbank erstellen:
Hierfür muss das SQL Server Management Studio geöffnet werden.
  • "DB_name" DB auswählen und im Kontext-Menü TASKS --> SKRIPTS GENERIEREN auswählen. 
  • Anschließend auf "Weiter" klicken. Die Datenbank auswählen "DB_name".
  • Damit auch die INSERT-Befehle gesichert werden, unter Tabellen-/Sichtoptionen --> "Skript für Daten erstellen" auf TRUE setzen. Als Objekttyp "Tabellen" auswählen. 
  • Im nächsten Fenster sollten alle Tabellen (Alles auswählen) markiert werden. 
  • Jetzt können die CREATE und INSERT Befehle in einer Datei oder in einem Abfragefenster gespeichert werden. 
  •  Einspielen: Um die Befehle für die richtige DB auszuführen, muss direkt in der ersten Zeile nach USE die richtige DB angegeben werden. In unserem Fall "USE [DB_name]"

Montag, 13. Mai 2013

Gehen Sie effizient mit E-Mails um!

Wie können Sie Ihren Büro-Tag effizient gestalten und sich nicht unnütz durch E-Mails ablenken lassen?

Hier meine Regeln, welche sich in der Praxis gut anwenden lassen:
  • Sendepause. Stellen Sie sämtliche Benachrichtigung für den Posteingang ab.
  • Entspannen. Wie wichtig ist es, sekundengenau über neue Post informiert zu sein? Reicht es nicht auch diese erst in 3 Stunden zu beantworten?
  • E‐Mails nur viermal am Tag lesen. Legen Sie für sich feste Mail-Abholzeiten fest und einen Antwortzeitraum. Zum Beispiel: Morgens, vor der Mittagspause, nach der Mittagspause und kurz vor dem Feierabend
  • Verbieten Sie CC‐Mails. CC-Mails sind ein sehr größter Zeitfresser. Ist die Information überhaupt wichtig für mich? Antworten alle auf eine CC-Mail, kann es schnell in SPAM ausarten.
  • Arbeiten mit Ordnern, Filtern oder Ticket-System. Verlagern Sie zum Beispiel E-Mails die einzelne Produkte oder Systeme angeht direkt in ein Ticket-System.
  • Halten Sie Ihre E-Mails kurz. Investieren jeweils nur zwei Minuten für eine Antwort. Sie können zum Beispiel auch nur die Betreffzeile für eine kurz Info verwenden und mit EOM (end of message) beenden.
  • Rufen Sie bei komplexen Themen an. Um Ideen zu entwickeln oder auch Konflikte zu lösen, sind E-Mails eher nicht geeignet.

Ich wünsche viel Spaß beim Ausprobieren :-)


Übung: Versuchen Sie doch einen E-Mail freien Tag die Woche einzurichten.


Weitere nützliche Tipps finden Sie in dem Buch: Büro-Effizienz von Rositta Beck-Rappen

Sonntag, 5. Mai 2013

Rund um Linux - Einige nützliche Befehle für die Shell I

Anbei eine Auflistung einiger nützlichen Linux Befehle (ich verwendet vorwiegend Ubuntu), die ich von Woche zu Woche, mal mehr oder weniger verwende.

Vielleicht ist ja auch für euch was nützliches dabei :-)


Datei(en) finden
 find /var/www/* | grep index*.*  

Belegter Platzen-Platz checken
 du -h --exclude=/proc --exclude=/sys --exclude=/media --exclude=/dev --max-depth=1 /  

Datei mit scp auf einen anderen Server kopieren
 scp -P 222 tomcat.sh user@test.server.de:/etc/init.d  

Duplikate von Dateien finden
Dafür kann man das Programm fdupes verwenden, siehe auch http://www.tuxfutter.de/wiki/Fdupes
 fdupes -r /opt/olw/nfs/elc_roh/archive > /home/ubuntu/xdupes.txt  

PermitRootLogin
Mit der Option "PermitRootLogin" gibt man an ob sich der User root direkt per SSH anmelden darf oder ob man sich erst mit einem normalen User authentifizieren muss und dann per "su -" zu root wird.
 /etc/ssh$ sudo vi sshd_config  
PermitRootLogin auf "no" setzen oder auskommentieren!
Anschließend neustart von sshd (/etc/init.d/ssh restart)

ll: command not found
 alias ll='ls -l'  

Dateigröße in MB/GB anzeigen
 du -hs catalina.out  

Verzeichnis packen und entpacken mit tar.gz
Um ein Verzeichnis mit tar.gz zu packen:
 tar cfvz irgendeinname.tar.gz verzeichnisname/  
Um ein Verzeichnis mit tar.gz zu entpacken:
 tar xfvz test.tar.gz  

Eine Datei auf 0 byte setzen
 >catalina.out  
Dies ist z.B. sinnvoll, wenn man im laufenden Betrieb die Datei nicht löschen oder leeren kann.

Mit grep innerhalb von Dateien suchen 
 grep -r 'JkWorkersFile' /etc/*  

Aktuell offene Ports anzeigen
 sudo netstat -tulpen | grep -v '127.0.0.1' | grep -v '::1:'  

Portscanner von einem anderen Rechner aus starten
 sudo nmap 130.80.47.XXX  

Repositories von Ubuntu anzeigen
 less /etc/apt/sources.list  

wget - failed: Connection refused
Evtl. muss ein Proxy Server eingetragen werden!
 http_proxy=http://proxy.uni.de:80; export http_proxy  
 https_proxy=http://proxy.uni.de:443; export https_proxy  
Falls dies bei dem sudo Befehl vorkommt:
 sudo visudo
 Defaults !env_reset  
Siehe auch:  https://bbs.archlinux.org/viewtopic.php?id=94273

Falsche Server Zeit aktulisieren
1. Die Hardware-Uhr umstellen
 sudo hwclock --set --date="12/28/2011 12:26:10"  
2. Die Systemzeit nach der Hardware-Uhr stellen
 sudo hwclock --hctosys  
3. Zeitzone einstellen
 sudo tzselect  

Su/Sudo Script ohne nachfragen des Passworts 
 sudo visudo  
 ubuntu ALL = (ALL) NOPASSWD: /etc/init.d/tomcat6  

Cron-Job für den Neustart von Tomcats in der Nacht um 03:00 UHr 
sudo vi /etc/crontab oder crontab aufrufen -e aufrufen
 0 3   * * *  ubuntu /etc/init.d/tomcat6 restart