text:
package uq.deco2800.coaster.game.entities;

import javafx.scene.canvas.GraphicsContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import uq.deco2800.coaster.game.entities.npcs.AttackableNPC;
import uq.deco2800.coaster.game.entities.npcs.BaseNPC;
import uq.deco2800.coaster.game.entities.particles.Particle;
import uq.deco2800.coaster.game.entities.puzzle.TerrainEntity;
import uq.deco2800.coaster.game.entities.weapons.Projectile;
import uq.deco2800.coaster.game.mechanics.BodyPart;
import uq.deco2800.coaster.game.mechanics.Side;
import uq.deco2800.coaster.game.tiles.Tile;
import uq.deco2800.coaster.game.tiles.TileInfo;
import uq.deco2800.coaster.game.world.Chunk;
import uq.deco2800.coaster.game.world.World;
import uq.deco2800.coaster.graphics.LayerList;
import uq.deco2800.coaster.graphics.Viewport;
import uq.deco2800.coaster.graphics.sprites.Sprite;
import uq.deco2800.coaster.graphics.sprites.SpriteList;
import uq.deco2800.coaster.graphics.sprites.SpriteRelation;

import java.util.*;
import java.util.function.Predicate;

public abstract class Entity {
	private static final Logger logger = LoggerFactory.getLogger(Entity.class);

	public static final float GRAVITY = 50f;
	public static final float terminalVelocity = 50f; // Max falling speed
	public static final float UNDER_WATER_GRAVITY_MULTIPLIER = 0.7f;

	protected World world;
	protected Sprite sprite = null;

	// For now, coordinate system is top-left just so we don't have to flip it
	// when rendering. If this turns out

	// Map of extra sprites that are not bound to the entity's hitbox. They are
	// described by SpriteRelations, which
	// contain the sprite and how they are connected with the owner entity.
	protected Map<BodyPart, SpriteRelation> additionalSprites = new HashMap<>();
	// When true, facing = last movement direction. When false, facing is not
	// updated in this fashion.
	protected boolean strafeActive = false;

	protected int renderFacing = 1;

	protected LayerList layer;

	// For now, coordinate system is top-left just so we don't have to flip it
	// when rendering. If this turns out
	// horrible then I'll consider changing it to bottom-left.
	protected AABB bounds;
	protected List<AABB> hitboxes = new ArrayList<>();

	protected float prevX; // For projectile collision detection
	protected float prevY; // For projectile collision detection
	protected float posX;
	protected float posY;
	protected float prevVelX;
	protected float prevVelY;
	protected float velX;
	protected float velY;
	// Entity states regarding physics to avoid recalculation
	protected boolean onGround;
	protected boolean isUnderLiquid;
	protected int onWall = 0; // -1 for wall on left, 1 for right, 0 for not on wall
	protected boolean onCeiling;
	// Some properties all entities should have
	protected boolean enableGravity = true; // Affected by gravity?
	protected boolean hurtByProjectiles = true; // Collides with projectiles?
	private boolean blocksOtherEntities = true;
	protected boolean renderFlag = true; // Does the sprite get rendered? Other effects still rendered
	protected int facing = 1; // -1 for left, 1 for right.\
	protected Predicate<Entity> collisionFilter;
	Viewport viewport;
	boolean firstTick = true;

	protected long latestTick = 5000;

	private List<AABB> checkedTiles = new LinkedList<AABB>();

	public Entity() {
		layer = LayerList.DEFAULT;
		this.world = World.getInstance();
		setCollisionFilter(e -> true);
	}

	/**
	 * Will intialise some of the properties of an entity
	 *
	 * @param sprite              the type of sprite to use
	 * @param blocksOtherEntities whether or not this entity blocks other entities
	 * @param collisionFilter     a predicate which filters collisions
	 */
	protected void initEntity(SpriteList sprite, boolean blocksOtherEntities, Predicate<Entity> collisionFilter) {
		setSprite(new Sprite(sprite));
		setBlocksOtherEntities(blocksOtherEntities);
		bounds = new AABB(posX, posY, this.sprite.getWidth() / 32, this.sprite.getHeight() / 32);
		setCollisionFilter(collisionFilter);
	}

	/**
	 * Sets this entity's sprite to the specified sprite instance
	 */
	public void setSprite(Sprite sprite) {
		this.sprite = sprite;
	}

	/**
	 * Getter for this entity's sprite
	 *
	 * @return the current Sprite instance
	 */
	public Sprite getSprite() {
		return this.sprite;
	}

	/**
	 * Set rendering layer
	 */
	public void setLayer(LayerList layer) {
		this.layer = layer;
	}

	/**
	 * Return rendering layer
	 */
	public LayerList getLayer() {
		return layer;
	}

	/**
	 * Sets the additional sprites, which are rendered over the top of this entity and are not hitbox-aligned.
	 *
	 * @param additionalSprites a map of <SpritePart, SpriteRelation>
	 */
	public void setAdditionalSprites(Map<BodyPart, SpriteRelation> additionalSprites) {
		this.additionalSprites = additionalSprites;
	}

	/**
	 * Returns the ID of the current Sprite
	 *
	 * @return the ID of the current Sprite
	 */
	public SpriteList getSpriteID() {
		return sprite.getSpriteId();
	}

	/**
	 * Getter for the entity's bounds This is an axis-aligned bounding box (AABB), which is essentially the rectangle
	 * that defines the entity's size and location This can also be thought of as a hitbox.
	 *
	 * @return the entity's hitbox
	 */
	public AABB getBounds() {
		return bounds;
	}

	/**
	 * Sets the size of the AABB (and therefore the entity)
 Warning: This should NOT be used for collision-sensitive
	 * entities (e.g Player, NPCs) as it can cause all kinds of funky physics issues.
 For those entities,
	 * changeBounds is the preferred method.
	 *
	 * @param width  new width in tiles
	 * @param height new height in tiles
	 */
	public void setSize(float width, float height) {
		this.bounds.setAABB(posX, posY, width, height);
	}

	/**
	 * Sets the direction that the entity is facing in. Note that this is distinct to renderFacing due to the difference
	 * between movement and rendering
	 *
	 * @require facing == 1, to make the entity face right OR facing == -1 to make the entity face left
	 */
	public void setFacing(int facing) {
		this.facing = facing;
	}

	/**
	 * Returns the direction the entity is facing (in terms of movement)
	 *
	 * @return -1 if the entity is facing to the left, 1 if to the right
	 */
	public int getFacing() {
		return facing;
	}

	/**
	 * Returns the direction the entity is rendered as facing
	 *
	 * @return -1 if the entity is rendered to the left, 1 if to the right
	 */
	public int getRenderFacing() {
		return renderFacing;
	}

	/**
	 * Sets the direction that the entity is rendered as facing in. Note that this is distinct to facing due to the
	 * difference between movement and rendering
	 *
	 * @require renderFacing == 1, to make the entity face right OR renderFacing == -1 to make the entity face left
	 */
	public void setRenderFacing(int renderFacing) {
		this.renderFacing = renderFacing;
	}

	/**
	 * Creates and returns a child hitbox offset from this entity's bounds
	 *
	 * @param bodyPart the bodyPart assigned to this
	 * @param sizeX    the hitbox's width in tiles
	 * @param sizeY    hitbox's height
	 * @param offsetX  offset from the entity's left edge to this hitbox's left edge when facing right
	 * @param offsetY  offset from the entity's top edge to this hitbox's top edge
	 * @return a child hitbox described by the input information
	 */

	public AABB defineHitbox(BodyPart bodyPart, float sizeX, float sizeY, float offsetX, float offsetY) {
		AABB hitbox = new AABB(posX, posY, sizeX, sizeY, offsetX, offsetY);
		hitbox.makeChild(true);
		hitbox.setBodyPart(bodyPart);
		return hitbox;
	}

	/**
	 * Removes all hitboxes described by the input body part from the list of hitboxes
	 *
	 * @param armourPart
	 */
	public void removeHitbox(BodyPart armourPart) {
		for (int i = 0; i < hitboxes.size(); i++) {
			if (hitboxes.get(i).getBodyPart() == armourPart) {
				hitboxes.remove(i);
			}
		}
	}

	/**
	 * Sets the entity's position (top-left corner) to the specified point

	 * Note that movement commands are queued so we can process collision a bit easier
	 *
	 * @param x the new x coordinate in tiles
	 * @param y the new y coordinate in tiles
	 */
	public void setPosition(float x, float y) {
		prevX = posX;
		prevY = posY;
		posX = x;
		posY = y;
		bounds.setX(posX);
		bounds.setY(posY);

		updateHitboxes();

		World tempWorld = World.getInstance();
		if (this instanceof Player) {
			int offset = -getNearestChunkX();
			tempWorld.resetTiles();
			tempWorld.getTiles().setOffset(offset);
			tempWorld.loadAroundPlayer((Player) this);
		}
	}

	/**
	 * Sets the entity's velocity to the specified vector
	 *
	 * @param x the new x velocity in tiles/second
	 * @param y the new y velocity in tiles/second
	 */
	public void setVelocity(float x, float y) {
		velX = x;
		velY = y;
	}

	/**
	 * Returns the starting x coordinate of the chunk the player is standing on.
	 */
	public int getNearestChunkX() {
		return Chunk.CHUNK_WIDTH * Math.round(posX / Chunk.CHUNK_WIDTH);
	}

	/**
	 * Gets the x-coordinate of the entity's top-left corner
	 *
	 * @return x-coordinate of the entity's top-left corner in tiles
	 */
	public float getX() {
		return posX;
	}

	/**
	 * Gets the y-coordinate of the entity's top-left corner
	 *
	 * @return y-coordinate of the entity's top-left corner in tiles
	 */
	public float getY() {
		return posY;
	}

	/**
	 * sets the x-coordinate of the entity's top-left corner
	 */
	public void setX(float xPos) {
		this.posX = xPos;
		bounds.setX(xPos);
		updateHitboxes();
	}

	/**
	 * sets the y-coordinate of the entity's top-left corner
	 */
	public void setY(float yPos) {
		this.posY = yPos;
		bounds.setY(yPos);
		updateHitboxes();
	}

	/**
	 * Gets the x velocity
	 *
	 * @return x-velocity in tiles/second
	 */
	public float getVelX() {
		return velX;
	}

	/**
	 * Gets the y velocity
	 *
	 * @return y-velocity in tiles/second
	 */
	public float getVelY() {
		return velY;
	}

	/**
	 * Get latest change in time in ms
	 */
	public long getTick() {
		return latestTick;
	}

	/**
	 * Gets the actual observed x velocity
	 *
	 * @return x-velocity in tiles/millisecond
	 */

	public float getMeasuredVelX() {
		return (getX() - getPrevX()) / getTick();

	}

	/**
	 * Gets the actual observed y velocity
	 *
	 * @return y-velocity in tiles/millisecond
	 */

	public float getMeasuredVelY() {
		return (getY() - getPrevY()) / getTick();

	}

	/**
	 * returns the x-coordinate of the player at the previous tick
	 *
	 * @return previous x-coordinate in tiles
	 */
	public float getPrevX() {
		return prevX;
	}

	/**
	 * returns the y-coordinate of the player at the previous tick
	 *
	 * @return previous y-coordinate in tiles
	 */
	public float getPrevY() {
		return prevY;
	}

	/**
	 * returns the width of this entity's hitbox
	 *
	 * @return the hitbox width in tiles
	 */
	public float getWidth() {
		return bounds.getWidth();
	}

	/**
	 * returns the height of this entity's hitbox
	 *
	 * @return the hitbox height in tiles
	 */
	public float getHeight() {
		return bounds.getHeight();
	}

	/**
	 * returns whether or not this entity is hurt by projectiles
	 *
	 * @return true if projectiles hurt this entity, otherwise false.
	 */
	public boolean isHurtByProjectiles() {
		return hurtByProjectiles;
	}

	/**
	 * returns whether or not this entity blocks other entities i.e. returns true this entity is a physical object in
	 * game, and false if it is permeable
	 *
	 * @return true if this entity blocks other entities, otherwise false.
	 */
	public boolean blocksOtherEntities() {
		return doesItBlockOtherEntities();
	}

	/**
	 * returns if gravity causes this entity to accelerate downwards when not onGround
	 *
	 * @return true if gravity affects this entity, otherwise false
	 */
	public boolean isEnableGravity() {
		return enableGravity;
	}

	/**
	 * toggles gravity
	 */
	public void toggleGravity() {
		enableGravity = !enableGravity;
	}

	/**
	 * returns if the entity is currently on the ground i.e. if the entity is unable to move downwards due to a
	 * collision Standing on top of terrain or other entities both cause this to be true
	 *
	 * @return true if the entity is on the ground
	 */
	public boolean isOnGround() {
		return onGround;
	}

