Showing posts with label Code. Show all posts
Showing posts with label Code. Show all posts

Tuesday, 7 June 2016

Creating a Web Drive on AWS

I don't trust cloud storage services, and you should either. So here is a guide to create your own online drive.

I should note, there are a couple services out there like ownCloud and soon to be NextCloud which will likely fulfill your cloud storage needs, but I found them to be cumbersome for my small use case. Plus doing it myself was a great way to learn some new things.

I choose AWS as a hosting solution because I already use them for my website and other random projects.

1. Create an EC2 Instance

In the AWS console, navigate to EC2 then click Launch Instance.

Note: Make sure you have selected the region you want the instance to be created in.

Select an Ubuntu Server AMI instance.
Select an Instance Type. I'm choosing t2.micro because it should fit my needs. This size is also in the free tier for those that are new to AWS.
Click Next
Click Next
Add some tags to your instance for identification. e.g. Name=CloudDrive
Configure Security Group. Add HTTP to your security group.
Launch the instance and generate a new key pair. It is always good practice to generate a new keypair for each instance.
Write down the created instances public IP address for future reference.

2. (Optional) Update your DNS Records

This will allow a friendly name for your site. e.g. webdrive.standen.link

In Route 53, or your favourite domain registrar, add a CNAME with a value of the public DNS of the instance you just created.

3. Install Apache with SSL

SSH into your instance, using the public IP address obtained earlier.

3.1 SSH using PuTTY on Windows (Skip this step if you are not using PuTTY on Windows)

Access PuTTY Key Generator and load your keypair downloaded earlier. (xxx.pem)
Click Save private Key to store a xxx.pek file that is accessible for PuTTY
When accessing your instance via PuTTY you will need to add this file under Connection > SSH > Auth in the "private key file for authentication" box.

3. Cont. 

Login as user ubuntu

Obtain root permissions
sudo -s

Update apt-get cache
apt-get update

Install Apache with SSL
apt-get install apache2 libapache2-mod-auth-mysql apache2-utils

4. Get a Certificate for SSL

There are a couple options for this. Each is outlined or linked below. I recommend option 3.

4.1 Generate and Self Sign your own Certificate. 

Browsers will not trust your certificate by default.
This will still enable secure communication.

Execute the following commands and fill in information as requested.

sudo openssl genrsa -des3 -out server.key 1024
sudo openssl req -new -key server.key -out server.csr
sudo openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt

Copy the certificate into the correct folder
cp server.crt /etc/ssl/certs
cp server.key /etc/ssl/private

4.2 Use your a Certificate provided by your Favourite Certificate Authority

Costs money. Why would you pay for something that is (and should be) free? Look below.

4.3 Use Lets Encrypt

Install git on your instance
apt-get install git

Clone the certbot repository
git clone https://github.com/certbot/certbot

Update certbot and install your certificate
cd certbot
./certbot-auto --apache

During this you will have to supply the URL you will be accessing your instance from. This will either be your instance public IP address, or the address you specified in optional step 2.

Provide a valid email address! Just in case something goes wrong.

Agree to the terms and conditions, select Secure connection only.

4. Cont. 

Confirm your SSL configuration is adequate at https://www.ssllabs.com/ssltest/analyze.html?d=<your_website_here>

5. Set up WebDav

a2enmod dav
a2enmod dav_fs

Create a directory to share, and apply the appropritate permissions
mkdir /home/ubuntu/share
chown www-data:ubuntu /home/ubuntu/share

Set up a password
a2enmod auth_digest
mkdir /etc/password

Create a password for each user
htdigest -c /etc/password/digest-password CloudShare user1

Note: Additional users do not use the -c flag, as this overwrites the file.

Apply appropriate permissions to the password file
chown www-data:ubuntu /etc/password/digest-password

Edit the default-ssl config file (your config file may be default-ssl.conf)
nano /etc/apache2/sites-enabled/000-le-default-ssl.conf


Find the line CustomLog /var/log/apache2/ssl_access.log combined and under that place the following:

Alias /share /home/ubuntu/share

<Directory /home/ubuntu/share/>
  Options Indexes MultiViews
  AllowOverride None
  Order allow,deny
  allow from all
