From 16decc701b5b1430880d03b854e1ddd2920fbc47 Mon Sep 17 00:00:00 2001 From: "tony.chenl" Date: Wed, 9 Nov 2011 07:57:10 +0000 Subject: [PATCH] =?UTF-8?q?DUBBO-43=20invoke=E4=B9=8B=E5=89=8D=E5=88=A4?= =?UTF-8?q?=E7=A9=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: http://code.alibabatech.com/svn/dubbo/trunk@214 1a56cb94-b969-4eaa-88fa-be21384802f2 --- .../support/FailbackClusterInvoker.java | 8 ++- .../support/FailfastClusterInvoker.java | 3 +- .../support/FailsafeClusterInvoker.java | 8 ++- .../support/ForkingClusterInvoker.java | 6 +- .../support/AbstractClusterInvokerTest.java | 50 +++++++------- .../support/FailSafeClusterInvokerTest.java | 24 +++++++ .../support/FailbackClusterInvokerTest.java | 29 ++++++++- .../support/FailfastClusterInvokerTest.java | 65 +++++++++++++------ .../support/FailoverClusterInvokerTest.java | 58 ++++++++++++----- .../support/ForkingClusterInvokerTest.java | 27 +++++++- dubbo-cluster/src/test/resources/log4j.xml | 4 +- 11 files changed, 212 insertions(+), 70 deletions(-) diff --git a/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/support/FailbackClusterInvoker.java b/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/support/FailbackClusterInvoker.java index ae52ac74d4..ae3254cacf 100644 --- a/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/support/FailbackClusterInvoker.java +++ b/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/support/FailbackClusterInvoker.java @@ -25,9 +25,11 @@ import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; +import com.alibaba.dubbo.common.Version; import com.alibaba.dubbo.common.logger.Logger; import com.alibaba.dubbo.common.logger.LoggerFactory; import com.alibaba.dubbo.common.utils.NamedThreadFactory; +import com.alibaba.dubbo.common.utils.NetUtils; import com.alibaba.dubbo.rpc.Invocation; import com.alibaba.dubbo.rpc.Invoker; import com.alibaba.dubbo.rpc.Result; @@ -37,7 +39,7 @@ import com.alibaba.dubbo.rpc.cluster.Directory; import com.alibaba.dubbo.rpc.cluster.LoadBalance; /** - * FailBackClusterInvoker.java + * 失败自动恢复,后台记录失败请求,定时重发,通常用于消息通知操作。 * * @author tony.chenl */ @@ -99,8 +101,10 @@ public class FailbackClusterInvoker extends AbstractClusterInvoker { } protected Result doInvoke(Invocation invocation, List> invokers, LoadBalance loadbalance) throws RpcException { - Invoker invoker = select(loadbalance, invocation, invokers, null); try { + if (invokers == null || invokers.size() == 0) + throw new RpcException("No provider available for service " + getInterface().getName() + " on consumer " + NetUtils.getLocalHost() + " use dubbo version " + Version.getVersion() + ", Please check whether the service do exist or version is right firstly, and check the provider has started."); + Invoker invoker = select(loadbalance, invocation, invokers, null); return invoker.invoke(invocation); } catch (Throwable e) { logger.error("Failback to invoke " + invocation + ", wait for retry in background. Ignored exception: " diff --git a/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/support/FailfastClusterInvoker.java b/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/support/FailfastClusterInvoker.java index e7af8c7207..26d0b06b47 100644 --- a/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/support/FailfastClusterInvoker.java +++ b/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/support/FailfastClusterInvoker.java @@ -41,7 +41,8 @@ public class FailfastClusterInvoker extends AbstractClusterInvoker{ } public Result doInvoke(Invocation invocation, List> invokers, LoadBalance loadbalance) throws RpcException { - + if (invokers == null || invokers.size() == 0) + throw new RpcException("No provider available for service " + getInterface().getName() + " on consumer " + NetUtils.getLocalHost() + " use dubbo version " + Version.getVersion() + ", Please check whether the service do exist or version is right firstly, and check the provider has started."); Invoker invoker = select(loadbalance, invocation, invokers, null); try { return invoker.invoke(invocation); diff --git a/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/support/FailsafeClusterInvoker.java b/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/support/FailsafeClusterInvoker.java index df62be2c7f..bd4b7e7050 100644 --- a/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/support/FailsafeClusterInvoker.java +++ b/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/support/FailsafeClusterInvoker.java @@ -17,8 +17,10 @@ package com.alibaba.dubbo.rpc.cluster.support; import java.util.List; +import com.alibaba.dubbo.common.Version; import com.alibaba.dubbo.common.logger.Logger; import com.alibaba.dubbo.common.logger.LoggerFactory; +import com.alibaba.dubbo.common.utils.NetUtils; import com.alibaba.dubbo.rpc.Invocation; import com.alibaba.dubbo.rpc.Invoker; import com.alibaba.dubbo.rpc.Result; @@ -42,8 +44,10 @@ public class FailsafeClusterInvoker extends AbstractClusterInvoker{ } public Result doInvoke(Invocation invocation, List> invokers, LoadBalance loadbalance) throws RpcException { - Invoker invoker = select(loadbalance, invocation, invokers, null); - try { + try { + if (invokers == null || invokers.size() == 0) + throw new RpcException("No provider available for service " + getInterface().getName() + " on consumer " + NetUtils.getLocalHost() + " use dubbo version " + Version.getVersion() + ", Please check whether the service do exist or version is right firstly, and check the provider has started."); + Invoker invoker = select(loadbalance, invocation, invokers, null); return invoker.invoke(invocation); } catch (Throwable e) { logger.error("Failsafe ignore exception: " + e.getMessage(), e); diff --git a/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/support/ForkingClusterInvoker.java b/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/support/ForkingClusterInvoker.java index 9f61c45231..25e717878d 100644 --- a/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/support/ForkingClusterInvoker.java +++ b/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/support/ForkingClusterInvoker.java @@ -25,7 +25,9 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.Version; import com.alibaba.dubbo.common.utils.NamedThreadFactory; +import com.alibaba.dubbo.common.utils.NetUtils; import com.alibaba.dubbo.rpc.Invocation; import com.alibaba.dubbo.rpc.Invoker; import com.alibaba.dubbo.rpc.Result; @@ -47,7 +49,9 @@ public class ForkingClusterInvoker extends AbstractClusterInvoker{ private final ExecutorService executor = Executors.newCachedThreadPool(new NamedThreadFactory("forking-cluster-timer", true)); - public Result doInvoke(final Invocation invocation, List> invokers, LoadBalance loadbalance) throws RpcException { + public Result doInvoke(final Invocation invocation, List> invokers, LoadBalance loadbalance) throws RpcException { + if (invokers == null || invokers.size() == 0) + throw new RpcException("No provider available for service " + getInterface().getName() + " on consumer " + NetUtils.getLocalHost() + " use dubbo version " + Version.getVersion() + ", Please check whether the service do exist or version is right firstly, and check the provider has started."); final List> selected; final int forks = getUrl().getParameter(Constants.FORKS_KEY, Constants.DEFAULT_FORKS); final int timeout = getUrl().getParameter(Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT); diff --git a/dubbo-cluster/src/test/java/com/alibaba/dubbo/rpc/cluster/support/AbstractClusterInvokerTest.java b/dubbo-cluster/src/test/java/com/alibaba/dubbo/rpc/cluster/support/AbstractClusterInvokerTest.java index d0a7a9ddbb..48fb483b1e 100644 --- a/dubbo-cluster/src/test/java/com/alibaba/dubbo/rpc/cluster/support/AbstractClusterInvokerTest.java +++ b/dubbo-cluster/src/test/java/com/alibaba/dubbo/rpc/cluster/support/AbstractClusterInvokerTest.java @@ -15,31 +15,31 @@ */ package com.alibaba.dubbo.rpc.cluster.support; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.atomic.AtomicLong; - -import junit.framework.Assert; - -import org.easymock.EasyMock; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; - -import com.alibaba.dubbo.common.ExtensionLoader; -import com.alibaba.dubbo.common.URL; -import com.alibaba.dubbo.rpc.Invocation; -import com.alibaba.dubbo.rpc.Invoker; -import com.alibaba.dubbo.rpc.Result; -import com.alibaba.dubbo.rpc.RpcConstants; -import com.alibaba.dubbo.rpc.RpcException; -import com.alibaba.dubbo.rpc.cluster.Directory; -import com.alibaba.dubbo.rpc.cluster.LoadBalance; -import com.alibaba.dubbo.rpc.cluster.loadbalance.LeastActiveLoadBalance; -import com.alibaba.dubbo.rpc.cluster.loadbalance.RandomLoadBalance; -import com.alibaba.dubbo.rpc.cluster.loadbalance.RoundRobinLoadBalance; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicLong; + +import junit.framework.Assert; + +import org.easymock.EasyMock; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +import com.alibaba.dubbo.common.ExtensionLoader; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.rpc.Invocation; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.Result; +import com.alibaba.dubbo.rpc.RpcConstants; +import com.alibaba.dubbo.rpc.RpcException; +import com.alibaba.dubbo.rpc.cluster.Directory; +import com.alibaba.dubbo.rpc.cluster.LoadBalance; +import com.alibaba.dubbo.rpc.cluster.loadbalance.LeastActiveLoadBalance; +import com.alibaba.dubbo.rpc.cluster.loadbalance.RandomLoadBalance; +import com.alibaba.dubbo.rpc.cluster.loadbalance.RoundRobinLoadBalance; /** * AbstractClusterInvokerTest diff --git a/dubbo-cluster/src/test/java/com/alibaba/dubbo/rpc/cluster/support/FailSafeClusterInvokerTest.java b/dubbo-cluster/src/test/java/com/alibaba/dubbo/rpc/cluster/support/FailSafeClusterInvokerTest.java index 14bcac2fb8..c5f9f0fe30 100644 --- a/dubbo-cluster/src/test/java/com/alibaba/dubbo/rpc/cluster/support/FailSafeClusterInvokerTest.java +++ b/dubbo-cluster/src/test/java/com/alibaba/dubbo/rpc/cluster/support/FailSafeClusterInvokerTest.java @@ -15,6 +15,8 @@ */ package com.alibaba.dubbo.rpc.cluster.support; +import static org.junit.Assert.assertEquals; + import java.util.ArrayList; import java.util.List; @@ -26,6 +28,7 @@ import org.junit.Before; import org.junit.Test; import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.utils.LogUtil; import com.alibaba.dubbo.rpc.Invocation; import com.alibaba.dubbo.rpc.Invoker; import com.alibaba.dubbo.rpc.Result; @@ -105,5 +108,26 @@ public class FailSafeClusterInvokerTest { Result ret = invoker.invoke(invocation); Assert.assertSame(result, ret); } + + @Test() + public void testNoInvoke() { + dic = EasyMock.createMock(Directory.class); + invocation = EasyMock.createMock(Invocation.class); + + EasyMock.expect(dic.getUrl()).andReturn(url).anyTimes(); + EasyMock.expect(dic.list(invocation)).andReturn(null).anyTimes(); + EasyMock.expect(dic.getInterface()).andReturn(DemoService.class).anyTimes(); + + EasyMock.expect(invocation.getMethodName()).andReturn("method1").anyTimes(); + EasyMock.replay(dic,invocation); + + resetInvokerToNoException(); + + FailsafeClusterInvoker invoker = new FailsafeClusterInvoker(dic); + LogUtil.start(); + invoker.invoke(invocation); + assertEquals(1,LogUtil.findMessage("No provider")); + LogUtil.stop(); + } } \ No newline at end of file diff --git a/dubbo-cluster/src/test/java/com/alibaba/dubbo/rpc/cluster/support/FailbackClusterInvokerTest.java b/dubbo-cluster/src/test/java/com/alibaba/dubbo/rpc/cluster/support/FailbackClusterInvokerTest.java index ac227e49d8..00e23a973b 100644 --- a/dubbo-cluster/src/test/java/com/alibaba/dubbo/rpc/cluster/support/FailbackClusterInvokerTest.java +++ b/dubbo-cluster/src/test/java/com/alibaba/dubbo/rpc/cluster/support/FailbackClusterInvokerTest.java @@ -15,6 +15,8 @@ */ package com.alibaba.dubbo.rpc.cluster.support; +import static org.junit.Assert.assertEquals; + import java.util.ArrayList; import java.util.List; @@ -26,6 +28,7 @@ import org.junit.Before; import org.junit.Test; import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.utils.LogUtil; import com.alibaba.dubbo.rpc.Invocation; import com.alibaba.dubbo.rpc.Invoker; import com.alibaba.dubbo.rpc.Result; @@ -110,6 +113,30 @@ public class FailbackClusterInvokerTest { Assert.assertSame(result, ret); } + @Test() + public void testNoInvoke() { + dic = EasyMock.createMock(Directory.class); + invocation = EasyMock.createMock(Invocation.class); + + EasyMock.expect(dic.getUrl()).andReturn(url).anyTimes(); + EasyMock.expect(dic.list(invocation)).andReturn(null).anyTimes(); + EasyMock.expect(dic.getInterface()).andReturn(FailbackClusterInvokerTest.class).anyTimes(); + + EasyMock.expect(invocation.getMethodName()).andReturn("method1").anyTimes(); + EasyMock.replay(dic, invocation); + + invokers.add(invoker); + + resetInvokerToNoException(); + + FailbackClusterInvoker invoker = new FailbackClusterInvoker( + dic); + LogUtil.start(); + invoker.invoke(invocation); + assertEquals(1, LogUtil.findMessage("Failback to invoke")); + LogUtil.stop(); + } + @Test() public void testRetryFailed() { @@ -122,4 +149,4 @@ public class FailbackClusterInvokerTest { invoker.retryFailed();// when retry the invoker which get from failed map already is not the mocked invoker,so // it can be invoke successfully } -} \ No newline at end of file +} diff --git a/dubbo-cluster/src/test/java/com/alibaba/dubbo/rpc/cluster/support/FailfastClusterInvokerTest.java b/dubbo-cluster/src/test/java/com/alibaba/dubbo/rpc/cluster/support/FailfastClusterInvokerTest.java index bcb7a4abc6..a06b6df4ef 100644 --- a/dubbo-cluster/src/test/java/com/alibaba/dubbo/rpc/cluster/support/FailfastClusterInvokerTest.java +++ b/dubbo-cluster/src/test/java/com/alibaba/dubbo/rpc/cluster/support/FailfastClusterInvokerTest.java @@ -15,24 +15,26 @@ */ package com.alibaba.dubbo.rpc.cluster.support; -import java.util.ArrayList; -import java.util.List; - -import junit.framework.Assert; - -import org.easymock.EasyMock; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -import com.alibaba.dubbo.common.URL; -import com.alibaba.dubbo.rpc.Invocation; -import com.alibaba.dubbo.rpc.Invoker; -import com.alibaba.dubbo.rpc.Result; -import com.alibaba.dubbo.rpc.RpcContext; -import com.alibaba.dubbo.rpc.RpcException; -import com.alibaba.dubbo.rpc.RpcResult; -import com.alibaba.dubbo.rpc.cluster.Directory; +import static org.junit.Assert.fail; + +import java.util.ArrayList; +import java.util.List; + +import junit.framework.Assert; + +import org.easymock.EasyMock; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.rpc.Invocation; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.Result; +import com.alibaba.dubbo.rpc.RpcContext; +import com.alibaba.dubbo.rpc.RpcException; +import com.alibaba.dubbo.rpc.RpcResult; +import com.alibaba.dubbo.rpc.cluster.Directory; /** * FailfastClusterInvokerTest @@ -103,6 +105,31 @@ public class FailfastClusterInvokerTest { FailfastClusterInvoker invoker = new FailfastClusterInvoker(dic); Result ret = invoker.invoke(invocation); Assert.assertSame(result, ret); - } + } + + @Test() + public void testNoInvoke() { + dic = EasyMock.createMock(Directory.class); + invocation = EasyMock.createMock(Invocation.class); + + EasyMock.expect(dic.getUrl()).andReturn(url).anyTimes(); + EasyMock.expect(dic.list(invocation)).andReturn(null).anyTimes(); + EasyMock.expect(dic.getInterface()).andReturn(FailfastClusterInvokerTest.class).anyTimes(); + + EasyMock.expect(invocation.getMethodName()).andReturn("method1").anyTimes(); + EasyMock.replay(dic,invocation); + + invokers.add(invoker1); + + resetInvoker1ToNoException(); + + FailfastClusterInvoker invoker = new FailfastClusterInvoker(dic); + try { + invoker.invoke(invocation); + fail(); + } catch (RpcException expected) { + } + } + } \ No newline at end of file diff --git a/dubbo-cluster/src/test/java/com/alibaba/dubbo/rpc/cluster/support/FailoverClusterInvokerTest.java b/dubbo-cluster/src/test/java/com/alibaba/dubbo/rpc/cluster/support/FailoverClusterInvokerTest.java index 5e8f01f17d..9abe8fb836 100644 --- a/dubbo-cluster/src/test/java/com/alibaba/dubbo/rpc/cluster/support/FailoverClusterInvokerTest.java +++ b/dubbo-cluster/src/test/java/com/alibaba/dubbo/rpc/cluster/support/FailoverClusterInvokerTest.java @@ -15,22 +15,24 @@ */ package com.alibaba.dubbo.rpc.cluster.support; -import java.util.ArrayList; -import java.util.List; - -import junit.framework.Assert; - -import org.easymock.EasyMock; -import org.junit.Before; -import org.junit.Test; - -import com.alibaba.dubbo.common.URL; -import com.alibaba.dubbo.rpc.Invocation; -import com.alibaba.dubbo.rpc.Invoker; -import com.alibaba.dubbo.rpc.Result; -import com.alibaba.dubbo.rpc.RpcException; -import com.alibaba.dubbo.rpc.RpcResult; -import com.alibaba.dubbo.rpc.cluster.Directory; +import static org.junit.Assert.fail; + +import java.util.ArrayList; +import java.util.List; + +import junit.framework.Assert; + +import org.easymock.EasyMock; +import org.junit.Before; +import org.junit.Test; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.rpc.Invocation; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.Result; +import com.alibaba.dubbo.rpc.RpcException; +import com.alibaba.dubbo.rpc.RpcResult; +import com.alibaba.dubbo.rpc.cluster.Directory; /** * FailoverClusterInvokerTest @@ -138,5 +140,29 @@ public class FailoverClusterInvokerTest { System.out.println(e.getMessage()); Assert.assertTrue(e.getMessage().indexOf((retries+1)+" times")>0); } + } + + @Test() + public void testNoInvoke() { + dic = EasyMock.createMock(Directory.class); + invocation = EasyMock.createMock(Invocation.class); + + EasyMock.expect(dic.getUrl()).andReturn(url).anyTimes(); + EasyMock.expect(dic.list(invocation)).andReturn(null).anyTimes(); + EasyMock.expect(dic.getInterface()).andReturn(FailoverClusterInvokerTest.class).anyTimes(); + + EasyMock.expect(invocation.getMethodName()).andReturn("method1").anyTimes(); + EasyMock.replay(dic,invocation); + + invokers.add(invoker1); + + + FailoverClusterInvoker invoker = new FailoverClusterInvoker(dic); + try { + invoker.invoke(invocation); + fail(); + } catch (RpcException expected) { + expected.printStackTrace(); + } } } \ No newline at end of file diff --git a/dubbo-cluster/src/test/java/com/alibaba/dubbo/rpc/cluster/support/ForkingClusterInvokerTest.java b/dubbo-cluster/src/test/java/com/alibaba/dubbo/rpc/cluster/support/ForkingClusterInvokerTest.java index 79b826292b..9b1996fb66 100644 --- a/dubbo-cluster/src/test/java/com/alibaba/dubbo/rpc/cluster/support/ForkingClusterInvokerTest.java +++ b/dubbo-cluster/src/test/java/com/alibaba/dubbo/rpc/cluster/support/ForkingClusterInvokerTest.java @@ -15,6 +15,8 @@ */ package com.alibaba.dubbo.rpc.cluster.support; +import static org.junit.Assert.assertTrue; + import java.util.ArrayList; import java.util.List; @@ -29,7 +31,7 @@ import com.alibaba.dubbo.common.URL; import com.alibaba.dubbo.rpc.Invocation; import com.alibaba.dubbo.rpc.Invoker; import com.alibaba.dubbo.rpc.Result; -import com.alibaba.dubbo.rpc.RpcContext; +import com.alibaba.dubbo.rpc.RpcException; import com.alibaba.dubbo.rpc.RpcResult; import com.alibaba.dubbo.rpc.cluster.Directory; @@ -140,4 +142,27 @@ public class ForkingClusterInvokerTest { Result ret = invoker.invoke(invocation); Assert.assertSame(result, ret); } + + @Test() + public void testNoInvoke() { + dic = EasyMock.createMock(Directory.class); + invocation = EasyMock.createMock(Invocation.class); + + EasyMock.expect(dic.getUrl()).andReturn(url).anyTimes(); + EasyMock.expect(dic.list(invocation)).andReturn(null).anyTimes(); + EasyMock.expect(dic.getInterface()).andReturn(ForkingClusterInvokerTest.class).anyTimes(); + + EasyMock.expect(invocation.getMethodName()).andReturn("method1").anyTimes(); + EasyMock.replay(dic, invocation); + + resetInvokerToNoException(); + + ForkingClusterInvoker invoker = new ForkingClusterInvoker( + dic); + try { + invoker.invoke(invocation); + } catch (RpcException expected) { + assertTrue(expected.getMessage().contains("No provider")); + } + } } \ No newline at end of file diff --git a/dubbo-cluster/src/test/resources/log4j.xml b/dubbo-cluster/src/test/resources/log4j.xml index b3394a4c0d..e2c0263014 100644 --- a/dubbo-cluster/src/test/resources/log4j.xml +++ b/dubbo-cluster/src/test/resources/log4j.xml @@ -16,13 +16,13 @@ --> - + - + \ No newline at end of file