<file_sep>package ramsden.ryan.GUI;

import java.awt.Canvas;
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.KeyEvent;

import ramsden.ryan.Control;

public class TextInput extends Interface {

	public String text;
	public Font font = new Font("Verdana", Font.PLAIN, 12);
	public FontMetrics fm;
	public int caratPosition, caratX;
	
	public TextInput(Interface i, String text, Rectangle r) {
		super(i, r);
		setText(text);
		setColor(new Color(0xe2e2e2));
		fm = new Canvas().getFontMetrics(font);
	}

	
	@Override
	public void drawInterface(Graphics2D g2d, int offsetX, int offsetY) {
		g2d.setColor(getColor());
		g2d.setFont(font);
		Rectangle r = getContainer();
		g2d.fillRect(r.x+offsetX, r.y+offsetY, r.width, r.height);
		g2d.setColor(Color.BLACK);
		g2d.drawString(getText(), r.x+2+offsetX, 8+r.y+fm.getHeight()/2+offsetY);
		//Not too happy with this.
		if(Control.selectedTextBox == this && System.currentTimeMillis()%1000<700) 
			g2d.drawLine(caratX+offsetX+r.x+2, r.y+offsetY+3, caratX+offsetX+r.x+2, r.y+offsetY+r.height-4);
		
	}

	
	
	@Override
	public void click(Point p, boolean onClickDown) {
		Control.selectedTextBox = this;
		p.translate(-4, 0); //This is so we dont have to round to the nearest letter.
		int caratPosition = 0;
		while(fm.stringWidth(getText().substring(0, caratPosition)) < p.getX()) 
			if(++caratPosition >= getText().length()) break;
		updateCarat(caratPosition);
	}
	
	public void updateCarat(int position)
	{
		caratPosition = Math.max(Math.min(position, getText().length()),0);
		caratX = fm.stringWidth(getText().substring(0, caratPosition));
	}
	public void enter()
	{
		System.out.println("Enter");
	}

	public void setText(String text)
	{
		if(text == null) text = "";
		this.text = text;
		if(text.length() > caratPosition) updateCarat(text.length());
	}

	public void setFont(Font font)
	{
		this.font = font;
	}

	public void updateContainer()
	{
		int hgt = fm.getHeight();
		int adv = fm.stringWidth(getText());
		getContainer().setSize(adv+2 , hgt-2);
	}

	public String getText() {
		if(text == null) return "";
		return text;
	}

	public boolean validate(char c)
	{
		return Character.isAlphabetic(c) || Character.isDigit(c);
	}
	
	public void addCharacter(int i, char c) {
		if(i == KeyEvent.VK_LEFT) updateCarat(caratPosition-1);
		else if(i == KeyEvent.VK_RIGHT) updateCarat(caratPosition+1);
		else if(i == 8 && text.length() > 0 && caratPosition > 0) {
			text = text.substring(0, caratPosition-1) + text.substring(caratPosition);
			updateCarat(caratPosition-1);
		} else if(i == 127 && text.length() > caratPosition) {
			text = text.substring(0, caratPosition) + text.substring(caratPosition+1);
		} else if(i == 10) {
			enter();
		} else if(validate(c)) {
			text = text.substring(0, caratPosition) + c + text.substring(caratPosition);
			updateCarat(caratPosition+1);
		} 
		
		
	}
}
<file_sep>package ramsden.ryan.GUI;

import java.awt.Canvas;
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;

public class TextComponent extends Interface {

	public String text;
	public Font font = new Font("Verdana", Font.PLAIN, 12);
	
	public TextComponent(Interface i, String text, Point p) {
		super(i, new Rectangle(p.x, p.y, 0, 0));
		setText(text);
		setStyle(Font.BOLD);
		if(i instanceof Dialog) setColor(Color.LIGHT_GRAY);
		else setColor(Color.BLACK);
		click = false;
	}
	
