Details
diff --git a/network-resilience/src/br/ufrgs/inf/bdinetr/capability/AnomalyDetectionCapability.java b/network-resilience/src/br/ufrgs/inf/bdinetr/capability/AnomalyDetectionCapability.java
index ed7a1a3..cd2599d 100644
--- a/network-resilience/src/br/ufrgs/inf/bdinetr/capability/AnomalyDetectionCapability.java
+++ b/network-resilience/src/br/ufrgs/inf/bdinetr/capability/AnomalyDetectionCapability.java
@@ -25,10 +25,7 @@ import java.util.Set;
import bdi4jade.belief.Belief;
import bdi4jade.belief.PropositionalBelief;
-import bdi4jade.core.Capability;
import bdi4jade.core.GoalUpdateSet;
-import bdi4jade.goal.BeliefPresentGoal;
-import bdi4jade.goal.PropositionalBeliefValueGoal;
import bdi4jade.reasoning.AbstractReasoningStrategy;
import bdi4jade.reasoning.OptionGenerationFunction;
import br.ufrgs.inf.bdinetr.domain.IpPreposition.Anomalous;
@@ -38,7 +35,7 @@ import br.ufrgs.inf.bdinetr.domain.IpPreposition.Restricted;
/**
* @author Ingrid Nunes
*/
-public class AnomalyDetectionCapability extends Capability {
+public class AnomalyDetectionCapability extends BDINetRAppCapability {
private class ReasoningStrategy extends AbstractReasoningStrategy implements
OptionGenerationFunction {
@@ -49,20 +46,8 @@ public class AnomalyDetectionCapability extends Capability {
for (Belief<?, ?> belief : anomalousIpBeliefs) {
PropositionalBelief<Anomalous> anomalous = (PropositionalBelief<Anomalous>) belief;
if (anomalous.getValue()) {
- getMyAgent()
- .addGoal(
- AnomalyDetectionCapability.this,
- new PropositionalBeliefValueGoal<Restricted>(
- new Restricted(anomalous.getName()
- .getIp()), Boolean.TRUE));
- log.debug("goal(restricted(" + anomalous.getName().getIp()
- + "))");
- getMyAgent().addGoal(
- AnomalyDetectionCapability.this,
- new BeliefPresentGoal<Benign>(new Benign(anomalous
- .getName().getIp())));
- log.debug("goal(?benign(" + anomalous.getName().getIp()
- + "))");
+ goal(new Restricted(anomalous.getName().getIp()), true);
+ goal(new Benign(anomalous.getName().getIp()));
}
}
@@ -75,15 +60,9 @@ public class AnomalyDetectionCapability extends Capability {
.getBelief(
new Anomalous(restricted.getName().getIp()));
if (anomalous != null && !anomalous.getValue()) {
- getMyAgent().addGoal(
- AnomalyDetectionCapability.this,
- new PropositionalBeliefValueGoal<Restricted>(
- new Restricted(restricted.getName()
- .getIp()), Boolean.FALSE));
- log.debug("goal(not restricted("
- + restricted.getName().getIp() + "))");
+ goal(new Restricted(restricted.getName().getIp()),
+ false);
}
-
}
}
}
diff --git a/network-resilience/src/br/ufrgs/inf/bdinetr/capability/BDINetRAppCapability.java b/network-resilience/src/br/ufrgs/inf/bdinetr/capability/BDINetRAppCapability.java
new file mode 100644
index 0000000..5e9386b
--- /dev/null
+++ b/network-resilience/src/br/ufrgs/inf/bdinetr/capability/BDINetRAppCapability.java
@@ -0,0 +1,58 @@
+//----------------------------------------------------------------------------
+// Copyright (C) 2011 Ingrid Nunes
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library 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
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// To contact the authors:
+// http://inf.ufrgs.br/prosoft/bdi4jade/
+//
+//----------------------------------------------------------------------------
+package br.ufrgs.inf.bdinetr.capability;
+
+import bdi4jade.belief.TransientPropositionalBelief;
+import bdi4jade.core.Capability;
+import bdi4jade.goal.BeliefPresentGoal;
+import bdi4jade.goal.PropositionalBeliefValueGoal;
+
+/**
+ * @author Ingrid Nunes
+ */
+public class BDINetRAppCapability extends Capability {
+
+ private static final long serialVersionUID = -3491170777812144486L;
+
+ protected void belief(Object proposition, Boolean value) {
+ if (value == null) {
+ getWholeCapability().getBeliefBase().removeBelief(proposition);
+ log.debug("belief(~" + proposition + "))");
+ } else {
+ getWholeCapability().getBeliefBase().addOrUpdateBelief(
+ new TransientPropositionalBelief(proposition, value));
+ log.debug("belief(" + (value ? "" : "not ") + proposition + ")");
+ }
+ }
+
+ protected void goal(Object proposition) {
+ getMyAgent().addGoal(this, new BeliefPresentGoal(proposition));
+ log.debug("goal(?" + proposition + "))");
+ }
+
+ protected void goal(Object proposition, Boolean value) {
+ getMyAgent().addGoal(this,
+ new PropositionalBeliefValueGoal(proposition, value));
+ log.debug("goal(" + (value ? "" : "not ") + proposition + "))");
+ }
+
+}
diff --git a/network-resilience/src/br/ufrgs/inf/bdinetr/capability/ClassifierCapability.java b/network-resilience/src/br/ufrgs/inf/bdinetr/capability/ClassifierCapability.java
index 150bef6..100cd13 100644
--- a/network-resilience/src/br/ufrgs/inf/bdinetr/capability/ClassifierCapability.java
+++ b/network-resilience/src/br/ufrgs/inf/bdinetr/capability/ClassifierCapability.java
@@ -25,9 +25,7 @@ import java.util.Set;
import bdi4jade.belief.Belief;
import bdi4jade.belief.PropositionalBelief;
-import bdi4jade.core.Capability;
import bdi4jade.core.GoalUpdateSet;
-import bdi4jade.goal.PropositionalBeliefValueGoal;
import bdi4jade.reasoning.AbstractReasoningStrategy;
import bdi4jade.reasoning.OptionGenerationFunction;
import br.ufrgs.inf.bdinetr.domain.FlowPreposition.Threat;
@@ -36,7 +34,7 @@ import br.ufrgs.inf.bdinetr.domain.FlowPreposition.ThreatResponded;
/**
* @author Ingrid Nunes
*/
-public class ClassifierCapability extends Capability {
+public class ClassifierCapability extends BDINetRAppCapability {
private class ReasoningStrategy extends AbstractReasoningStrategy implements
OptionGenerationFunction {
@@ -47,13 +45,7 @@ public class ClassifierCapability extends Capability {
for (Belief<?, ?> belief : threatBeliefs) {
PropositionalBelief<Threat> threat = (PropositionalBelief<Threat>) belief;
if (threat.getValue()) {
- getMyAgent().addGoal(
- ClassifierCapability.this,
- new PropositionalBeliefValueGoal<ThreatResponded>(
- new ThreatResponded(threat.getName()
- .getFlow()), Boolean.TRUE));
- log.debug("goal(threatResponded("
- + threat.getName().getFlow() + "))");
+ goal(new ThreatResponded(threat.getName().getFlow()), true);
}
}
}
diff --git a/network-resilience/src/br/ufrgs/inf/bdinetr/capability/FlowExporterCapability.java b/network-resilience/src/br/ufrgs/inf/bdinetr/capability/FlowExporterCapability.java
index 19e51de..edefb12 100644
--- a/network-resilience/src/br/ufrgs/inf/bdinetr/capability/FlowExporterCapability.java
+++ b/network-resilience/src/br/ufrgs/inf/bdinetr/capability/FlowExporterCapability.java
@@ -21,14 +21,10 @@
//----------------------------------------------------------------------------
package br.ufrgs.inf.bdinetr.capability;
-import bdi4jade.core.Capability;
-import bdi4jade.reasoning.AbstractReasoningStrategy;
-import bdi4jade.reasoning.BeliefRevisionStrategy;
-
/**
* @author Ingrid Nunes
*/
-public class FlowExporterCapability extends Capability {
+public class FlowExporterCapability extends BDINetRAppCapability {
private static final long serialVersionUID = -1705728861020677126L;
diff --git a/network-resilience/src/br/ufrgs/inf/bdinetr/capability/LinkMonitorCapability.java b/network-resilience/src/br/ufrgs/inf/bdinetr/capability/LinkMonitorCapability.java
index f16b455..338d9fb 100644
--- a/network-resilience/src/br/ufrgs/inf/bdinetr/capability/LinkMonitorCapability.java
+++ b/network-resilience/src/br/ufrgs/inf/bdinetr/capability/LinkMonitorCapability.java
@@ -26,11 +26,7 @@ import java.util.Set;
import bdi4jade.belief.Belief;
import bdi4jade.belief.PropositionalBelief;
import bdi4jade.belief.TransientBelief;
-import bdi4jade.belief.TransientPropositionalBelief;
-import bdi4jade.core.Capability;
import bdi4jade.core.GoalUpdateSet;
-import bdi4jade.goal.BeliefPresentGoal;
-import bdi4jade.goal.PropositionalBeliefValueGoal;
import bdi4jade.reasoning.AbstractReasoningStrategy;
import bdi4jade.reasoning.BeliefRevisionStrategy;
import bdi4jade.reasoning.OptionGenerationFunction;
@@ -45,7 +41,7 @@ import br.ufrgs.inf.bdinetr.domain.LinkProposition.Usage;
/**
* @author Ingrid Nunes
*/
-public class LinkMonitorCapability extends Capability {
+public class LinkMonitorCapability extends BDINetRAppCapability {
private class ReasoningStrategy extends AbstractReasoningStrategy implements
BeliefRevisionStrategy, OptionGenerationFunction {
@@ -61,22 +57,9 @@ public class LinkMonitorCapability extends Capability {
new AttackPrevented(overUsage.getName()
.getLink()));
if (attackPrevented == null || !attackPrevented.getValue()) {
- getMyAgent()
- .addGoal(
- LinkMonitorCapability.this,
- new PropositionalBeliefValueGoal<AttackPrevented>(
- new AttackPrevented(overUsage
- .getName().getLink()),
- Boolean.TRUE));
- log.debug("goal(attackPrevented("
- + overUsage.getName().getLink() + "))");
- getMyAgent().addGoal(
- LinkMonitorCapability.this,
- new BeliefPresentGoal<RegularUsage>(
- new RegularUsage(overUsage.getName()
- .getLink())));
- log.debug("goal(?regularUsage("
- + overUsage.getName().getLink() + "))");
+ goal(new AttackPrevented(overUsage.getName().getLink()),
+ Boolean.TRUE);
+ goal(new RegularUsage(overUsage.getName().getLink()));
}
}
}
@@ -88,35 +71,21 @@ public class LinkMonitorCapability extends Capability {
.getBeliefsByType(Usage.class);
for (Belief<?, ?> belief : linkUsageBeliefs) {
Belief<Usage, Double> linkUsage = (Belief<Usage, Double>) belief;
+ OverUsage overUsage = new OverUsage(linkUsage.getName()
+ .getLink());
double percentageUsed = linkUsage.getName().getLink()
.getUsedBandwidthPercentage();
linkUsage.setValue(percentageUsed);
if (percentageUsed > overUsageThreshold.getValue()) {
- PropositionalBelief<OverUsage> overUsage = (PropositionalBelief<OverUsage>) getBeliefBase()
- .getBelief(
- new OverUsage(linkUsage.getName().getLink()));
- if (overUsage == null || !overUsage.getValue()) {
- getBeliefBase().addOrUpdateBelief(
- new TransientPropositionalBelief<OverUsage>(
- new OverUsage(linkUsage.getName()
- .getLink()), Boolean.TRUE));
- log.debug("belief(overUsage("
- + linkUsage.getName().getLink() + "))");
- getBeliefBase()
- .removeBelief(
- new RegularUsage(linkUsage.getName()
- .getLink()));
- log.debug("belief(~regularUsage("
- + linkUsage.getName().getLink() + "))");
+ PropositionalBelief<OverUsage> overUsageBelief = (PropositionalBelief<OverUsage>) getBeliefBase()
+ .getBelief(overUsage);
+ if (overUsageBelief == null || !overUsageBelief.getValue()) {
+ belief(overUsage, true);
+ belief(new RegularUsage(linkUsage.getName().getLink()),
+ null);
}
} else {
- getBeliefBase()
- .addOrUpdateBelief(
- new TransientPropositionalBelief<OverUsage>(
- new OverUsage(linkUsage.getName()
- .getLink()), Boolean.FALSE));
- log.debug("belief(not overUsage("
- + linkUsage.getName().getLink() + "))");
+ belief(overUsage, false);
}
}
}
diff --git a/network-resilience/src/br/ufrgs/inf/bdinetr/capability/RateLimiterCapability.java b/network-resilience/src/br/ufrgs/inf/bdinetr/capability/RateLimiterCapability.java
index 1c526ca..eed9a26 100644
--- a/network-resilience/src/br/ufrgs/inf/bdinetr/capability/RateLimiterCapability.java
+++ b/network-resilience/src/br/ufrgs/inf/bdinetr/capability/RateLimiterCapability.java
@@ -27,18 +27,22 @@ import bdi4jade.annotation.Parameter;
import bdi4jade.annotation.Parameter.Direction;
import bdi4jade.belief.Belief;
import bdi4jade.belief.PropositionalBelief;
-import bdi4jade.belief.TransientPropositionalBelief;
-import bdi4jade.core.Capability;
import bdi4jade.core.GoalUpdateSet;
import bdi4jade.goal.BeliefGoal;
import bdi4jade.goal.Goal;
import bdi4jade.goal.GoalTemplateFactory;
-import bdi4jade.goal.PropositionalBeliefValueGoal;
import bdi4jade.plan.DefaultPlan;
import bdi4jade.plan.Plan;
import bdi4jade.plan.planbody.BeliefGoalPlanBody;
import bdi4jade.reasoning.AbstractReasoningStrategy;
import bdi4jade.reasoning.OptionGenerationFunction;
+import br.ufrgs.inf.bdinetr.BDINetRAgent.RootCapability;
+import br.ufrgs.inf.bdinetr.domain.Device;
+import br.ufrgs.inf.bdinetr.domain.IpAddress;
+import br.ufrgs.inf.bdinetr.domain.IpPreposition.Anomalous;
+import br.ufrgs.inf.bdinetr.domain.IpPreposition.Benign;
+import br.ufrgs.inf.bdinetr.domain.IpPreposition.RateLimited;
+import br.ufrgs.inf.bdinetr.domain.IpPreposition.Restricted;
import br.ufrgs.inf.bdinetr.domain.Link;
import br.ufrgs.inf.bdinetr.domain.LinkProposition.AttackPrevented;
import br.ufrgs.inf.bdinetr.domain.LinkProposition.FullyOperational;
@@ -48,8 +52,69 @@ import br.ufrgs.inf.bdinetr.domain.LinkProposition.RegularUsage;
/**
* @author Ingrid Nunes
*/
-public class RateLimiterCapability extends Capability {
+public class RateLimiterCapability extends BDINetRAppCapability {
+ public class LimitIPRatePlan extends BeliefGoalPlanBody {
+ private static final long serialVersionUID = -3493377510830902961L;
+
+ @bdi4jade.annotation.Belief(name = RootCapability.DEVICE_BELIEF)
+ private Belief<String, Device> device;
+ private IpAddress ip;
+
+ @Override
+ public void execute() {
+ device.getValue().limitIp(ip, IP_LIMIT_RATE);
+ belief(new RateLimited(ip), true);
+ belief(new Restricted(ip), true);
+
+ boolean exists = false;
+ Set<Belief<?, ?>> anomalousBeliefs = getBeliefBase()
+ .getBeliefsByType(Anomalous.class);
+ for (Belief<?, ?> belief : anomalousBeliefs) {
+ PropositionalBelief<Anomalous> anomalous = (PropositionalBelief<Anomalous>) belief;
+ if (anomalous.getValue()) {
+ PropositionalBelief<Restricted> restricted = (PropositionalBelief<Restricted>) getBeliefBase()
+ .getBelief(
+ new Restricted(anomalous.getName().getIp()));
+ if (restricted == null || !restricted.getValue()) {
+ exists = true;
+ }
+
+ }
+ }
+ if (!exists) {
+ // FIXME
+ belief(new RegularUsage(new Link("")), true);
+ }
+
+ log.info(getGoal());
+ }
+
+ @Parameter(direction = Direction.IN)
+ public void setBeliefName(Restricted restricted) {
+ this.ip = restricted.getIp();
+ }
+ }
+
+ public class LimitLinkRatePlan extends BeliefGoalPlanBody {
+ private static final long serialVersionUID = -3493377510830902961L;
+
+ private Link link;
+
+ @Override
+ public void execute() {
+ link.setLimitedBandwidth(LINK_LIMIT_RATE * link.getBandwidth());
+ belief(new FullyOperational(link), false);
+ belief(new AttackPrevented(link), true);
+ log.info(getGoal());
+ }
+
+ @Parameter(direction = Direction.IN)
+ public void setBeliefName(AttackPrevented attackPrevented) {
+ this.link = attackPrevented.getLink();
+ }
+ }
+
private class ReasoningStrategy extends AbstractReasoningStrategy implements
OptionGenerationFunction {
@Override
@@ -64,17 +129,8 @@ public class RateLimiterCapability extends Capability {
new RegularUsage(fullyOperational.getName()
.getLink()));
if (regularUsage != null && regularUsage.getValue()) {
- getMyAgent()
- .addGoal(
- RateLimiterCapability.this,
- new PropositionalBeliefValueGoal<FullyOperational>(
- new FullyOperational(
- fullyOperational
- .getName()
- .getLink()),
- Boolean.TRUE));
- log.debug("goal(fullyOperational("
- + fullyOperational.getName().getLink() + "))");
+ goal(new FullyOperational(fullyOperational.getName()
+ .getLink()), true);
}
}
@@ -82,37 +138,29 @@ public class RateLimiterCapability extends Capability {
}
}
- public static final double LINK_LIMIT_RATE = 0.5;
-
- private static final long serialVersionUID = -1705728861020677126L;
-
- public static class LimitLinkRatePlan extends BeliefGoalPlanBody {
+ public class RestoreIPRatePlan extends BeliefGoalPlanBody {
private static final long serialVersionUID = -3493377510830902961L;
- private Link link;
+ @bdi4jade.annotation.Belief(name = RootCapability.DEVICE_BELIEF)
+ private Belief<String, Device> device;
+ private IpAddress ip;
@Override
public void execute() {
- link.setLimitedBandwidth(LINK_LIMIT_RATE * link.getBandwidth());
- getBeliefBase().addOrUpdateBelief(
- new TransientPropositionalBelief<FullyOperational>(
- new FullyOperational(link), Boolean.FALSE));
- getCapability()
- .getWholeCapability()
- .getBeliefBase()
- .addOrUpdateBelief(
- new TransientPropositionalBelief<AttackPrevented>(
- new AttackPrevented(link), Boolean.TRUE));
+ device.getValue().unlimitIp(ip);
+ belief(new RateLimited(ip), false);
+ belief(new Restricted(ip), false);
+ belief(new Anomalous(ip), null);
log.info(getGoal());
}
@Parameter(direction = Direction.IN)
- public void setBeliefName(AttackPrevented attackPrevented) {
- this.link = attackPrevented.getLink();
+ public void setBeliefName(Restricted restricted) {
+ this.ip = restricted.getIp();
}
}
- public static class RestoreLinkRate extends BeliefGoalPlanBody {
+ public class RestoreLinkRate extends BeliefGoalPlanBody {
private static final long serialVersionUID = -3493377510830902961L;
private Link link;
@@ -120,15 +168,8 @@ public class RateLimiterCapability extends Capability {
@Override
public void execute() {
link.setLimitedBandwidth(null);
- getBeliefBase().addOrUpdateBelief(
- new TransientPropositionalBelief<FullyOperational>(
- new FullyOperational(link), Boolean.TRUE));
- getCapability()
- .getWholeCapability()
- .getBeliefBase()
- .addOrUpdateBelief(
- new TransientPropositionalBelief<AttackPrevented>(
- new AttackPrevented(link), null));
+ belief(new FullyOperational(link), true);
+ belief(new AttackPrevented(link), null);
log.info(getGoal());
}
@@ -138,15 +179,20 @@ public class RateLimiterCapability extends Capability {
}
}
+ public static final double IP_LIMIT_RATE = 0.5;
+ public static final double LINK_LIMIT_RATE = 0.5;
+
+ private static final long serialVersionUID = -1705728861020677126L;
+
@bdi4jade.annotation.Plan
- private Plan restoreLinkRate = new DefaultPlan(
- GoalTemplateFactory.hasValueForBeliefOfType(FullyOperational.class,
- Boolean.TRUE), RestoreLinkRate.class) {
+ private Plan limitIpRate = new DefaultPlan(
+ GoalTemplateFactory.hasValueForBeliefOfType(Restricted.class,
+ Boolean.TRUE), LimitIPRatePlan.class) {
public boolean isContextApplicable(Goal goal) {
- BeliefGoal<FullyOperational> bg = (BeliefGoal<FullyOperational>) goal;
- PropositionalBelief<RegularUsage> regularUsage = (PropositionalBelief<RegularUsage>) getBeliefBase()
- .getBelief(new RegularUsage(bg.getBeliefName().getLink()));
- return (regularUsage != null && regularUsage.getValue());
+ BeliefGoal<Restricted> bg = (BeliefGoal<Restricted>) goal;
+ PropositionalBelief<Anomalous> anomalous = (PropositionalBelief<Anomalous>) getBeliefBase()
+ .getBelief(new Anomalous(bg.getBeliefName().getIp()));
+ return (anomalous != null && anomalous.getValue());
};
};
@@ -162,6 +208,33 @@ public class RateLimiterCapability extends Capability {
};
};
+ @bdi4jade.annotation.Plan
+ private Plan restoreIpRate = new DefaultPlan(
+ GoalTemplateFactory.hasValueForBeliefOfType(Restricted.class,
+ Boolean.FALSE), RestoreIPRatePlan.class) {
+ public boolean isContextApplicable(Goal goal) {
+ BeliefGoal<Restricted> bg = (BeliefGoal<Restricted>) goal;
+ PropositionalBelief<Benign> benign = (PropositionalBelief<Benign>) getBeliefBase()
+ .getBelief(new Benign(bg.getBeliefName().getIp()));
+ PropositionalBelief<RateLimited> rateLimited = (PropositionalBelief<RateLimited>) getBeliefBase()
+ .getBelief(new RateLimited(bg.getBeliefName().getIp()));
+ return (benign != null && benign.getValue())
+ && (rateLimited != null && rateLimited.getValue());
+ };
+ };
+
+ @bdi4jade.annotation.Plan
+ private Plan restoreLinkRate = new DefaultPlan(
+ GoalTemplateFactory.hasValueForBeliefOfType(FullyOperational.class,
+ Boolean.TRUE), RestoreLinkRate.class) {
+ public boolean isContextApplicable(Goal goal) {
+ BeliefGoal<FullyOperational> bg = (BeliefGoal<FullyOperational>) goal;
+ PropositionalBelief<RegularUsage> regularUsage = (PropositionalBelief<RegularUsage>) getBeliefBase()
+ .getBelief(new RegularUsage(bg.getBeliefName().getLink()));
+ return (regularUsage != null && regularUsage.getValue());
+ };
+ };
+
public RateLimiterCapability() {
ReasoningStrategy strategy = new ReasoningStrategy();
setOptionGenerationFunction(strategy);
diff --git a/network-resilience/src/br/ufrgs/inf/bdinetr/domain/Device.java b/network-resilience/src/br/ufrgs/inf/bdinetr/domain/Device.java
index e9f3c1a..5b9985a 100644
--- a/network-resilience/src/br/ufrgs/inf/bdinetr/domain/Device.java
+++ b/network-resilience/src/br/ufrgs/inf/bdinetr/domain/Device.java
@@ -67,9 +67,17 @@ public class Device {
return ip == null ? 0 : ip.hashCode();
}
+ public void limitIp(IpAddress ip, double rate) {
+ // TODO
+ }
+
@Override
public String toString() {
return ip.toString();
}
+ public void unlimitIp(IpAddress ip) {
+ // TODO
+ }
+
}