	/**
	 * Returns the onWall status
	 * i.e. -1 if the entity is colliding with a wall on the left, 1 for a wall on the right
	 * returns 0 for no horizontal collision
	 *
	 * @return
	 */
	public int getOnWall() {
		return onWall;
	}

	/**
	 * returns if the entity is currently in the Water
	 *
	 * @return true if the entity is in the water
	 */
	public boolean isUnderLiquid() {
		return isUnderLiquid;
	}

	/**
	 * Sets the collision filter to the input predicate
	 *
	 * @param predicate a boolean used to determine whether or not a collision will occur with the input entity
	 */
	public void setCollisionFilter(Predicate<Entity> predicate) {
		collisionFilter = predicate;
	}

	/**
	 * Updates the entity's y velocity to reflect gravity.

	 * Note that an ifEnableGravity check should be made first.

	 *

	 * Downwards velocity due to gravity is capped at terminalVelocity.

	 * The rate of acceleration is slowed down when underwater
	 *
	 * @param ms time since the last tick in milliseconds.
	 */
	protected void updateVelYFromGravity(float ms) {
		float seconds = ms / (float) 1000;

		velY += GRAVITY * seconds * (isUnderLiquid ? UNDER_WATER_GRAVITY_MULTIPLIER : 1f); // Top left coordinate system, so gravity is positive.
		if (velY > terminalVelocity) {
			velY = terminalVelocity;

		}
	}

	/**
	 * Get a list of nearby entities of a given property, excluding this entity
	 *
	 * @param radius    the radius of the search
	 * @param classType the type of class to select
	 * @return A list of entities
	 */

	public List<Entity> getNearbyEntities(int radius, Class<?> classType) {
		ArrayList<Entity> nearbyEntities = new ArrayList<>();
		for (Entity entity : world.getAllEntities()) {

			float distX = bounds.posX() - entity.getBounds().posX();
			float distY = bounds.posY() - entity.getBounds().posY();
			double distSquared = distX * distX + distY * distY;
			if ((distSquared < (radius * radius)) && entity != this && classType.isInstance(entity)) {
				nearbyEntities.add(entity);
			}
		}
		return nearbyEntities;
	}

	/**
	 * Get a list of nearby entities, excluding this entity
	 *
	 * @param radius the radius of the search
	 * @return A list of entities
	 */
	public List<Entity> getNearbyEntities(int radius) {
		return getNearbyEntities(radius, Entity.class);
	}

	/**
	 * Get a list of nearby enemy NPCs
	 *
	 * @param radius the radius of the search
	 * @return A list of BaseNPCs
	 */
	public List<BaseNPC> getNearbyAttackableNPCs(int radius) {
		ArrayList<BaseNPC> nearbyEnemyNPCs = new ArrayList<>();
		for (Entity entity : getNearbyEntities(radius, AttackableNPC.class)) {
			nearbyEnemyNPCs.add((BaseNPC) entity);
		}
		return nearbyEnemyNPCs;
	}

	/**
	 * Returns the straight-line distance between this entity's top-left and that of the target
	 *
	 * @param e an entity to which the distance is calculated
	 * @return the straight line distance in tiles
	 */
	public float distanceFrom(Entity e) {
		return Math.abs((this.posX + this.getWidth() / 2) - (e.posX + e.getWidth() / 2));
	}

	/**
	 * Returns the closest entity out of the input list.
	 *
	 * @param entities a list of entities
	 * @return the closest of these entities
	 */
	public Entity getClosest(List<Entity> entities) {
		float dist;
		float closestDistance = Float.MAX_VALUE;
		Entity closest = null;
		for (Entity entity : entities) {
			// Check if this player is closer
			dist = this.distanceFrom(entity);
			if (dist < closestDistance) {
				closest = entity;
				closestDistance = dist;
			}
		}
		return closest;
	}

	/*
	 * ------------------------------------------------------------------------
	 */
	/*
	 * ------------------------------------------------------------------------
	 */
	/*
	 * Below here is lots of physics, state, framework and rendering code
	 */
	/*
	 * ------------------------------------------------------------------------
	 */
	/*
	 * ------------------------------------------------------------------------
	 */

	/**
	 * Updates the position of all hitboxes relative to bounds (the main hitbox)
	 */
	protected void updateHitboxes() {
		if (hitboxes != null) {
			for (AABB hitbox : hitboxes) {
				hitbox.setPos(bounds, renderFacing);
			}
		}
	}

	/**
	 * Checks if a change of bounds would cause collision issues
	 *

	 * This does not actually change the bounds, only checks for collisions at all locations within the potential new bounds
	 *
	 * @param posX   the potential new x position in tiles
	 * @param posY   the potential new y position in tiles
	 * @param width  the potential new width in tiles
	 * @param height the potential new height in tiles
	 * @return false if changing to these bounds would cause a collision, otherwise true
	 */
	protected boolean checkChangeOfBounds(float posX, float posY, float width, float height) {
		AABB testAABB = new AABB(posX, posY, width, height);

		int flooredLeft = (int) Math.floor(testAABB.left());
		int ceilRight = (int) Math.ceil(testAABB.right());
		int flooredTop = (int) Math.floor(testAABB.top());
		int ceilBottom = (int) Math.ceil(testAABB.bottom());
		for (int x = flooredLeft; x < ceilRight; x++) {
			for (int y = flooredTop; y < ceilBottom; y++) {
				if (!world.getTiles().test(x, y)) {
					continue;
				}
				TileInfo tile = world.getTiles().get(x, y).getTileType();
				AABB tileAABB = new AABB(x, y, 1, 1);
				if (tile.isObstacle() && testAABB.collides(tileAABB)) {
					return false;
				}
			}
		}
		return true;
	}

	/**
	 * Change the entity's bounds/size.
	 *

	 * Used when changing state e.g. moving -> sliding.

	 * Adjusts the position to ensure fluidity
	 */
	protected boolean changeBounds(float width, float height) {
		float oldPosX = posX;
		float oldPosY = posY;
		if (onGround) {
			posY += getHeight() - height;
		}
		if (facing == -1 && getWidth() < width) {
			posX += getWidth() - width;
		}
		if (checkChangeOfBounds(posX, posY, width, height)) {
			setSize(width, height);
			return true;
		} else {
			posX = oldPosX;
			posY = oldPosY;
			return false;
		}
	}

	/**
	 * Returns the number of steps per collision detection.
	 *

	 * This should ensure that an entity never moves horizontally more than half their width per step
	 * And also that an entity never moves vertically more that half their height per step
	 * Minimum return value is 4
	 *
	 * @return the number of steps to take.
	 */
	private int getCollisionScale(long ms) {
		float seconds = ms / (float) 1000;
		float distX = Math.abs(velX * seconds);
		float distY = Math.abs(velY * seconds);

		int stepsX = (int) Math.ceil(distX / bounds.getHalfWidth());
		int stepsY = (int) Math.ceil(distY / bounds.getHalfHeight());

		return Math.max(Math.max(stepsX, stepsY), 4);
	}

	/**
	 * The physics engine
	 *

	 * Initialises/clears fields used to detect/process/react to collisions

	 * then calls delegate methods to actually process this

	 *

	 * We process collisions in steps, to keep the distance between checks small

	 * This way we gain a lot more precision than we would get from just doing this once per tick
	 *
	 * @param ms time since the last tick in milliseconds
	 * @WilliamHayward - I've made this public so that it can be overridden
	 * @ckent-78 aight
	 * @WilliamHayward - I've made this public so that it can be overridden
	 */
	public void updatePhysics(long ms) {
		float seconds = ms / (float) 1000;
		// apply gravity
		if (enableGravity) {
			updateVelYFromGravity(ms);
		}

		// Save previous states
		prevX = posX;
		prevY = posY;
		prevVelX = velX;
		prevVelY = velY;

		// initialise list of collided entites and BodyParts
		List<Entity> collidedEntities = new ArrayList<>(); // which entities have I collided with?
		List<BodyPart> hitLocations = new ArrayList<>(); // where did they hit me?

		// initialise list of collided tiles
		List<int[]> collidedTerrain = new ArrayList<>(); // coordinates of tile collisions
		List<Side> hitDirections = new ArrayList<>(); // which side of this entity is the tile on

		// Clearing collision flags used in various state machines

		onGround = false;
		onWall = 0;
		onCeiling = false;

		int collisionScale = getCollisionScale(ms);

		// distance travelled in one step
		float diffX = velX * seconds / collisionScale;
		float diffY = velY * seconds / collisionScale;

		// clear the list of tile hitboxes
		// this list is used for debugging terrain collisions
		// we render all of these hitboxes to show which ones were checked for collisions
		checkedTiles.clear();

		// saves the starting locatins of each hitbox

		bounds.saveCoords();
		if (hitboxes != null) {
			for (AABB hitbox : hitboxes) {
				hitbox.saveCoords();
			}

		}

		// This Reduces the speed of the Character when he is in Liquid

		if (isUnderLiquid) {
			diffX *= 0.7f;
			diffY *= 0.7f;
		}
		isUnderLiquid = false; // reset flag

		// process things one step at a time
		for (int step = 0; step < collisionScale; step++) {

			// increment position
			bounds.setX(bounds.left() + diffX);
			bounds.setY(bounds.top() + diffY);

			// process on bounds first
			// resolving any collisions with terrain
			processStep(bounds, collidedTerrain, hitDirections, collidedEntities, hitLocations);

			// then process all additional hitboxes, updating their's and bounds locations to maintain offsets
			// resolving any collisions with terrain

			if (hitboxes != null) {
				for (AABB hitbox : hitboxes) {
					hitbox.setPos(bounds, renderFacing);
					processStep(hitbox, collidedTerrain, hitDirections, collidedEntities, hitLocations);
					bounds.setPos(hitbox, renderFacing);
				}
			}

		}
		// End step

		detectWater();

		if (!strafeActive) {
			renderFacing = facing;
		}

		posX = bounds.left();
		posY = bounds.top();
		updateHitboxes();

		// This is kinda inefficient and hacky but it fixes some broken stuff
		// Note: not applicable to projectiles bc extra hitboxes
		// Basically if it all screwed up and you're about to warp through a wall
		// We snap you back to your previous location
		// Only a problem in small spaces like rooms
		if (this instanceof StateEntity && checkRemainingCollisions()) {
			posX = prevX;
			posY = prevY;
			bounds.setPos(posX, posY);
		}

		// React to collisions with terrain
		if (!collidedTerrain.isEmpty()) {
			collideWithTerrain(collidedTerrain, hitDirections);
		}
		if (!collidedEntities.isEmpty()) {
			onEntityCollide(collidedEntities, hitLocations);
		}
	}

	/**
	 * Scans along the top edge of the entity for liquid tiles

	 * If a liquid tile is found, sets the isLiquid flag
	 */

	private void detectWater() {
		int topY = (int) Math.floor(bounds.top());
		int rightX = (int) Math.ceil(bounds.right() - 1);
		int leftX = (int) Math.floor(bounds.left());

		for (int testX = leftX; testX <= rightX; testX++) {

			if (!world.getTiles().test(testX, topY)) {
				continue;
			}
			TileInfo tile = world.getTiles().get(testX, topY).getTileType();
			AABB tileAABB = new AABB(testX, topY, 1, 1);
			if (tile.isLiquid() && bounds.collides(tileAABB)) {
				isUnderLiquid = true;
			}
		}
	}

	/**
	 * Detects if the input hitbox is currently colliding with anything and resolves the collision
	 *

	 * Populates a list of entities and terrain with which we are colliding
	 * You can pass null into collidedTerrain and collidedEntities if you want to avoid onTerrainCollide and onEntityCollide form being called
	 *
	 * @param hitbox           the hitbox being processed
	 * @param collidedTerrain  a list of terrain locations that we've collided with in this tick
	 * @param hitDirections    which side of this entity did that collision occur on
	 * @param collidedEntities a list of entities that we've collided with in this tick
	 * @param hitLocations     which of our body parts collided with the entity
	 */