	public TextComponent(Interface i, String text, Point p, int size) {
		this(i, text, p);
		setSize(size);
	}
	
	public TextComponent(Interface i, String text, Point p, int size, int style) {
		this(i, text, p, size);
		setStyle(style);
	}
	
	public TextComponent(Interface i, String text, Point p, int size, int style, Color c) {
		this(i, text, p, size, style);
		setColor(c);
	}

	@Override
	public void drawInterface(Graphics2D g2d, int offsetX, int offsetY) {
		g2d.setColor(getColor());
		g2d.setFont(font);
		Rectangle r = getContainer();
		g2d.drawString(text, r.x+offsetX, r.y+offsetY+r.height);
	}

	@Override
	public void click(Point p, boolean onClickDown) {}

	public void setText(String text)
	{
		this.text = text;
		updateContainer();
	}

	public void setFont(Font font)
	{
		this.font = font;
		
	}
	
	public void setStyle(int style)
	{
		setFont(font.deriveFont(style, font.getSize()));
	}
	
	public void setSize(int px)
	{
		setFont(font.deriveFont(font.getStyle(), px));
	}

	public void updateContainer()
	{
		FontMetrics fm = new Canvas().getFontMetrics(font);
		int hgt = fm.getHeight();
		int adv = fm.stringWidth(text);
		getContainer().setSize(adv+2 , hgt-2);
	}

	public String getText() {
		return text;
	}
}
<file_sep>package ramsden.ryan;

import java.util.ArrayList;

import ramsden.ryan.GUI.DisplayPanel;

public class Engine {

	public static final int MAX_ATOMS = 20;
	private ArrayList<Particle> atoms;


	private Vector p1 = new Vector(); // position
	private Vector p2 = new Vector();
	private Vector v1 = new Vector(); // velocity 
	private Vector v2 = new Vector();
	private Vector n  = new Vector(); // normal vector
	private Vector un = new Vector(); // unit normal
	private Vector ut = new Vector(); // unit tangent

	public int collisions, gameTicks, maxGameTicks = 0, collideAtTicks = 0;

	private int width = 0, height = 0;



	/** Construct a container of atoms. */
	public Engine(int width, int height) {
		atoms = new ArrayList<Particle>(MAX_ATOMS);
		this.width = width;
		this.height = height;
	}

	public Engine(Engine copy) {
		setState(copy);
	}

	public void setState(Engine copy) {
		atoms = new ArrayList<Particle>(MAX_ATOMS);
		collisions = 0;
		maxGameTicks = 0;
		gameTicks = 0;
		collideAtTicks = 0;
		for(Particle p : copy.atoms) atoms.add(new Particle(p));
		if(this != Control.model) {
			setWidth(copy.getWidth());
			setHeight(copy.getHeight());
		} else {
			scale(copy.getWidth(), copy.getHeight(), Control.width, Control.height);
		}
	}

	public void scale(int widthOld, int heightOld, int width, int height) {

		double scaleW = 1;
		double scaleH = 1;
		if(Control.currentQuestion == null) {
			scaleW = (double)width/widthOld;
			scaleH = (double)height/heightOld;
		}
		for(Particle p : atoms) {
			Vector pos = p.getPosition();
			p.setPosition(width/2 + (pos.x - widthOld/2)*scaleW, height/2 + (pos.y - heightOld/2)*scaleH);
		}

	}

	public void updateImages() {
		for (Particle atom : getAtoms()) {atom.updateImage(); atom.updateDrawPosition();}
	}

	public void updateDrawPositions() {
		for (Particle atom : getAtoms()) {atom.updateDrawPosition();}
	}

	public void updateGame() {
		gameTicks++;
		if(Control.currentQuestion != null && maxGameTicks != 0 && gameTicks >= maxGameTicks) {
			Control.setPlaying(false);
			if(gameTicks > maxGameTicks) {
				Control.model.setState(Control.currentQuestion.generateQuestionEngine());
				Control.model.updateImages();
				DisplayPanel.collided1=null;
				DisplayPanel.collided2=null;
			}
			return;
		}
		for (Particle atom : getAtoms()) iterate(atom);
		for (Particle atom : getAtoms()) checkCollisions(atom);

	}

