Archive for the ‘regular’ Category

Synergy – free mouse/keyboard sharing across operating systems

November 11, 2010 2 comments

Any sufficiently advanced technology is indistinguishable from magic

-Arthur Clarke

I love technology.  I especially love discovering and using technology that makes me more productive.  I’m writing about a piece of software called Synergy that allows you to use one mouse and keyboard to control multiple computers, each of which may be running different operating systems.  In my case, my primary display is for my Mac, and a secondary display off to the right is connected to a Windows PC.  Previously, any time I needed to use the Windows machine I had to unplug the USB cable powering the keyboard/mouse combo and physically plug it into the windows machine.  (Alternatively I could have bought an extra keyboard and mouse and had to juggle with the physical hardware.) If I needed to transfer text (e.g. a sourcecode snippet) from one machine to the other, I would have to resort to shuttling files or e-mailing it to myself.

By using Synergy, the mouse no longer stops at the right edge of my Mac display.  Instead, the cursor continues to move to the right, onto the Windows desktop.  Suddenly both your mouse and keyboard control the PC.  If you copy text from a file on Windows and revert to controlling the Mac by moving the cursor back to the left, the text is in your Mac clipboard.

That’s not to say that Synergy is perfect.  The main problem is that certain key combinations on the Windows side do not transfer correctly.  For instance, Ctrl + Alt + Delete is pretty necessary in Windows land, but pressing those keys does not trigger the corresponding action.  The Synergy FAQ page has this issue at the very top, but none of the workarounds work for me.  I’ve noticed the following keys do not get sent over correctly:

Key combo Description
Ctrl Alt Delete Bring up task manager
Print screen Take a screen shot of desktop
Windows + Any other key (Windows L = Lock, Windows D = show desktop/hide all windows)

Other limitations I’ve seen are as follows:

  • Pasting is limited to plain text (e.g. you can’t copy an image from one computer to the other).
  • You can’t drag and drop files between the screens (this would be awesome); instead best workaround I can find is to have a networked folder accessible to both computers and use it as a dropbox to ferry around files.  It’s a bit kludgy but it works.

Each computer will need to install the software and be accessible on the same network.  The computer into which the mouse and keyboard are plugged should be the Server.  Each of the computers that you wish to control via the mouse and keyboard need to be running the Client software and connect to the server, and the server needs a configuration file which tells it how the screens are physically located (which computer is to the left of which, which is above, etc.)

Finally, there’s a bit of work you need to do to get it to work on windows vista/ 7 – see here for the details.

This is a really great piece of free software, and it allows me to do my job more effectively.  I hope you find it useful as well.

Human fallibility – static analysis tools

February 9, 2010 5 comments

The theme of this post is human fallibility: no one’s perfect and we’re bound to make mistakes while coding.  The following tools can help statically analyze source or markup and find mistakes early.


I am a huge fan of Python as a scripting language, as its syntax and language features allow you to code quickly and with minimal fuss. (I will definitely use it as a springboard for future blog discussion, especially with respect to its differences from Java).  I am used to statically compiled languages like the aforementioned Java, where the compiler will catch typos and uses of uninitialized variables; not having this ability in Python always makes me feel a bit hesitant to use it for more than quick scripts and small programming tasks.  (Clearly Python is well-suited to large scale production environments; this is more my hangup and lack of expertise in the language than anything else.)

Enter PyChecker, an open-source project that aims to detect some of the most common coding mistakes, including references to variables before assignment, passing wrong numbers of arguments to functions, and calling methods that don’t exist.   It won’t find all your mistakes, but if you have any long-running Python scripts, you’d much prefer to catch a typo before you start running than 90% through the computation.