	private void processStep(AABB hitbox, List<int[]>
			collidedTerrain, List<Side> hitDirections, List<Entity> collidedEntities, List<BodyPart> hitLocations) {
		// the relevant row/column of tiles on each side
		// the -1 bc tiles are top left coords, so we want to look at the row that starts inside the player on the bottom/right edge
		int bottomY = (int) Math.ceil(hitbox.bottom() - 1);
		int topY = (int) Math.floor(hitbox.top());
		int rightX = (int) Math.ceil(hitbox.right() - 1);
		int leftX = (int) Math.floor(hitbox.left());

		if (velX < 0) {
			leftX += 1;
		} else if (velX > 0) {
			rightX -= 1;
		}

		if (velY > 0) { // moving down -> check the bottom edge for terrain/terrain entities
			for (int testX = leftX; testX <= rightX; testX++) {
				if (checkTileCollision(hitbox, collidedTerrain, hitDirections, testX, bottomY, Side.BOTTOM)) {
					break;
				}
			}
			TerrainEntity collidedTerrainEntity = checkTerrainEntities(bounds, Side.BOTTOM);
			if (collidedTerrainEntity != null) {
				insertInCollidedTerrain(collidedTerrain, hitDirections, collidedTerrainEntity.bounds);
			}
		} else if (velY < 0) { // moving up -> check the top edge for terrain/terrain entities
			for (int testX = leftX; testX <= rightX; testX++) {
				if (checkTileCollision(hitbox, collidedTerrain, hitDirections, testX, topY, Side.TOP)) {
					break;
				}
			}
			TerrainEntity collidedTerrainEntity = checkTerrainEntities(bounds, Side.TOP);
			if (collidedTerrainEntity != null) {
				insertInCollidedTerrain(collidedTerrain, hitDirections, collidedTerrainEntity.bounds);
			}
		}

		bottomY = (int) Math.ceil(hitbox.bottom() - 1);
		topY = (int) Math.floor(hitbox.top());
		rightX = (int) Math.ceil(hitbox.right() - 1);
		leftX = (int) Math.floor(hitbox.left());

		if (velX > 0) { // moving right -> check the right edge for terrain/terrain entities
			facing = 1;
			for (int testY = bottomY; testY >= topY; testY--) {
				if (checkTileCollision(hitbox, collidedTerrain, hitDirections, rightX, testY, Side.RIGHT)) {
					break;
				}
			}
			TerrainEntity collidedTerrainEntity = checkTerrainEntities(bounds, Side.RIGHT);
			if (collidedTerrainEntity != null) {
				insertInCollidedTerrain(collidedTerrain, hitDirections, collidedTerrainEntity.bounds);
			}
		} else if (velX < 0) {  // moving left -> check the left edge for terrain/terrain entities
			facing = -1;
			for (int testY = bottomY; testY >= topY; testY--) {
				// single | is deliberate, we don't want short circuiting
				if (checkTileCollision(hitbox, collidedTerrain, hitDirections, leftX, testY, Side.LEFT)) {
					break;
				}
			}
			TerrainEntity collidedTerrainEntity = checkTerrainEntities(bounds, Side.LEFT);
			if (collidedTerrainEntity != null) {
				insertInCollidedTerrain(collidedTerrain, hitDirections, collidedTerrainEntity.bounds);
			}
		}
		checkEntityCollisions(hitbox, collidedEntities, hitLocations);

	}

	/**
	 * Checks if the input hitbox collides with any terrain at the specified location
	 *

	 * If a collision occurs, it is resolved (i.e. player is pushed out so they don't collided anymore)

	 * And the coordinates of the collided tile are entered into the list
	 *
	 * @param hitbox          the hitbox for which we are checking collisions
	 * @param collidedTerrain a list of coordinates, storing which tiles we've collided with
	 * @param hitDirections   a list of Sides, storing on which side we've collided with a tile
	 * @param x               the x coordinate of the tile we're checking
	 * @param y               the y coordinate of the tile we're checking
	 * @param side            the side on which we're checking/use to resolve the collision
	 * @return true if a collision is found, otherwise false
	 */
	private boolean checkTileCollision(AABB hitbox, List<int[]> collidedTerrain, List<Side> hitDirections, int x,
	                                   int y, Side side) {
		if (!world.getTiles().test(x, y)) {
			return false;
		}
		TileInfo tile = world.getTiles().get(x, y).getTileType();
		AABB tileAABB = new AABB(x, y, 1, 1);
		if (world.renderHitboxes()) {
			checkedTiles.add(tileAABB);
		}
		if (tile.isObstacle() && hitbox.collides(tileAABB)) {
			warpGuard(hitbox, tileAABB, side);
			insertInCollidedTerrain(collidedTerrain, hitDirections, tileAABB);
			return true;
		}
		return false;
	}

	/**
	 * Sometimes just throwing a straight resolveCollision at things does not in fact resolve the collision
	 * Instead it sometimes warps you up or down even if that's not the idea
	 * What this does is instead check if that resolution makes sense before applying it.
	 * I.e. if resolving a left collision would move you further left, we push you up or down depending on velY
	 * And same goes for collisions on the right.
	 *
	 * @param hitbox      this entity's hitbox, that we want to move out of the other one
	 * @param otherHitbox the hitbox being compared against to fix collisions
	 * @param direction   the direction on which the collision occurs
	 */

	private void warpGuard(AABB hitbox, AABB otherHitbox, Side direction) {
		switch (direction) {
			case LEFT:
				if (otherHitbox.right() > hitbox.startLeft()) {
					if (velY > 0) {
						resolveCollision(hitbox, otherHitbox, Side.BOTTOM);
					} else if (velY < 0) {
						resolveCollision(hitbox, otherHitbox, Side.TOP);
					}
				} else {
					resolveCollision(hitbox, otherHitbox, Side.LEFT);
				}
				break;
			case RIGHT:
				if (otherHitbox.left() < hitbox.startRight()) {
					if (velY > 0) {
						resolveCollision(hitbox, otherHitbox, Side.BOTTOM);
					} else if (velY < 0) {
						resolveCollision(hitbox, otherHitbox, Side.TOP);
					}
				} else {
					resolveCollision(hitbox, otherHitbox, Side.RIGHT);
				}
				break;
			default:
				resolveCollision(hitbox, otherHitbox, direction);
				return;
		}
	}

	/**
	 * The most basic way of resolving a collision. When we detect overlapping hitboxes, we call this
	 *

	 * What this does is set an edge of this hitbox to be equal to the opposite edge of the other hitbox

	 * And so there is no more collision
	 *

	 * i.e. set our left edge to equal their right edge
	 *
	 * @param ownHitbox   the hitbox being moved i.e. the one being processed in this step
	 * @param otherHitbox the hitbox eing compared against
	 * @param direction   the side of ownHitbox on which the collision occurred
	 */

	private void resolveCollision(AABB ownHitbox, AABB otherHitbox, Side direction) {
		switch (direction) {
			case BOTTOM:
				ownHitbox.setBottomY(otherHitbox.ownerTop());
				onGround = true;
				break;
			case TOP:
				ownHitbox.setY(otherHitbox.ownerBottom());
				onCeiling = true;
				break;
			case LEFT:
				ownHitbox.setX(otherHitbox.ownerRight());
				onWall = -1;
				break;
			case RIGHT:
				ownHitbox.setRightX(otherHitbox.ownerLeft());
				onWall = 1;
				break;
			case VOID:
			default:
				break;
		}
	}

	/**
	 * Checks for collisions with terrainEntities and resolves them as we would for regular ol tiles

	 * Also informs the terrain entity about the collision, so that it can apply its affects on the next tick
	 *
	 * @param hitbox our hitbox that we're processing to check for collisions
	 * @param side   the side on which we're looking for collisions/resolve them
	 * @return the terrain entity with which we've collided, otherwise null
	 */

	private TerrainEntity checkTerrainEntities(AABB hitbox, Side side) {
		for (TerrainEntity platform : world.getTerrainEntities()) {
			if (platform.collidesWith(this, side) && hitbox.collides(platform) != BodyPart.VOID) {
				resolveCollision(hitbox, platform.bounds, side);
				platform.addToList(this);
				return platform;
			}
		}
		return null;
	}

	/**
	 * Checks if we've collided with any entities

	 * If we have, records the entity and the BodyPart with which we collided in the lists
	 *
	 * @param hitbox           our hitbox that we're processing to check for collisions
	 * @param collidedEntities a list of entities with which we've collided this tick
	 * @param hitLocations     a list of BodyParts recording where we hit these enitities
	 */

	protected void checkEntityCollisions(AABB ownHitbox, List<Entity> collidedEntities, List<BodyPart> hitLocations) {
		if (collidedEntities == null || hitLocations == null) {
			return;
		}
		for (Entity entity : world.getAllEntities()) {
			if (entity == this || entity == null || entity instanceof Decoration || entity instanceof Particle) {
				continue;
			}
			if (entity.doesItBlockOtherEntities() && collisionFilter.test(entity)) {
				BodyPart location = ownHitbox.collides(entity);
				if (location != BodyPart.VOID) {
					insertInCollidedEntities(collidedEntities, hitLocations, entity, location);
				}
			}
		}
	}

	/**
	 * A very basic check that resolves any collisions along the right edge
	 * Used only in crates atm to stop them being pushed into walls
	 */
	public void basicRightEdgeCheck() {
		int bottomY = (int) Math.ceil(bounds.bottom() - 1);
		int topY = (int) Math.floor(bounds.top());
		int rightX = (int) Math.ceil(bounds.right() - 1);
		for (int testY = bottomY; testY >= topY; testY--) {
			if (checkTileCollision(bounds, null, null, rightX, testY, Side.RIGHT)) {
				break;
			}
		}
		checkTerrainEntities(bounds, Side.RIGHT);
	}

	/**
	 * A very basic check that resolves any collisions along the left edge
	 * Used only in crates atm to stop them being pushed into walls
	 */

	public void basicLeftEdgeCheck() {
		int bottomY = (int) Math.ceil(bounds.bottom() - 1);
		int topY = (int) Math.floor(bounds.top());
		int leftX = (int) Math.floor(bounds.left());

		for (int testY = bottomY; testY >= topY; testY--) {
			if (checkTileCollision(bounds, null, null, leftX, testY, Side.LEFT)) {
				break;
			}
		}
		checkTerrainEntities(bounds, Side.LEFT);
	}

	/**
	 * Entity specific logic that runs every tick. See StateEntity for an example (stateUpdate).
	 *
	 * @param ms millisecond tick the entity is being handled on
	 */
	protected abstract void tick(long ms);

	/**
	 * Entity collision event handler;
	 *
	 * @param hitLocations
	 */
	protected abstract void onEntityCollide(List<Entity> entities, List<BodyPart> hitLocations);

	/**
	 * Terrain collision event handler;
	 *
	 * @param side
	 */
	protected abstract void onTerrainCollide(int tileX, int tileY, Side side);

	/**
	 * On death event handler;
	 *
	 * @param cause entity that caused the death
	 */
	protected abstract void onDeath(Entity cause);

	/**
	 * Performs a special collision detection on the first tick an entity is added to the game

	 * Otherwise calls updatePhysics
	 *
	 * @param ms The time since the last tick
	 */
	public void entityLoop(long ms) {
		this.latestTick = ms;
		// We do a special first tick, where we just place it into the world and
		// see if it collides with anything.
		// i.e. there is no movement on the first tick.
		if (firstTick) {
			if (this instanceof Projectile) {
				// if its a projectile, we check if it's colliding with terrain and let it kill itself if so
				firstTickCheckTerrainCollide();
			} else {
				// otherwise we push it upwards until its free (in theory)
				hardcoreCollisionResolution();
			}
			firstTick = false;
		} else {
			// don't apply physics to decorations or particles. They don't deserve it
			if (!(this instanceof Decoration || this instanceof Particle)) {
				updatePhysics(ms);
			}
		}
		if (onGround || onCeiling) {
			velY = 0;
		}
		tick(ms);

		if (this.isOnGround()) {
			applyTileEffects(ms);
		}
	}

	/**
	 * Applies effects from tiles that we're standing on
	 *
	 * @param ms time since last tick
	 */
	protected void applyTileEffects(long ms) {
		int centerX = (int) Math.floor(posX + getWidth() / 2);
		int bottomY = (int) Math.floor(posY + getHeight());
		if (world.getTiles().test(centerX, bottomY)) {
			Tile tile = world.getTiles().get(centerX, bottomY);
			tile.getTileType().onEntityOnTopOfBlock(this, tile, ms);
		}
	}

	/**
	 * Checks all tiles with which me might still be colliding
	 *

	 * This is used to detect and prevent serious errors in the physics engine

	 * e.g. warping right through walls in puzzle rooms
	 *
	 * @return true if we find a collision, otherwise false
	 */

	private boolean checkRemainingCollisions() {
		int flooredLeft = (int) Math.floor(this.bounds.ownerLeft());
		int ceilRight = (int) Math.ceil(this.bounds.ownerRight());
		int flooredTop = (int) Math.floor(this.bounds.ownerTop());
		int ceilBottom = (int) Math.ceil(this.bounds.ownerBottom());

		for (int x = flooredLeft; x < ceilRight; x++) {
			for (int y = flooredTop; y < ceilBottom; y++) {
				if (!world.getTiles().test(x, y)) {
					continue;
				}
				TileInfo tile = world.getTiles().get(x, y).getTileType();
				AABB tileAABB = new AABB(x, y, 1, 1);
				if (tile.isObstacle() && bounds.collides(tileAABB)) {
					return true;
				}
			}
		}
		return false;
	}