	/** Advance each atom. */
	public void iterate(Particle atom1) {
		if(this == Control.model) atom1.updateDrawPosition();
		if(DisplayPanel.currentDrag == atom1) return;
		p1 = atom1.getPosition();
		v1 = atom1.getVelocity();
		p1.add(v1);
		atom1.setPosition(p1);

	}



	public void checkCollisions(Particle atom1)
	{
		ArrayList<Particle> collisions = new ArrayList<Particle>();
		for (int i = atoms.indexOf(atom1); i < atoms.size(); i++) {
			Particle atom2 = atoms.get(i);
			if(atom1 == atom2) continue;
			if(willCollide(atom1, atom2)) collisions.add(atom2); 
		}
		for(Particle atom2 : collisions)
		{
			collideAtoms(atom1, atom2);			
			//			atom1.updateDrawPosition();
			//			atom2.updateDrawPosition();
		}
		collideWalls(atom1);
	}

	public boolean willCollide(Particle a1, Particle a2) {
		double radius = a1.getR() + a2.getR();
		p1 = a1.getPosition(new Vector());
		p2 = a2.getPosition(new Vector());
		n = n.set(p1).subtract(p2);
		double norm = n.norm();
		if(norm > radius - 5 && a1.getVelocity().isZero() && a2.getVelocity().isZero()) return false; 
		return (norm < radius);
	}

	private void collideAtoms(Particle a1, Particle a2) {

		collisions++;

		if(!(Control.stepMode && this == Control.model && collideAtTicks > gameTicks)) {
			double radius = a1.getR() + a2.getR();

			//This is so the collision is more accurate when velocity is large
			//It moves the particles so they have a smaller intersection upon collision, making it more accurate.
			//
			double divideBy = Math.max(a1.getVelocity().norm(), a2.getVelocity().norm());
			if(divideBy == 0) divideBy = 5;
			for(int i = 0;i < Math.ceil(divideBy); i++) {
				a1.setPosition(a1.getPosition().subtract(a1.getVelocity().divide(divideBy)));
				a2.setPosition(a2.getPosition().subtract(a2.getVelocity().divide(divideBy)));
				if(!willCollide(a1, a2)) break;
			}
			p1 = a1.getPosition();
			p2 = a2.getPosition();
			n = n.set(p1).subtract(p2);
			if(!willCollide(a1, a2)) {
				a1.setPosition(a1.getPosition().add(a1.getVelocity().divide(divideBy)));
				a2.setPosition(a2.getPosition().add(a2.getVelocity().divide(divideBy)));
			}
			if(willCollide(a1, a2)) {
				double dr = (radius - n.norm()) / 2;
				un = un.set(n).unitVector();
				p1.add(un.scale(dr));
				un = un.set(n).unitVector();
				p2.add(un.scale(-dr));
				a1.setPosition(p1);
				a2.setPosition(p2);
			}
		}
		if(Control.stepMode && this == Control.model) {
			Control.setPlaying(false);
			DisplayPanel.collided1 = a1;
			DisplayPanel.collided2 = a2;
			if(collideAtTicks < gameTicks) {
				collideAtTicks = gameTicks+1;
				return;
			}
		}
		if(Control.currentQuestion != null && collisions >= 1) {
			for(int i = 0; i < 8; i++) {
				a1.view[i] = false;
				a2.view[i] = false;
			}
			maxGameTicks = (int) (gameTicks + Control.GAME_HERTZ/4);
		}

		p1 = a1.getPosition(new Vector());
		p2 = a2.getPosition(new Vector());

		// Find normal and tangential components of v1/v2
		n = n.set(p1).subtract(p2);
		un = un.set(n).unitVector();
		ut = ut.set(-un.y, un.x);
		v1 = a1.getVelocity(v1);
		v2 = a2.getVelocity(v2);            
		double v1n = un.dot(v1);
		double v1t = ut.dot(v1);
		double v2n = un.dot(v2);
		double v2t = ut.dot(v2);
		// Calculate new v1/v2 in normal direction
		double m1 = a1.getM();
		double m2 = a2.getM();
		double v1nNew = Control.efficiency*(v1n * (m1 - m2) + 2d * m2 * v2n) / (m1 + m2);
		double v2nNew = Control.efficiency*(v2n * (m2 - m1) + 2d * m1 * v1n) / (m1 + m2);
		// Update velocities with sum of normal & tangential components
		v1 = v1.set(un).scale(v1nNew);
		v2 = v2.set(ut).scale(v1t);
		a1.setVelocity(v1.add(v2));
		v1 = v1.set(un).scale(v2nNew);
		v2 = v2.set(ut).scale(v2t);
		a2.setVelocity(v1.add(v2));

		//Control.outputValues();

	}