</Directory>

<Location /share>
  DAV On
  AuthType Digest
  AuthName "CloudShare"
  AuthUserFile /etc/password/digest-password
  Require valid-user
</Location>


Now restart Apache
/etc/init.d/apache2 restart


That's it!!

Well, kind of.

For information on how to map your cloud drive to your instance, check here http://www.webdavsystem.com/server/access/

You can also remove the default apache configuration for a cleaner look. You might also want to replace the instance storage with S3 or EBS storage.
I'm investigating the latter and will hopefully provide an update here when that's done.

Let me know if you have any problems in the comments below.

Wednesday, 3 September 2014

Apache Server Permission Error

Every single time I create a new apache server I forget to give permissions to the www-data group. So I'm pasting a great answer I got from stackoverflow to this blog for future reference.

//Create new group
$ sudo addgroup webdev

//Change the group of your web directory:
$ sudo chgrp -R webdev /var/www/
$ sudo chmod -R g+rw /var/www/

//Set the guid bit on all folders in your web directory:
$ sudo find /var/www -type d -exec chmod +s {} \;

//Add Apache to the webdev group:
$ sudo usermod -a -G webdev www-data

//Add your user to the webdev group:
$ sudo usermod -a -G webdev <user_name>

Hopefully this helps someone

Thursday, 28 July 2011

Http Server Implementing GET

Hi all,

Had to create a very very simple http server, that only implements the GET function, in Java for one of our assignments.
When run you can get file from your computer using http://127.0.0.1:8001/filename.jpg.

Could use this kind of thing for some multiplayer game in the future.

Am currently working on an augmented reality program. Should be AWESOME!


Am also testing out a new code formatter. Hopefully things become readable. Unfortunately tabs do not appear as tabs... Big thanks to David Craft.

Here's the code for the server.

import java.net.ServerSocket;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetAddress;
import java.net.Socket;
import java.util.StringTokenizer;

/**
 * @author Milk
 *
 */
public class HttpServer {

 /**
  * 
  * @param args
  */
 public static void main(String[] args) {
  try {
   ServerSocket socket = new ServerSocket(8001);
   InetAddress serverHost = InetAddress.getLocalHost();
   System.out.println("Server destination: " + serverHost.getHostAddress() + 
     ", "+ socket.getLocalPort());
   // Repeatedly handle requests for processing.
   while(true){
    Socket clientConnection = socket.accept();
    System.err.println("Connection established.");
    BufferedReader in = new BufferedReader(new InputStreamReader(
      clientConnection.getInputStream()));
    DataOutputStream out = new DataOutputStream(clientConnection.getOutputStream());
    // Read string.
    String inString = in.readLine();
    System.out.println(inString);
    StringTokenizer st = new StringTokenizer(inString);
    st.nextToken();
    String request = "." + st.nextToken();
    // Read the requested file.
    FileInputStream f;
    try{
     f = new FileInputStream(new File(request));
     sendFile(f, out);
    } catch (FileNotFoundException e){
     try{
     // Display 404 screen.
     f = new FileInputStream(new File("./404.jpg"));
     sendFile(f, out);
     } catch (FileNotFoundException e2){
      out.writeBytes("HTTP/1.0 404 Not Found\r\n");
     }
    }
    // Close this connection.
    clientConnection.close();
    System.err.println("Connection closed.");
   }
  }
  catch(IOException e) {
   e.printStackTrace();
  }
 }
 
 /**
  * Sends the file.
  * @param f The file to be sent.
  * @param out The DataOutputStream.
  * @throws IOException
  */
 private static void sendFile(FileInputStream f, DataOutputStream out) throws IOException{
  // Send the file byte by byte.
  while(true){
   int b = f.read();
   if (b == -1){
    break;
   }
   out.write(b);
  }
 }
}

Cheers,
Milk

Sunday, 8 May 2011

How To Kill A Computer

Here is a couple things everyone should know how to do from the command line.

To get the command line, click on the start button, then in the search bar type cmd and press enter.


To change the location.
Command: cd path
e.g.: cd C:\Windows\system32