	/**
	 * Checks if the entity is intersecting with any obstacle tiles.
	 *
 If so, moves
	 * the entity upwards until they are free.

	 * Intended to resolve entities that get trapped in the ground on spawning
	 */
	private void hardcoreCollisionResolution() {
		boolean collidedTerrain = true;

		while (collidedTerrain) {
			int flooredLeft = (int) Math.floor(this.bounds.ownerLeft());
			int ceilRight = (int) Math.ceil(this.bounds.ownerRight());
			int flooredTop = (int) Math.floor(this.bounds.ownerTop());
			int ceilBottom = (int) Math.ceil(this.bounds.ownerBottom());

			collidedTerrain = false;
			for (int x = flooredLeft; x < ceilRight; x++) {
				for (int y = flooredTop; y < ceilBottom; y++) {
					if (checkTileCollision(bounds, null, null, x, y, Side.BOTTOM)) {
						collidedTerrain = true;
						break;
					}
				}
				if (collidedTerrain) {
					break;
				}
			}
		}

	}

	/**
	 * Inserts the input entity and BodyPart in the corresponding lists, to record the collision and deal with it at the
	 * end of the tick
	 *

	 * If the a collision has already been recorded with the input entity, the BodyPart is overwritten if it has higher
	 * priority

	 * Priority is determined by the order these elements occur in the BodyPart enum, with the lower down (higher index)
	 * elements having greater priority
	 *
	 * @param collidedEntities a list of which entities we've collided with this tick
	 * @param hitLocations     a list of locations with where on those entities we collided
	 * @param e                the entity with which we have collided, to add to the list
	 * @param bp               the location on e that the collision occurred, to add to the list
	 *                         >>>>>>> master
	 * @require both lists have the same size, so that for all entities in collidedEntities, the BodyPart with equal
	 * index denotes where the collision with that entity occurred
	 */
	private void insertInCollidedEntities(List<Entity> collidedEntities, List<BodyPart> hitLocations, Entity
			e, BodyPart bp) {
		if (collidedEntities == null || hitLocations == null) {
			return;
		}
		if (!collidedEntities.contains(e)) {
			collidedEntities.add(e);
			hitLocations.add(bp);
		} else {
			int index = collidedEntities.indexOf(e);
			BodyPart currentPart = hitLocations.get(index);
			if (bp.compareTo(currentPart) > 0) {
				hitLocations.set(index, bp);
			}
		}
	}

	/**
	 * Inserts the coordinates of the input bounds, and the side on which the collision occurred, into the lists.

	 * This allows these tile collisions to be dealt with at the end of the tick
	 *

	 * the side we insert is not necessarily the same as the one we use to resolve collisions

	 * we determine the side based on the relative positions of the two center points.
	 * this is the side of our hitbox on which the collision occured, not the face of the tile.
	 *
	 * @param collidedTerrain list of coordintates, in which we store the coords of tiles we've collided with
	 * @param hitDirections   list of Sides, in which we store the side we struck those tiles
	 * @param tileBounds
	 * @require both lists have the same size, so that for all coords in collidedTerrain, the hitDirections with equal
	 * index denotes where the collision with that tile occurred
	 */
	private void insertInCollidedTerrain(List<int[]> collidedTerrain, List<Side> hitDirections, AABB tileBounds) {
		if (collidedTerrain == null || hitDirections == null) {
			return;
		}
		int[] thisPoint = {(int) tileBounds.left(), (int) tileBounds.top()};
		for (int[] otherPoint : collidedTerrain) {
			if (Arrays.equals(thisPoint, otherPoint)) {
				return;
			}
		}
		collidedTerrain.add(thisPoint);
		hitDirections.add(getDirection(this, tileBounds));
	}

	/**
	 * Returns the direction of the input AABB from the input entity
	 *

	 * This is based on partitioning space into quadrants aligned on the diagonals.
	 *

	 * The comparison is based on the centre points of the entity's bounds and the AABB
	 *
	 * @param entity the entity being processed
	 * @param other  the hitbox we want the direction of
	 * @return the direction in which the hitbox lies
	 */

	private Side getDirection(Entity entity, AABB other) {
		float diffX = entity.bounds.posX() - other.posX();
		float diffY = entity.bounds.posY() - other.posY();

		if (diffY < diffX && diffY < -diffX) {
			return Side.BOTTOM;
		} else if (diffY > diffX && diffY > -diffX) {
			return Side.TOP;
		} else if (diffY < diffX && diffY > -diffX) {
			return Side.RIGHT;
		} else if (diffY > diffX && diffY < -diffX) {
			return Side.LEFT;
		}
		return Side.VOID;
	}

	/**
	 * Checks all overlapping tiles/terrainEntities/Entities for collisions
	 *

	 * Calls the relevant handle methods (onTerrainCollide and onEntityCollide)
	 *

	 * To be used for projectiles so that they are still functional if they spawn inside stuff.
	 */

	private void firstTickCheckTerrainCollide() {
		List<Entity> collidedEntities = new ArrayList<>();
		List<BodyPart> hitLocations = new ArrayList<>();

		List<int[]> collidedTerrain = new ArrayList<>();
		List<Side> hitDirections = new ArrayList<>();

		bounds.setPos(posX, posY);
		processStep(bounds, collidedTerrain, hitDirections, collidedEntities, hitLocations);

		if (hitboxes != null) {
			for (AABB hitbox : hitboxes) {
				hitbox.setPos(bounds, renderFacing);
				processStep(hitbox, collidedTerrain, hitDirections, collidedEntities, hitLocations);
				bounds.setPos(hitbox, renderFacing);
			}
		}

		if (!collidedTerrain.isEmpty()) {
			collideWithTerrain(collidedTerrain, hitDirections);
		}

		if (!collidedEntities.isEmpty()) {
			onEntityCollide(collidedEntities, hitLocations);
		}
	}

	/**
	 * iterates through the list of tile collisions and hit directions

	 * Applies onTerrainCollide to them
	 *

	 * tbh we shoulda set this up the same was as onEntityCollide where it takes the list but oh well. Everyone else had
	 * their methods set up nice and pretty and cbf changing them
	 *
	 * @param collidedTerrain
	 * @param hitDirections
	 */

	public void collideWithTerrain(List<int[]> collidedTerrain, List<Side> hitDirections) {
		if (!collidedTerrain.isEmpty()) {
			for (int i = 0; i < collidedTerrain.size(); i++) {
				int x = collidedTerrain.get(i)[0];
				int y = collidedTerrain.get(i)[1];
				Side side = hitDirections.get(i);
				onTerrainCollide(x, y, side);
			}
		}
	}

	/**
	 * Gracefully calls the onDeath function for the entity to do any post-death animations before removing itself.
	 *
	 * @param cause the entity responsible for this entity's death
	 */
	public void kill(Entity cause) {
		onDeath(cause);
	}

	/**
	 * Deletes this entity from the world Does not call the onDeath callback
	 */
	public void delete() {
		world.deleteEntity(this);
	}

	/**
	 * Renders the entity's sprite and any additional sprites
 Renders hitboxes as well if world.renderHitboxes is
	 * true
	 *
	 * @param gc       the graphics context on which the sprites are rendered
	 * @param viewport the viewport in which the sprites are rendered
	 * @param ms       the number of seconds since the last tick
	 */
	public void render(GraphicsContext gc, Viewport viewport, long ms) {
		if (!renderFlag) {
			return;
		}
		// do some maths
		this.viewport = viewport;
		float tileSize = viewport.getTileSideLength();
		int leftBorder = viewport.getLeftBorder();
		int topBorder = viewport.getTopBorder();

		int left = (int) Math.floor(viewport.getLeft());
		int top = (int) Math.floor(viewport.getTop());

		float subTileShiftX = (viewport.getLeft() - left) * tileSize;
		float subTileShiftY = (viewport.getTop() - top) * tileSize;

		float x = (posX - left) * tileSize + leftBorder - subTileShiftX;
		float y = (posY - top) * tileSize + topBorder - subTileShiftY;

		// Render the sprite
		if (sprite != null) {
			if (renderFacing > 0) {
				gc.drawImage(sprite.getFrame(), x, y, getWidth() * tileSize, getHeight() * tileSize);
			} else {
				gc.drawImage(sprite.getFrame(), x + getWidth() * tileSize, y, -getWidth() * tileSize,
						getHeight() * tileSize);
			}
		}

		// Render additional sprites
		if (additionalSprites != null && !additionalSprites.isEmpty()) {
			for (SpriteRelation sr : additionalSprites.values()) {
				if (sr != null) {
					sr.renderSprite(gc, tileSize, x, y);
				}
			}
		}

		// Render collision line hitboxes
		if (world.renderHitboxes()) {
			bounds.render(gc, viewport);
			for (AABB tile : checkedTiles) {
				tile.render(gc, viewport);
			}
			if (hitboxes != null) {
				for (AABB hitbox : hitboxes) {
					hitbox.render(gc, viewport);
				}
			}
		}
	}

	/**
	 * set the entity to belong to the input world
	 *
	 * @param world the new world
	 */
	public void setWorld(World world) {
		this.world = world;
	}

	/**
	 * @return whether the entity blocks Other Entities
	 */
	public boolean doesItBlockOtherEntities() {
		return blocksOtherEntities;
	}

	/**
	 * @param blocksOtherEntities set blocksOtherEntities to true to block other entities
	 */
	public void setBlocksOtherEntities(boolean blocksOtherEntities) {
		this.blocksOtherEntities = blocksOtherEntities;
	}
}


text:
package net.ripe.db.whois.update.handler;

import com.google.common.collect.Sets;
import net.ripe.db.whois.common.DateTimeProvider;
import net.ripe.db.whois.common.Message;
import net.ripe.db.whois.common.Messages;
import net.ripe.db.whois.common.domain.PendingUpdate;
import net.ripe.db.whois.common.rpsl.RpslObject;
import net.ripe.db.whois.update.authentication.Authenticator;
import net.ripe.db.whois.update.dao.PendingUpdateDao;
import net.ripe.db.whois.update.domain.*;
import net.ripe.db.whois.update.log.LoggerContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.CheckForNull;
import java.util.Set;

@Component
class PendingUpdateHandler {
    private static final Logger LOGGER = LoggerFactory.getLogger(PendingUpdateHandler.class);

    private final PendingUpdateDao pendingUpdateDao;
    private final Authenticator authenticator;
    private final UpdateObjectHandler updateObjectHandler;
    private final DateTimeProvider dateTimeProvider;
    private final LoggerContext loggerContext;

    @Autowired
    public PendingUpdateHandler(final PendingUpdateDao pendingUpdateDao, final Authenticator authenticator, UpdateObjectHandler updateObjectHandler, DateTimeProvider dateTimeProvider, LoggerContext loggerContext) {
        this.pendingUpdateDao = pendingUpdateDao;
        this.authenticator = authenticator;
        this.updateObjectHandler = updateObjectHandler;
        this.dateTimeProvider = dateTimeProvider;
        this.loggerContext = loggerContext;
    }

    public void handle(final PreparedUpdate preparedUpdate, final UpdateContext updateContext) {
        final RpslObject rpslObject = preparedUpdate.getUpdatedObject();
        final PendingUpdate pendingUpdate = find(rpslObject);
        final Set<String> passedAuthentications = updateContext.getSubject(preparedUpdate).getPassedAuthentications();

        if (pendingUpdate == null) {
            loggerContext.log(new Message(Messages.Type.INFO, "No pending updates found; storing in DB"));
            pendingUpdateDao.store(new PendingUpdate(passedAuthentications, rpslObject, dateTimeProvider.getCurrentDateTime()));
            updateContext.addMessage(preparedUpdate, UpdateMessages.updatePendingAuthentication());
            updateContext.addMessage(preparedUpdate, UpdateMessages.updatePendingAuthenticationSaved(preparedUpdate.getUpdatedObject()));
        } else {
            final Set<String> allPassedAuthentications = Sets.newHashSet();
            allPassedAuthentications.addAll(pendingUpdate.getPassedAuthentications());
            allPassedAuthentications.addAll(passedAuthentications);

            if (authenticator.isAuthenticationForTypeComplete(rpslObject.getType(), allPassedAuthentications)) {
                loggerContext.log(new Message(Messages.Type.INFO, "Pending update found and completes authentication; dropping from DB"));
                pendingUpdateDao.remove(pendingUpdate);

                updateContext.prepareForReattempt(preparedUpdate);
                updateContext.addMessage(preparedUpdate, UpdateMessages.updateConcludesPendingUpdate(preparedUpdate.getUpdatedObject()));

                final PreparedUpdate freshPreparedUpdate = new PreparedUpdate(preparedUpdate.getUpdate(), null, preparedUpdate.getUpdatedObject(), Action.CREATE);
                updateContext.setPreparedUpdate(freshPreparedUpdate);
                updateContext.setAction(freshPreparedUpdate, Action.CREATE);

                updateObjectHandler.execute(preparedUpdate, updateContext);
            } else {
                updateContext.status(preparedUpdate, UpdateStatus.FAILED);
                updateContext.addMessage(preparedUpdate, UpdateMessages.updateAlreadyPendingAuthentication());
            }
        }
    }