	public boolean willCollideWhenPlaced(Particle atom1)
	{
		for (int i = 0; i < getAtoms().size(); i++) {
			Particle atom2 = getAtoms().get(i);
			if(atom1 == atom2) continue;
			if(willCollide(atom1, atom2)) return true;
		}
		return false;
	}

	// Check for collision with wall
	private void collideWalls(Particle atom) {
		double radius = atom.getR();
		boolean hitWall = false;
		p1 = atom.getPosition(p1);
		v1 = atom.getVelocity(v1);
		if (p1.x < radius) {
			p1.x = radius;
			v1.x = -v1.x;
			hitWall = true;
		}
		if (p1.y < radius) {
			p1.y = radius;
			v1.y = -v1.y;
			hitWall = true;
		}

		if (p1.x > getWidth() - radius) {
			p1.x = getWidth() - radius;
			v1.x = -v1.x;
			hitWall = true;
		}
		if (p1.y > getHeight() - radius) {
			p1.y = getHeight() - radius;
			v1.y = -v1.y;
			hitWall = true;
		}

		if(hitWall){
			if(maxGameTicks != 0) maxGameTicks = gameTicks-1; //Walls will bug everything out
			else {
				atom.setVelocity(v1);
				atom.setPosition(p1);
			}
		}
	}

	public void clear()
	{
		atoms.clear();
		gameTicks = 0;
		collideAtTicks = 0;
		maxGameTicks = 0;
	}

	public ArrayList<Particle> getAtoms() { return atoms; }

	public void addAtom(Particle p) {
		atoms.add(p);
	}

	public Particle getNewAtom()
	{
		Particle p = new Particle();
		p.setR(100);
		p.updateImage();

		return p;
	}

	public int getWidth() {
		return (this == Control.model ? Control.width : width);
	}

	public void setWidth(int width) {
		this.width = width;
	}

	public int getHeight() {
		return (this == Control.model ? Control.height : height);
	}

	public void setHeight(int height) {
		this.height = height;
	}

}
<file_sep>package ramsden.ryan;

import java.awt.Color;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.util.Random;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.imageio.ImageIO;

import ramsden.ryan.GUI.DisplayPanel;
import ramsden.ryan.GUI.Information;
import ramsden.ryan.GUI.TextComponent;
import ramsden.ryan.GUI.TextInput;

public class Control {


	public static final double GAME_HERTZ = 30;