Change your password without knowing the old one.
Location: C:\Windows\system32
Command is: net user user_name new_password
e.g.: net user Milk Password01

Only catch is you have to already be logged in. Good to change a friends password if they leave their computer on. Would be lols.

Format hard drive.
Warning: Don't run this!!!
Location: anywhere in any drive
Command: del drive *.* /s /q
e.g.: del C:\ *.* /s /q



This silently deletes every file in every folder on your directory without asking "Are you sure?"
Pretty dangerous couple of characters.

Works great if you are on a flash drive. Deletes all the hidden files and meta-data as well. So it is very efficient.

Get your IP address.
Location: anywhere
Command: ipconfig



Gives you a whole bunch of information, very handy for LANs and setting up your minecraft server.

Print a tree.
Location: anywhere
Command: tree



Lost a folder? Set the location to a starting point and use the tree command. This prints out everything in the folder and folders below that, so that you can find something. It's fantastic.

These are only a couple cool looking things you can use in command line. They are only a very small part of what you can do. But this should be enough to impress your friends. Everyone knows that command line pulls the chicks.

Thursday, 10 March 2011

miTanks, Part 11

FINALLY!!! After 5 days searching the net and testing heaps of different custom views, I've drawn a circle. That's right. 5 days of work and all I've done is draw a circle. This must sound rediculous but this is the biggest break though. Look! Here it is:



It's amazing. Now I simply had to copy over the view handling bits of code to miTanks and BAM!



We get an ugly, badly drawn game of tanks. It's nice. So now I'm working on tweeking the look so that it, well, works. For those of you using the code snippets I'm putting on here, the main bits are:

In the main class:

public class miTanks extends Activity {

private GameView gv;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
GameView gv = new GameView(this);
setContentView(gv);
}

In the GameView:

public class GameView extends View{

private final Paint PAINT;
private static final Bitmap[] TANK_IMAGES = new Bitmap[8];
private static final int[] TANK_COLOURS = new int[8];
private final GradientDrawable BACKGROUND_GRADIENT;
private static GameView INSTANCE;

/**
 * Initialises the GameView.
 * @param context
 */
public GameView(Context context) {
super(context);
setFocusable(true);
setFocusableInTouchMode(true);
...
/**
 * Draws the game onto the canvas.
 */
protected void onDraw(Canvas canvas){
drawBackground(canvas);
drawGround(canvas);
drawTanks(canvas);
}

In the main.xml:

<?xml version="1.0" encoding="utf-8" ?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:orientation="vertical"
 android:layout_width="fill_parent"
 android:layout_height="fill_parent">
 <com.miTanks.game.GameView
  android:id="@+id/View01"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:maxHeight="40dip" />
 </LinearLayout>

Thursday, 17 February 2011

miMTGCrawler

So as per my previous post, I have written a very simple program to show me the value of Magic Cards. All you do is run the program and type in the name of the card. Then it prints out the value of the card for each version it is in. In addition it also saves and formats the printed bits in a txt file, which is compatable with spreadsheet software. See images below.

Simply type in the card you are looking for and press enter.


That is then saved here.


Which you can then import...



Here!


It also takes into account cards that do not exist. But not half typed. i.e. If I typed 'myr' it would return everything with myr in the title... No really worth fixing. More the error / aid of the website it's searching.

[Small error fixed: 'Mirrodin Besieged Singles' was picked up from the ads on the side bar. Now the first category is correct. I'm not replacing the screenshots though. You get the picture. (Spot the pun)]

Code below:

#!C:/Program Files/Python/Python 2.7

import urllib

print "miMTGCrawler version 0.1"

f = open('cardList.txt', 'a')

# The below URL is the link to a card. The card name is appended, also '+' replaces ' '. Case is irrelevent.
# e.g. 'Myr Enforcer' = 'Myr+Enforcer'
# Searches the website starcitygames.com for the information.
scLink = 'http://sales.starcitygames.com/search.php?substring='

while(True):
    print "Please enter card name: "
    card = raw_input()
    if card == 'q':
        break
   
    #Builds the URL for the card.
    cardLink = scLink + card.replace(' ', '+')
    page = urllib.urlopen(cardLink).read()
   
    # Search for the category. e.g. 'Mirridon'
    categoryString = 'http://sales.starcitygames.com//category.php?cat='
   
    # Jumps to the first listing.
    pos = page.find('tooltip')
       
    pos = page.find(categoryString, pos)
    # Loops through this process until there are no more valid categories on the page.
    while (pos != -1):
        pos = page.find('>', pos) + 1
        # This will build a string for the Card and it's categories and values of the listing found.
        cardString = card + '\t' + page[pos : page.find('<', pos)] + '\t'
        pos = page.find('">$', pos)
        # Checks to see if a price was found following the category.
        if pos == -1:
            print 'There is no such card: ' + card
            break
        cardString = cardString + page[page.find('$', pos) : page.find('</td>', pos)]
        print cardString + '\n'
        f.write(cardString + '\n')
        # Look for the next category.
        pos = page.find(categoryString, pos)

      

Tuesday, 18 January 2011

C Four, Connect Four, miGame

I'm taking a break from miTanks for a while. Here's one of my first ever programs.

I spend alot of my time in lectures at University playing Connect Four on a piece of paper against friends. This is the best paper game we could come up with. Turn based, so could simply pass notes or signal which column to drop in. And there was no need for an eraser; imaging trying to play chess with a pen.

At the time we were learning C programming and had to come up with some simple program to prove we learnt something in the course. Alot of people went with a Facebook similar 'What animal are you?' kind of game. Boring!



It took about 2-3 hours. Remember this was my first C program I created purely by myself, aside from Visual Basic and MicroWorlds (if that even counts).

Code:

#define _CRT_SECURE_NO_DEPRECATE
#include <stdio.h>
//C(onnect) Four
//Created by: Milk
//Date of final build: 19/10/09
//Height of each line
#define LINE_HEIGHT 6
#define LINE_WIDTH 7
void DrawBoard(int grid[LINE_HEIGHT][LINE_WIDTH]);
int CalculateWin(int grid[LINE_HEIGHT][LINE_WIDTH], int player);
int ValidInput(int input, int grid[LINE_HEIGHT][LINE_WIDTH]);
int main(void)
{
 //Plays connect four
 int grid[LINE_HEIGHT][LINE_WIDTH] = {0};
 int gameOver = 0;
 int input = 0;
 int player = 1;
 char inputValid;
 int i;

 //Draw the intitial board (empty)
 DrawBoard(grid);
 while (gameOver == 0 && (grid[LINE_HEIGHT - 1][0] == 0 || grid[LINE_HEIGHT - 1][1] == 0 || grid[LINE_HEIGHT - 1][2] == 0 || grid[LINE_HEIGHT - 1][3] == 0 || grid[LINE_HEIGHT - 1][4] == 0 || grid[LINE_HEIGHT - 1][5] == 0 || grid[LINE_HEIGHT - 1][6] == 0)) {
  //Get input from user
  input = 0;
  printf("\nWhere would you like to go, player %d?\n", player);
  scanf("%d", &input);
  //Decide if input is a valid move
  inputValid = ValidInput(input, grid);
  //If input is not valid prompt for a valid move
  while (inputValid == 0) {
   printf("Please choose a valid position: ");
   scanf("%d", &input);
   inputValid = ValidInput(input, grid);
  }
  //Add input to grid
  for (i = 0; i < LINE_WIDTH; i++) {
   if (grid[i][input - 1] == 0) {
    grid[i][input - 1] = player;
    break;
   }
  }
  //Draw the board
  DrawBoard(grid);
  //Calculate if there is a win
  gameOver = CalculateWin(grid, player);
  //Set the next players turn
  if (player == 1) {
   player = 2;
  } else {
   player = 1;
  }
 }
 //Print winner
 if (gameOver == 0) {
  printf("\n\nThere are no more available moves!\nIt's a draw\n");
 } else {
  printf("\n\nCongratulations player %d!\nYou won\n", gameOver);
 }
 return 0;
}
void DrawBoard(int grid[LINE_HEIGHT][LINE_WIDTH])
{
 //Draws the board
 int i, j;
 printf("\n\n\n\n\n");
 for (i = LINE_HEIGHT - 1; i >= 0; i--) {
  printf("\nI");
  for (j = 0; j < LINE_WIDTH; j++) {
   if (grid[i][j] == 0) {
    printf("   I");
   } else if (grid[i][j] == 1) {
    printf(" X I");
   } else {
    printf(" O I");
   }
  }
 }
 printf("\n__1___2___3___4___5___6___7__");
 return;
}
int ValidInput(int input, int grid[LINE_HEIGHT][LINE_WIDTH])
{
 //Calculate if input is valid
 if (input < 0 || input > 8 || grid[LINE_HEIGHT - 1][input - 1] != 0) {
  return 0;
 } else {
  return 1;
 }
}
int CalculateWin(int grid[LINE_HEIGHT][LINE_WIDTH], int player)
{
 int i, j;
 //Calculate if there is a win on the horizontal
 for (j = 0; j < LINE_WIDTH - 3; j++) {
  for (i = 0; i < LINE_HEIGHT; i++) {
   if (grid[i][j] == grid[i][j + 1] && grid[i][j] == grid[i][j + 2] && grid[i][j] == grid[i][j + 3] && grid[i][j] != 0) {
    return player;
   }
  }
 }
 //Calculate if there is a vertical win
 for (i = 0; i < LINE_HEIGHT - 3; i++) {
  for (j = 0; j < LINE_WIDTH; j++) {
   if (grid[i][j] == grid[i + 1][j] && grid[i][j] == grid[i + 2][j] && grid[i][j] == grid[i + 3][j] && grid[i][j] != 0) {
    return player;
   }
  }
 }
 //Calculate if there is a diagonal up-right win
 for (i = 0; i < LINE_HEIGHT - 3; i++) {
  for (j = 0; j < LINE_WIDTH - 3; j++) {
   if (grid[i][j] == grid[i + 1][j + 1] && grid[i][j] == grid[i + 2][j + 2] && grid[i][j] == grid[i + 3][j + 3] && grid[i][j] != 0) {
    return player;
   }
  }
 }
 //Calculate if there is a diagonal up-left win
 for (i = 0; i < LINE_HEIGHT - 3; i++) {
  for (j = LINE_WIDTH - 1; j >= 0; j--) {
   if (grid[i][j] == grid[i + 1][j - 1] && grid[i][j] == grid[i + 2][j - 2] && grid[i][j] == grid[i + 3][j - 3] && grid[i][j] != 0) {
    return player;
   }
  }
 }
 //No win
 return 0;
}


When compiled the exe file is only 56.0KiB. So it's pretty much always on my USB drive now.
And here it is:
http://rapidshare.com/files/443141503/Connect4.txt
I don't think rapidshare likes exe files so once you download just change the file extension (txt) to exe, and it will work. Give it a go.

Looking back at this code there is not actually too many things I would do differently. Would've been a nice OO exercise though.

If anyone wants to give me a game just tell me your starting move. Let's play. Lol

Cheers,
Milk

Wednesday, 12 January 2011

miTanks, Part 8, Initial Release!!!

Added another ground type, gravel. But thats about it.


The ground is randomly up and down, but never so high that you can't climb it. I think it's the most realistic ground I have made. Suprisingly easy as well.

Ok guys. I'm running out of ideas. Foo's to get to work on having the menu up and running. I'll going to get to work on some of the inside bits.

I really want to make a release for you guys. What I'm going to do is find a way to put up a .jar file. Because the program has no real visual output, I'll leave you instructions on how to run it through the command line. This will allow you to see what I see. Playable, but in no way is it finished.

Download Link:
http://rapidshare.com/files/442108182/miTanks.jar

How to use:
Download the jar file and place it somewhere on your computer.
Right-click on the file and click 'Properties'.
Copy the location of the file.

Open the command line. (Windows > Search > "cmd").
Type "cd [location in full]" and press enter.
Type "java -jar miTanks.jar" and press enter.

This will open the game.

Notes:
The ground is gravel and there are 3 players (2 human controlled and a computer controlled). The first player is the blue one, he is human controlled. The second is red, and is also human controlled. The last is still red, but he is a computer player that randomly picks a direction, power and fires.
If I get some comments, I'll upload versions with a certain amount of what players and what ground etc.
The angle works like this: 0 is straight up, -90 is left, 90 is right.
Power goes between 0 and 100.
Your power and angle will be displayed in the command line.
Your life comes up here as well as you get damaged.
And some other crap. Sorry I'm still using these tracers so that's why they are still there.
Once you win you will have to close and open again. Just press up when in the command line then Enter.
Controls:
w = increase power
s = decrease power
a = decrease angle
d = increase angle
z = move left
x = move right
q = previous weapon
e = next weapon
Enter = fire

Please leave a comment! Chances are, there will be some issues with this.

Sunday, 9 January 2011

miTanks, Part 6

A little more progress. Moved the ground builder into the Ground enum so that each type of ground has it's own way to build the terrain. Implemented a Sand random ground generator and a Rock random ground generator. Guess which one is which.



You can see the code behind building these is only a few lines each. Writing the rock one took less then 10 mins. The sand one was just over an hour.

The sand one still has some issues. I haven't quite got the constraints for the range, period and shift of the wave. And then applying some additional scaling so that it doesn't fall off the bottom of the game.

Haven't done much else really. Will look at adding a straight shot weapon that moves through the floor. This is probably going to be alot more enjoyable then the game to work. To be honest there isn't that much else to do to get it playable.

There are a couple of steps I have when I create a game:
Working = It does what it should.
Playable = You can see it doing what it should.
Done/Fun = There is enough story/options/levels/bells and wistles that you will enjoy playing it.
Finished = It's actually done.

At the moment miTanks for PC is at a proof of concept stage. Which is some wierd combination of fun and playable, but not quite working. This usaully happens when I get bored of doing behind the scenes code and start making stuff that I can actually see. Like the ground generators.

Please read this:
I've made the sound support on this PC version. Still waiting some sound effects. If you go to Vocaroo and make me a sound, I will put it in my game, and your name in credits.
Just post the Vocaroo link in a reply below.
If you want a weapon just tell me what it should do, how to move and shoot. I'll put that in aswel. Credit will be made to you also.

See example comment below.

Friday, 7 January 2011

miTanks, Part 5

Here's a some pics of what I've got so far for testing.


Support for an arbitrary amount of players. They are actually all human controlled at the moment.



In this one you can see the error with damage. You can see it has broken one line correctly. But hasn't done the others.


 If anyone can help me with code formatting on here let me know. Here's a screen of it. Lol.




ground is a 2d array of size game_width x game_height. All the others should be self explanatory.
When it prints we see:


Destroy: -5, 0
Destroy: -4, 0
Destroy: -3, 0
Destroy: -2, 0
Destroy: -1, 0
Destroy: 0, 0
Destroy: 1, 0
Destroy: 2, 0
Destroy: 3, 0
Destroy: 4, 0
Destroy: 5, 0

So for every x, y = 0. But why! Should be something like. x = -5, y = 0; x = -4, y = 1; ...

[Edit: Found it!!

Not sure why I was scaling y by the bullet location... Removed this.bullet_x and this.bullet_y in the y calculation and it works. Too easy. Doesn't even look that circular... How to fix that?

]

Wednesday, 22 December 2010

miNote

Problem:
University requires we keep some form of log book. Physical or virtual. As I am doing software a virtual one sounded good. Now, I'm not rich so I use Open Office. Compatibility and laziness meant I didn't want to use any word editting software like Microsoft Word or Open Writer. Using notepad is also pretty lame. Now I don't need to know all the crap I had written in earlier; don't need to correct spelling mistakes; CLI is fine; all I need is a time stamp with each post. Didn't want an online thing, like this blog, incase I couldn't get online when I needed it. So I decided to create my own note taking program.

tl;dr Need a program to take notes and timestamp.

Solution:
Decided to go with Java for this one. Just because I was using it at the time. This would probably be much better had it been written in C or something equiv. Since there is no need for high performance the language speed is irrelevent. I went with a basic CLI interface that logs each 'post' with a timestamp on an enter key press. Having seen a friend make a similar GUI version and struggle with clicking a button for each post, he was trying to include multiline posts, it seemed the CLI was a good plan. The posts are only timestamped if the times differ by more than a minute. This will probably be increased later on as up to the minute is a bit over the top for recording information in this case.

Code:

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Scanner;
/**
 * @author Michael Standen
 * Saves my notes, with appropriate time stamp.
 */
public class MiNote {

 /**
  * @param args
  * @throws IOException
  */
 public static void main(String[] args) throws IOException {
  // Initialise things.
  Scanner scanner = new Scanner(System.in);
  System.out.println("Please enter the path of the notes file:");
  File notes = new File(scanner.nextLine());
  // Checks file exists.
  while (!notes.exists()){
   System.out.println("File does not exist. Create new? Y/N");
   if (scanner.nextLine().equalsIgnoreCase("y")){
    // Creates a new file with the name provided.
    if (!notes.createNewFile()){
     // Error in creation, get new file name.
     System.out.println("Error in file creation. Please enter new file path:");
     notes = new File(scanner.nextLine());
    } else {
     new BufferedWriter(new FileWriter(notes, true)).append("Created " +
       new SimpleDateFormat("(d MMM yyyy 'at' HH:mm z)").format(new Date())
       + '\n').close();
    }
   } else {
    System.out.print("Please enter the path of the notes file:");
    notes = new File(scanner.nextLine());
   }
  }
  // Success. Outputs the current date.
  System.out.println("Success. The current time is: " +
    new SimpleDateFormat("(d MMM yyyy 'at' HH:mm z)" + '\n').format(new Date()));
  // Write the opening date and time.
  new BufferedWriter(new FileWriter(notes, true)).append("" + '\n' + "Opened " +
    new SimpleDateFormat("(d MMM yyyy 'at' HH:mm z)" +
      '\n').format(new Date())).close();

  while(true){
   String line = scanner.nextLine();
   if (line.equalsIgnoreCase("q")){
    // Quits the program.
    break;
   } else if (line.equalsIgnoreCase("r")){
    // Outputs the entire file.
    readNotes(notes);
   } else {
    writeNotes(notes, line);
   }
  }
 }
 /**
  * Appends the note to the file and adds appropriate time and date stamp.
  * @param notes the file to be writen to.
  * @param line the String to be added.
  * @throws IOException
  */
 private static void writeNotes(File notes, String line) throws IOException{
  // Make the file writable.
  notes.setWritable(true);
  // Create the file writer.
  BufferedWriter writer = new BufferedWriter(new FileWriter(notes, true));
  // Create date variables to see if time stamp is applicable.
  Calendar now = Calendar.getInstance();
  now.setTime(new Date());
  Calendar edit = Calendar.getInstance();
  edit.setTime(new Date(notes.lastModified()));
  // Create formatter for the time stamp
  SimpleDateFormat formatter;
  // Appends the date if it is different then the last edited date.
  if (now.get(Calendar.DAY_OF_MONTH) != edit.get(Calendar.DAY_OF_MONTH)){
   formatter = new SimpleDateFormat("(d MMM yyyy 'at' HH:mm z)");
   writer.append("" + '\n' + formatter.format(new Date()) + ": " + '\n');
  } else if (now.get(Calendar.HOUR_OF_DAY) != edit.get(Calendar.HOUR_OF_DAY) ||
    now.get(Calendar.MINUTE) != edit.get(Calendar.MINUTE)){
   formatter = new SimpleDateFormat("(HH:mm z)");
   writer.append("" + '\n' + formatter.format(new Date()) + ": " + '\n');
  }
  writer.append(line + '\n');
  writer.close();
 }
 /**
  * Reads the file and prints the standard output.
  * @param notes the file to be read.
  * @return false if unable to read, true otherwise.
  * @throws FileNotFoundException
  */
 private static void readNotes(File notes) throws FileNotFoundException {
  // Outputs the file.
  notes.setReadable(true);
  Scanner scanner = new Scanner(notes);
  while(scanner.hasNext()){
   System.out.println(scanner.nextLine());
  }
 }
}


Notes:
CLI programming is cool. If someone has no idea what's going on, they will be impressed. Also comments are important. Remember that.