    @CheckForNull
    private PendingUpdate find(final RpslObject object) {
        for (final PendingUpdate update : pendingUpdateDao.findByTypeAndKey(object.getType(), object.getKey().toString())) {
            if (object.equals(update.getObject())) {
                return update;
            }
        }
        return null;
    }
}

redpajama_set_name: RedPajamaGithub


text:
import logging
from six.moves.urllib import request
import yaml

from heatclient.common import template_utils
from heatclient.common import utils
from heatclient.openstack.common import jsonutils

import heatclient.exc as exc

logger = logging.getLogger(__name__)

@utils.arg('-f', '--template-file', metavar='<FILE>',
           help='Path to the template.')
@utils.arg('-e', '--environment-file', metavar='<FILE or URL>',
           help='Path to the environment.')
@utils.arg('-u', '--template-url', metavar='<URL>',
           help='URL of template.')
@utils.arg('-o', '--template-object', metavar='<URL>',
           help='URL to retrieve template object (e.g. from swift).')
@utils.arg('-c', '--create-timeout', metavar='<TIMEOUT>',
           type=int,
           help='Stack creation timeout in minutes.'
                '  DEPRECATED use --timeout instead.')
@utils.arg('-t', '--timeout', metavar='<TIMEOUT>',
           type=int,
           help='Stack creation timeout in minutes.')
@utils.arg('-r', '--enable-rollback', default=False, action="store_true",
           help='Enable rollback on create/update failure.')
@utils.arg('-P', '--parameters', metavar='<KEY1=VALUE1;KEY2=VALUE2...>',
           help='Parameter values used to create the stack. '
           'This can be specified multiple times, or once with parameters '
           'separated by a semicolon.',
           action='append')
@utils.arg('name', metavar='<STACK_NAME>',
           help='Name of the stack to create.')
def do_create(hc, args):
    '''DEPRECATED! Use stack-create instead.'''
    logger.warning('DEPRECATED! Use stack-create instead.')
    do_stack_create(hc, args)

@utils.arg('-f', '--template-file', metavar='<FILE>',
           help='Path to the template.')
@utils.arg('-e', '--environment-file', metavar='<FILE or URL>',
           help='Path to the environment.')
@utils.arg('-u', '--template-url', metavar='<URL>',
           help='URL of template.')
@utils.arg('-o', '--template-object', metavar='<URL>',
           help='URL to retrieve template object (e.g. from swift).')
@utils.arg('-c', '--create-timeout', metavar='<TIMEOUT>',
           type=int,
           help='Stack creation timeout in minutes.'
                '  DEPRECATED use --timeout instead.')
@utils.arg('-t', '--timeout', metavar='<TIMEOUT>',
           type=int,
           help='Stack creation timeout in minutes.')
@utils.arg('-r', '--enable-rollback', default=False, action="store_true",
           help='Enable rollback on create/update failure.')
@utils.arg('-P', '--parameters', metavar='<KEY1=VALUE1;KEY2=VALUE2...>',
           help='Parameter values used to create the stack. '
           'This can be specified multiple times, or once with parameters '
           'separated by a semicolon.',
           action='append')
@utils.arg('name', metavar='<STACK_NAME>',
           help='Name of the stack to create.')
def do_stack_create(hc, args):
    '''Create the stack.'''
    tpl_files, template = template_utils.get_template_contents(
        args.template_file,
        args.template_url,
        args.template_object,
        hc.http_client.raw_request)
    env_files, env = template_utils.process_environment_and_files(
        env_path=args.environment_file)

    if args.create_timeout:
        logger.warning('-c/--create-timeout is deprecated, '
                       'please use -t/--timeout instead')

    fields = {
        'stack_name': args.name,
        'timeout_mins': args.timeout or args.create_timeout,
        'disable_rollback': not(args.enable_rollback),
        'parameters': utils.format_parameters(args.parameters),
        'template': template,
        'files': dict(list(tpl_files.items()) + list(env_files.items())),
        'environment': env
    }

    hc.stacks.create(**fields)
    do_stack_list(hc)

@utils.arg('-f', '--template-file', metavar='<FILE>',
           help='Path to the template.')
@utils.arg('-e', '--environment-file', metavar='<FILE or URL>',
           help='Path to the environment.')
@utils.arg('-u', '--template-url', metavar='<URL>',
           help='URL of template.')
@utils.arg('-o', '--template-object', metavar='<URL>',
           help='URL to retrieve template object (e.g from swift).')
@utils.arg('-c', '--create-timeout', metavar='<TIMEOUT>',
           type=int,
           help='Stack creation timeout in minutes.'
                '  DEPRECATED use --timeout instead.')
@utils.arg('-t', '--timeout', metavar='<TIMEOUT>',
           type=int,
           help='Stack creation timeout in minutes.')
@utils.arg('-a', '--adopt-file', metavar='<FILE or URL>',
           help='Path to adopt stack data file.')
@utils.arg('-r', '--enable-rollback', default=False, action="store_true",
           help='Enable rollback on create/update failure.')
@utils.arg('-P', '--parameters', metavar='<KEY1=VALUE1;KEY2=VALUE2...>',
           help='Parameter values used to create the stack. '
           'This can be specified multiple times, or once with parameters '
           'separated by a semicolon.',
           action='append')
@utils.arg('name', metavar='<STACK_NAME>',
           help='Name of the stack to adopt.')
def do_stack_adopt(hc, args):
    '''Adopt a stack.'''
    tpl_files, template = template_utils.get_template_contents(
        args.template_file,
        args.template_url,
        args.template_object,
        hc.http_client.raw_request)
    env_files, env = template_utils.process_environment_and_files(
        env_path=args.environment_file)

    if not args.adopt_file:
        raise exc.CommandError('Need to specify --adopt-file')

    adopt_url = template_utils.normalise_file_path_to_url(args.adopt_file)
    adopt_data = request.urlopen(adopt_url).read()

    if args.create_timeout:
        logger.warning('-c/--create-timeout is deprecated, '
                       'please use -t/--timeout instead')

    fields = {
        'stack_name': args.name,
        'timeout_mins': args.timeout or args.create_timeout,
        'disable_rollback': not(args.enable_rollback),
        'adopt_stack_data': adopt_data,
        'parameters': utils.format_parameters(args.parameters),
        'template': template,
        'files': dict(list(tpl_files.items()) + list(env_files.items())),
        'environment': env
    }

    hc.stacks.create(**fields)
    do_stack_list(hc)

@utils.arg('-f', '--template-file', metavar='<FILE>',
           help='Path to the template.')
@utils.arg('-e', '--environment-file', metavar='<FILE or URL>',
           help='Path to the environment.')
@utils.arg('-u', '--template-url', metavar='<URL>',
           help='URL of template.')
@utils.arg('-o', '--template-object', metavar='<URL>',
           help='URL to retrieve template object (e.g from swift)')
@utils.arg('-c', '--create-timeout', metavar='<TIMEOUT>',
           default=60, type=int,
           help='Stack timeout in minutes. Default: 60')
@utils.arg('-r', '--enable-rollback', default=False, action="store_true",
           help='Enable rollback on failure')
@utils.arg('-P', '--parameters', metavar='<KEY1=VALUE1;KEY2=VALUE2...>',
           help='Parameter values used to preview the stack. '
           'This can be specified multiple times, or once with parameters '
           'separated by semicolon.',
           action='append')
@utils.arg('name', metavar='<STACK_NAME>',
           help='Name of the stack to preview.')
def do_stack_preview(hc, args):
    '''Preview the stack.'''
    tpl_files, template = template_utils.get_template_contents(
        args.template_file,
        args.template_url,
        args.template_object,
        hc.http_client.raw_request)
    env_files, env = template_utils.process_environment_and_files(
        env_path=args.environment_file)

    fields = {
        'stack_name': args.name,
        'timeout_mins': args.create_timeout,
        'disable_rollback': not(args.enable_rollback),
        'parameters': utils.format_parameters(args.parameters),
        'template': template,
        'files': dict(list(tpl_files.items()) + list(env_files.items())),
        'environment': env
    }

    stack = hc.stacks.preview(**fields)
    formatters = {
        'description': utils.text_wrap_formatter,
        'template_description': utils.text_wrap_formatter,
        'stack_status_reason': utils.text_wrap_formatter,
        'parameters': utils.json_formatter,
        'outputs': utils.json_formatter,
        'resources': utils.json_formatter,
        'links': utils.link_formatter,
    }
    utils.print_dict(stack.to_dict(), formatters=formatters)

@utils.arg('id', metavar='<NAME or ID>', nargs='+',
           help='Name or ID of stack(s) to delete.')
def do_delete(hc, args):
    '''DEPRECATED! Use stack-delete instead.'''
    logger.warning('DEPRECATED! Use stack-delete instead.')
    do_stack_delete(hc, args)

@utils.arg('id', metavar='<NAME or ID>', nargs='+',
           help='Name or ID of stack(s) to delete.')
def do_stack_delete(hc, args):
    '''Delete the stack(s).'''
    failure_count = 0

    for sid in args.id:
        fields = {'stack_id': sid}
        try:
            hc.stacks.delete(**fields)
        except exc.HTTPNotFound as e:
            failure_count += 1
            print(e)
    if failure_count == len(args.id):
        raise exc.CommandError("Unable to delete any of the specified "
                               "stacks.")
    do_stack_list(hc)

@utils.arg('id', metavar='<NAME or ID>',
           help='Name or ID of stack to abandon.')
def do_stack_abandon(hc, args):
    '''Abandon the stack.'''
    fields = {'stack_id': args.id}
    try:
        stack = hc.stacks.abandon(**fields)
    except exc.HTTPNotFound:
        raise exc.CommandError('Stack not found: %s' % args.id)
    else:
        print(jsonutils.dumps(stack, indent=2))

@utils.arg('id', metavar='<NAME or ID>',
           help='Name or ID of stack to suspend.')
def do_action_suspend(hc, args):
    '''Suspend the stack.'''
    fields = {'stack_id': args.id}
    try:
        hc.actions.suspend(**fields)
    except exc.HTTPNotFound:
        raise exc.CommandError('Stack not found: %s' % args.id)
    else:
        do_stack_list(hc)

@utils.arg('id', metavar='<NAME or ID>', help='Name or ID of stack to resume.')
def do_action_resume(hc, args):
    '''Resume the stack.'''
    fields = {'stack_id': args.id}
    try:
        hc.actions.resume(**fields)
    except exc.HTTPNotFound:
        raise exc.CommandError('Stack not found: %s' % args.id)
    else:
        do_stack_list(hc)

@utils.arg('id', metavar='<NAME or ID>',
           help='Name or ID of stack to describe.')
def do_describe(hc, args):
    '''DEPRECATED! Use stack-show instead.'''
    logger.warning('DEPRECATED! Use stack-show instead.')
    do_stack_show(hc, args)

@utils.arg('id', metavar='<NAME or ID>',
           help='Name or ID of stack to describe.')
def do_stack_show(hc, args):
    '''Describe the stack.'''
    fields = {'stack_id': args.id}
    try:
        stack = hc.stacks.get(**fields)
    except exc.HTTPNotFound:
        raise exc.CommandError('Stack not found: %s' % args.id)
    else:
        formatters = {
            'description': utils.text_wrap_formatter,
            'template_description': utils.text_wrap_formatter,
            'stack_status_reason': utils.text_wrap_formatter,
            'parameters': utils.json_formatter,
            'outputs': utils.json_formatter,
            'links': utils.link_formatter
        }
        utils.print_dict(stack.to_dict(), formatters=formatters)

@utils.arg('-f', '--template-file', metavar='<FILE>',
           help='Path to the template.')
@utils.arg('-e', '--environment-file', metavar='<FILE or URL>',
           help='Path to the environment.')
@utils.arg('-u', '--template-url', metavar='<URL>',
           help='URL of template.')