	public static DisplayPanel view;
	public static Engine model;
	public static Question currentQuestion;
	private static boolean playing = true;
	public static boolean questionFinished = false;
	public static boolean running = true;
	public static boolean stepMode = false;
	public static double efficiency = 1.00;
	public static int sqSize = 50;
	public static int width = 1000; //same ratio as 1920/1058 (Maximised on 1080p)
	public static int height = 551; //Minimum height and width
	public static int currentSeed = 0;
	public static Control manager;
	public static Color bgColor = new Color(0xc9c9c9);//0xb3b3b3);
	public static Color lineColor = new Color(0xb3b3b3);//0xa1a1a1);
	public static int fps = 60;
	public static Particle selected;
	private int frameCount = 0;
	private static int studentID = 0;
	private static String username;
	public static TextInput selectedTextBox;
	public static TextComponent clickedAnswer;
	private SQL sql;


	//TODO REMOVE THIS

	public static void takeSnapShot() {
		System.out.println("Taking screenshot");
		BufferedImage bufImage = new BufferedImage(view.getSize().width, view.getSize().height,BufferedImage.TYPE_INT_RGB);
		view.paint(bufImage.createGraphics());
		String filename = "" + (System.currentTimeMillis()/1000);
		File imageFile = new File("screenshots"+File.separator+filename+".png");

		try{
			System.out.println("Saved at "+imageFile.getAbsolutePath());
			imageFile.createNewFile();
			ImageIO.write(bufImage, "png", imageFile);

		}catch(Exception ex){ ex.printStackTrace();}

		PrintWriter writer;
		try {
			writer = new PrintWriter("screenshots"+File.separator+filename+".txt", "UTF-8");
			double totalKE =0, totalMx=0, totalMy=0; int pindex = 0;
			for(Particle p : model.getAtoms()) {
				pindex++;
				double ke = p.getConvertedKE();
				double mx = p.getConvertedMomentumX();
				double my = p.getConvertedMomentumY();
				totalKE += ke;
				totalMx += mx;
				totalMy += my;
				writer.println("Particle "+pindex+": K.E = "+Information.format(ke)+"   Mx = "+Information.format(mx)+"   My = "+Information.format(my)+"   Mass = "+Information.format(p.getConvertedMass())+" Velocity = "+Information.format(p.getConvertedVelocity())+" Vx = "+Information.format(p.getConvertedVelocityX())+" Vy = "+Information.format(p.getConvertedVelocityY()));
				
			}
			writer.println("Total K.E. : "+Information.format(totalKE));		
			writer.println("Total X Momentum : "+Information.format(totalMx));
			writer.println("Total Y Momentum : "+Information.format(totalMy));
			writer.close();
		} catch (FileNotFoundException | UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		//outputValues();
	}


	public Control(DisplayPanel view, Engine model) {
		Control.view = view;
		Control.model = model;
	}

	public static boolean isPlaying() {
		return playing;
	}


	public static void setPlaying(boolean playing) {
		if(playing) {
			DisplayPanel.collided1 = null;
			DisplayPanel.collided2 = null;
		}
		model.updateDrawPositions();
		Control.playing = playing;
	}


	public void runGameLoop()
	{
		Thread loop = new Thread()
		{
			public void run()
			{
				gameLoop();
			}
		};
		loop.start();
	}

	private void gameLoop()
	{

		final double TIME_BETWEEN_UPDATES = 1000000000 / GAME_HERTZ;
		final int MAX_UPDATES_BEFORE_RENDER = 1;
		double lastUpdateTime = System.nanoTime();
		double lastRenderTime = System.nanoTime();
		final double TARGET_FPS = 60;
		final double TARGET_TIME_BETWEEN_RENDERS = 1000000000 / TARGET_FPS;

		//Simple way of finding FPS.
		int lastSecondTime = (int) (lastUpdateTime / 1000000000);

		while (running)
		{
			double now = System.nanoTime();
			int updateCount = 0;
			//Do as many game updates as we need to, potentially playing catchup.
			if(isPlaying()) {
				while(now - lastUpdateTime > TIME_BETWEEN_UPDATES && updateCount < MAX_UPDATES_BEFORE_RENDER)
				{
					model.updateGame();
					lastUpdateTime += TIME_BETWEEN_UPDATES;
					updateCount++;
				}
			} else lastUpdateTime = now;
			//Render. To do so, we need to calculate interpolation for a smooth render.
			float interpolation = Math.min(1.0f, (float) ((now - lastUpdateTime) / TIME_BETWEEN_UPDATES));
			view.drawGame(interpolation);
			Toolkit.getDefaultToolkit().sync();
			frameCount++;
			lastRenderTime = now;

			//Update the frames we got.
			int thisSecond = (int) (lastUpdateTime / 1000000000);
			if (thisSecond > lastSecondTime)
			{
				fps = frameCount;
				frameCount = 0;			
				lastSecondTime = thisSecond;
				Information.toggleCursor();
			}
			DisplayPanel.fps.text = "FPS: "+fps; //We dont want to do settext, because it will update the container
			//Yield until it has been at least the target time between renders. This saves the CPU from hogging.

			while (now - lastRenderTime < TARGET_TIME_BETWEEN_RENDERS && now - lastUpdateTime < TIME_BETWEEN_UPDATES)
			{
				Thread.yield();
				try {Thread.sleep(1);} catch(Exception e) {} 

				now = System.nanoTime();
			}
		}
	}

	public static void setQuestion(Question question) {
		currentQuestion = question;
		Particle.r = new Random(question.seed);
		view.questionText.setText(Control.currentQuestion.question);
		view.questionInput.setText(question.myAnswer);
		view.questionButton.setText("Mark");
		view.questionButton.setSize(40, 20);
		view.questionDialog.setSize(Math.max(view.questionText.getContainer().width+16, 160), 80);
		view.questionDialog.setHidden(false);
		view.add.setHidden(true);
		DisplayPanel.collided1=null;DisplayPanel.collided2=null;
		model.setState(Control.currentQuestion.generateQuestionEngine());
		model.updateImages();
	}

	public SQL getSQL() {
		if(sql == null) {
			System.out.println("Connecting to server");
			sql = new SQL();
//			Thread connectThread = new Thread(){
//				@Override
//				public void run()
//				{
					if(!sql.connect()) {
						if(view.sid.getText().equals("Connecting")) view.connectionError.setHidden(false);
						view.loggedinAs.setText("Failed to connect");

						sql = null;
					}
//				}
//			};
//			connectThread.start();
		} 
		return sql;
	}

	public void closeSQL() {
		sql.close();
	}

	public boolean isConnected()
	{
		return (sql != null && sql.isConnected());
	}

	public static String getUsername() {

		if(username == null || username.trim().isEmpty()) {
			if(studentID != 0 && username == null) return ""+studentID;
			else return "";
		} else return username.trim();
	}

	public static int getStudentID() {
		return studentID;
	}

	public static void setStudentID(int id) {
		studentID = id;
	}
	
	public static void setStudentID(String studentID) {
		if(studentID.trim().isEmpty()) {
			Control.setStudentID(0);
			return;
		}
		if(validate(studentID)) {
			if(studentID.length() == 6) {
				studentID = studentID.substring(1);
			}
		}
		Control.setStudentID(Integer.parseInt(studentID));
	}
	
	public static boolean validate(String studentID)
	{
		if(studentID.length() == 5) {
			Pattern p = Pattern.compile("\\d{5}$");
			Matcher matcher = p.matcher(studentID);
			return matcher.find();
		} else if(studentID.length() == 6){
			Pattern p = Pattern.compile("s\\d{5}$");
			Matcher matcher = p.matcher(studentID);
			return matcher.find();
		}
		return false;
	}


	public static void setUsername(String user) {
		username = user;
	}
}<file_sep>package ramsden.ryan.GUI;

import java.awt.Color;
import java.awt.Font;
import java.awt.Point;
import java.awt.Rectangle;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;

import ramsden.ryan.Control;
import ramsden.ryan.Question;
import ramsden.ryan.SQL;

public class ResultsViewer {

