diff --git a/java/3-5-Clipboard/ClipboardDemo.java b/java/3-5-Clipboard/ClipboardDemo.java
new file mode 100644
index 0000000000000000000000000000000000000000..3539ddee087e4ffb32c58e5120c8577f4fc322de
--- /dev/null
+++ b/java/3-5-Clipboard/ClipboardDemo.java
@@ -0,0 +1,161 @@
+import java.awt.Dimension;
+import java.awt.FlowLayout;
+import java.awt.Toolkit;
+import java.awt.datatransfer.Clipboard;
+import java.awt.datatransfer.ClipboardOwner;
+import java.awt.datatransfer.DataFlavor;
+import java.awt.datatransfer.Transferable;
+import java.awt.datatransfer.UnsupportedFlavorException;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.IOException;
+
+import javax.swing.JButton;
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+import javax.swing.JTextArea;
+
+public class ClipboardDemo extends JPanel implements ClipboardOwner {
+
+    private JTextArea textArea;
+    
+    public ClipboardDemo() {
+        
+        this.setLayout(new FlowLayout());
+
+        // Create a text area for copy and paste tests
+        // Note that by default, text widgets will support keyboard shortcuts
+        // for copy/paste
+        textArea = new JTextArea();
+        textArea.setMinimumSize(new Dimension(300, 150));
+        textArea.setPreferredSize(textArea.getMinimumSize());
+        textArea.setLineWrap(true);
+        textArea.setWrapStyleWord(true);
+        this.add(textArea);
+
+        textArea.setText("Lorem ipsum dolor sit amet, semper dissentiet concludaturque an has, " +
+                         "case vivendo vix an. Probo tempor laoreet quo ad.");
+
+        // Create copy/cut/paste buttons to support manual copying and pasting
+        JButton copyButton = new JButton("Copy");
+        JButton cutButton = new JButton("Cut");
+        JButton pasteButton = new JButton("Paste");
+        this.add(copyButton);
+        this.add(cutButton);
+        this.add(pasteButton);
+
+        // Add action listeners to perform the clipboard operations
+        copyButton.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent e) {
+                doCopy();
+            }
+        });
+
+        cutButton.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent e) {
+                doCut();
+            }
+        });
+
+        pasteButton.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent e) {
+                doPaste();
+            }
+        });
+    }
+    
+    private void doCopy() {
+
+        System.out.println(String.format("COPY: `%s`", textArea.getSelectedText()));
+        
+        // Get the system clipboard
+        Clipboard cb = Toolkit.getDefaultToolkit().getSystemClipboard();
+
+        // Create a transferable object encapsulating all the info for the copy
+        Transferable transferObject = new Transferable() {
+
+            private String text = textArea.getSelectedText();
+            
+            // Returns the copy data
+            public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException ,IOException {
+                System.out.println("  Transferable.getTransferData as " + flavor);
+                if (flavor.equals(DataFlavor.stringFlavor)) {
+                    return text;
+                }
+                throw new UnsupportedFlavorException(flavor);
+            }
+            
+            // Returns the set of data formats we can provide
+            public DataFlavor[] getTransferDataFlavors() {
+                System.out.println("  Transferable.getTransferDataFlavors");
+                return new DataFlavor[] { DataFlavor.stringFlavor };
+            }
+            
+            // Indicates whether we can provide data in the specified format
+            public boolean isDataFlavorSupported(DataFlavor flavor) {
+                System.out.println("  Transferable.isDataFlavorSupported: " + flavor);
+                return flavor.equals(DataFlavor.stringFlavor);
+            }
+        };
+        
+        // Now set the contents of the clipboard to our transferable object
+        // NOTE: The second argument "this" tells the system that this 
+        //       object would like to be the owner of the clipboard.
+        //       As such, this object must implement the ClipboardOwner interface
+        System.out.println("COPY: set system clipboard to Transferable");
+        cb.setContents(transferObject, this);
+    }
+
+    private void doCut() {
+
+        System.out.println("CUT");
+
+        // cut is just a copy that also removes data from document
+        doCopy();
+        textArea.replaceSelection("");
+    }
+    
+    private void doPaste() {
+
+        System.out.println("PASTE");
+        
+        // Grab system clipboard
+        Clipboard systemClipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
+
+        System.out.println(String.format("PASTE: %d available flavours ... ",
+                systemClipboard.getAvailableDataFlavors().length));
+        for (DataFlavor f: systemClipboard.getAvailableDataFlavors()) {
+            System.out.println("  " + f.getHumanPresentableName() + "  " + f.toString());
+        }
+
+        // Check if we can get the data as a string
+        if (systemClipboard.isDataFlavorAvailable(DataFlavor.stringFlavor)) {
+            System.out.println("PASTE: DataFlavor.stringFlavor available");
+            try {
+                // Grab the data, set our text area to the data
+                String theText = (String)systemClipboard.getData(DataFlavor.stringFlavor);
+                textArea.replaceSelection(theText);
+                System.out.println("PASTE: '" + theText + "'");
+            } catch (UnsupportedFlavorException e) {
+                e.printStackTrace();
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        } else {
+            System.out.println("PASTE: DataFlavor.stringFlavor NOT available");
+        }
+    }
+
+    // Implement the ClipboardOwner interface
+    public void lostOwnership(Clipboard clipboard, Transferable contents) {
+        System.out.println("ClipboardOwner: lost clipboard ownership");
+    }
+
+    public static void main(String[] args) {
+        JFrame f = new JFrame("Clipboard");
+        f.getContentPane().add(new ClipboardDemo());
+        f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
+        f.pack();
+        f.setVisible(true);
+    }
+}
diff --git a/java/3-5-Clipboard/DragAndDropDemo.java b/java/3-5-Clipboard/DragAndDropDemo.java
new file mode 100644
index 0000000000000000000000000000000000000000..3e7521b3f3f52a66dd52475ca778fa3c1240e9cd
--- /dev/null
+++ b/java/3-5-Clipboard/DragAndDropDemo.java
@@ -0,0 +1,180 @@
+import java.awt.*;
+import java.awt.datatransfer.DataFlavor;
+import java.awt.datatransfer.Transferable;
+import java.awt.datatransfer.UnsupportedFlavorException;
+import java.io.IOException;
+import java.io.File;
+
+import javax.swing.*;
+import javax.swing.event.MouseInputAdapter;
+import java.awt.event.MouseEvent;
+
+public class DragAndDropDemo extends JPanel {
+
+    private JLabel imageLabel;
+    private Image image;
+
+    public DragAndDropDemo() {
+
+        setLayout(new GridLayout());
+
+        // drag target
+        imageLabel = new JLabel("", SwingConstants.CENTER);
+        imageLabel.setBackground(Color.WHITE);
+        imageLabel.setOpaque(true);
+        add(imageLabel);
+
+        imageLabel.setTransferHandler(new ImageTransferHandler());
+
+        // create a drag gesture
+        DragGesture dg = new DragGesture();
+        imageLabel.addMouseListener(dg); // For mouseDragged
+        imageLabel.addMouseMotionListener(dg); // For mouseReleased
+    }
+
+    // create an image transfer handler
+    private class ImageTransferHandler extends TransferHandler {
+
+        protected Transferable createTransferable(JComponent c) {
+
+            System.out.println("Creating Transferable");
+
+
+            return new Transferable() {
+
+                public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
+                    if (flavor.equals(DataFlavor.imageFlavor)) {
+                        System.out.println("getTransferData: " + image);
+                        ImageIcon icon = (ImageIcon)imageLabel.getIcon();
+                        if(icon != null){                            
+                            return icon.getImage();
+                        }else{
+                            return null;
+                        }
+                    }
+                    throw new UnsupportedFlavorException(flavor);
+                }
+
+                public DataFlavor[] getTransferDataFlavors() {
+                    return new DataFlavor[] { DataFlavor.imageFlavor };
+                }
+
+                public boolean isDataFlavorSupported(DataFlavor flavor) {
+                    return flavor.equals(DataFlavor.imageFlavor);
+                }
+            };
+        }
+
+
+        public int getSourceActions(JComponent c) {
+            return TransferHandler.COPY;
+        }
+
+        public boolean importData(JComponent c, Transferable t) {
+            System.out.print("importData: ");
+            JLabel label = (JLabel)c;
+
+            imageLabel.setBackground(Color.WHITE);
+
+            if (t.isDataFlavorSupported(DataFlavor.imageFlavor)) {
+
+                System.out.println("imageFlavour");
+
+                try {
+                    // Get the data and set our label's image icon to the new image.
+                    // Save a copy of the image so we can support dragging it out
+                    image = (Image)t.getTransferData(DataFlavor.imageFlavor);
+
+                    label.setIcon(new ImageIcon(image));
+                } catch (UnsupportedFlavorException e) {
+                    e.printStackTrace();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+                return true;
+
+            } else if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
+                System.out.println("javaFileListFlavour");
+
+                try {
+                    // Get the data and set our label's image icon to the new image.
+                    java.util.List<File> files = (java.util.List<File>) t.getTransferData(DataFlavor.javaFileListFlavor);
+                    File f = files.get(0);
+
+                    System.out.println("filePath: " + f.getAbsolutePath());
+                    ImageIcon iIcon = new ImageIcon(f.getAbsolutePath());
+                    image = iIcon.getImage();
+                    imageLabel.setIcon(iIcon);
+                } catch (UnsupportedFlavorException e) {
+                    e.printStackTrace();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+                return true;
+            }
+
+            System.out.println("rejecting");
+            return false;
+        }
+
+        public boolean canImport(JComponent c, DataFlavor[] transferFlavors) {
+
+            for(int i = 0; i < transferFlavors.length; i++) {
+                DataFlavor df = transferFlavors[i];
+                if (df.equals(DataFlavor.imageFlavor) || 
+                    df.equals(DataFlavor.javaFileListFlavor)) {
+                    // feedback to show CAN drag into widget
+                    imageLabel.setBackground(Color.GREEN.brighter());
+                    return true;
+                }
+            }
+            // feedback to show CAN'T drag into widget
+            imageLabel.setBackground(Color.RED.brighter());
+            return false;
+        }
+
+        protected void exportDone(JComponent c, Transferable data, int action) {
+            imageLabel.setBackground(Color.WHITE);
+            System.out.println("exportDone");
+        }
+
+    }
+
+    // A simple recognizer for the drag gesture
+    // The mouseDragged method is called whenever the mouse button is down and
+    // the mouse is moving. We only want to initiate drag & drop, for each drag
+    // gesture. As such, we only take action the first time mouseDragged is called,
+    // resetting whenever the mouse button is released.
+    private class DragGesture extends MouseInputAdapter {
+
+        private boolean armed = true;
+
+        public void mouseDragged(MouseEvent e) {
+
+            // Enter the conditional only once, at the start of the drag
+            if (armed) {
+                System.out.println("Drag starting");
+
+                // Initiate drag and drop
+                JComponent c = (JComponent)e.getSource();
+                TransferHandler handler = c.getTransferHandler();
+                handler.exportAsDrag(c, e, TransferHandler.COPY);
+
+                armed = false;
+            }
+        }
+
+        public void mouseReleased(MouseEvent e) {
+            // Get ready for the next drag
+            armed = true;
+        }
+    }
+
+    public static void main(String[] args) {
+        JFrame f = new JFrame("DragAndDropDemo");
+        f.setSize(200, 200);
+        f.getContentPane().add(new DragAndDropDemo());
+        f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
+        f.setVisible(true);
+    }
+}
diff --git a/java/3-5-Clipboard/makefile b/java/3-5-Clipboard/makefile
new file mode 100644
index 0000000000000000000000000000000000000000..ba8e39c7083b6038edaa41c98d2807f924a74f84
--- /dev/null
+++ b/java/3-5-Clipboard/makefile
@@ -0,0 +1,15 @@
+# super simple makefile
+# call it using 'make NAME=name_of_code_file_without_extension'
+# (assumes a .java extension)
+NAME = "ClipboardDemo"
+
+all:
+	@echo "Compiling..."
+	javac *.java
+
+run: all
+	@echo "Running..."
+	java $(NAME)
+
+clean:
+	rm -rf *.class
diff --git a/java/3-5-Clipboard/transferDemo/DragableImage.java b/java/3-5-Clipboard/transferDemo/DragableImage.java
new file mode 100644
index 0000000000000000000000000000000000000000..485d8ff9ddbd65692f9a302e1927cbae58359c07
--- /dev/null
+++ b/java/3-5-Clipboard/transferDemo/DragableImage.java
@@ -0,0 +1,157 @@
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.event.MouseInputAdapter;
+
+/*
+ * A DragableImage displays an image and handles drag-and-drop data transfer.
+ */
+class DragableImage extends JComponent {
+
+	private Image image;
+
+	/* Create a image using either getImageFromFile or getEmptyImage */
+    private DragableImage(Image image) {
+        super();
+		this.image = image;
+		this.setFocusable(true);
+		
+		DragGesture dg = new DragGesture();
+		this.addMouseListener(dg);
+        this.addMouseMotionListener(dg);
+		this.addFocusListener(new HighlightWhenFocusedListener());
+    }
+    
+    /* Get an empty image (displays nothing) */
+    public static DragableImage getEmptyImage() {
+    	return new DragableImage(null);
+    }
+    
+    /* Get a image from an image file. */
+    public static DragableImage getImageFromFile(String path) {
+    	if (path == null) {
+    		return new DragableImage(null);
+    	}
+    	
+        java.net.URL imageURL = TransferDemo.class.getResource(path);
+
+        if (imageURL == null) {
+            System.err.println("Resource not found: " + path);
+            return new DragableImage(null);
+        } else {
+            return new DragableImage(new ImageIcon(imageURL, path).getImage());
+        }
+    }
+
+    public void setImage(Image image) {
+        this.image = image;
+        this.repaint();
+    }
+
+    public Image getImage() {
+        return this.image;
+    }
+    
+
+	protected void paintComponent(Graphics graphics) {
+		Graphics g = graphics.create();
+
+		// Draw in our entire space, even if isOpaque is false.
+		g.setColor(Color.WHITE);
+		g.fillRect(0, 0, image == null ? 125 : image.getWidth(this),
+				image == null ? 125 : image.getHeight(this));
+
+		if (image != null) {
+			// Draw image at its natural size of 125x125.
+			g.drawImage(image, 0, 0, this);
+		}
+
+		// Add a border, red if image currently has focus
+		if (this.isFocusOwner()) {
+			g.setColor(Color.RED);
+		} else {
+			g.setColor(Color.BLACK);
+		}
+		g.drawRect(0, 0, image == null ? 125 : image.getWidth(this),
+				image == null ? 125 : image.getHeight(this));
+		g.dispose();
+	}
+	
+	class HighlightWhenFocusedListener implements FocusListener {
+		public void focusGained(FocusEvent e) {
+			// Draw the component with a red border
+			// indicating that it has focus.
+			DragableImage.this.repaint();
+		}
+
+		public void focusLost(FocusEvent e) {
+			// Draw the component with a black border
+			// indicating that it doesn't have focus.
+			DragableImage.this.repaint();
+		}
+
+	}
+	
+	/*---------------------- Drag and Drop support ----------------------*/
+	
+	// MouseInputAdapter implements and provides default methods for 
+	// both MouseListener and MouseMotionListener interfaces.
+	class DragGesture extends MouseInputAdapter {
+	    private MouseEvent firstMouseEvent = null;
+
+	    public void mouseClicked(MouseEvent e) {
+			// Since the user clicked on us, let's get focus!
+			requestFocusInWindow();
+		}	
+		
+	    public void mousePressed(MouseEvent e) {
+
+	        // Don't bother to drag if there is no image.
+	        if (DragableImage.this.image == null) return;
+
+	        firstMouseEvent = e;
+
+	        // prevent any other listeners from acting on this event
+	        e.consume();
+	    }
+	    
+	    public void mouseReleased(MouseEvent e) {
+	        firstMouseEvent = null;
+	    }
+
+	    public void mouseDragged(MouseEvent e) {
+
+            // Don't bother to drag if the component displays no image.
+            if (DragableImage.this.image == null) return;
+
+            if (firstMouseEvent != null) {
+            	// prevent other listeners from acting on this event
+                e.consume();
+
+                int dx = Math.abs(e.getX() - firstMouseEvent.getX());
+                int dy = Math.abs(e.getY() - firstMouseEvent.getY());
+
+                // Arbitrarily define a 5-pixel shift as the
+                // official beginning of a drag.
+                if (dx > 5 || dy > 5) {
+                    // This is a drag, not a click.
+
+                    // If they are holding down the control key, COPY rather than MOVE
+                    int ctrlMask = InputEvent.CTRL_DOWN_MASK;
+                    int action = ((e.getModifiersEx() & ctrlMask) == ctrlMask) ?
+                          TransferHandler.COPY : TransferHandler.MOVE;
+
+                    // drag transfer setup
+                    JComponent c = (JComponent)e.getSource();
+                    TransferHandler handler = c.getTransferHandler();
+                    
+                    // Tell the transfer handler to initiate the drag.
+                    handler.exportAsDrag(c, firstMouseEvent, action);
+
+                    firstMouseEvent = null;
+                }
+            }
+        }	
+	}
+
+}
diff --git a/java/3-5-Clipboard/transferDemo/ImageGridPanel.java b/java/3-5-Clipboard/transferDemo/ImageGridPanel.java
new file mode 100644
index 0000000000000000000000000000000000000000..b391829fcbc8d8acbbbf5371e0bff67bba060e36
--- /dev/null
+++ b/java/3-5-Clipboard/transferDemo/ImageGridPanel.java
@@ -0,0 +1,243 @@
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.FlowLayout;
+import java.awt.GridLayout;
+import java.awt.Image;
+import java.awt.Toolkit;
+import java.awt.datatransfer.Clipboard;
+import java.awt.datatransfer.DataFlavor;
+import java.awt.datatransfer.Transferable;
+import java.awt.datatransfer.ClipboardOwner;
+import java.awt.datatransfer.UnsupportedFlavorException;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
+import java.awt.event.KeyEvent;
+import java.io.IOException;
+
+import javax.swing.BorderFactory;
+import javax.swing.JButton;
+import javax.swing.JMenu;
+import javax.swing.JMenuBar;
+import javax.swing.JMenuItem;
+import javax.swing.JPanel;
+import javax.swing.KeyStroke;
+
+public class ImageGridPanel extends JPanel implements ClipboardOwner {
+
+	// Show up to 12 images
+	private DragableImage[] pics = new DragableImage[12];
+
+	// Data to load images into some of the 12 images.
+	private String[] picNames =
+			new String[] { "angry", "happy", "worried",  "laughing" };
+
+	// currently selected image index (-1 if none selected)
+	private int selectedPic = -1;
+	
+	// Buttons to make Cut/Copy/Paste visible
+	private JButton cutButton = new JButton("Cut");
+	private JButton copyButton = new JButton("Copy");
+	private JButton pasteButton = new JButton("Paste");
+
+	public ImageGridPanel() {
+		super(new BorderLayout());
+		this.layoutComponent();
+		this.registerControllers();
+	}
+	
+	private void layoutComponent() {
+
+		JPanel images = new JPanel(new GridLayout(3, 4));
+
+		for (int i = 0; i < this.pics.length; i++) {
+			if (i < this.picNames.length) {
+				this.pics[i] = DragableImage.getImageFromFile("images/"
+						+ picNames[i] + ".jpg");
+			} else {
+				this.pics[i] = DragableImage.getEmptyImage();
+			}
+			images.add(this.pics[i]);
+		}
+		this.add(images, BorderLayout.CENTER);
+
+		this.setPreferredSize(new Dimension(630, 520));
+		this.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
+
+		// out cut/copy/paste buttons into bottom panel
+		JPanel buttons = new JPanel(new FlowLayout(FlowLayout.LEFT));
+
+		buttons.add(cutButton);
+		buttons.add(copyButton);
+		buttons.add(pasteButton);
+
+		this.add(buttons, BorderLayout.NORTH);
+		
+	}
+	
+	private void registerControllers() {
+		// The transfer handler handles the drag-drop and cut-paste
+		// infrastructure
+		ImageTransferHandler picHandler = new ImageTransferHandler();
+		// This maintains the index of the currently selected image
+		// (this.selectedPic)
+		FocusListener fl = new PicFocusListener();
+		
+		for (int i = 0; i < this.pics.length; i++) {
+			this.pics[i].setTransferHandler(picHandler);
+			this.pics[i].addFocusListener(fl);
+		}
+		
+		cutButton.addActionListener(new ActionListener() {
+			public void actionPerformed(ActionEvent e) {
+				doCut();
+			}
+		});
+		
+		copyButton.addActionListener(new ActionListener() {
+			public void actionPerformed(ActionEvent e) {
+				doCopy();
+			}
+		});
+		
+		pasteButton.addActionListener(new ActionListener() {
+			public void actionPerformed(ActionEvent e) {
+				doPaste();
+			}
+		});
+
+	}
+	
+	// Called when this component no longer owns the clipboard
+	public void lostOwnership(Clipboard clipboard, Transferable contents) {
+		System.out.println("Lost clipboard ownership for " + selectedPic);
+	}
+	
+
+	/*
+	 * Copy the currently selected image.
+	 */
+	private void doCopy() {
+
+		// Get the system clipboard
+		Clipboard systemClipboard = Toolkit.getDefaultToolkit()
+				.getSystemClipboard();
+
+		// Create a transferable object encapsulating all the info for the copy
+		Transferable transferObject = new ImageTransferable(pics[selectedPic]);
+
+		// Now set the contents of the clipboard to our transferable object
+		systemClipboard.setContents(transferObject, this);
+		
+	}
+
+	private void doCut() {
+		this.doCopy(); // most of a cut is the same as a copy
+		this.pics[selectedPic].setImage(null);
+	}
+
+	private void doPaste() {
+
+		// Grab system clipboard
+		Clipboard systemClipboard = Toolkit.getDefaultToolkit()
+				.getSystemClipboard();
+
+		// For our own edification, print out the data formats available on the
+		// clipboard
+		for (DataFlavor flavor : systemClipboard.getAvailableDataFlavors()) {
+			System.out.println("Flavor: " + flavor);
+		}
+
+		// Check if we can get the data as an image
+		if (systemClipboard.isDataFlavorAvailable(DataFlavor.imageFlavor)) {
+			try {
+				// Grab the data, set the selected image to the provided image
+				Image img = (Image) systemClipboard
+						.getData(DataFlavor.imageFlavor);
+				assert img != null;
+				this.pics[selectedPic].setImage(img);
+			} catch (UnsupportedFlavorException e) {
+				e.printStackTrace();
+			} catch (IOException e) {
+				e.printStackTrace();
+			}
+		}
+	}
+
+	/*
+	 * A listener to help us keep track of which image has been selected.
+	 */
+	class PicFocusListener implements FocusListener {
+		public void focusGained(FocusEvent e) {
+			Component c = e.getComponent();
+			for (int i = 0; i < pics.length; i++) {
+				if (pics[i] == c) {
+					selectedPic = i;
+					return;
+				}
+			}
+			assert false;
+		}
+
+		public void focusLost(FocusEvent e) {
+		}
+	}
+
+
+	/*
+	 * Create a set of cut/copy/paste menus. They call doCopyOrCut and doPaste.
+	 */
+	public JMenuBar createMenuBar() {
+		JMenuBar menubar = new JMenuBar();
+
+		JMenu file = new JMenu("File");
+
+		JMenuItem quit = new JMenuItem("Quit");
+		quit.addActionListener(new ActionListener() {
+			public void actionPerformed(ActionEvent e) {
+				System.exit(0);
+			}
+		});
+		quit.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Q,
+				ActionEvent.META_MASK));
+		file.add(quit);
+
+		JMenu edit = new JMenu("Edit");
+		JMenuItem cut = new JMenuItem("Cut");
+		cut.addActionListener(new ActionListener() {
+			public void actionPerformed(ActionEvent e) {
+				doCut();
+			}
+		});
+		cut.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_X,
+				ActionEvent.META_MASK));
+
+		JMenuItem copy = new JMenuItem("Copy");
+		copy.addActionListener(new ActionListener() {
+			public void actionPerformed(ActionEvent e) {
+				doCopy();
+			}
+		});
+		copy.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C,
+				ActionEvent.META_MASK));
+
+		JMenuItem paste = new JMenuItem("Paste");
+		paste.addActionListener(new ActionListener() {
+			public void actionPerformed(ActionEvent e) {
+				doPaste();
+			}
+		});
+		paste.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_V,
+				ActionEvent.META_MASK));
+
+		edit.add(cut);
+		edit.add(copy);
+		edit.add(paste);
+
+		menubar.add(file);
+		menubar.add(edit);
+		return menubar;
+	}
+}
diff --git a/java/3-5-Clipboard/transferDemo/ImageTransferHandler.java b/java/3-5-Clipboard/transferDemo/ImageTransferHandler.java
new file mode 100644
index 0000000000000000000000000000000000000000..fe31ebd78158ada0ded8be5ddeaf0ed55944d7b1
--- /dev/null
+++ b/java/3-5-Clipboard/transferDemo/ImageTransferHandler.java
@@ -0,0 +1,87 @@
+import java.io.*;
+import java.awt.*;
+import java.awt.datatransfer.*;
+import javax.swing.*;
+import java.util.List;
+
+class ImageTransferHandler extends TransferHandler {
+
+    DragableImage sourceImage;
+    boolean shouldRemove;
+
+    /* 
+     * Can we import one of the flavors provided? 
+     */
+    public boolean canImport(JComponent c, DataFlavor[] flavors) {
+        for (int i = 0; i < flavors.length; i++) {
+            if (flavors[i].equals(DataFlavor.imageFlavor) ||
+                    flavors[i].equals(DataFlavor.javaFileListFlavor)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /* 
+     * Import the data from the transferable to the component.
+     */
+    public boolean importData(JComponent c, Transferable t) {
+        Image image;
+        if (canImport(c, t.getTransferDataFlavors())) {
+            DragableImage dragableImage = (DragableImage)c;
+            //Don't drop on myself.
+            if (sourceImage == dragableImage) {
+                shouldRemove = false;
+                return true;
+            }
+            
+            try {
+            	if (t.isDataFlavorSupported(DataFlavor.imageFlavor)) {
+            		image = (Image)t.getTransferData(DataFlavor.imageFlavor);
+            	} else if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
+                	List<File> files = (List<File>) t.getTransferData(DataFlavor.javaFileListFlavor);
+                    File f = files.get(0);
+                	ImageIcon iIcon = new ImageIcon(f.getAbsolutePath());
+                    image = iIcon.getImage();
+            	} else {
+            		image = null;	// assure compiler everything was initialized
+            		assert false;
+            	}
+                //Set the component to the new image.
+                dragableImage.setImage(image);
+                return true;
+            } catch (UnsupportedFlavorException ufe) {
+                System.out.println("importData: unsupported data flavor");
+            } catch (IOException ioe) {
+                System.out.println("importData: I/O exception");
+            }
+        }
+        return false;
+    }
+
+    /* 
+     * What kinds of drag actions can we support?
+     */
+    public int getSourceActions(JComponent c) {
+        return COPY_OR_MOVE;
+    }
+
+    /*
+     * Create a transferable to drag somewhere else.
+     */
+    protected Transferable createTransferable(JComponent c) {
+        sourceImage = (DragableImage)c;
+        shouldRemove = true;
+        return new ImageTransferable(sourceImage);
+    }
+
+    /*
+     * Finish the export.
+     */
+    protected void exportDone(JComponent c, Transferable data, int action) {
+        if (shouldRemove && (action == MOVE)) {
+            sourceImage.setImage(null);
+        }
+        sourceImage = null;
+    }
+}
diff --git a/java/3-5-Clipboard/transferDemo/ImageTransferable.java b/java/3-5-Clipboard/transferDemo/ImageTransferable.java
new file mode 100644
index 0000000000000000000000000000000000000000..93db6945fa05c224f530db7d11b2bdcaa8dea5de
--- /dev/null
+++ b/java/3-5-Clipboard/transferDemo/ImageTransferable.java
@@ -0,0 +1,33 @@
+import java.awt.Image;
+import java.awt.datatransfer.DataFlavor;
+import java.awt.datatransfer.Transferable;
+import java.awt.datatransfer.UnsupportedFlavorException;
+
+/*
+ * Transfer an image from one source to another.
+ */
+public class ImageTransferable implements Transferable {
+
+    private Image image;
+
+    ImageTransferable(DragableImage pic) {
+        image = pic.getImage();
+    }
+
+    public Object getTransferData(DataFlavor flavor)
+        throws UnsupportedFlavorException {
+        if (!isDataFlavorSupported(flavor)) {
+            throw new UnsupportedFlavorException(flavor);
+        } 
+        return image;
+    }
+
+    public DataFlavor[] getTransferDataFlavors() {
+        return new DataFlavor[] { DataFlavor.imageFlavor };
+    }
+
+    public boolean isDataFlavorSupported(DataFlavor flavor) {
+        return flavor.equals(DataFlavor.imageFlavor);
+    }
+}
+
diff --git a/java/3-5-Clipboard/transferDemo/TransferDemo.java b/java/3-5-Clipboard/transferDemo/TransferDemo.java
new file mode 100644
index 0000000000000000000000000000000000000000..9fe21f1ecce61a1af26602db47b1ec9b8a6a9903
--- /dev/null
+++ b/java/3-5-Clipboard/transferDemo/TransferDemo.java
@@ -0,0 +1,59 @@
+/*
+ * This demo started life as part of Sun's Java Tutorial for Drag and Drop/Cut and Paste.
+ * The tutorial had already been updated to Java 6 (which includes changes to
+ * TransferHandler that I didn't want to use yet), so a cached version was found
+ * at http://mockus.us/optimum/JavaTutorial/mustang/uiswing/dnd/examples/index.html#DragPictureDemo
+ * (retrieved June 17, 2009).
+ * 
+ * It was modified by Byron Weber Becker as follows:
+ * -- code to initialize the pictures was simplified with an array and loop
+ * -- removed unused imports 
+ * -- used inner classes for listeners rather than exposing the
+ *    methods in a class's public interface
+ * -- there were funny inheritance interactions between DragablePicture and Picture
+ *    in the mouse and mousemotion listeners, so combined the two classes
+ * -- added support for the javaFileList data flavor, enabling drag 'n drop
+ *    from the desktop and to other applications such as image editors
+ * -- removed the copy/cut/paste magic using action maps and the automatic 
+ *    stuff in TransferHandler and replaced it with direct and easier to
+ *    understand implementations.
+ */
+
+import javax.swing.*;
+
+public class TransferDemo  {
+
+    /**
+     * Create the GUI and show it.  For thread safety,
+     * this method should be invoked from the
+     * event-dispatching thread.
+     */
+    private static void createAndShowGUI() {
+
+        //Create and set up the window.
+        JFrame frame = new JFrame("TransferDemo");
+        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+
+        //Create and set up the menu bar and content pane.
+        ImageGridPanel demo = new ImageGridPanel();
+        frame.setContentPane(demo);
+        frame.setJMenuBar(demo.createMenuBar());
+        
+        //Display the window.
+        frame.pack();
+        frame.setVisible(true);
+    }
+
+    public static void main(String[] args) {
+    	System.out.println("You may need to copy the images directory from the");
+    	System.out.println("source code directory to the same directory as TransferDemo.class.");
+
+        //Schedule a job for the event-dispatching thread:
+        //creating and showing this application's GUI.
+        javax.swing.SwingUtilities.invokeLater(new Runnable() {
+            public void run() {
+                createAndShowGUI();
+            }
+        });
+    }
+}
diff --git a/java/3-5-Clipboard/transferDemo/images/angry.jpg b/java/3-5-Clipboard/transferDemo/images/angry.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..8286039b09faa546c59143feb6ffcfe59f04e9da
Binary files /dev/null and b/java/3-5-Clipboard/transferDemo/images/angry.jpg differ
diff --git a/java/3-5-Clipboard/transferDemo/images/happy.jpg b/java/3-5-Clipboard/transferDemo/images/happy.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..b090961235515ac0abf7531a1b66c6dc83b198b5
Binary files /dev/null and b/java/3-5-Clipboard/transferDemo/images/happy.jpg differ
diff --git a/java/3-5-Clipboard/transferDemo/images/laughing.jpg b/java/3-5-Clipboard/transferDemo/images/laughing.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..f61710e418ed865e9b205f28cbb0c34b15f7697b
Binary files /dev/null and b/java/3-5-Clipboard/transferDemo/images/laughing.jpg differ
diff --git a/java/3-5-Clipboard/transferDemo/images/worried.jpg b/java/3-5-Clipboard/transferDemo/images/worried.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..4e71289d3de7fe3691244ddddb4caa17edd77747
Binary files /dev/null and b/java/3-5-Clipboard/transferDemo/images/worried.jpg differ
diff --git a/java/3-5-Clipboard/transferDemo/makefile b/java/3-5-Clipboard/transferDemo/makefile
new file mode 100644
index 0000000000000000000000000000000000000000..5c951d0c89b7875b3efd389d117b3299ce77cf76
--- /dev/null
+++ b/java/3-5-Clipboard/transferDemo/makefile
@@ -0,0 +1,15 @@
+# super simple makefile
+# call it using 'make NAME=name_of_code_file_without_extension'
+# (assumes a .java extension)
+NAME = "TransferDemo"
+
+all:
+	@echo "Compiling..."
+	javac $(NAME).java
+
+run: all
+	@echo "Running..."
+	java $(NAME)
+
+clean:
+	rm -rf *.class