@utils.arg('-o', '--template-object', metavar='<URL>',
           help='URL to retrieve template object (e.g. from swift).')
@utils.arg('-P', '--parameters', metavar='<KEY1=VALUE1;KEY2=VALUE2...>',
           help='Parameter values used to create the stack. '
           'This can be specified multiple times, or once with parameters '
           'separated by a semicolon.',
           action='append')
@utils.arg('id', metavar='<NAME or ID>',
           help='Name or ID of stack to update.')
def do_update(hc, args):
    '''DEPRECATED! Use stack-update instead.'''
    logger.warning('DEPRECATED! Use stack-update instead.')
    do_stack_update(hc, args)

@utils.arg('-f', '--template-file', metavar='<FILE>',
           help='Path to the template.')
@utils.arg('-e', '--environment-file', metavar='<FILE or URL>',
           help='Path to the environment.')
@utils.arg('-u', '--template-url', metavar='<URL>',
           help='URL of template.')
@utils.arg('-o', '--template-object', metavar='<URL>',
           help='URL to retrieve template object (e.g. from swift).')
@utils.arg('-t', '--timeout', metavar='<TIMEOUT>',
           type=int,
           help='Stack update timeout in minutes.')
@utils.arg('-P', '--parameters', metavar='<KEY1=VALUE1;KEY2=VALUE2...>',
           help='Parameter values used to create the stack. '
           'This can be specified multiple times, or once with parameters '
           'separated by a semicolon.',
           action='append')
@utils.arg('id', metavar='<NAME or ID>',
           help='Name or ID of stack to update.')
def do_stack_update(hc, args):
    '''Update the stack.'''

    tpl_files, template = template_utils.get_template_contents(
        args.template_file,
        args.template_url,
        args.template_object,
        hc.http_client.raw_request)

    env_files, env = template_utils.process_environment_and_files(
        env_path=args.environment_file)

    fields = {
        'stack_id': args.id,
        'parameters': utils.format_parameters(args.parameters),
        'template': template,
        'files': dict(list(tpl_files.items()) + list(env_files.items())),
        'environment': env
    }

    if args.timeout:
        fields['timeout_mins'] = args.timeout

    hc.stacks.update(**fields)
    do_stack_list(hc)

def do_list(hc, args=None):
    '''DEPRECATED! Use stack-list instead.'''
    logger.warning('DEPRECATED! Use stack-list instead.')
    do_stack_list(hc)

@utils.arg('-f', '--filters', metavar='<KEY1=VALUE1;KEY2=VALUE2...>',
           help='Filter parameters to apply on returned stacks. '
           'This can be specified multiple times, or once with parameters '
           'separated by a semicolon.',
           action='append')
@utils.arg('-l', '--limit', metavar='<LIMIT>',
           help='Limit the number of stacks returned.')
@utils.arg('-m', '--marker', metavar='<ID>',
           help='Only return stacks that appear after the given stack ID.')
def do_stack_list(hc, args=None):
    '''List the user's stacks.'''
    kwargs = {}
    if args:
        kwargs = {'limit': args.limit,
                  'marker': args.marker,
                  'filters': utils.format_parameters(args.filters)}

    stacks = hc.stacks.list(**kwargs)
    fields = ['id', 'stack_name', 'stack_status', 'creation_time']
    utils.print_list(stacks, fields, sortby_index=3)

@utils.arg('id', metavar='<NAME or ID>',
           help='Name or ID of stack to query.')
def do_output_list(hc, args):
    '''Show available outputs.'''
    try:
        stack = hc.stacks.get(stack_id=args.id)
    except exc.HTTPNotFound:
        raise exc.CommandError('Stack not found: %s' % args.id)
    else:
        outputs = stack.to_dict()['outputs']
        fields = ['output_key', 'description']
        formatters = {
            'output_key': lambda x: x['output_key'],
            'description': lambda x: x['description'],
        }

        utils.print_list(outputs, fields, formatters=formatters)

@utils.arg('id', metavar='<NAME or ID>',
           help='Name or ID of stack to query.')
@utils.arg('output', metavar='<OUTPUT NAME>',
           help='Name of an output to display.')
def do_output_show(hc, args):
    '''Show a specific stack output.'''
    try:
        stack = hc.stacks.get(stack_id=args.id)
    except exc.HTTPNotFound:
        raise exc.CommandError('Stack not found: %s' % args.id)
    else:
        for output in stack.to_dict().get('outputs', []):
            if output['output_key'] == args.output:
                value = output['output_value']
                break
        else:
            return

        print (jsonutils.dumps(value, indent=2))

def do_resource_type_list(hc, args={}):
    '''List the available resource types.'''
    kwargs = {}
    types = hc.resource_types.list(**kwargs)
    utils.print_list(types, ['resource_type'], sortby_index=0)

@utils.arg('resource_type', metavar='<RESOURCE_TYPE>',
           help='Resource type to get the details for.')
def do_resource_type_show(hc, args={}):
    '''Show the resource type.'''
    try:
        resource_type = hc.resource_types.get(args.resource_type)
    except exc.HTTPNotFound:
        raise exc.CommandError(
            'Resource Type not found: %s' % args.resource_type)
    else:
        print(jsonutils.dumps(resource_type, indent=2))

@utils.arg('id', metavar='<NAME or ID>',
           help='Name or ID of stack to get the template for.')
def do_gettemplate(hc, args):
    '''DEPRECATED! Use template-show instead.'''
    logger.warning('DEPRECATED! Use template-show instead.')
    do_template_show(hc, args)

@utils.arg('id', metavar='<NAME or ID>',
           help='Name or ID of stack to get the template for.')
def do_template_show(hc, args):
    '''Get the template for the specified stack.'''
    fields = {'stack_id': args.id}
    try:
        template = hc.stacks.template(**fields)
    except exc.HTTPNotFound:
        raise exc.CommandError('Stack not found: %s' % args.id)
    else:
        if 'heat_template_version' in template:
            print(yaml.safe_dump(template, indent=2))
        else:
            print(jsonutils.dumps(template, indent=2))

@utils.arg('-u', '--template-url', metavar='<URL>',
           help='URL of template.')
@utils.arg('-f', '--template-file', metavar='<FILE>',
           help='Path to the template.')
@utils.arg('-e', '--environment-file', metavar='<FILE or URL>',
           help='Path to the environment.')
@utils.arg('-o', '--template-object', metavar='<URL>',
           help='URL to retrieve template object (e.g. from swift).')
@utils.arg('-P', '--parameters', metavar='<KEY1=VALUE1;KEY2=VALUE2...>',
           help='Parameter values to validate. '
           'This can be specified multiple times, or once with parameters '
           'separated by a semicolon.',
           action='append')
def do_validate(hc, args):
    '''DEPRECATED! Use template-validate instead.'''
    logger.warning('DEPRECATED! Use template-validate instead.')
    do_template_validate(hc, args)

@utils.arg('-u', '--template-url', metavar='<URL>',
           help='URL of template.')
@utils.arg('-f', '--template-file', metavar='<FILE>',
           help='Path to the template.')
@utils.arg('-e', '--environment-file', metavar='<FILE or URL>',
           help='Path to the environment.')
@utils.arg('-o', '--template-object', metavar='<URL>',
           help='URL to retrieve template object (e.g. from swift).')
@utils.arg('-P', '--parameters', metavar='<KEY1=VALUE1;KEY2=VALUE2...>',
           help='Parameter values to validate. '
           'This can be specified multiple times, or once with parameters '
           'separated by a semicolon.',
           action='append')
def do_template_validate(hc, args):
    '''Validate a template with parameters.'''

    tpl_files, template = template_utils.get_template_contents(
        args.template_file,
        args.template_url,
        args.template_object,
        hc.http_client.raw_request)

    env_files, env = template_utils.process_environment_and_files(
        env_path=args.environment_file)
    fields = {
        'parameters': utils.format_parameters(args.parameters),
        'template': template,
        'files': dict(list(tpl_files.items()) + list(env_files.items())),
        'environment': env
    }

    validation = hc.stacks.validate(**fields)
    print(jsonutils.dumps(validation, indent=2))

@utils.arg('id', metavar='<NAME or ID>',
           help='Name or ID of stack to show the resources for.')
def do_resource_list(hc, args):
    '''Show list of resources belonging to a stack.'''
    fields = {'stack_id': args.id}
    try:
        resources = hc.resources.list(**fields)
    except exc.HTTPNotFound:
        raise exc.CommandError('Stack not found: %s' % args.id)
    else:
        fields = ['resource_type', 'resource_status', 'updated_time']
        if len(resources) >= 1:
            if hasattr(resources[0], 'resource_name'):
                fields.insert(0, 'resource_name')
            else:
                fields.insert(0, 'logical_resource_id')

        utils.print_list(resources, fields, sortby_index=3)

@utils.arg('id', metavar='<NAME or ID>',
           help='Name or ID of stack to show the resource for.')
@utils.arg('resource', metavar='<RESOURCE>',
           help='Name of the resource to show the details for.')
def do_resource(hc, args):
    '''DEPRECATED! Use resource-show instead.'''
    logger.warning('DEPRECATED! Use resource-show instead.')
    do_resource_show(hc, args)

@utils.arg('id', metavar='<NAME or ID>',
           help='Name or ID of stack to show the resource for.')
@utils.arg('resource', metavar='<RESOURCE>',
           help='Name of the resource to show the details for.')
def do_resource_show(hc, args):
    '''Describe the resource.'''
    fields = {'stack_id': args.id,
              'resource_name': args.resource}
    try:
        resource = hc.resources.get(**fields)
    except exc.HTTPNotFound:
        raise exc.CommandError('Stack or resource not found: %s %s' %
                               (args.id, args.resource))
    else:
        formatters = {
            'links': utils.link_formatter,
            'required_by': utils.newline_list_formatter
        }
        utils.print_dict(resource.to_dict(), formatters=formatters)

@utils.arg('resource', metavar='<RESOURCE>',
           help='Name of the resource to generate a template for.')
@utils.arg('-F', '--format', metavar='<FORMAT>',
           help="The template output format, one of: %s."
                % ', '.join(utils.supported_formats.keys()))
def do_resource_template(hc, args):
    '''Generate a template based on a resource.'''
    fields = {'resource_name': args.resource}
    try:
        template = hc.resources.generate_template(**fields)
    except exc.HTTPNotFound:
        raise exc.CommandError('Resource %s not found.' % args.resource)
    else:
        if args.format:
            print(utils.format_output(template, format=args.format))
        else:
            print(utils.format_output(template))

@utils.arg('id', metavar='<NAME or ID>',
           help='Name or ID of stack to show the resource metadata for.')
@utils.arg('resource', metavar='<RESOURCE>',
           help='Name of the resource to show the metadata for.')
def do_resource_metadata(hc, args):
    '''List resource metadata.'''
    fields = {'stack_id': args.id,
              'resource_name': args.resource}
    try:
        metadata = hc.resources.metadata(**fields)
    except exc.HTTPNotFound:
        raise exc.CommandError('Stack or resource not found: %s %s' %
                               (args.id, args.resource))
    else:
        print(jsonutils.dumps(metadata, indent=2))

@utils.arg('id', metavar='<NAME or ID>',
           help='Name or ID of stack the resource belongs to.')
@utils.arg('resource', metavar='<RESOURCE>',
           help='Name of the resource to signal.')
@utils.arg('-D', '--data', metavar='<DATA>',
           help='JSON Data to send to the signal handler.')
@utils.arg('-f', '--data-file', metavar='<FILE>',
           help='File containing JSON data to send to the signal handler.')
def do_resource_signal(hc, args):
    '''Send a signal to a resource.'''
    fields = {'stack_id': args.id,
              'resource_name': args.resource}
    data = args.data
    data_file = args.data_file
    if data and data_file:
        raise exc.CommandError('Can only specify one of data and data-file')
    if data_file:
        data_url = template_utils.normalise_file_path_to_url(data_file)
        data = request.urlopen(data_url).read()
    if data:
        try:
            data = jsonutils.loads(data)
        except ValueError as ex:
            raise exc.CommandError('Data should be in JSON format: %s' % ex)
        if not isinstance(data, dict):
            raise exc.CommandError('Data should be a JSON dict')
        fields['data'] = data
    try:
        hc.resources.signal(**fields)
    except exc.HTTPNotFound:
        raise exc.CommandError('Stack or resource not found: %s %s' %
                               (args.id, args.resource))

@utils.arg('id', metavar='<NAME or ID>',
           help='Name or ID of stack to show the events for.')
@utils.arg('-r', '--resource', metavar='<RESOURCE>',
           help='Name of the resource to filter events by.')