JSON is an alternative to XML as a “lightweight data-interchange format”.  Unlike XML with its opening and closing angle brackets, JSON has a very clean syntax with few extraneous marks.  Here’s an example JSON file:

    "number": 1,
    "array": [
            "nested list"
    "birthdayMap": {
        "Nick": "3/24",
        "Andrew": "12/1"

I was working on a project using JSON as its means of representing data when I ran into problems with my hand-generated JSON – I had made mistakes, omitting brackets, not closing quotation marks, or other silly mistakes.  The Java library I was using to parse the JSON read in the whole file as a String, meaning all the contextual information was lost.  When an error ocurred, I was left with a cryptic error message like “syntax error, unexpected $end, expecting ‘}’ at character 2752” with no idea where in the file the error lay.

Thanks to my coworker Dave, I found the excellent tool JSONLint which not only highlights the exact line and location of your syntax error, it also reformats your JSON to a consistent amount of indentation for each nested level.  JSONLint is indispensible if you’re fat-fingering your JSON code.


PMD is a plugin for NetBeans, Eclipse, and a host of other Java IDEs and standard text editors that warns you of bad coding practices in your source code, as well as alerting you to potential errors.  There are a variety of rules specified in either XQuery notation or Java code that can be turned on and off at will; for instance if you are doing a lot of coding with interfaces to C and need to use shorts and bytes, you probably won’t want the “Don’t use shorts” warning popping up on every line you use a short in.

Some of the most useful rules I’ve found are the fall through in switch statements,
Not all of the rules are cut-and-dried, which the website acknowledges with the addition of a Controversial Rules section.  Some might be due to stylistic differences or just disagreements over whether or not certain constructs are bad practice.  For instance,


Since: PMD 1.0

A method should have only one exit point, and that should be the last statement in the method.

This rule is defined by the following Java class:


public class OneReturnOnly1 {
    public void foo(int x) {
        if (x > 0) {
            return "hey"; // oops, multiple exit points!
        return "hi";

Doing a search for “java multiple exit points” reveals that there is definitely a lot of discussion as to best practices in this regard, hence its inclusion in the Controversial Rules section.

Hopefully you’ve gained at least one new tool from this post; if not I’ll be posting more in days to come.

Apache Log4j

February 3, 2010 1 comment

Apache Log4J

This is the second Java library I’ve mentioned (the first was Apache Commons Primitives), and it won’t be the last.

Apache Log4J is a logging system that is designed to have the same interface as java.util.Logging’s (the faq suggests a find and replace of all the util.Logger calls with org.apache.log4j.Logger will do the trick).

Why should you use a logging framework rather than System.out.println / System.err.println calls throughout your code? Here are a few reasons

  • Ability to specify the level of detail of a message, whether it is a warning vs an error vs a debug statement. With this granularity you can filter out all but a certain level of messages so as to avoid scroll blindness when too much is being printed out to the screen.
  • Ability to configure the logger at run time without changing the binary as to whether or not certain logging is performed.
  • You get more information about when and where a logged statement came from. By default you get the time the statement was logged, as well as name of the logger that logged the message (which, if you follow the Log4j suggestion to use the class name of the file containing the logger, will tell you where the statement came from)
  • It will prepare you for developing for the Android operating system, where you cannot just call System.out.println and have it appear in a terminal. I learned about logging from Android before finding out about this log4j library; they have very similar syntax, though with slightly more succint method names
  • You can customize the way objects are rendered as text by the logger via an ObjectRenderer instance

Here’s some source code to get you started:

// Similar to the example from

// with additional comments

public class TestLogging {

    // Idiomatic way of getting one logger per class; will automatically

    // extract class name etc from this .class object

    private static final Logger logger = Logger.getLogger(TestLogging.class);

    public static void main(String[] args) {

        // This call is necessary somewhere to actually hook up the Logger's

        // with sensible default values.  If you don't need course grained

        // control over what is logged, this is sufficient.  Output

        // will go to standard out (terminal) after this command.


        logger.error("There was an error");

        logger.warn("Warning");"Informational message");

        logger.debug("Debug message");

        logger.trace("Really, really fine grained detail")



I haven’t learned all the ins and outs of the library yet, but it definitely seems a bit more scalable and professional than having print statements littered throughout the code base. Furthermore, the library was designed with speed in mind so the cost of logging statements is barely more than simply dumping it to standard out.

Categories: Java, programming, regular Tags: ,

How to make a solar system: Introduction to affine transformations and Java 2D

February 2, 2010 5 comments

At the heart of all computer graphics lies linear algebra, and specifically matrix multiplication. One can use matrices to perform all sorts of operations, such as transformations to move from one coordinate system to another, as well as a set known as affine transformations. Affine transformations are those that map lines to lines in the transformed coordinate space, and which preserve the relative distance between points. An affine transformation consists of one or more translation, rotation, scaling, and shearing transformations.

See the following external sites for translation and rotation examples, shearing, scaling.

Java has a class to represent these affine transformations, as well as shorthand methods to apply them to a Graphics2D context.

Rotate about origin
Rotate about a point
Scale x and y axis by given amount

If you do any work involving Graphics2D in Java (and if you work with Swing components, you implicitly do), knowing how to use affine transforms is extremely beneficial. With them you can express and code things more succintly, and clearly than is possible without them.

We’ll start with a simple example, once with standard Swing painting code, and once using affine transformations. Finally we will end with a more fully fleshed out example that really illustrates the power of affine transformations, rendering a simplified overhead view of the solar system. This example would be extremely difficult to replicate without affine transformations.

For the simple example, let’s draw dots in a circle pattern. The easiest way to start drawing to the screen is simply to subclass the JComponent class and override the paintComponent(Graphics g) method. Here we go:

     * Draw a series of dots in a circular pattern
     * @param g
    public void paintComponent(Graphics g) {
        // Don't forget to call the super method

        int radius = getWidth() / 2;

        for (int i = 0; i < NUM_DOTS; i++) {
            double theta = 2 * Math.PI * ((double) i / NUM_DOTS);
            int x = (int) (radius * Math.cos(theta));
            int y = (int) (radius * Math.sin(theta));

            // these x and y are relative to center of circle; currently origin
            // is at upper left corner of window.  Add to x and y to
            // translate.
            x += getWidth() / 2;
            y += getHeight() / 2;

            g.drawOval(x, y, 1, 1);


Here’s a picture of the result.

(Full source)

Now, here’s that same code using the implicit affine transformation of the rotate() method of Graphics2D.

     * Draw a series of dots in a circular pattern
     * @param g
    public void paintComponent(Graphics g) {
        Graphics2D g2 = (Graphics2D) g;
        // Don't forget to call the super method

        int radius = getWidth()/2;

        // Translate the origin to the center of window
        g2.translate(getWidth() /2, getHeight() /2);
        for (int i = 0; i < NUM_DOTS; i++) {
            // We have rotated about the origin; draw a ray out along x axis
            // of new coordinate system
            g2.drawOval(radius, 0, 1, 1);


(Full Source)

As you can see from the screenshots, they come out functionally the same. In this case there’s not a huge advantage to using the rotation over the standard method. But what if we weren’t drawing dots along the radius of the circle, but instead were drawing rectangles that laid tangent to the circle? Here’s how simple that is to do using the rotations..

// Define the number of pixels wide each box is
private static final int BOX_SIZE = 5;

// Replace the call to drawOval with fillRect
g2.fillRect(radius, 0, BOX_SIZE, BOX_SIZE);

Here is the result

(Full source)

Think how complicated this would be to accomplish if you were not using affine transforms; you would need to manually calculate the coordinates of each corner of each box, create a polygon from those points, and then call fillShape on the polygon.

The other place where affine transformations shine is when you need to place objects relative to each other. For instance, you might draw a table with a bowl of fruit on it; if your table moves, you would like the bowl to move as well. I will show you how you can render a simplified version of the solar system where the earth revolves around the sun, while at the same time the moon orbits the earth. As you can imagine, implementing this without affine transformations would be absolutely infeasible.

First we separate our model from our view as per the model view controller pattern; the state of the solar system is kept in the model which the view uses to render itself. Since the state of the model will be observed by the view, we make it a subclass of the Java Observable class.

package solarsystem;

import java.util.Observable;

public class SolarSystemModel extends Observable {

    public static final int DAYS_PER_EARTH_REVOLUTION_AROUND_SUN = 365;
    public static final int HOURS_PER_EARTH_REVOLUTION_AROUND_AXIS = 24;

    // <a href=""></a>
    // "The orbit of the Moon around the Earth is completed in approximately 27.3 days"
    public static final float DAYS_PER_MOON_ORBIT_AROUND_EARTH = 27.3f;

    private int day;
    private int hour;

    public int getDay() {
        return day;

    public void setDay(int day) {
        int oldDay =; = clampDay(day);
        if (oldDay != {

    public int getHour() {
        return hour;

    public void setHour(int hour) {
        int oldHour = this.hour;
        this.hour = clampHour(hour);
        if (oldHour != this.hour) {

    private int clampDay(int day) {

    private int clampHour(int hour) {


(Note that we need to call setChanged() before notifyObservers() or our Observers registered with the model will not be updated.)

Now that we have our model defined, we need to make a view to actually render the solar system. Just as in our previous examples, I make the view extend JComponent for ease of display in a JFrame.

public class SolarSystemView extends JComponent implements Observer

The Observer interface allows classes to be notified when an Observable object changes; since we want to keep our view in sync with the model, this is just what we will do.

Here is the meat of the class:

        public void paintComponent(Graphics g) {
            Graphics2D g2 = (Graphics2D) g;


            // Set the origin to be in the center of the screen
            g2.translate(getWidth()/2, getHeight()/2);

            // Order matters, since the earth placement is dependent upon the sun
            // placement, and the moon placement is dependent upon the earth placement



The graphics context is passed into each drawing method, which may or may not modify the context. The drawSpaceBackdrop method merely draws a few random stars on a black background; see the following screenshot:

The code for that is fairly straightforward:

         * Draws a black backdrop with star field
         * @param g2
        private void drawSpaceBackdrop(Graphics2D g2) {
            // Draw background as black
            g2.fillRect(0, 0, getWidth(), getHeight());

            for (int i = 0; i &lt; NUM_STARS; i++) {
                g2.fillOval(starX[i], starY[i], starRadius[i], starRadius[i]);


starX, starY, starRadius are parallel int arrays that are initialized earlier in the program by a random int generator.

     * Creates and populates our arrays of star x values, star y values, and
     * star radii
     * @param width     what is max x value we should consider for star
     * @param height    what is max y value we should consider for star
    private void createStarField(int width, int height, int maxRadius) {
        // Create the arrays
        starX = new int[NUM_STARS];
        starY = new int[NUM_STARS];
        starRadius = new int[NUM_STARS];
        // Fill them in with random values
        for (int i = 0; i &lt; NUM_STARS; i++) {
            starX[i] = random.nextInt(width);
            starY[i] = random.nextInt(height);
            starRadius[i] = random.nextInt(maxRadius);

After initializing the arrays and drawing the stars, we then draw the sun. Note that we translate the origin from the upper left corner to the center of the screen; this allows each of the drawing methods to consider its own local coordinate system and not have to remember to translate from upper left corner of screen. For instance, the center of the sun is at (0,0) in its coordinate system.

         * @param g2 graphics context with (0,0) in center of screen (where sun will
         * be centered)
        private void drawSun(Graphics2D g2) {
            int sunRadius = (int) (SUN_RADIUS_PROPORTION * getWidth());
            GradientPaint sunColor = new GradientPaint(0, 0, Color.YELLOW, 0, sunRadius, Color.RED);
            g2.fillOval(-sunRadius/2, -sunRadius/2, sunRadius, sunRadius);

We apply a gradient just to make it look slightly nicer than a monochrome sun.

After having drawn the sun, it’s time to draw the earth.

         * Draws the earth to the screen, whose position is dependent upon the
         * day of the year
         * @param g2 the graphics context with its origin in the center of the sun
        private void drawEarth(Graphics2D g2) {
            // Draw the earth
            // Calculate what portion along its orbit the earth is, and thus how
            // far to rotate about our centerpoint
            double earthTheta = map(model.getDay(), 0, SolarSystemModel.DAYS_PER_EARTH_REVOLUTION_AROUND_SUN, 0, TWO_PI);

            // Rotate our coordinate system by that much
            // Translate the earth
            int distanceFromEarthToSun = (int) (EARTH_DISTANCE_PROPORTION_SCREEN * getWidth());
            g2.translate(distanceFromEarthToSun, 0);

            int earthRadius = (int) (EARTH_RADIUS_PROPORTION * getWidth());
            GradientPaint earthColor = new GradientPaint(0, 0, Color.BLUE, 0, earthRadius, Color.GREEN.darker(), true);

            g2.fillOval(-earthRadius/2, -earthRadius/2, earthRadius, earthRadius);

If you’ve read my earlier blog post on the map function, you know that it maps a value from one range of numbers to another. We must calculate the number of radians to rotate so that we can position our earth correctly along its orbit.

Note that we first rotate and then translate; if we did it in the opposite direction we would see the earth spin about its axis but it would not revolve around the earth.

The drawMoon method is much the same; the main difference is that we calculate its position along its orbit based on its much smaller time to orbit the earth.

         * Draw the moon to the screen, whose position is dependent upon that of
         * the earth and the day of the year, which dictates its position along
         * its orbit around earth
         * @param g2 the graphics context with its origin in the center of the earth
        private void drawMoon(Graphics2D g2) {
            double moonTheta = map(model.getDay(), 0, SolarSystemModel.DAYS_PER_MOON_ORBIT_AROUND_EARTH, 0, TWO_PI);

            int moonRadius = (int) (MOON_RADIUS_PROPORTION * getWidth());
            int distanceFromEarthToMoon = (int) (MOON_DISTANCE_PROPORTION_SCREEN * getWidth());
            // Translate the earth
            g2.translate(distanceFromEarthToMoon, 0);
            g2.fillOval(-moonRadius/2, -moonRadius/2, moonRadius, moonRadius);

Finally all we have to do is create an instance of the model and view, hook them together, and display them in a JFrame.

        public static void main(String[] args) {
            JFrame frame = new JFrame("Solar System");

            final SolarSystemModel model = new SolarSystemModel();
            final SolarSystemView view = new SolarSystemView(model);

            JPanel panel = new JPanel();


If we run it as is, we see the planets aligned, since the model starts off at day zero. It’s a lot more fun to be able to interact with the model. To do that, we add a JSlider that modifies the model.

            final JSlider daySlider = new JSlider(0,SolarSystemModel.DAYS_PER_EARTH_REVOLUTION_AROUND_SUN);
            daySlider.addChangeListener(new ChangeListener() {
                public void stateChanged(ChangeEvent e) {

With that addition, we can move the slider and watch the planets move.

That’s it for this time. Can you figure out how to use the hour field of the model with another slider to make the earth rotate about its axis as it revolves around the sun?

Full model source
Full view source

Categories: Java, programming, regular Tags: , , ,


January 31, 2010 Leave a comment

 Well, it’s almost February so the New Year’s Resolution rush has probably gone by.  If you’re anything like me, there are a lot of things you would like to do, habits to get into, but that you can’t really find the time or energy to keep them up.  I stumbled upon a website that promises to help you meet and sustain your goals – The premise of the site is simple: it takes 21 days to make a habit stick (despite that often-quoted number, the science might not be there to back it up).  Regardless, you enter in your goal and the site e-mails you each day to determine whether or not you met your goal during the past day.  It keeps a counter of the number of consecutive ‘yes’ days, as well as statistics on your overall success, failure, and non-response rates.  If you miss a day, the counter goes back to zero. I like the site for two main reasons.  The first is that it has a pull rather than a push mechanism for receiving your responses.  I don’t have to remember to log into the site and enter my information (push); as long as I check my e-mail daily, it actively solicits a yes or no response taking no more than one click.     

When you have a single goal, the e-mails consist of a single Yes/No choice
With multiple goals, you visit another webpage and use radio buttons to say yes or no for each goal

  The second reason I like the site is that it actually seems to be working – it’s fun to see the dots of progress for consecutive completed days fill up, and it’s very painful to see them reset back to zero if you miss a day.  I certainly have been writing a lot more than I would have otherwise had it not been for the reminders of the site.  The site’s not perfect; right now there is no way to indicate that a goal only applies to specific days of the week (e.g. goals that are related to work habits probably don’t mean much on weekends), but the site promises that feature is coming.  My  second complaint is that if you forget to respond to the e-mail, it counts that as a no-response and resets the timers back to zero.  Fortunately, there is a way to go back and edit past responses to fill in the missed e-mail solicitation; this puts the counters back to their rightful place.  Until I found that option, I was a bit pissed at that idea; to me a lack of a data point should not be equivalent with a no or yes answer; it should keep the counter at what it is and just update the yes, no, no-response rate statistics.  

The idea of doing a task on consecutive days to improve at it and make it a habit is not a new thing; Jerry Seinfeld credits a similar system with helping him be so prolific and productive, though the method is a bit lower tech. I personally really enjoy this service, and hope it can be of some use to you too.

Categories: regular Tags:

Review: The Passionate Programmer

January 19, 2010 Leave a comment

Cover of book with stylized saxophone

The Passionate Programmer: Creating a Remarkable Career in Software Development
by Chad Fowler
Publisher: The Pragmatic Bookshelf

I received a gift card to Border’s for Christmas and was perusing their voluminous computer section when I saw Chad Fowler’s The Passionate Programmer: Creating a Remarkable Career in Software Development.  The cover of the book features a stylized rendition of a saxophone and immediately drew my attention.  The fact that it was part of the Pragmatic series helped as well; I already have purchased The Pragmatic Programmer: From Journey To Master and Textmate: Power Editing for the Mac and thoroughly enjoyed both of them.
The saxophone on the cover is a reference to the fact that the author was a professional jazz saxophonist before becoming a software developer; this drastic switch in careers leads to some new insights I had never fully considered before.  Before getting to an example of that, I’d like to talk a little about the structure.

This book is actually the second edition of what was originally called “My Job Went to India: 52 Ways to Save Your Job”, and it keeps the same format as the original: each chapter is numbered and presents a single focused idea for differentiating yourself as a software developer and to have a successful career.  The book is divided into five large sections:

  • Choosing Your Market (deciding what technologies you should specialize in)
  • Investing in Your Product (how to gain real expertise with your technology of choice)
  • Executing (combatting apathy, productivity ideas)
  • Marketing… Not Just for Suits (hits on the fact that you can be the best coder in the world but if no one but you knows it, you’re not doing yourself any favors)
  • Maintaining Your Edge (don’t get complacent; technology is incredibly fast-paced and you must keep up to date if you wish to remain relevant)

While a lot of the advice is similar to what you can find online for free, they are stated in ways I have never read before and truly made me think.  For instance, the chapter “Practice, Practice, Practice” draws on his experience as a jazz musician.  Here is a choice excerpt:

When you practice music, it shouldn’t sound good.  If you always sound good during practice sessions, it means you’re not stretching your limits.  That’s what practice is for…
Our industry tends to practice on the job.  Can you imagine a professional musician getting onstage and replicating the gibberish from my university’s practice rooms?  It wouldn’t be tolerated.  Musicians are paid to perform in public—not to practice… If we’re going to try to compete based on quality, we have to stop treating our jobs as a practice session.  We have to invest the time in our craft.

With that interesting lead in, he suggests some ways to meaningfully practice software development, while maintaining the metaphor of musicianship:

  • Learn the core APIs and function libraries of your language of choice (roughly equivalent to gaining muscle memory with scales etc.)
  • Code for an open source project, as well as reading the same (~ sight reading practice)
  • Practice programming with self-imposed constraints, e.g. finding some problem like 99 Bottles of Beer on the Wall and implementing it in as few lines of code and as quickly as possible in your given language (~ improvisation)

This book was a very entertaining, useful, knowledge-rich book, and has my highest recommendation.

Categories: programming, regular Tags: ,

Useful utility functions – 0 of n

December 15, 2009 Leave a comment

This is the first in what I’m sure will be a lengthy series of posts about utility functions I find myself needing time and time again.  When I say utility function, I generally just mean a static function that does something useful (aka helper function), whose logic is often self-contained and unrelated to a specific class or component.

The first of these methods I never knew I was missing until I played around with Processing one weekend.  The method in question is a mapping function taking a value in one range to a value in another range.  Its signature is as follows:

map(value, low1, high1, low2, high2)

The Processing description of the method says

Re-maps a number from one range to another. In the example above, the number ‘25’ is converted from a value in the range 0..100 into a value that ranges from the left edge (0) to the right edge (width) of the screen.

Numbers outside the range are not clamped to 0 and 1, because out-of-range values are often intentional and useful.

My Java implementation of map is as follows:

 * @param value The incoming value to be converted
 * @param low1  Lower bound of the value's current range
 * @param high1 Upper bound of the value's current range
 * @param low2  Lower bound of the value's target range
 * @param high2 Upper bound of the value's target range
public static final double map(double value, double low1, double high1, double low2, double high2) {

    double diff = value - low1;
    double proportion = diff / (high1 - low1);

    return lerp(low2, high2, proportion);

// Linearly interpolate between two values
public static final double lerp(double value1, double value2, double amt) {
    return ((value2 - value1) * amt) + value1;

Any time you’re converting from one range of numbers to another, this method will come in handy.  You probably have code already to handle this on an ad hoc basis; I know I certainly did before seeing the method in Processing.  Hopefully this is helpful to you.

Categories: Java, programming, regular Tags: ,