2013-08-08 19:10:11 +02:00
|
|
|
/**
|
|
|
|
* Copyright (c) SpaceToad, 2011 http://www.mod-buildcraft.com
|
|
|
|
*
|
|
|
|
* BuildCraft is distributed under the terms of the Minecraft Mod Public License
|
|
|
|
* 1.0, or MMPL. Please check the contents of the license located in
|
|
|
|
* http://www.mod-buildcraft.com/MMPL-1.0.txt
|
|
|
|
*/
|
|
|
|
package buildcraft.api.power;
|
|
|
|
|
|
|
|
import net.minecraft.nbt.NBTTagCompound;
|
|
|
|
import net.minecraftforge.common.ForgeDirection;
|
2013-12-01 07:41:01 +01:00
|
|
|
import buildcraft.api.core.SafeTimeTracker;
|
2013-08-08 19:10:11 +02:00
|
|
|
|
2013-12-01 07:41:01 +01:00
|
|
|
public final class PowerHandler
|
|
|
|
{
|
2013-08-08 19:10:11 +02:00
|
|
|
|
2013-12-01 07:41:01 +01:00
|
|
|
public static enum Type
|
|
|
|
{
|
2013-08-08 19:10:11 +02:00
|
|
|
|
|
|
|
ENGINE, GATE, MACHINE, PIPE, STORAGE;
|
|
|
|
|
2013-12-01 07:41:01 +01:00
|
|
|
public boolean canReceiveFromPipes()
|
|
|
|
{
|
|
|
|
switch (this)
|
|
|
|
{
|
2013-08-08 19:10:11 +02:00
|
|
|
case MACHINE:
|
|
|
|
case STORAGE:
|
|
|
|
return true;
|
|
|
|
default:
|
2013-09-30 23:37:16 +02:00
|
|
|
return false;
|
2013-08-08 19:10:11 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-01 07:41:01 +01:00
|
|
|
public boolean eatsEngineExcess()
|
|
|
|
{
|
|
|
|
switch (this)
|
|
|
|
{
|
2013-08-08 19:10:11 +02:00
|
|
|
case MACHINE:
|
|
|
|
case STORAGE:
|
|
|
|
return true;
|
|
|
|
default:
|
2013-09-30 23:37:16 +02:00
|
|
|
return false;
|
2013-08-08 19:10:11 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-01 07:41:01 +01:00
|
|
|
public static class PerditionCalculator
|
|
|
|
{
|
2013-08-08 19:10:11 +02:00
|
|
|
|
|
|
|
public static final float DEFAULT_POWERLOSS = 1F;
|
|
|
|
public static final float MIN_POWERLOSS = 0.01F;
|
|
|
|
private final float powerLoss;
|
|
|
|
|
2013-12-01 07:41:01 +01:00
|
|
|
public PerditionCalculator()
|
|
|
|
{
|
2013-08-08 19:10:11 +02:00
|
|
|
powerLoss = DEFAULT_POWERLOSS;
|
|
|
|
}
|
|
|
|
|
2013-12-01 07:41:01 +01:00
|
|
|
public PerditionCalculator(float powerLoss)
|
|
|
|
{
|
|
|
|
if (powerLoss < MIN_POWERLOSS)
|
|
|
|
{
|
2013-08-08 19:10:11 +02:00
|
|
|
powerLoss = MIN_POWERLOSS;
|
|
|
|
}
|
|
|
|
this.powerLoss = powerLoss;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2013-12-01 07:41:01 +01:00
|
|
|
* Apply the perdition algorithm to the current stored energy. This function can only be
|
|
|
|
* called once per tick, but it might not be called every tick. It is triggered by any
|
|
|
|
* manipulation of the stored energy.
|
|
|
|
*
|
2013-08-08 19:10:11 +02:00
|
|
|
* @param powerHandler the PowerHandler requesting the perdition update
|
|
|
|
* @param current the current stored energy
|
|
|
|
* @param ticksPassed ticks since the last time this function was called
|
|
|
|
* @return
|
|
|
|
*/
|
2013-12-01 07:41:01 +01:00
|
|
|
public float applyPerdition(PowerHandler powerHandler, float current, long ticksPassed)
|
|
|
|
{
|
2013-08-08 19:10:11 +02:00
|
|
|
current -= powerLoss * ticksPassed;
|
2013-12-01 07:41:01 +01:00
|
|
|
if (current < 0)
|
|
|
|
{
|
2013-08-08 19:10:11 +02:00
|
|
|
current = 0;
|
|
|
|
}
|
|
|
|
return current;
|
|
|
|
}
|
|
|
|
}
|
2013-12-01 07:41:01 +01:00
|
|
|
|
2013-08-25 15:36:29 +02:00
|
|
|
public static final PerditionCalculator DEFAULT_PERDITION = new PerditionCalculator();
|
2013-08-08 19:10:11 +02:00
|
|
|
private float minEnergyReceived;
|
|
|
|
private float maxEnergyReceived;
|
|
|
|
private float maxEnergyStored;
|
|
|
|
private float activationEnergy;
|
|
|
|
private float energyStored = 0;
|
|
|
|
private final SafeTimeTracker doWorkTracker = new SafeTimeTracker();
|
|
|
|
private final SafeTimeTracker sourcesTracker = new SafeTimeTracker();
|
|
|
|
private final SafeTimeTracker perditionTracker = new SafeTimeTracker();
|
|
|
|
public final int[] powerSources = new int[6];
|
|
|
|
public final IPowerReceptor receptor;
|
|
|
|
private PerditionCalculator perdition;
|
|
|
|
private final PowerReceiver receiver;
|
|
|
|
private final Type type;
|
|
|
|
|
2013-12-01 07:41:01 +01:00
|
|
|
public PowerHandler(IPowerReceptor receptor, Type type)
|
|
|
|
{
|
2013-08-08 19:10:11 +02:00
|
|
|
this.receptor = receptor;
|
|
|
|
this.type = type;
|
|
|
|
this.receiver = new PowerReceiver();
|
2013-08-25 15:36:29 +02:00
|
|
|
this.perdition = DEFAULT_PERDITION;
|
2013-08-08 19:10:11 +02:00
|
|
|
}
|
|
|
|
|
2013-12-01 07:41:01 +01:00
|
|
|
public PowerReceiver getPowerReceiver()
|
|
|
|
{
|
2013-08-08 19:10:11 +02:00
|
|
|
return receiver;
|
|
|
|
}
|
|
|
|
|
2013-12-01 07:41:01 +01:00
|
|
|
public float getMinEnergyReceived()
|
|
|
|
{
|
2013-08-08 19:10:11 +02:00
|
|
|
return minEnergyReceived;
|
|
|
|
}
|
|
|
|
|
2013-12-01 07:41:01 +01:00
|
|
|
public float getMaxEnergyReceived()
|
|
|
|
{
|
2013-08-08 19:10:11 +02:00
|
|
|
return maxEnergyReceived;
|
|
|
|
}
|
|
|
|
|
2013-12-01 07:41:01 +01:00
|
|
|
public float getMaxEnergyStored()
|
|
|
|
{
|
2013-08-08 19:10:11 +02:00
|
|
|
return maxEnergyStored;
|
|
|
|
}
|
|
|
|
|
2013-12-01 07:41:01 +01:00
|
|
|
public float getActivationEnergy()
|
|
|
|
{
|
2013-08-08 19:10:11 +02:00
|
|
|
return activationEnergy;
|
|
|
|
}
|
|
|
|
|
2013-12-01 07:41:01 +01:00
|
|
|
public float getEnergyStored()
|
|
|
|
{
|
2013-08-08 19:10:11 +02:00
|
|
|
return energyStored;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Setup your PowerHandler's settings.
|
2013-12-01 07:41:01 +01:00
|
|
|
*
|
|
|
|
* @param minEnergyReceived This is the minimum about of power that will be accepted by the
|
|
|
|
* PowerHandler. This should generally be greater than the activationEnergy if you plan to use
|
|
|
|
* the doWork() callback. Anything greater than 1 will prevent Redstone Engines from powering
|
|
|
|
* this Provider.
|
|
|
|
* @param maxEnergyReceived The maximum amount of power accepted by the PowerHandler. This
|
|
|
|
* should generally be less than 500. Too low and larger engines will overheat while trying to
|
|
|
|
* power the machine. Too high, and the engines will never warm up. Greater values also place
|
|
|
|
* greater strain on the power net.
|
|
|
|
* @param activationEnergy If the stored energy is greater than this value, the doWork()
|
|
|
|
* callback is called (once per tick).
|
|
|
|
* @param maxStoredEnergy The maximum amount of power this PowerHandler can store. Values tend
|
|
|
|
* to range between 100 and 5000. With 1000 and 1500 being common.
|
2013-08-08 19:10:11 +02:00
|
|
|
*/
|
2013-12-01 07:41:01 +01:00
|
|
|
public void configure(float minEnergyReceived, float maxEnergyReceived, float activationEnergy, float maxStoredEnergy)
|
|
|
|
{
|
|
|
|
if (minEnergyReceived > maxEnergyReceived)
|
|
|
|
{
|
2013-08-08 19:10:11 +02:00
|
|
|
maxEnergyReceived = minEnergyReceived;
|
|
|
|
}
|
|
|
|
this.minEnergyReceived = minEnergyReceived;
|
|
|
|
this.maxEnergyReceived = maxEnergyReceived;
|
|
|
|
this.maxEnergyStored = maxStoredEnergy;
|
|
|
|
this.activationEnergy = activationEnergy;
|
|
|
|
}
|
|
|
|
|
2013-12-01 07:41:01 +01:00
|
|
|
public void configurePowerPerdition(int powerLoss, int powerLossRegularity)
|
|
|
|
{
|
|
|
|
if (powerLoss == 0 || powerLossRegularity == 0)
|
|
|
|
{
|
2013-08-08 19:10:11 +02:00
|
|
|
perdition = new PerditionCalculator(0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
perdition = new PerditionCalculator((float) powerLoss / (float) powerLossRegularity);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2013-12-01 07:41:01 +01:00
|
|
|
* Allows you to define a new PerditionCalculator class to handler perdition calculations.
|
|
|
|
*
|
|
|
|
* For example if you want exponentially increasing loss based on amount stored.
|
|
|
|
*
|
2013-08-08 19:10:11 +02:00
|
|
|
* @param perdition
|
|
|
|
*/
|
2013-12-01 07:41:01 +01:00
|
|
|
public void setPerdition(PerditionCalculator perdition)
|
|
|
|
{
|
2013-08-25 15:36:29 +02:00
|
|
|
if (perdition == null)
|
|
|
|
perdition = DEFAULT_PERDITION;
|
2013-08-08 19:10:11 +02:00
|
|
|
this.perdition = perdition;
|
|
|
|
}
|
|
|
|
|
2013-12-01 07:41:01 +01:00
|
|
|
public PerditionCalculator getPerdition()
|
|
|
|
{
|
2013-08-08 19:10:11 +02:00
|
|
|
if (perdition == null)
|
2013-08-25 15:36:29 +02:00
|
|
|
return DEFAULT_PERDITION;
|
2013-08-08 19:10:11 +02:00
|
|
|
return perdition;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2013-12-01 07:41:01 +01:00
|
|
|
* Ticks the power handler. You should call this if you can, but its not required.
|
|
|
|
*
|
|
|
|
* If you don't call it, the possibility exists for some weirdness with the perdition algorithm
|
|
|
|
* and work callback as its possible they will not be called on every tick they otherwise would
|
|
|
|
* be. You should be able to design around this though if you are aware of the limitations.
|
2013-08-08 19:10:11 +02:00
|
|
|
*/
|
2013-12-01 07:41:01 +01:00
|
|
|
public void update()
|
|
|
|
{
|
2013-08-08 19:10:11 +02:00
|
|
|
applyPerdition();
|
|
|
|
applyWork();
|
|
|
|
validateEnergy();
|
|
|
|
}
|
|
|
|
|
2013-12-01 07:41:01 +01:00
|
|
|
private void applyPerdition()
|
|
|
|
{
|
|
|
|
if (perditionTracker.markTimeIfDelay(receptor.getWorld(), 1) && energyStored > 0)
|
|
|
|
{
|
2013-08-08 19:10:11 +02:00
|
|
|
float newEnergy = getPerdition().applyPerdition(this, energyStored, perditionTracker.durationOfLastDelay());
|
2013-08-25 15:36:29 +02:00
|
|
|
if (newEnergy == 0 || newEnergy < energyStored)
|
2013-08-08 19:10:11 +02:00
|
|
|
energyStored = newEnergy;
|
2013-08-25 15:36:29 +02:00
|
|
|
else
|
|
|
|
energyStored = DEFAULT_PERDITION.applyPerdition(this, energyStored, perditionTracker.durationOfLastDelay());
|
2013-08-08 19:10:11 +02:00
|
|
|
validateEnergy();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-01 07:41:01 +01:00
|
|
|
private void applyWork()
|
|
|
|
{
|
|
|
|
if (energyStored >= activationEnergy)
|
|
|
|
{
|
|
|
|
if (doWorkTracker.markTimeIfDelay(receptor.getWorld(), 1))
|
|
|
|
{
|
2013-08-08 19:10:11 +02:00
|
|
|
receptor.doWork(this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-01 07:41:01 +01:00
|
|
|
private void updateSources(ForgeDirection source)
|
|
|
|
{
|
|
|
|
if (sourcesTracker.markTimeIfDelay(receptor.getWorld(), 1))
|
|
|
|
{
|
|
|
|
for (int i = 0; i < 6; ++i)
|
|
|
|
{
|
2013-08-08 19:10:11 +02:00
|
|
|
powerSources[i] -= sourcesTracker.durationOfLastDelay();
|
2013-12-01 07:41:01 +01:00
|
|
|
if (powerSources[i] < 0)
|
|
|
|
{
|
2013-08-08 19:10:11 +02:00
|
|
|
powerSources[i] = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (source != null)
|
|
|
|
powerSources[source.ordinal()] = 10;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2013-12-01 07:41:01 +01:00
|
|
|
* Extract energy from the PowerHandler. You must call this even if doWork() triggers.
|
|
|
|
*
|
2013-08-08 19:10:11 +02:00
|
|
|
* @param min
|
|
|
|
* @param max
|
|
|
|
* @param doUse
|
|
|
|
* @return amount used
|
|
|
|
*/
|
2013-12-01 07:41:01 +01:00
|
|
|
public float useEnergy(float min, float max, boolean doUse)
|
|
|
|
{
|
2013-08-08 19:10:11 +02:00
|
|
|
applyPerdition();
|
|
|
|
|
|
|
|
float result = 0;
|
|
|
|
|
2013-12-01 07:41:01 +01:00
|
|
|
if (energyStored >= min)
|
|
|
|
{
|
|
|
|
if (energyStored <= max)
|
|
|
|
{
|
2013-08-08 19:10:11 +02:00
|
|
|
result = energyStored;
|
2013-12-01 07:41:01 +01:00
|
|
|
if (doUse)
|
|
|
|
{
|
2013-08-08 19:10:11 +02:00
|
|
|
energyStored = 0;
|
|
|
|
}
|
2013-12-01 07:41:01 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2013-08-08 19:10:11 +02:00
|
|
|
result = max;
|
2013-12-01 07:41:01 +01:00
|
|
|
if (doUse)
|
|
|
|
{
|
2013-08-08 19:10:11 +02:00
|
|
|
energyStored -= max;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
validateEnergy();
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2013-12-01 07:41:01 +01:00
|
|
|
public void readFromNBT(NBTTagCompound data)
|
|
|
|
{
|
2013-08-08 19:10:11 +02:00
|
|
|
readFromNBT(data, "powerProvider");
|
|
|
|
}
|
|
|
|
|
2013-12-01 07:41:01 +01:00
|
|
|
public void readFromNBT(NBTTagCompound data, String tag)
|
|
|
|
{
|
2013-08-08 19:10:11 +02:00
|
|
|
NBTTagCompound nbt = data.getCompoundTag(tag);
|
|
|
|
energyStored = nbt.getFloat("storedEnergy");
|
|
|
|
}
|
|
|
|
|
2013-12-01 07:41:01 +01:00
|
|
|
public void writeToNBT(NBTTagCompound data)
|
|
|
|
{
|
2013-08-08 19:10:11 +02:00
|
|
|
writeToNBT(data, "powerProvider");
|
|
|
|
}
|
|
|
|
|
2013-12-01 07:41:01 +01:00
|
|
|
public void writeToNBT(NBTTagCompound data, String tag)
|
|
|
|
{
|
2013-08-08 19:10:11 +02:00
|
|
|
NBTTagCompound nbt = new NBTTagCompound();
|
|
|
|
nbt.setFloat("storedEnergy", energyStored);
|
|
|
|
data.setCompoundTag(tag, nbt);
|
|
|
|
}
|
|
|
|
|
2013-12-01 07:41:01 +01:00
|
|
|
public final class PowerReceiver
|
|
|
|
{
|
2013-08-08 19:10:11 +02:00
|
|
|
|
2013-12-01 07:41:01 +01:00
|
|
|
private PowerReceiver()
|
|
|
|
{
|
2013-08-08 19:10:11 +02:00
|
|
|
}
|
|
|
|
|
2013-12-01 07:41:01 +01:00
|
|
|
public float getMinEnergyReceived()
|
|
|
|
{
|
2013-08-08 19:10:11 +02:00
|
|
|
return minEnergyReceived;
|
|
|
|
}
|
|
|
|
|
2013-12-01 07:41:01 +01:00
|
|
|
public float getMaxEnergyReceived()
|
|
|
|
{
|
2013-08-08 19:10:11 +02:00
|
|
|
return maxEnergyReceived;
|
|
|
|
}
|
|
|
|
|
2013-12-01 07:41:01 +01:00
|
|
|
public float getMaxEnergyStored()
|
|
|
|
{
|
2013-08-08 19:10:11 +02:00
|
|
|
return maxEnergyStored;
|
|
|
|
}
|
|
|
|
|
2013-12-01 07:41:01 +01:00
|
|
|
public float getActivationEnergy()
|
|
|
|
{
|
2013-08-08 19:10:11 +02:00
|
|
|
return activationEnergy;
|
|
|
|
}
|
|
|
|
|
2013-12-01 07:41:01 +01:00
|
|
|
public float getEnergyStored()
|
|
|
|
{
|
2013-08-08 19:10:11 +02:00
|
|
|
return energyStored;
|
|
|
|
}
|
|
|
|
|
2013-12-01 07:41:01 +01:00
|
|
|
public Type getType()
|
|
|
|
{
|
2013-08-08 19:10:11 +02:00
|
|
|
return type;
|
|
|
|
}
|
|
|
|
|
2013-12-01 07:41:01 +01:00
|
|
|
public void update()
|
|
|
|
{
|
2013-08-08 19:10:11 +02:00
|
|
|
PowerHandler.this.update();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The amount of power that this PowerHandler currently needs.
|
2013-12-01 07:41:01 +01:00
|
|
|
*
|
2013-08-08 19:10:11 +02:00
|
|
|
* @return
|
|
|
|
*/
|
2013-12-01 07:41:01 +01:00
|
|
|
public float powerRequest()
|
|
|
|
{
|
2013-08-25 15:36:29 +02:00
|
|
|
update();
|
2013-08-08 19:10:11 +02:00
|
|
|
return Math.min(maxEnergyReceived, maxEnergyStored - energyStored);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Add power to the PowerReceiver from an external source.
|
2013-12-01 07:41:01 +01:00
|
|
|
*
|
2013-08-08 19:10:11 +02:00
|
|
|
* @param quantity
|
|
|
|
* @param from
|
|
|
|
* @return the amount of power used
|
|
|
|
*/
|
2013-12-01 07:41:01 +01:00
|
|
|
public float receiveEnergy(Type source, final float quantity, ForgeDirection from)
|
|
|
|
{
|
2013-08-08 19:10:11 +02:00
|
|
|
float used = quantity;
|
2013-12-01 07:41:01 +01:00
|
|
|
if (source == Type.ENGINE)
|
|
|
|
{
|
|
|
|
if (used < minEnergyReceived)
|
|
|
|
{
|
2013-08-08 19:10:11 +02:00
|
|
|
return 0;
|
2013-12-01 07:41:01 +01:00
|
|
|
}
|
|
|
|
else if (used > maxEnergyReceived)
|
|
|
|
{
|
2013-08-08 19:10:11 +02:00
|
|
|
used = maxEnergyReceived;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
updateSources(from);
|
2013-11-06 02:07:38 +01:00
|
|
|
|
2013-08-08 19:10:11 +02:00
|
|
|
used = addEnergy(used);
|
|
|
|
|
|
|
|
applyWork();
|
|
|
|
|
2013-12-01 07:41:01 +01:00
|
|
|
if (source == Type.ENGINE && type.eatsEngineExcess())
|
|
|
|
{
|
|
|
|
return Math.min(quantity, maxEnergyReceived);
|
2013-08-08 19:10:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return used;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2013-12-01 07:41:01 +01:00
|
|
|
*
|
2013-08-08 19:10:11 +02:00
|
|
|
* @return the amount the power changed by
|
|
|
|
*/
|
2013-12-01 07:41:01 +01:00
|
|
|
public float addEnergy(float quantity)
|
|
|
|
{
|
2013-08-08 19:10:11 +02:00
|
|
|
energyStored += quantity;
|
|
|
|
|
2013-12-01 07:41:01 +01:00
|
|
|
if (energyStored > maxEnergyStored)
|
|
|
|
{
|
2013-08-08 19:10:11 +02:00
|
|
|
quantity -= energyStored - maxEnergyStored;
|
|
|
|
energyStored = maxEnergyStored;
|
2013-12-01 07:41:01 +01:00
|
|
|
}
|
|
|
|
else if (energyStored < 0)
|
|
|
|
{
|
2013-08-08 19:10:11 +02:00
|
|
|
quantity -= energyStored;
|
|
|
|
energyStored = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
applyPerdition();
|
|
|
|
|
|
|
|
return quantity;
|
|
|
|
}
|
|
|
|
|
2013-12-01 07:41:01 +01:00
|
|
|
public void setEnergy(float quantity)
|
|
|
|
{
|
2013-08-08 19:10:11 +02:00
|
|
|
this.energyStored = quantity;
|
|
|
|
validateEnergy();
|
|
|
|
}
|
|
|
|
|
2013-12-01 07:41:01 +01:00
|
|
|
public boolean isPowerSource(ForgeDirection from)
|
|
|
|
{
|
2013-08-08 19:10:11 +02:00
|
|
|
return powerSources[from.ordinal()] != 0;
|
|
|
|
}
|
|
|
|
|
2013-12-01 07:41:01 +01:00
|
|
|
private void validateEnergy()
|
|
|
|
{
|
|
|
|
if (energyStored < 0)
|
|
|
|
{
|
2013-08-08 19:10:11 +02:00
|
|
|
energyStored = 0;
|
|
|
|
}
|
2013-12-01 07:41:01 +01:00
|
|
|
if (energyStored > maxEnergyStored)
|
|
|
|
{
|
2013-08-08 19:10:11 +02:00
|
|
|
energyStored = maxEnergyStored;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|