diff options
Diffstat (limited to 'src')
24 files changed, 262 insertions, 425 deletions
diff --git a/src/main/java/net/cshift/transit/Transit.java b/src/main/java/net/cshift/transit/Transit.java index ef440c5..71d3fea 100644 --- a/src/main/java/net/cshift/transit/Transit.java +++ b/src/main/java/net/cshift/transit/Transit.java @@ -1,8 +1,12 @@ package net.cshift.transit; import net.fabricmc.api.ModInitializer; -import net.cshift.transit.type.group.simple.SimpleGroups; +import net.cshift.transit.type.group.SimpleGroups; +/** + * @author Kyle Gunger + * @apiNote This is the main entry point for Transit. The api is mostly intended for use on server-side connections. + */ public class Transit implements ModInitializer { @Override diff --git a/src/main/java/net/cshift/transit/basic/AbstractAcceptorNode.java b/src/main/java/net/cshift/transit/basic/AbstractAcceptorNode.java deleted file mode 100644 index e2e6711..0000000 --- a/src/main/java/net/cshift/transit/basic/AbstractAcceptorNode.java +++ /dev/null @@ -1,51 +0,0 @@ -package net.cshift.transit.basic; - -import net.cshift.transit.network.packet.*; -import net.cshift.transit.network.system.*; -import net.cshift.transit.network.system.swap.*; -import net.minecraft.block.entity.*; - -public abstract class AbstractAcceptorNode extends AbstractNode implements IAcceptorNode { - - public AbstractAcceptorNode(BlockEntityType<?> type) { - super(type); - } - - @Override - public abstract <T> boolean accept(IStaticPacket<T> packet, String group); - - @Override - public boolean linkProvider(IProviderNode requestor, String group) { - if(this.hasGroup(group)) - { - for (Connection c : connections) { - if(c.getNode() == requestor) - return false; - } - - connections.add(new Connection(requestor, (short) 2)); - - return true; - } - - return false; - } - - @Override - public boolean unlinkProvider(IProviderNode requestor) { - for (Connection c : connections) { - if(c.getNode() == requestor) - { - if(c.isAccepting()) - c.setProviding(false); - else - connections.remove(c); - - return true; - } - } - - return false; - } - -} diff --git a/src/main/java/net/cshift/transit/basic/AbstractNode.java b/src/main/java/net/cshift/transit/basic/AbstractNode.java deleted file mode 100644 index a87fba4..0000000 --- a/src/main/java/net/cshift/transit/basic/AbstractNode.java +++ /dev/null @@ -1,45 +0,0 @@ -package net.cshift.transit.basic; - -import java.util.*; - -import net.cshift.transit.network.system.*; -import net.minecraft.block.entity.*; - -public abstract class AbstractNode extends BlockEntity implements INode { - - public AbstractNode(BlockEntityType<?> type) { - super(type); - } - - HashMap<String, Object> data = new HashMap<String, Object>(); - ArrayList<Connection> connections = new ArrayList<Connection>(0); - - @Override - public abstract boolean hasGroup(String groupID); - - @Override - public ISystem getSystem() { - return null; - } - - @Override - public Object getData(String groupID) { - return data.get(groupID); - } - - @Override - public void setData(Object dat, String groupID) { - data.put(groupID, dat); - } - - @Override - public Connection[] getConnections() { - return (Connection[]) connections.toArray(); - } - - @Override - public int connectionCount() { - return connections.size(); - } - -} diff --git a/src/main/java/net/cshift/transit/basic/AbstractProviderNode.java b/src/main/java/net/cshift/transit/basic/AbstractProviderNode.java deleted file mode 100644 index cc81544..0000000 --- a/src/main/java/net/cshift/transit/basic/AbstractProviderNode.java +++ /dev/null @@ -1,47 +0,0 @@ -package net.cshift.transit.basic; - -import net.cshift.transit.network.system.*; -import net.cshift.transit.network.system.swap.*; -import net.minecraft.block.entity.*; - -public abstract class AbstractProviderNode extends AbstractNode implements IProviderNode { - - public AbstractProviderNode(BlockEntityType<?> type) { - super(type); - } - - @Override - public boolean linkAcceptor(IAcceptorNode requestor, String group) { - if(this.hasGroup(group)) - { - for (Connection c : connections) { - if(c.getNode() == requestor) - return false; - } - - connections.add(new Connection(requestor, (short) 1)); - - return true; - } - - return false; - } - - @Override - public boolean unlinkAcceptor(IAcceptorNode requestor) { - for (Connection c : connections) { - if(c.getNode() == requestor) - { - if(c.isProviding()) - c.setAccepting(false); - else - connections.remove(c); - - return true; - } - } - - return false; - } - -} diff --git a/src/main/java/net/cshift/transit/basic/AbstractTwoWayNode.java b/src/main/java/net/cshift/transit/basic/AbstractTwoWayNode.java deleted file mode 100644 index cc06eeb..0000000 --- a/src/main/java/net/cshift/transit/basic/AbstractTwoWayNode.java +++ /dev/null @@ -1,47 +0,0 @@ -package net.cshift.transit.basic; - -import net.cshift.transit.network.system.*; -import net.cshift.transit.network.system.swap.*; -import net.minecraft.block.entity.*; - -public abstract class AbstractTwoWayNode extends AbstractAcceptorNode implements IProviderNode { - - public AbstractTwoWayNode(BlockEntityType<?> type) { - super(type); - } - - @Override - public boolean linkAcceptor(IAcceptorNode requestor, String group) { - if(this.hasGroup(group)) - { - for (Connection c : connections) { - if(c.getNode() == requestor) - return false; - } - - connections.add(new Connection(requestor, (short) 1)); - - return true; - } - - return false; - } - - @Override - public boolean unlinkAcceptor(IAcceptorNode requestor) { - for (Connection c : connections) { - if(c.getNode() == requestor) - { - if(c.isProviding()) - c.setAccepting(false); - else - connections.remove(c); - - return true; - } - } - - return false; - } - -} diff --git a/src/main/java/net/cshift/transit/network/Channel.java b/src/main/java/net/cshift/transit/network/Channel.java new file mode 100644 index 0000000..43dbabc --- /dev/null +++ b/src/main/java/net/cshift/transit/network/Channel.java @@ -0,0 +1,119 @@ +package net.cshift.transit.network; + +import net.cshift.transit.network.packet.IStaticPacket; + +/** + * @author Kyle Gunger + * @apiNote A channel represents a connection between two nodes. It is able to send data in packets, and serves as a way to organize incoming traffic. + * @param <D> The type of data the packets will be transfering + */ +public class Channel<D> { + private INode to; + private int id; + private String group; + + /** This constructor should be called by a node approving a connection. The approving node can give the connection an ID and group. + * Negative IDs indicate a terminated connection, so do not initialize the class with a negative ID. + * + * @param node The recieving node + * @param id The channel's id, as assigned by the recieving node. + * @param group + */ + public Channel(INode node, int id, String group) + { + to = node; + this.id = id; + this.group = group; + } + + + + // #################### + // # Channel specific # + // #################### + + /** The recieving INode + * + * @return + */ + public INode getReciever() + { + return to; + } + + /** The ID of the connection, assigned by the recieving INode + * + * @return + */ + public int getID() + { + return id; + } + + /** The group that the channel operates on + * + * @return + */ + public String getGroup() { + return group; + } + + /** Returns true if the connection has been terminated + * + * @return + */ + public boolean isTerminated() + { + return id < 0; + } + + + + // ################################ + // # Info from the recieving node # + // ################################ + + /** Pressure + * + * @return A Number representing the pressure from the channel (in base group units). + */ + public Number pressure() + { + return to.getPressure(this); + } + + /** Max transfer rate + * + * @return A Number representing the max transfer rate from the channel (in base group units). + */ + public Number rate() + { + return to.getRate(this); + } + + + + // ################################ + // # Interact with the other node # + // ################################ + + /** Terminates the connection and relays the termination to the recieving node + */ + public void terminate() + { + id = -1; + to.onTerminate(this); + } + + /** Send a packet to the recieving node + * + * @param packet the packet to send + * @return {@code true} if the recieving node accepts the packet + */ + public boolean send(IStaticPacket<D> packet) + { + if(!this.isTerminated()) + return to.accept(packet, this); + return false; + } +} diff --git a/src/main/java/net/cshift/transit/network/INode.java b/src/main/java/net/cshift/transit/network/INode.java new file mode 100644 index 0000000..0396347 --- /dev/null +++ b/src/main/java/net/cshift/transit/network/INode.java @@ -0,0 +1,73 @@ +package net.cshift.transit.network; + +import net.cshift.transit.network.packet.*; + +/** + * @author Kyle Gunger + * @apiNote A node inside or outside a system. + */ +public interface INode +{ + /** Returns true if the group given is used by the node + * + * @param group the group to query + * @return {@code true} if the node supports the group + */ + public boolean hasGroup(String group); + + /** Get the system managing the node or {@code null} if there isn't one + * + * @return System + */ + public ISystem getSystem(); + + + + // ############### + // # Connections # + // ############### + + /** Call this function to establish a connection with a node. + * + * @param <T> The type of connection being asked for + * @param group The group of connection being asked for + * @param asker The asking node + * @return A channel if the node accepts the request, {@code null} otherwise + */ + public <T> Channel<T> connect(String group, INode asker); + + /** Accept a packet from a channel (or not). + * + * @apiNote Do not call this function, use Channel.send(packet) instead. + * @param <T> The type of the packet and channel + * @param packet The packet to be vetted + * @param channel The channel which the packet is coming through + * @return true if the node accepts the packet + */ + public <T> boolean accept(IStaticPacket<T> packet, Channel<T> channel); + + /** Pressure + * + * @apiNote Do not call this function, use Channel.pressure() instead. + * @param channel The channel asking for the pressure + * @return A Number representing the pressure from the channel (in base group units). + */ + public <T> Number getPressure(Channel<T> channel); + + /** Transfer rate + * + * @apiNote Do not call this function, use Channel.rate() instead. + * @param channel The channel asking for the transfer rate + * @return A Number representing the transfer rate from the channel (in base group units). + */ + public <T> Number getRate(Channel<T> channel); + + /** Called when a channel is terminated + * + * @apiNote Do not call this function, use Channel.terminate() instead. + * @param <T> The type of the channel + * @param channel The channel being terminated + */ + public <T> void onTerminate(Channel<T> channel); + +} diff --git a/src/main/java/net/cshift/transit/network/system/ISystem.java b/src/main/java/net/cshift/transit/network/ISystem.java index 9e01645..8d41c1d 100644 --- a/src/main/java/net/cshift/transit/network/system/ISystem.java +++ b/src/main/java/net/cshift/transit/network/ISystem.java @@ -1,4 +1,4 @@ -package net.cshift.transit.network.system; +package net.cshift.transit.network; /** diff --git a/src/main/java/net/cshift/transit/network/packet/dynamic/DynamicPacket.java b/src/main/java/net/cshift/transit/network/packet/DynamicPacket.java index d5feb92..60ad177 100644 --- a/src/main/java/net/cshift/transit/network/packet/dynamic/DynamicPacket.java +++ b/src/main/java/net/cshift/transit/network/packet/DynamicPacket.java @@ -1,4 +1,4 @@ -package net.cshift.transit.network.packet.dynamic; +package net.cshift.transit.network.packet; import net.cshift.transit.type.Type; diff --git a/src/main/java/net/cshift/transit/network/packet/dynamic/IDynamicPacket.java b/src/main/java/net/cshift/transit/network/packet/IDynamicPacket.java index ffb68a3..8b7c330 100644 --- a/src/main/java/net/cshift/transit/network/packet/dynamic/IDynamicPacket.java +++ b/src/main/java/net/cshift/transit/network/packet/IDynamicPacket.java @@ -1,6 +1,4 @@ -package net.cshift.transit.network.packet.dynamic; - -import net.cshift.transit.network.packet.IStaticPacket; +package net.cshift.transit.network.packet; /** Interface describing a fluid packet. * @author Kyle Gunger diff --git a/src/main/java/net/cshift/transit/network/packet/dynamic/MetaDynamicPacket.java b/src/main/java/net/cshift/transit/network/packet/MetaDynamicPacket.java index 9e7d293..b87c2ed 100644 --- a/src/main/java/net/cshift/transit/network/packet/dynamic/MetaDynamicPacket.java +++ b/src/main/java/net/cshift/transit/network/packet/MetaDynamicPacket.java @@ -1,4 +1,4 @@ -package net.cshift.transit.network.packet.dynamic; +package net.cshift.transit.network.packet; import net.cshift.transit.type.Type; diff --git a/src/main/java/net/cshift/transit/network/system/Connection.java b/src/main/java/net/cshift/transit/network/system/Connection.java deleted file mode 100644 index a111795..0000000 --- a/src/main/java/net/cshift/transit/network/system/Connection.java +++ /dev/null @@ -1,49 +0,0 @@ -package net.cshift.transit.network.system; - -public class Connection { - INode node; - short mask; - - public Connection(INode n) - { - node = n; - mask = 0; - } - - public Connection(INode n, short m) - { - node = n; - mask = m; - } - - public INode getNode() - { - return node; - } - - public boolean isAccepting() - { - return (mask & 1) == 1; - } - - public void setAccepting(boolean value) - { - if(isAccepting() && value == false) - mask -= 1; - else if(!isAccepting() && value == true) - mask += 1; - } - - public boolean isProviding() - { - return (mask & 2) == 2; - } - - public void setProviding(boolean value) - { - if(isProviding() && value == false) - mask -= 2; - else if(!isProviding() && value == true) - mask += 2; - } -} diff --git a/src/main/java/net/cshift/transit/network/system/INode.java b/src/main/java/net/cshift/transit/network/system/INode.java deleted file mode 100644 index 5c901a9..0000000 --- a/src/main/java/net/cshift/transit/network/system/INode.java +++ /dev/null @@ -1,53 +0,0 @@ -package net.cshift.transit.network.system; - -/** - * @author Kyle Gunger - * @apiNote A node inside or outside a system. - */ -public interface INode -{ - - /**Returns true if the group given is used by the node - * - * @param groupID the group to querry - * @return bool - */ - public boolean hasGroup(String groupID); - - - /**Get the system managing the node or {@code null} if there isn't one - * - * @return System - */ - public ISystem getSystem(); - - - /** Get the data of one of the TypeGroups the Node supports - * - * @param groupID - * @return - */ - public Object getData(String groupID); - - - /** Set the group data for the node - * - * @param dat - * @param groupID - */ - public void setData(Object dat, String groupID); - - - /** Get the nodes that this node is connected to - * - * @return Node[] - */ - public Connection[] getConnections(); - - - /** Get the number of nodes that this node is connected to - * - * @return int - */ - public int connectionCount(); -} diff --git a/src/main/java/net/cshift/transit/network/system/swap/IAcceptorNode.java b/src/main/java/net/cshift/transit/network/system/swap/IAcceptorNode.java deleted file mode 100644 index b64d4cc..0000000 --- a/src/main/java/net/cshift/transit/network/system/swap/IAcceptorNode.java +++ /dev/null @@ -1,37 +0,0 @@ -package net.cshift.transit.network.system.swap; - -import net.cshift.transit.network.packet.IStaticPacket; -import net.cshift.transit.network.system.INode; - -/** - * @author Kyle Gunger - * @apiNote A node which can accept packets of specific types - */ -public interface IAcceptorNode extends INode -{ - - /** Link another node as a provider - * - * @param requester The object to be a provider - * @param group - * @return - */ - public boolean linkProvider(IProviderNode requestor, String group); - - - /** Unlink a provider from the acceptor - * - * @param requestor - * @return - */ - public boolean unlinkProvider(IProviderNode requestor); - - - /** Accept a packet from a provider - * - * @param packet - * @param group - * @return - */ - public <T> boolean accept(IStaticPacket<T> packet, String group); -} diff --git a/src/main/java/net/cshift/transit/network/system/swap/IProviderNode.java b/src/main/java/net/cshift/transit/network/system/swap/IProviderNode.java deleted file mode 100644 index 5a3bd80..0000000 --- a/src/main/java/net/cshift/transit/network/system/swap/IProviderNode.java +++ /dev/null @@ -1,27 +0,0 @@ -package net.cshift.transit.network.system.swap; - -import net.cshift.transit.network.system.INode; - -/** - * @author Kyle Gunger - * @apiNote A node which can provide packets of specific types - */ -public interface IProviderNode extends INode{ - - /** Link another node as an acceptor - * - * @param requester The object requesting the Acceptor - * @param group - * @return boolean - */ - public boolean linkAcceptor(IAcceptorNode requestor, String group); - - - /** Unlink a provider from the acceptor - * - * @param requestor - * @return - */ - public boolean unlinkAcceptor(IAcceptorNode requestor); - -} diff --git a/src/main/java/net/cshift/transit/type/SimpleTypes.java b/src/main/java/net/cshift/transit/type/SimpleTypes.java new file mode 100644 index 0000000..ee8dd01 --- /dev/null +++ b/src/main/java/net/cshift/transit/type/SimpleTypes.java @@ -0,0 +1,19 @@ +package net.cshift.transit.type; + +public final class SimpleTypes { + /** Transfers energy. Energy is stored as a numeric. + */ + public static final Type<Number> TransitJoule = new Type<Number>("TJoule", "ENERGY"); + + /** Transfers mana. TMana stores mana count and type. + */ + public static final Type<TMana> TransitMana = new Type<TMana>("TMana", "MANA"); + + /** Transfers items. TItem stores an item and an item count. + */ + public static final Type<TItem> TransitItem = new Type<TItem>("TItem", "ITEM"); + + /** Transfers fluid. TFluid stores fluid and mB. + */ + public static final Type<TFluid> TransitFluid = new Type<TFluid>("TFluid", "FLUID"); +} diff --git a/src/main/java/net/cshift/transit/type/TItem.java b/src/main/java/net/cshift/transit/type/TItem.java index 966267d..b3cc160 100644 --- a/src/main/java/net/cshift/transit/type/TItem.java +++ b/src/main/java/net/cshift/transit/type/TItem.java @@ -2,7 +2,7 @@ package net.cshift.transit.type; import net.minecraft.item.*; -/** Units of fluid. +/** Item storage * @author Kyle Gunger */ public class TItem { @@ -10,23 +10,22 @@ public class TItem { private Number count; /** Constructor. - * Since a bucket of fluid is the same as a block of a fluid, mb can be called millibuckets or milliblocks. * - * @param i Fluid stored (Water/Lava/etc.) - * @param c Item countie + * @param i Item stored + * @param c Item count */ public TItem(Item i, Number c) { item = i; count = c; } - /** Get the fluid stored. + /** Get the item stored. */ public Item getItem() { return item; } - /** Get the millibuckets stored. + /** Get the item count. */ public Number getCount() { return count; diff --git a/src/main/java/net/cshift/transit/type/Type.java b/src/main/java/net/cshift/transit/type/Type.java index 2ea5bf4..9049135 100644 --- a/src/main/java/net/cshift/transit/type/Type.java +++ b/src/main/java/net/cshift/transit/type/Type.java @@ -4,7 +4,7 @@ import net.cshift.transit.network.packet.*; /**@author Kyle Gunger * - * @param T The type of object transfered by packets of this type + * @param <T> The type of object transfered by packets of this type */ public class Type<T> { diff --git a/src/main/java/net/cshift/transit/type/group/GroupRegistry.java b/src/main/java/net/cshift/transit/type/group/GroupRegistry.java index f16f31a..cfebb03 100644 --- a/src/main/java/net/cshift/transit/type/group/GroupRegistry.java +++ b/src/main/java/net/cshift/transit/type/group/GroupRegistry.java @@ -30,7 +30,6 @@ public final class GroupRegistry { return true; } - @SuppressWarnings("unchecked") public static final <T> TypeGroup<T> groupByID(String groupID) { for(TypeGroup<?> g : GROUPS) @@ -50,7 +49,12 @@ public final class GroupRegistry { public static final <T> Type<T> typeByIdentity(String groupID, String typeID) { - return GroupRegistry.<T>groupByID(groupID).getType(typeID); + TypeGroup<T> group = GroupRegistry.<T>groupByID(groupID); + + if(group != null) + return group.getType(typeID); + + return null; } } diff --git a/src/main/java/net/cshift/transit/type/group/SimpleGroups.java b/src/main/java/net/cshift/transit/type/group/SimpleGroups.java new file mode 100644 index 0000000..d68c5a5 --- /dev/null +++ b/src/main/java/net/cshift/transit/type/group/SimpleGroups.java @@ -0,0 +1,29 @@ +package net.cshift.transit.type.group; + +import net.cshift.transit.type.*; + +public final class SimpleGroups { + /** Transfers energy. Basic unit is TJoule (Transit Joule). + */ + public static final TypeGroup<Number> ENERGY = new TypeGroup<Number>(SimpleTypes.TransitJoule); + + /** Transfers mana. Basic unit is TMana (Transit Mana). + */ + public static final TypeGroup<TMana> MANA = new TypeGroup<TMana>(SimpleTypes.TransitMana); + + /** Transfers items. Basic unit is TItem. + */ + public static final TypeGroup<TItem> ITEM = new TypeGroup<TItem>(SimpleTypes.TransitItem); + + /** Transfers fluids. Basic unit is TFluid. + */ + public static final TypeGroup<TFluid> FLUID = new TypeGroup<TFluid>(SimpleTypes.TransitFluid); + + public static final void init() + { + GroupRegistry.addGroup(ENERGY); + GroupRegistry.addGroup(MANA); + GroupRegistry.addGroup(ITEM); + GroupRegistry.addGroup(FLUID); + } +} diff --git a/src/main/java/net/cshift/transit/type/group/simple/SimpleGroups.java b/src/main/java/net/cshift/transit/type/group/simple/SimpleGroups.java deleted file mode 100644 index 95b151a..0000000 --- a/src/main/java/net/cshift/transit/type/group/simple/SimpleGroups.java +++ /dev/null @@ -1,31 +0,0 @@ -package net.cshift.transit.type.group.simple; - -import net.cshift.transit.type.group.*; -import net.cshift.transit.type.simple.*; -import net.cshift.transit.type.*; - -public final class SimpleGroups { - /** Transfers energy. Basic unit is TJoule (Transit Joule). - */ - public static final TypeGroup<Number> ENERGY_GROUP = new TypeGroup<Number>(SimpleTypes.TransitJoule); - - /** Transfers mana. Basic unit is TMana (Transit Mana). - */ - public static final TypeGroup<TMana> MANA_GROUP = new TypeGroup<TMana>(SimpleTypes.TransitMana); - - /** Transfers items. Basic type is ItemStack. - */ - public static final TypeGroup<TItem> ITEM_GROUP = new TypeGroup<TItem>(SimpleTypes.Item); - - /** Transfers fluids. Basic unit is TFluid. - */ - public static final TypeGroup<TFluid> FLUID_GROUP = new TypeGroup<TFluid>(SimpleTypes.Fluid); - - public static final void init() - { - GroupRegistry.addGroup(ENERGY_GROUP); - GroupRegistry.addGroup(MANA_GROUP); - GroupRegistry.addGroup(ITEM_GROUP); - GroupRegistry.addGroup(FLUID_GROUP); - } -} diff --git a/src/main/java/net/cshift/transit/type/simple/SimpleTypes.java b/src/main/java/net/cshift/transit/type/simple/SimpleTypes.java deleted file mode 100644 index 26171b1..0000000 --- a/src/main/java/net/cshift/transit/type/simple/SimpleTypes.java +++ /dev/null @@ -1,21 +0,0 @@ -package net.cshift.transit.type.simple; - -import net.cshift.transit.type.*; - -public final class SimpleTypes { - /** Transfers energy. Energy is stored as a numeric, base value is TJoule (TransitJoule) - */ - public static final Type<Number> TransitJoule = new Type<Number>("TJoule", "ENERGY"); - - /** Transfers mana. TMana stores mana count and type. - */ - public static final Type<TMana> TransitMana = new Type<TMana>("TMana", "MANA"); - - /** Transfers items in a itemstack. - */ - public static final Type<TItem> Item = new Type<TItem>("Item", "ITEM"); - - /** Transfers fluid. TFluid stores fluid and mB. - */ - public static final Type<TFluid> Fluid = new Type<TFluid>("Fluid", "FLUID"); -} diff --git a/src/main/resources/assets/transit-api/icon.png b/src/main/resources/assets/transit-api/icon.png Binary files differdeleted file mode 100644 index d1f4688..0000000 --- a/src/main/resources/assets/transit-api/icon.png +++ /dev/null diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index a2a499d..1ef3567 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -1,7 +1,7 @@ { "schemaVersion": 1, "id": "transit-api", - "version": "2.0.0", + "version": "2.0.0-alpha.predev", "name": "Transit API", "description": "Move things about!", |