	private TableDialog answerViewer;
	public HashMap<Integer, ArrayList<Answer>> seedStorage = new HashMap<Integer, ArrayList<Answer>>();
	private ScrollBar sb;
	private TextComponent results;
	private TextInput textInput;
	private Comparator<String> comparator;
	private String searchQuery;

	public ArrayList<Button> currAnswers = new ArrayList<Button>();
	public String currStudentName;
	public int currStudentID;
	private TextComponent currViewing;


	public ResultsViewer(Rectangle r) {
		init(r);

		comparator = new Comparator<String>() {
			public int compare(String s1, String s2) {
				if(!s1.substring(0, searchQuery.length()).equals(s2.substring(0, searchQuery.length()))) {
					if(s1.startsWith(searchQuery)) return -1;
					if(s2.startsWith(searchQuery)) return 1;
				}
				return s1.compareTo(s2);
			}
		};
	}

	public void search(String text) {
		if(Control.manager == null) return;
		SQL sql = Control.manager.getSQL();
		if(sql == null || !sql.isConnected() || answerViewer.isHidden()) return;
		searchQuery = text;
		answerViewer.clear();
		seedStorage.clear();
		ResultSet rs;
		ArrayList<String> students = new ArrayList<String>();
		if(text.matches("[A-z]+")) rs = sql.query("SELECT * FROM `students` WHERE ((`firstname` LIKE '%"+text+"%') OR (`surname` LIKE '%"+text+"%'))"); 
		else rs = sql.query("SELECT * FROM `students` WHERE `studentID` LIKE '%"+text.replaceFirst("s", "")+"%'");
		try {
			while(rs.next()) {
				//Check if this user has any answers;
				students.add(rs.getString(2)+" "+rs.getString(3)+":"+rs.getString(1));
			}
		} catch (SQLException e) {}
		Collections.sort(students, comparator);
		for(String s : students) {
			int i=0, correct=0, id = Integer.parseInt(s.split(":")[1]);
			ResultSet ans = sql.query("SELECT * FROM `answers` WHERE `studentID`="+id);
			try { 
				ArrayList<Answer> seed = new ArrayList<Answer>();
				while(ans.next() || i == 0) { 
					i++;
					if(Integer.parseInt(ans.getString(4)) == 1) correct++;
					seed.add(new Answer(ans.getInt(2), ans.getString(3), Integer.parseInt(ans.getString(4)) == 1));


				};
				seedStorage.put(id, seed);
				answerViewer.addRow(new String[]{s.split(":")[0],s.split(":")[1], correct+"/"+i+" "+(int)(100*(double)correct/i)+"%"});
			} catch (SQLException e) {e.printStackTrace();}
		}
		if(answerViewer.getText(1, answerViewer.selectedRow) != null) {
			viewAnswers(answerViewer.getText(0, answerViewer.selectedRow),Integer.parseInt(answerViewer.getText(1, answerViewer.selectedRow)));
		}
		results.setText(answerViewer.rowArray.size() + " Results");
	}