def do_event_list(hc, args):
    '''List events for a stack.'''
    fields = {'stack_id': args.id,
              'resource_name': args.resource}
    try:
        events = hc.events.list(**fields)
    except exc.HTTPNotFound as ex:
        # it could be the stack or resource that is not found
        # just use the message that the server sent us.
        raise exc.CommandError(str(ex))
    else:
        fields = ['id', 'resource_status_reason',
                  'resource_status', 'event_time']
        if len(events) >= 1:
            if hasattr(events[0], 'resource_name'):
                fields.insert(0, 'resource_name')
            else:
                fields.insert(0, 'logical_resource_id')
        utils.print_list(events, fields)

@utils.arg('id', metavar='<NAME or ID>',
           help='Name or ID of stack to show the events for.')
@utils.arg('resource', metavar='<RESOURCE>',
           help='Name of the resource the event belongs to.')
@utils.arg('event', metavar='<EVENT>',
           help='ID of event to display details for.')
def do_event(hc, args):
    '''DEPRECATED! Use event-show instead.'''
    logger.warning('DEPRECATED! Use event-show instead.')
    do_event_show(hc, args)

@utils.arg('id', metavar='<NAME or ID>',
           help='Name or ID of stack to show the events for.')
@utils.arg('resource', metavar='<RESOURCE>',
           help='Name of the resource the event belongs to.')
@utils.arg('event', metavar='<EVENT>',
           help='ID of event to display details for.')
def do_event_show(hc, args):
    '''Describe the event.'''
    fields = {'stack_id': args.id,
              'resource_name': args.resource,
              'event_id': args.event}
    try:
        event = hc.events.get(**fields)
    except exc.HTTPNotFound as ex:
        # it could be the stack/resource/or event that is not found
        # just use the message that the server sent us.
        raise exc.CommandError(str(ex))
    else:
        formatters = {
            'links': utils.link_formatter,
            'resource_properties': utils.json_formatter
        }
        utils.print_dict(event.to_dict(), formatters=formatters)

def do_build_info(hc, args):
    '''Retrieve build information.'''
    result = hc.build_info.build_info()
    formatters = {
        'api': utils.json_formatter,
        'engine': utils.json_formatter,
    }
    utils.print_dict(result, formatters=formatters)


text:
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html
    PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/xhtml1-strict.dtd">

  <title>QDial Class Reference</title>
  <link href="classic.css" rel="stylesheet" type="text/css" />

QDial Class Reference

[com.trolltech.qt.widgets package]

Inherits QAbstractSlider.

Constructor

void QDial(QWidget parent)

Constructor Properties

prototype: The QDial prototype object

Prototype Object Properties

The QDial prototype object inherits properties from the QAbstractSlider prototype object and also has the following properties.

QSize minimumSizeHint()

void setNotchTarget(double target)

QSize sizeHint()

Instance Properties

QDial objects inherit properties from the QDial prototype object and also have the following properties.

wrapping

notchSize

notchTarget

notchesVisible


text:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>io.flowing.retail</groupId>
	<artifactId>flowing-retail-kafka-choreography</artifactId>
	<packaging>pom</packaging>
	<version>0.0.1-SNAPSHOT</version>

	<modules>
		<module>payment</module>
		<module>inventory</module>
		<module>shipping</module>
		<!--
		<module>zeebe-monitor</module>
		-->
	</modules>

	<build>
		<defaultGoal>clean install</defaultGoal>
	</build>

</project>


text:
package jMapGen.com.nodename.Delaunay;

import java.util.Vector;

	public class Triangle
	{
		private Vector<Site> _sites;
		public Vector<Site> getSites()
		{
			return _sites;
		}

		public Triangle(Site a, Site b, Site c)
		{
			_sites = new Vector<Site>();
			_sites.add(a); _sites.add(b); _sites.add(c);
		}
	}


text:
#region Licence

#endregion

using System;
using System.Runtime.Serialization;
using WmcSoft.Units;

namespace WmcSoft.Business.Accounting
{
    /// <summary>
    /// The exception that is thrown when an operation involving two <see cref="Money"/> uses different currencies.
    /// </summary>
    [Serializable]
    public class IncompatibleCurrencyException : IncompatibleMetricException
    {
        public IncompatibleCurrencyException()
            : base(DefaultMessage) {
        }

        public IncompatibleCurrencyException(string message)
            : base(message) {
        }

        protected IncompatibleCurrencyException(SerializationInfo info, StreamingContext context)
            : base(info, context) {
        }

        public IncompatibleCurrencyException(string message, Exception innerException)
            : base(message, innerException) {
        }

        #region DefaultMessage

        public new static string DefaultMessage {
            get {
                if (defaultMessage == null) {
                    defaultMessage = RM.GetString(RM.IncompatibleCurrencyException);
                }
                return defaultMessage;
            }
        }
        static string defaultMessage;

        #endregion
    }
}


text:
ACCEPTED

#### According to
The Catalogue of Life, 3rd January 2011

#### Published in
Docums Mycol. 20(no. 79): 57 (1990)

#### Original name
Armillaria rickenii Bohus, 1970

### Remarks
null


text:
package com.xrtb.common;
import redis.clients.jedis.Jedis;

public class MyJedisPool extends ObjectPool<Jedis> {

	public static String host = "localhost";
	public static int port = 6379;
	public MyJedisPool(int minIdle) {
		super(minIdle);
	}

	public MyJedisPool(final int minIdle, final int maxIdle, final long validationInterval) {
		super(minIdle, maxIdle, validationInterval);
	}

	@Override
	protected Jedis createObject() {
		Jedis jedis = new Jedis(host,port);
		jedis.connect();

		return jedis;
	}

}


text:
package org.jboss.resteasy.test.providers.jaxb.resource;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;

@Path("/zoo")
public class InheritanceResource {

    @GET
    @Produces("application/xml")
    public InheritanceZoo getZoo() {
        InheritanceZoo aZoo = new InheritanceZoo();
        aZoo.add(new InheritanceDog("Foo"));
        aZoo.add(new InheritanceCat("Bar"));
        return aZoo;
    }
}


text:
@interface LeUserInfoCell ()
@property (weak, nonatomic) IBOutlet UIImageView *image;
@property (weak, nonatomic) IBOutlet UILabel *useName;

@end

@implementation LeUserInfoCell

- (void)awakeFromNib {
    [super awakeFromNib];
    self.image.layer.cornerRadius = self.image.frame.size.width * 0.5;
    self.image.layer.masksToBounds = YES;
}

- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
    [super setSelected:selected animated:animated];
}

-(void)setUserInfo:(LeUserInfo *)userInfo {
    _userInfo = userInfo;
    [self.image sd_setImageWithURL:[NSURL URLWithString:userInfo.userIcon]];
    self.useName.text = userInfo.userName;
}

@end


text:
namespace net {
class URLRequestContextGetter;
}  // namespace net

namespace remoting {

// This is the default prefix that is prepended to the kTalkGadgetUrl to form
// the complete talkgadget URL used by the host. Policy settings allow admins
// to change the prefix that is used.
extern const char kDefaultHostTalkGadgetPrefix[];

class DnsBlackholeChecker : public net::URLFetcherDelegate {
 public:
  DnsBlackholeChecker(
      scoped_refptr<net::URLRequestContextGetter> url_request_context_getter,
      std::string talkgadget_prefix);
  virtual ~DnsBlackholeChecker();

  // net::URLFetcherDelegate interface.
  virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE;

  // Initiates a check the verify that the host talkgadget has not been "DNS
  // blackholed" to prevent connections. If this is called again before the
  // callback has been called, then the second call is ignored.
  void CheckForDnsBlackhole(const base::Callback<void(bool)>& callback);

 private:
  // URL request context getter to use to create the URL fetcher.
  scoped_refptr<net::URLRequestContextGetter> url_request_context_getter_;

  // URL fetcher used to verify access to the host talkgadget.
  scoped_ptr<net::URLFetcher> url_fetcher_;

  // The string pre-pended to '.talkgadget.google.com' to create the full
  // talkgadget domain name for the host.
  std::string talkgadget_prefix_;

  // Called with the results of the connection check.
  base::Callback<void(bool)> callback_;

  DISALLOW_COPY_AND_ASSIGN(DnsBlackholeChecker);
};

}  // namespace remoting

#endif  // REMOTING_HOST_DNS_BLACKHOLE_CHECKER_H_


text:
@import ObjectiveC;

static NSMapTable<NSString*, id>* __tarckedObjectsMapping;

@interface GREYAppStateTracker (PrettyPrint) @end

@implementation GREYAppStateTracker (PrettyPrint)

- (NSString *)_pp__trackState:(GREYAppState)state forElement:(id)element;
{
	NSString* rv = [self _pp__trackState:state forElement:element];

	[__tarckedObjectsMapping setObject:element forKey:rv];

	return rv;
}

- (void)_pp__untrackState:(GREYAppState)state forElementWithID:(NSString *)elementID;
{
	[self _pp__untrackState:state forElementWithID:elementID];

	[__tarckedObjectsMapping removeObjectForKey:elementID];
}

+ (void)load
{
	static dispatch_once_t onceToken;
	dispatch_once(&onceToken, ^{
		__tarckedObjectsMapping = [NSMapTable mapTableWithKeyOptions:NSMapTableStrongMemory valueOptions:NSMapTableWeakMemory];

		Method m1 = class_getInstanceMethod(self, @selector(trackState:forElement:));
		Method m2 = class_getInstanceMethod(self, @selector(_pp__trackState:forElement:));

		method_exchangeImplementations(m1, m2);

		m1 = class_getInstanceMethod(self, @selector(untrackState:forElementWithID:));
		m2 = class_getInstanceMethod(self, @selector(_pp__untrackState:forElementWithID:));

		method_exchangeImplementations(m1, m2);
	});
}

@end

NSString* _prettyPrintAppState(GREYAppState state)
{
	NSMutableArray *eventStateString = [[NSMutableArray alloc] init];
	if (state == kGREYIdle) {
		return @"Idle";
	}

	if (state & kGREYPendingViewsToAppear)
	{
		[eventStateString addObject:@"Waiting for view controller's view to appear."];
	}
	if (state & kGREYPendingViewsToDisappear)
	{
		[eventStateString addObject:@"Waiting for view controller's view to disappear."];
	}
	if (state & kGREYPendingCAAnimation)
	{
		[eventStateString addObject:@"Waiting for an animation to finish. Continuous animations may never finish and must be stopped explicitly. Animations attached to hidden view may still be running in the background."];
	}
	if (state & kGREYPendingNetworkRequest)
	{
		[eventStateString addObject:@"Waiting for network requests to finish."];
	}
	if (state & kGREYPendingRootViewControllerToAppear)
	{
		[eventStateString addObject:@"Waiting for window's root view controller's view to appear."];
	}
	if (state & kGREYPendingGestureRecognition)
	{
		[eventStateString addObject:@"Waiting for gesture recognizer to detect or fail an ongoing gesture."];
	}
	if (state & kGREYPendingUIScrollViewScrolling)
	{
		[eventStateString addObject:@"Waiting for scroll view to finish scrolling and come to standstill."];
	}
	if (state & kGREYPendingUIWebViewAsyncRequest)
	{
		[eventStateString addObject:@"Waiting for web view to finish loading asynchronous request."];
	}
	if (state & kGREYPendingUIAnimation)
	{
		[eventStateString addObject:@"Waiting for animation to complete."];
	}
	if (state & kGREYIgnoringSystemWideUserInteraction)
	{
		[eventStateString addObject:@"System wide interaction events are being ignored."];
	}
	if (state & kGREYPendingKeyboardTransition)
	{
		[eventStateString addObject:@"Waiting for keyboard transition to finish."];
	}
	if (state & kGREYPendingDrawLayoutPass)
	{
		[eventStateString addObject:@"Waiting for view's draw or layout pass to complete."];
	}

	return [eventStateString componentsJoinedByString:@"\n"];
}

NSDictionary* _prettyPrintAppStateTracker(GREYAppStateTracker* tracker)
{
	NSMutableDictionary* rv = [NSMutableDictionary new];

	NSString* stateString = _prettyPrintAppState(tracker.currentState);
	rv[@"appState"] = stateString;

	NSHashTable* elements = [tracker valueForKey:@"elementIDs"];
	NSArray* allElements = [elements allObjects];

	NSMutableArray* elems = [NSMutableArray new];
	NSMutableArray* URLs = [NSMutableArray new];

	[allElements enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
		id actualElement = [__tarckedObjectsMapping objectForKey:obj];

		if(actualElement == nil)
		{
			return;
		}

		[elems addObject:[actualElement description]];

		if([actualElement isKindOfClass:[NSURLSessionTask class]])
		{
			[URLs addObject:[(NSURLSessionTask*)actualElement originalRequest].URL.absoluteString];
		}
	}];

	if(elems.count > 0)
	{
		rv[@"elements"] = elems;
	}

	if(URLs.count > 0)
	{
		rv[@"urls"] = URLs;
		rv[@"prettyPrint"]  = [NSString stringWithFormat:@"%@: %@", stateString, URLs];
	}

	return rv;
}

