You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@labs.apache.org by si...@apache.org on 2008/11/27 17:32:00 UTC

svn commit: r721230 - in /labs/magma/trunk/jobs-simple: ./ src/ src/main/ src/main/java/ src/main/java/org/ src/main/java/org/apache/ src/main/java/org/apache/magma/ src/main/java/org/apache/magma/jobs/ src/main/java/org/apache/magma/jobs/simple/ src/m...

Author: simoneg
Date: Thu Nov 27 08:32:00 2008
New Revision: 721230

URL: http://svn.apache.org/viewvc?rev=721230&view=rev
Log:
LABS-242 : Simple implementation of the scheduler

Added:
    labs/magma/trunk/jobs-simple/pom.xml
    labs/magma/trunk/jobs-simple/src/
    labs/magma/trunk/jobs-simple/src/main/
    labs/magma/trunk/jobs-simple/src/main/java/
    labs/magma/trunk/jobs-simple/src/main/java/org/
    labs/magma/trunk/jobs-simple/src/main/java/org/apache/
    labs/magma/trunk/jobs-simple/src/main/java/org/apache/magma/
    labs/magma/trunk/jobs-simple/src/main/java/org/apache/magma/jobs/
    labs/magma/trunk/jobs-simple/src/main/java/org/apache/magma/jobs/simple/
    labs/magma/trunk/jobs-simple/src/main/java/org/apache/magma/jobs/simple/InstallSimpleScheduler.aj
    labs/magma/trunk/jobs-simple/src/main/java/org/apache/magma/jobs/simple/JobData.java
    labs/magma/trunk/jobs-simple/src/main/java/org/apache/magma/jobs/simple/JobExecutingThread.java
    labs/magma/trunk/jobs-simple/src/main/java/org/apache/magma/jobs/simple/SimpleScheduler.java
    labs/magma/trunk/jobs-simple/src/main/resources/
    labs/magma/trunk/jobs-simple/src/test/
    labs/magma/trunk/jobs-simple/src/test/java/
    labs/magma/trunk/jobs-simple/src/test/java/org/
    labs/magma/trunk/jobs-simple/src/test/java/org/apache/
    labs/magma/trunk/jobs-simple/src/test/java/org/apache/magma/
    labs/magma/trunk/jobs-simple/src/test/java/org/apache/magma/jobs/
    labs/magma/trunk/jobs-simple/src/test/java/org/apache/magma/jobs/simple/
    labs/magma/trunk/jobs-simple/src/test/java/org/apache/magma/jobs/simple/SimpleSchedulerRunTest.java
    labs/magma/trunk/jobs-simple/src/test/java/org/apache/magma/jobs/simple/SimpleSchedulingTest.java
    labs/magma/trunk/jobs-simple/src/test/java/org/apache/magma/jobs/simple/StupidJob.java
    labs/magma/trunk/jobs-simple/src/test/resources/

Added: labs/magma/trunk/jobs-simple/pom.xml
URL: http://svn.apache.org/viewvc/labs/magma/trunk/jobs-simple/pom.xml?rev=721230&view=auto
==============================================================================
--- labs/magma/trunk/jobs-simple/pom.xml (added)
+++ labs/magma/trunk/jobs-simple/pom.xml Thu Nov 27 08:32:00 2008
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+  <parent>
+    <artifactId>magma-parent</artifactId>
+    <groupId>org.apache.magma</groupId>
+    <version>1</version>
+  </parent>
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.apache.magma</groupId>
+  <artifactId>jobs-simple</artifactId>
+  <name>Magma Simple Jobs system</name>
+  <version>0.0.1-SNAPSHOT</version>
+  <description/>
+  <packaging>magma</packaging>
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.magma</groupId>
+      <artifactId>foundation-jobs</artifactId>
+      <version>0.0.1-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.magma</groupId>
+      <artifactId>foundation-conversion</artifactId>
+      <version>0.0.1-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <version>4.5</version>
+    </dependency>
+  </dependencies>
+</project>
\ No newline at end of file