	public void sort()
	{

	}

	public void init(Rectangle r)
	{
		answerViewer = new TableDialog(null, r, 3, 20, 50);
		answerViewer.parent = this;
		answerViewer.setCloseable(true);
		textInput = new TextInput(answerViewer, "", new Rectangle(20, 255, answerViewer.columnWidth[1], 20)) {
			@Override
			public void addCharacter(int keyChar, char key)
			{
				super.addCharacter(keyChar, key);
				search(text);
			}
			@Override
			public boolean validate(char c)
			{
				return (Character.isLetterOrDigit(c) || (c+"").equals(" "));
			}
		};
		Color c = Color.LIGHT_GRAY;
		new TextComponent(answerViewer, "Student Answers", new Point(10, 8), 18, Font.BOLD,c);
		new TextComponent(answerViewer, "Name", new Point(20, 30), 14, Font.BOLD,c);
		new TextComponent(answerViewer, "ID", new Point(35+answerViewer.columnWidth[1], 30), 14, Font.BOLD,c);
		new TextComponent(answerViewer, "Questions", new Point(20+answerViewer.columnWidth[2], 30), 14, Font.BOLD,c);
		results = new TextComponent(answerViewer, "", new Point(answerViewer.columnWidth[1]+25, 255), 14);
		currViewing = new TextComponent(answerViewer, "", new Point(20, 285), 14,Font.BOLD, c);
		sb = new ScrollBar(answerViewer, new Rectangle(answerViewer.columnWidth[3]+20, 50, 20, 201), 40, this);
		sb.setColor(TableDialog.bd);
		newScroll(0);
	}