NSDictionary* _prettyPrintDispatchQueueIdlingResource(GREYDispatchQueueIdlingResource* queue)
{
	NSMutableDictionary* rv = [NSMutableDictionary new];
	rv[@"queue"] = [queue valueForKeyPath:@"dispatchQueueTracker.dispatchQueue.debugDescription"];
	rv[@"prettyPrint"] = [[NSString alloc] initWithUTF8String:dispatch_queue_get_label([queue valueForKeyPath:@"dispatchQueueTracker.dispatchQueue"])];

	return rv;
}

NSDictionary* _prettyPrintManagedObjectContextIdlingResource(GREYManagedObjectContextIdlingResource* ctx)
{
	NSMutableDictionary* rv = [NSMutableDictionary new];
	rv[@"managedObjectContext"] = [[ctx valueForKeyPath:@"managedObjectContext"] debugDescription];
	rv[@"prettyPrint"] = [[ctx valueForKeyPath:@"managedObjectContext"] debugDescription];

	return rv;
}

NSDictionary* _prettyPrintTimerIdlingResource(GREYNSTimerIdlingResource* timer)
{
	NSMutableDictionary* rv = [NSMutableDictionary new];
	rv[@"timer"] = [[timer valueForKeyPath:@"trackedTimer"] debugDescription];
	rv[@"name"] = [timer valueForKeyPath:@"name"];
	rv[@"nextFireDate"] = [[timer valueForKeyPath:@"trackedTimer.fireDate"] descriptionWithLocale:[NSLocale currentLocale]];
	rv[@"prettyPrint"] = rv[@"name"];

	return rv;
}

NSDictionary* _prettyPrintOperationQueueIdlingResource(GREYOperationQueueIdlingResource* opQ)
{
	NSMutableDictionary* rv = [NSMutableDictionary new];
	rv[@"operationQueue"] = [[opQ valueForKeyPath:@"operationQueue"] debugDescription];
	rv[@"name"] = [opQ valueForKeyPath:@"operationQueueName"];
	rv[@"prettyPrint"] = rv[@"name"];

	return rv;
}

NSDictionary* _prettyPrintTimedIdlingResource(GREYTimedIdlingResource* timed)
{
	NSMutableDictionary* rv = [NSMutableDictionary new];
	rv[@"object"] = [[timed valueForKeyPath:@"trackedObject"] debugDescription];
	rv[@"name"] = [timed valueForKeyPath:@"name"];
	rv[@"duration"] = [timed valueForKeyPath:@"duration"];
	rv[@"endTrackingDate"] = [[NSDate dateWithTimeIntervalSince1970:[[timed valueForKeyPath:@"endTrackingTime"] doubleValue]] descriptionWithLocale:[NSLocale currentLocale]];
	rv[@"prettyPrint"] = rv[@"name"];

	return rv;
}

NSDictionary* _prettyPrintWebViewIdlingResource(id webview)
{
	NSMutableDictionary* rv = [NSMutableDictionary new];
	rv[@"webView"] = [[webview valueForKeyPath:@"webView"] debugDescription];
	rv[@"name"] = [webview valueForKeyPath:@"webViewName"];
	rv[@"prettyPrint"] = rv[@"name"];

	return rv;
}

NSDictionary* _prettyPrintJSTimerObservationIdlingResource(WXJSTimerObservationIdlingResource* jsTimer)
{
	NSMutableDictionary* rv = [NSMutableDictionary new];
	rv[@"javascriptTimerIDs"] = [[jsTimer valueForKeyPath:@"observations.objectEnumerator.allObjects.@distinctUnionOfArrays.observedTimers"] sortedArrayUsingSelector:@selector(compare:)];
	rv[@"prettyPrint"] = [NSString stringWithFormat:@"Javascript Timers Ids: %@", [rv[@"javascriptTimerIDs"] componentsJoinedByString:@", "]];
	return rv;
}

NSDictionary* _prettyPrintRunLoopIdlingResource(WXRunLoopIdlingResource* runLoop)
{
	NSMutableDictionary* rv = [NSMutableDictionary new];
	rv[@"runLoop"] = [[runLoop valueForKeyPath:@"runLoop"] debugDescription];
	rv[@"prettyPrint"] = @"React Native thread is busy.";

	return rv;
}


text: <a href="<?php echo UserAR::weibo_login_url()?>">Grant Weibo Token


text:
require 'nmea_plus/message/ais/vdm_payload/payload'
require 'nmea_plus/message/ais/vdm_payload/mmsi_info'

module NMEAPlus
  module Message
    module AIS
      module VDMPayload

        # The base class for the {NMEAPlus::Message::AIS::VDM#ais AIS payload}, which uses its own encoding for its own subtypes
        class VDMMsg < NMEAPlus::Message::AIS::VDMPayload::Payload

          payload_reader :message_type, 0, 6, :_u
          payload_reader :repeat_indicator, 6, 2, :_u
          payload_reader :source_mmsi, 8, 30, :_u

          # Detailed information produced from the MMSI
          # @!parse attr_reader :source_mmsi_info
          # @return [MMSIInfo] MMSI information structure
          def source_mmsi_info
            MMSIInfo.new(source_mmsi)
          end

          # The ship cargo type description lookup table
          # @param code [Integer] The cargo type id
          # @return [String] Cargo type description
          def get_ship_cargo_type_description(code)
            case code
            when 0 then nil
            when 1...19 then "(future use)"
            when 20 then "WIG (any)"
            when 21 then "WIG Hazardous category A"
            when 22 then "WIG Hazardous category B"
            when 23 then "WIG Hazardous category C"
            when 24 then "WIG Hazardous category D"
            when 25...29 then "WIG (future use)"
            when 30 then "Fishing"
            when 31 then "Towing"
            when 32 then "Towing (large)"
            when 33 then "Dredging/underwater ops"
            when 34 then "Diving ops"
            when 35 then "Military ops"
            when 36 then "Sailing"
            when 37 then "Pleasure craft"
            when 38, 39 then "Reserved"
            when 40 then "High Speed Craft"
            when 41 then "HSC Hazardous category A"
            when 42 then "HSC Hazardous category B"
            when 43 then "HSC Hazardous category C"
            when 44 then "HSC Hazardous category D"
            when 45...48 then "HSC (reserved)"
            when 49 then "HSC (no additional information)"
            when 50 then "Pilot Vessel"
            when 51 then "Search and Rescue Vessel"
            when 52 then "Tug"
            when 53 then "Port Tender"
            when 54 then "Anti-pollution equipment"
            when 55 then "Law Enforcement"
            when 56, 57 then "Spare - Local Vessel"
            when 58 then "Medical Transport"
            when 59 then "Noncombatant ship according to RR Resolution No. 18"
            when 60 then "Passenger"
            when 61 then "Passenger, Hazardous category A"
            when 62 then "Passenger, Hazardous category B"
            when 63 then "Passenger, Hazardous category C"
            when 64 then "Passenger, Hazardous category D"
            when 65..68 then "Passenger, Reserved for future use"
            when 69 then "Passenger, No additional information"
            when 70 then "Cargo"
            when 71 then "Cargo, Hazardous category A"
            when 72 then "Cargo, Hazardous category B"
            when 73 then "Cargo, Hazardous category C"
            when 74 then "Cargo, Hazardous category D"
            when 75..78 then "Cargo, Reserved for future use"
            when 79 then "Cargo, No additional information"
            when 80 then "Tanker"
            when 81 then "Tanker, Hazardous category A"
            when 82 then "Tanker, Hazardous category B"
            when 83 then "Tanker, Hazardous category C"
            when 84 then "Tanker, Hazardous category D"
            when 85.88 then "Tanker, Reserved for future use"
            when 89 then "Tanker, No additional information"
            when 90 then "Other Type"
            when 91 then "Other Type, Hazardous category A"
            when 92 then "Other Type, Hazardous category B"
            when 93 then "Other Type, Hazardous category C"
            when 94 then "Other Type, Hazardous category D"
            when 95..98 then "Other Type, Reserved for future use"
            when 99 then "Other Type, no additional information"
            end
          end

          # An MMSI is associated with an auxiliary craft when it is of the form 98XXXYYYY
          def auxiliary_craft?
            source_mmsi_info.category == :auxiliary_craft
          end

          # @param code [Integer] The navigational status id
          # @return [String] Navigational status description
          def get_navigational_status_description(code)
            return nil if code.nil?
            case code
            when 0 then "Under way using engine"
            when 1 then "At anchor"
            when 2 then "Not under command"
            when 3 then "Restricted manoeuverability"
            when 4 then "Constrained by her draught"
            when 5 then "Moored"
            when 6 then "Aground"
            when 7 then "Engaged in Fishing"
            when 8 then "Under way sailing"
            when 9...13 then "Reserved for future use"
            when 14 then "AIS-SART active"
            else
              "Not defined"
            end
          end
        end

        # We haven't defined all the {NMEAPlus::Message::AIS::VDM#ais AIS payload} types, so this is a catch-all
        class VDMMsgUndefined < VDMMsg; end

      end
    end
  end
end


text:
package techreborn.client.compat.rei.fluidgenerator;

import com.google.common.collect.Lists;
import me.shedaniel.math.Point;
import me.shedaniel.math.Rectangle;
import me.shedaniel.rei.api.client.ClientHelper;
import me.shedaniel.rei.api.client.gui.Renderer;
import me.shedaniel.rei.api.client.gui.widgets.Tooltip;
import me.shedaniel.rei.api.client.gui.widgets.Widget;
import me.shedaniel.rei.api.client.gui.widgets.Widgets;
import me.shedaniel.rei.api.client.registry.display.DisplayCategory;
import me.shedaniel.rei.api.common.category.CategoryIdentifier;
import me.shedaniel.rei.api.common.util.EntryStacks;
import net.minecraft.text.Text;
import net.minecraft.util.Formatting;
import net.minecraft.util.Identifier;
import reborncore.client.gui.guibuilder.GuiBuilder;
import techreborn.TechReborn;
import techreborn.client.compat.rei.ReiPlugin;
import techreborn.init.TRContent;

import java.util.List;

public class FluidGeneratorRecipeCategory implements DisplayCategory<FluidGeneratorRecipeDisplay> {

	private final TRContent.Machine generator;
	private final CategoryIdentifier<? extends FluidGeneratorRecipeDisplay> identifier;

	public FluidGeneratorRecipeCategory(TRContent.Machine generator) {
		this.generator = generator;
		this.identifier = CategoryIdentifier.of(TechReborn.MOD_ID, generator.name);
	}

	@Override
	public CategoryIdentifier<? extends FluidGeneratorRecipeDisplay> getCategoryIdentifier() {
		return identifier;
	}

	@Override
	public Text getTitle() {
		return Text.translatable(identifier.toString());
	}

	@Override
	public Renderer getIcon() {
		return EntryStacks.of(generator);
	}

	@Override
	public List<Widget> setupDisplay(FluidGeneratorRecipeDisplay recipeDisplay, Rectangle bounds) {
		List<Widget> widgets = Lists.newArrayList();
		widgets.add(Widgets.createRecipeBase(bounds));
		widgets.add(ReiPlugin.createEnergyDisplay(new Rectangle(bounds.x + 108, bounds.y + 8, 14, 50), recipeDisplay.getTotalEnergy(), ReiPlugin.EntryAnimation.upwards(5000), tooltipContext -> {
			List<Text> list = Lists.newArrayList();
			list.add(Text.of("Energy"));
			list.add(Text.translatable("techreborn.jei.recipe.generator.total", recipeDisplay.getTotalEnergy()).formatted(Formatting.GRAY));
			list.add(Text.of(""));
			list.add(ClientHelper.getInstance().getFormattedModFromIdentifier(new Identifier("techreborn", "")));
			return Tooltip.create(tooltipContext.getPoint(), list);
		}));
		widgets.add(ReiPlugin.createFluidDisplay(new Rectangle(bounds.x + 16, bounds.y + 8, 16, 50), recipeDisplay.getInputEntries().get(0).get(0).cast(), ReiPlugin.EntryAnimation.downwards(5000)));
		widgets.add(ReiPlugin.createProgressBar(bounds.x + 76 - 16, bounds.y + 48 - 19, 5000, GuiBuilder.ProgressDirection.RIGHT));
		return widgets;
	}
}