Added: labs/magma/trunk/jobs-simple/src/main/java/org/apache/magma/jobs/simple/InstallSimpleScheduler.aj
URL: http://svn.apache.org/viewvc/labs/magma/trunk/jobs-simple/src/main/java/org/apache/magma/jobs/simple/InstallSimpleScheduler.aj?rev=721230&view=auto
==============================================================================
--- labs/magma/trunk/jobs-simple/src/main/java/org/apache/magma/jobs/simple/InstallSimpleScheduler.aj (added)
+++ labs/magma/trunk/jobs-simple/src/main/java/org/apache/magma/jobs/simple/InstallSimpleScheduler.aj Thu Nov 27 08:32:00 2008
@@ -0,0 +1,20 @@
+package org.apache.magma.jobs.simple;
+
+import org.apache.magma.jobs.Scheduler;
+
+public aspect InstallSimpleScheduler {
+
+	private SimpleScheduler current = null;
+	
+	Scheduler around() : call(Scheduler.new()) {
+		if (current == null) {
+			current = new SimpleScheduler();
+			Thread t = new Thread(current);
+			t.setDaemon(true);
+			t.setName("SimpleScheduler");
+			t.start();
+		}
+		return current;
+	}
+	
+}

Added: labs/magma/trunk/jobs-simple/src/main/java/org/apache/magma/jobs/simple/JobData.java
URL: http://svn.apache.org/viewvc/labs/magma/trunk/jobs-simple/src/main/java/org/apache/magma/jobs/simple/JobData.java?rev=721230&view=auto
==============================================================================
--- labs/magma/trunk/jobs-simple/src/main/java/org/apache/magma/jobs/simple/JobData.java (added)
+++ labs/magma/trunk/jobs-simple/src/main/java/org/apache/magma/jobs/simple/JobData.java Thu Nov 27 08:32:00 2008
@@ -0,0 +1,137 @@
+package org.apache.magma.jobs.simple;
+
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.magma.basics.MagmaException;
+import org.apache.magma.beans.BeanData;
+import org.apache.magma.beans.BeanHandler;
+import org.apache.magma.beans.PropertyInfo;
+import org.apache.magma.jobs.Job;
+import org.apache.magma.jobs.Report;
+import org.apache.magma.jobs.SimpleTrigger;
+import org.apache.magma.jobs.JobStatus;
+
+public class JobData implements JobStatus {
+
+	private Class<? extends Job> jobClass = null;
+	private Map<String,Object> binding = new HashMap<String, Object>();
+	private long lastExecuted = 0;
+	private SimpleTrigger trigger = null;
+	private Report lastReport = null;
+	private boolean running = false;
+	private int id = System.identityHashCode(this);
+	private String name = "Unknown";
+	
+	public JobData(Job job) {
+		this.jobClass = job.getClass();
+		BeanHandler handler = job.handler();
+		BeanData data = job.beanData();
+		Set<String> names = data.getPropertyNames();
+		for (String propname : names) {
+			PropertyInfo prop = data.getProperty(propname);
+			if (prop.isReadable() && prop.isWriteable()) {
+				Object val = null;
+				if (handler.isConverted(propname)) {
+					val = handler.getStringValue(propname);
+				} else {
+					val = handler.getValue(propname);
+				}
+				binding.put(propname, val);
+			}
+		}
+	}
+
+	public long getLastExecuted() {
+		return lastExecuted;
+	}
+
+	public void setLastExecuted(long lastExecuted) {
+		this.lastExecuted = lastExecuted;
+	}
+	
+	public Date getLastRun() {
+		return new Date(this.lastExecuted);
+	}
+
+	public SimpleTrigger getTrigger() {
+		return trigger;
+	}
+
+	public void setTrigger(SimpleTrigger trigger) {
+		this.trigger = trigger;
+	}
+
+	public Class<? extends Job> getJobClass() {
+		return jobClass;
+	}
+
+	public Map<String, Object> getParameters() {
+		return binding;
+	}
+	
+	public Job createInstance() {
+		try {
+			Job job = this.jobClass.newInstance();
+			BeanHandler handler = job.handler();
+			BeanData data = job.beanData();
+			Set<String> names = data.getPropertyNames();
+			for (String propname : names) {
+				PropertyInfo prop = data.getProperty(propname);
+				if (prop.isReadable() && prop.isWriteable()) {
+					Object val = binding.get(propname);
+					if (val instanceof String) {
+						handler.setStringValue(propname, (String)val);
+					} else {
+						handler.setValue(propname, val);
+					}
+				}
+			}
+			handler.commit();
+			return job;
+		} catch (Exception e) {
+			throw new MagmaException(e, "Error initializing and starting job of class {0}", this.jobClass);
+		}
+	}
+	
+	public boolean matches(JobData other) {
+		return 
+		  other.jobClass.equals(this.jobClass) && 
+		  other.trigger.getClass().equals(this.trigger.getClass()) && 
+		  other.trigger.equals(this.trigger);
+	}
+	
+	public long getNextExecutionTime() {
+		return lastExecuted + this.trigger.getEveryMillis();
+	}
+
+	public Report getReport() {
+		return lastReport;
+	}
+
+	public void setLastReport(Report lastReport) {
+		this.lastReport = lastReport;
+	}
+
+	public boolean isRunning() {
+		return running;
+	}
+
+	public void setRunning(boolean running) {
+		this.running = running;
+	}
+
+	public int getId() {
+		return id;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+}

Added: labs/magma/trunk/jobs-simple/src/main/java/org/apache/magma/jobs/simple/JobExecutingThread.java
URL: http://svn.apache.org/viewvc/labs/magma/trunk/jobs-simple/src/main/java/org/apache/magma/jobs/simple/JobExecutingThread.java?rev=721230&view=auto
==============================================================================
--- labs/magma/trunk/jobs-simple/src/main/java/org/apache/magma/jobs/simple/JobExecutingThread.java (added)
+++ labs/magma/trunk/jobs-simple/src/main/java/org/apache/magma/jobs/simple/JobExecutingThread.java Thu Nov 27 08:32:00 2008
@@ -0,0 +1,59 @@
+package org.apache.magma.jobs.simple;
+
+import org.apache.magma.beans.BeanHandler;
+import org.apache.magma.jobs.Job;
+import org.apache.magma.jobs.Report;
+
+public class JobExecutingThread extends Thread {
+
+	private Job job = null;
+	private Report report = new Report();
+	private JobData data = null;
+	private SimpleScheduler scheduler = null;
+	
+	public JobExecutingThread(Job job, SimpleScheduler scheduler) {
+		this.job = job;
+		this.setName("Job " + job.toString());
+		this.setDaemon(true);
+		this.scheduler = scheduler;
+	}
+
+	@Override
+	public synchronized void start() {
+		report.started();
+		super.start();
+	}
+	
+	public void run() {
+		if (job.beanData().getProperty("report") != null) {
+			BeanHandler handler = job.handler();
+			handler.setValue("report", report);
+			handler.commit();
+		}
+		try {
+			job.run();
+		} catch (Throwable t) {
+			report.error(t);
+		} finally {
+			report.finished();
+			synchronized (scheduler) {
+				scheduler.notifyAll();
+			}
+		}
+	}
+
+	public Report getReport() {
+		return report;
+	}
+
+	public JobData getData() {
+		return data;
+	}
+
+	public void setData(JobData data) {
+		this.data = data;
+		if (data != null) data.setLastReport(this.report);
+	}
+	
+	
+}

Added: labs/magma/trunk/jobs-simple/src/main/java/org/apache/magma/jobs/simple/SimpleScheduler.java
URL: http://svn.apache.org/viewvc/labs/magma/trunk/jobs-simple/src/main/java/org/apache/magma/jobs/simple/SimpleScheduler.java?rev=721230&view=auto
==============================================================================
--- labs/magma/trunk/jobs-simple/src/main/java/org/apache/magma/jobs/simple/SimpleScheduler.java (added)
+++ labs/magma/trunk/jobs-simple/src/main/java/org/apache/magma/jobs/simple/SimpleScheduler.java Thu Nov 27 08:32:00 2008
@@ -0,0 +1,191 @@
+package org.apache.magma.jobs.simple;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.magma.basics.MagmaException;
+import org.apache.magma.jobs.Job;
+import org.apache.magma.jobs.JobStatus;
+import org.apache.magma.jobs.Scheduler;
+import org.apache.magma.jobs.SimpleTrigger;
+import org.apache.magma.jobs.Trigger;
+
+public class SimpleScheduler extends Scheduler implements Runnable {
+
+	private List<JobData> datas = new ArrayList<JobData>();
+	private List<JobExecutingThread> running = new ArrayList<JobExecutingThread>();
+	private List<JobStatus> finisheds = new ArrayList<JobStatus>();
+	
+	private int maxThreads = 4;
+	
+	
+	@Override
+	public JobStatus run(String name, Job job) {
+		return internalRun(name, job);
+	}
+	
+	protected void internalRun(JobData data) {
+		JobExecutingThread jt = new JobExecutingThread(data.createInstance(), this);
+		setupThread(data, jt);
+	}
+
+	private void setupThread(JobData data, JobExecutingThread jt) {
+		jt.setData(data);
+		data.setLastExecuted(System.currentTimeMillis());
+		data.setRunning(true);
+		synchronized (this.running) {
+			jt.start();
+			this.running.add(jt);			
+		}
+		synchronized (this) {
+			this.notifyAll();			
+		}
+	}
+	
+	protected JobData internalRun(String name, Job job) {
+		JobData jd = new JobData(job);
+		jd.setName(name);
+		JobExecutingThread jt = new JobExecutingThread(job, this);
+		setupThread(jd, jt);
+		return jd;
+	}
+
+	@Override
+	public void schedule(String name, Job job, Trigger trigger) {
+		if (!(trigger instanceof SimpleTrigger)) throw new MagmaException("The simple scheduler is only able to handle SimpleTrigger");
+		SimpleTrigger strig = (SimpleTrigger) trigger;
+		JobData jd = new JobData(job);
+		jd.setName(name);
+		jd.setTrigger(strig);
+		synchronized (this.datas) {
+			datas.add(jd);			
+		}
+		synchronized (this) {
+			this.notifyAll();			
+		}
+	}
+
+	public long check() {
+		synchronized (this.running) {
+			for (Iterator<JobExecutingThread> iterator = this.running.iterator(); iterator.hasNext();) {
+				JobExecutingThread thread = iterator.next();
+				if (!thread.getReport().isRunning()) {
+					System.out.println("Finished " + thread);
+					iterator.remove();
+					if (!datas.contains(thread.getData())) {
+						if (finisheds.size() > 10) finisheds.remove(0);
+						finisheds.add(thread.getData());
+					}
+					thread.getData().setRunning(false);
+					synchronized (this) {
+						this.notifyAll();			
+					}
+				}
+			}			
+		}
+		long cur = System.currentTimeMillis();
+		long min = cur + 60000;
+		synchronized (datas) {
+			for (JobData data : this.datas) {
+				if (data.getNextExecutionTime() <= cur) {
+					if (this.running.size() > maxThreads) {
+						min = cur + 1000;
+					} else {
+						internalRun(data);
+					}
+				}
+				if (min > data.getNextExecutionTime()) min = data.getNextExecutionTime();
+			}			
+		}
+		return min - cur; 
+	}
+
+	public void run() {
+		while (true) {
+			long wait = 2000;
+			try {
+				wait = check();
+			} catch (Throwable t) {
+				t.printStackTrace();
+			}
+			try {
+				if (wait <= 0) wait = 1;
+				synchronized (this) {
+					System.out.println("Waiting " + wait);
+					this.wait(wait);
+					System.out.println("Awake");
+				}
+			} catch (InterruptedException e) {
+			}
+		}
+	}
+	
+	@Override
+	public List<JobStatus> getRunning() {
+		List<JobStatus> statuses = new ArrayList<JobStatus>();
+		synchronized (running) {
+			for (JobExecutingThread th : this.running) {
+				if (!datas.contains(th.getData())) {
+					statuses.add(th.getData());
+				}
+			}
+		}
+		return statuses;
+	}
+	
+	@Override
+	public List<JobStatus> getScheduled() {
+		List<JobStatus> statuses = new ArrayList<JobStatus>();
+		synchronized (datas) {
+			for (JobStatus jobStatus : this.datas) {
+				statuses.add(jobStatus);
+			}
+		}
+		return statuses;
+	}
+	
+	@Override
+	public List<JobStatus> getFinished() {
+		List<JobStatus> statuses = new ArrayList<JobStatus>();
+		synchronized (running) {
+			for (JobStatus status : this.finisheds) {
+				statuses.add(status);
+			}
+		}
+		
+		return statuses;
+	}
+	
+	@Override
+	public JobStatus getStatus(int id) {
+		synchronized (datas) {
+			for (JobStatus jobStatus : this.datas) {
+				if (jobStatus.getId() == id) return jobStatus;
+			}
+		}
+		synchronized (running) {
+			for (JobExecutingThread th : this.running) {
+				if (!datas.contains(th.getData())) {
+					if(th.getData().getId() == id) return th.getData();
+				}
+			}
+			for (JobStatus jobStatus : this.finisheds) {
+				if (jobStatus.getId() == id) return jobStatus;
+			}
+		}
+		return null;
+	}
+	
+	void reset() {
+		synchronized (this.datas) {
+			this.datas.clear();
+		}
+		synchronized (this.running) {
+			this.finisheds.clear();
+		}
+		synchronized (this) {
+			this.notifyAll();
+		}
+	}
+}

Added: labs/magma/trunk/jobs-simple/src/test/java/org/apache/magma/jobs/simple/SimpleSchedulerRunTest.java
URL: http://svn.apache.org/viewvc/labs/magma/trunk/jobs-simple/src/test/java/org/apache/magma/jobs/simple/SimpleSchedulerRunTest.java?rev=721230&view=auto
==============================================================================
--- labs/magma/trunk/jobs-simple/src/test/java/org/apache/magma/jobs/simple/SimpleSchedulerRunTest.java (added)
+++ labs/magma/trunk/jobs-simple/src/test/java/org/apache/magma/jobs/simple/SimpleSchedulerRunTest.java Thu Nov 27 08:32:00 2008
@@ -0,0 +1,55 @@
+package org.apache.magma.jobs.simple;
+
+import java.util.List;
+
+import org.apache.magma.jobs.JobStatus;
+import org.apache.magma.jobs.Scheduler;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+import static org.junit.matchers.JUnitMatchers.*;
+import static org.hamcrest.CoreMatchers.*;
+
+
+public class SimpleSchedulerRunTest {
+
+	@Test
+	public void run() throws Exception {
+		StupidJob.messages.clear();
+		Scheduler sched = new Scheduler();
+		StupidJob job = new StupidJob();
+		job.setMessage("simplerun");
+		sched.run("test", job);
+		synchronized (sched) {
+			sched.wait(60000);
+		}
+		assertThat(StupidJob.messages, hasItem(equalTo("simplerun")));
+	}
+	
+	@Test
+	public void multiRun() throws Exception {
+		StupidJob.messages.clear();
+		Scheduler sched = new Scheduler();
+		
+		for (int i = 1; i < 10; i++) {
+			StupidJob job = new StupidJob();
+			job.setMessage("simplerun" + i);
+			sched.run("test", job);
+			assertThat("Not found a job in the state for number " + i, sched.getRunning().size(), not(0));
+		}
+		
+		int cnt = 0;
+		while (sched.getRunning().size() > 0 && cnt < 20) {
+			synchronized (sched) {
+				sched.wait(1500);
+			}
+			cnt++;
+		}
+		assertThat(cnt, not(20));
+		
+		for (int i = 1; i < 10; i++) {		
+			assertThat(StupidJob.messages, hasItem(equalTo("simplerun" + i)));
+		}
+	}
+	
+}

Added: labs/magma/trunk/jobs-simple/src/test/java/org/apache/magma/jobs/simple/SimpleSchedulingTest.java
URL: http://svn.apache.org/viewvc/labs/magma/trunk/jobs-simple/src/test/java/org/apache/magma/jobs/simple/SimpleSchedulingTest.java?rev=721230&view=auto
==============================================================================
--- labs/magma/trunk/jobs-simple/src/test/java/org/apache/magma/jobs/simple/SimpleSchedulingTest.java (added)
+++ labs/magma/trunk/jobs-simple/src/test/java/org/apache/magma/jobs/simple/SimpleSchedulingTest.java Thu Nov 27 08:32:00 2008
@@ -0,0 +1,49 @@
+package org.apache.magma.jobs.simple;
+
+import org.apache.magma.jobs.Every;
+import org.apache.magma.jobs.FineEvery;
+import org.apache.magma.jobs.JobStatus;
+import org.apache.magma.jobs.Scheduler;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+import static org.junit.matchers.JUnitMatchers.*;
+import static org.hamcrest.CoreMatchers.*;
+
+public class SimpleSchedulingTest {
+
+	
+	@Test
+	public void scheduleRepeating() throws Exception {
+		StupidJob.messages.clear();
+		Scheduler sched = new Scheduler();
+		((SimpleScheduler)sched).reset();
+		
+		StupidJob job = new StupidJob();
+		job.setMessage("recurring");
+		sched.schedule("test", job, new FineEvery(0,0,3));
+		
+		assertThat(sched.getScheduled(), hasItem(not(nullValue(JobStatus.class))));
+		
+		long start = System.currentTimeMillis();
+		while (System.currentTimeMillis() < start + 14000) {
+			synchronized (sched) {
+				sched.wait(3000);
+			}			
+		}
+		
+		((SimpleScheduler)sched).reset();
+		assertThat(StupidJob.messages.size(), equalTo(5));
+		assertThat(StupidJob.messages, everyItem(equalTo("recurring")));
+		
+		int cnt = 0;
+		while (cnt < 10 && (sched.getScheduled().size() > 0 || sched.getRunning().size() > 0)) {
+			synchronized (sched) {
+				sched.wait(1000);
+			}			
+			cnt++;
+		}
+		assertThat("Scheduler didn't remove scheduled task, even if i waited", sched.getScheduled().size(), equalTo(0));
+		assertThat("Scheduler didn't remove running task, even if i waited", sched.getRunning().size(), equalTo(0));
+	}
+}

Added: labs/magma/trunk/jobs-simple/src/test/java/org/apache/magma/jobs/simple/StupidJob.java
URL: http://svn.apache.org/viewvc/labs/magma/trunk/jobs-simple/src/test/java/org/apache/magma/jobs/simple/StupidJob.java?rev=721230&view=auto
==============================================================================
--- labs/magma/trunk/jobs-simple/src/test/java/org/apache/magma/jobs/simple/StupidJob.java (added)
+++ labs/magma/trunk/jobs-simple/src/test/java/org/apache/magma/jobs/simple/StupidJob.java Thu Nov 27 08:32:00 2008
@@ -0,0 +1,45 @@
+package org.apache.magma.jobs.simple;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import org.apache.magma.beans.BeanData;
+import org.apache.magma.beans.BeanHandler;
+import org.apache.magma.jobs.Job;
+import org.apache.magma.jobs.Report;
+
+public class StupidJob implements Job {
+
+	public static List<String> messages = new ArrayList<String>();
+	
+	private String message = null;
+	private Report report = null;
+	
+	
+	public void run() {
+		System.out.println(Thread.currentThread().getName() + " - " + new Date() + " - WAIT");
+		try {
+			Thread.sleep(1000);
+		} catch (InterruptedException e) {
+		}
+		messages.add(message);
+		System.out.println(Thread.currentThread().getName() + " - " + new Date() + "MESSAGED " + message);
+		report.setState("messaging " + message);
+	}
+
+
+	public String getMessage() {
+		return message;
+	}
+
+	public void setMessage(String message) {
+		this.message = message;
+	}
+
+
+	public void setReport(Report report) {
+		this.report = report;
+	}
+
+}



---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@labs.apache.org
For additional commands, e-mail: commits-help@labs.apache.org