	public void newScroll(double amount)
	{
		answerViewer.scroll = amount;
	}

	public ScrollBar getScrollBar() {
		return sb;
	}

	public boolean isHidden()
	{
		return answerViewer.isHidden();
	}

	public void setHidden(boolean b) {

		if(b && Control.manager != null && !Control.manager.isConnected()) return;
		answerViewer.setHidden(b);
		if(!isHidden()) {
			search(""); //This will just get the initial results.
			Control.selectedTextBox = textInput;
		}
	}

	public void toggle() {
		//answerViewer.centerOnScreen();
		setHidden(!answerViewer.isHidden());
	}

	public void viewAnswers(String studentName, final int studentID) {
		for(Button b : currAnswers) b.remove();
		currAnswers.clear();
		currStudentName = studentName;
		currStudentID = studentID;
		currViewing.setText(studentName);
		for (int i = 0; i < seedStorage.get(studentID).size(); i++) {
			final int seed = seedStorage.get(studentID).get(i).seed;
			final String ans = seedStorage.get(studentID).get(i).answer;
			Button b = new Button(answerViewer, new Rectangle(20+(i%5)*54, 310+(i/5)*54, 50, 50), (seed%2==0 ? "2D" : "1D")) {
				@Override
				public void click(Point p, boolean onClickDown) {
					super.click(p, onClickDown);
					if(!onClickDown) {
						Question q = new Question(seed);
						q.myAnswer = ans;
						Control.setQuestion(q);
					}
				}
			};
			new TextComponent(b, (1+i)+"." ,new Point(2,-4), 8, Font.PLAIN);
			b.getTextComponent().setSize(16);
			b.getTextComponent().setStyle(Font.BOLD);
			b.setColor(seedStorage.get(studentID).get(i).correct ? Question.Colour.GREEN.getColor() : Question.Colour.RED.getColor());
			b.centerText();
			currAnswers.add(b);
		}
	}

	class Answer {
		int seed;
		String answer;
		boolean correct;
		public Answer(int s, String string, boolean c) {
			seed = s;
			answer = string;
			correct = c;
		}
	}
}
<file_sep>package ramsden.ryan.GUI;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;

public class Dialog extends Interface {

	public Color border = new Color(0xb2b2b2);
	public Color inside = new Color(0x4F5A69);
	public int borderSize = 4;
	
	public Dialog(Interface i, Rectangle r) {
		super(i, r);
		setColor(inside);
	}

	@Override
	public void drawInterface(Graphics2D g2d, int offsetX, int offsetY) {
		Rectangle r = getContainer();
		g2d.setColor(border);
		g2d.fillRect(r.x+offsetX, r.y+offsetY, r.width, r.height);
		g2d.setColor(getColor());
		g2d.fillRect(r.x+offsetX+borderSize, r.y+offsetY+borderSize, r.width-borderSize*2, r.height-borderSize*2);
		drawChildren(g2d, offsetX, offsetY);
	}

	@Override
	public void click(Point p, boolean isClickDown) {
		//We dont need to do anything
	}

}
<file_sep>import os
files = os.listdir('.')
index = 0
for filename in files:
    os.rename(filename, 'Image '+str(index+1)+'.png')
    index += 1