Wednesday, May 04, 2011

20 HTML Tags to do Almost Everything You Need a Web Page to do

Ah HTML. The gateway to programming, or at least mine. After the time I've spent as a developer, the importance of understanding how to put together some solid HTML has not waned. So, I thought it would be a good idea to distill the fundamentals down to a concise reference.

What's great is that there's only about twenty tags that you'll need to do all the basic important things in order to structure data. This is how it's going to go. You'll need to know what HTML is supposed to do first. Basic, but important. Then, you'll need to learn a couple simple rules to help categorize the types of tags you'll need. Finally, we'll put it all together so you can learn about how specific tags work.

What is HTML for?

Quite simply, HTML helps to describe your textual content. It stands for HyperText Markup Language. The markup part is what adds meaning to the content. Need an example? Let's say that I want to emphasize to a word in a sentence. To do that with plain text isn't possible without adding some extra information. When we speak, we can use inflection in our voice, but with a plain sentence, you can't do much. See the need? In order to do this, you can wrap content in HTML tags.

Here's a sentence that has some emphasis.
Here's a sentence that has <em>some</em> emphasis.

The "<em>... </em>" is an HTML tag that describes the text that it surrounds, emphasizing it.

Basics.

Let's start with an example, based on the example above. Here is our HTML

<p>Here's a sentence that has <em>some</em> emphasis.<br />This one appears on a new line.</p>

  1. Tags use angle brackets (less than, greater than characters) to distinguish themselves from the actual content. The example above starts with a <p> tag. The characters in between the angle brackets, in this case the "p" in the "<p>" indicates a tag with a specific purpose. The <p> indicates a paragraph, hence the "p".
  2. Tags have a start and a matching end. We call that "opening" and "closing." The main difference is that the closing tag has a forward slash, an opening tag does not. If a browser is reading the HTML you write from start to finish, when it reads "<p>" it says to itself "everything after this tag, until I reach the closing tag, is part of a paragraph". When it reaches the matching "</p>" it says to itself "I can stop rendering the paragraph now."

    Can you spot another opening and closing tag in our example? I thought so. "<em>some</em>" formats the word "some" with the "emphasize" tag.
  3. Some tags can be empty, where there is no content in between an opening and closing tag. There, a single tag can open and close itself. The syntax places the forward slash at the tail end of the tag. Our example above has a "<br />" tag, indicating a line break. These kinds of tags are "self-closing" or simply "empty" tags because they do not wrap content.
  4. Tags must be symmetric. This one is easiest to show with an example. This is not symmetric.

    <p>New paragraph <em>emphasized</p></em>

    In this example, you can see that the <p> opens, then an <em> tag opens. The </p> then closes before the </em> closes. Don't do this! This is how it should look

    <p>New paragraph <em>emphasized</em></p>
  5. Tags can be nested. That is, you can put tagged content inside other tags. In the example above, the <em> tag is nested in the <p> tag. This helps to build a hierarchy of structured content. Just remember to make sure that the the tags need to be symmetric.

    It is also important to note that all tags have their own set of rules. Some tags can have only specific types of tags nested within. Depending on the tag, some tags might be forbidden.
  6. There is a distinction between "block level" and "inline" tags. This is an important concept to understand which describes how the tag behaves on the page. You can think of a block level tag as behaving like a rectangular container. Inline tags wrap with the text that they contain.
  7. Tags can have attributes. These provide ways to configure the tag. An attribute of an HTML tag is simply a pair of a name and value. This is what a paragraph tag looks like with an "id".

    <p id="Something">The ID is Something</p>
Twenty tags you'll find most useful.

Now that you know a few rules, it's time to get into some specifics. Here is a list of 20 tags that will help you to build your very own HTML page. The intention here is to briefly describe the rules for how these tags behave so you have enough freedom to build your own HTML content.

The first set of tags help to set up the entire document structure.

1. <html>... </html>

If you're building a complete HTML file, it must open and close with this one. This is the root tag that you'll need to use.

This only appears at the root of the file. That is to say, there are no HTML tags that can wrap this one, and it can contain ONLY <head> and <body> tags, in that order.

2. <head>... </head>

The head tag sits as the first element in the HTML page. The contents describes the file, but does not contain content. THis is where you add the title, add style, javascript, and meta information.

This Must be the first tag to appear within the <html> tag. It does not contain any actual page content.

3. <title>... </title>

The title tag is what's used to give the page a title. This is what appears in the top bar of the browser window.
This appears only within the <head> tag and only contains text, no other tags.

4. <body>... </body>

The body tag is where the actual content appears.

This appears after the <head>... </head> tag and contains any content-bearing tags

Here's an example, with the basics of what we've learned so far

<html>
<head>
<title>My First HTML</title>
</head>
<body>This is the page content</body>
</html>

Not too hard, eh? Everything else helps to describe the actual content that falls inside the <body> tag.

5. <h1>...</h1> through <h6>...</h6>

These are headings. These help to indicate the title of content that follows, like a headline for a newspaper article. Search engines have traditionally placed greater emphasis to text within these tags. This makes sense semantically, because if there is a heading on the page, this is likely to indicate something significant that appears within. These help to identify what the content on the page is about. <h1> identifies the most important heading and <h6> the least. You can have as many of these as you like on the page.

This is a block level element. You can put a lot of different elements within it, including inline elements, images, line breaks. Other block level elements should stay out.

6. <p>

The paragraph tag is the main tag to use for blocks of text content. Similar to the headings, you can put inline elements, images, and line breaks within.

7. <a>

Ahh the anchor tag. This is what the world wide web was built on. The anchor tag allows you to link to another web page or other url's. To make it work, just add an "href" attribute.

<a href="http://wwww.lo-fi.net">THis is a link</a>
  • The value of the href attribute is the place where the link should take you.
  • This is an inline element
  • You can put other inline elements inside the anchor tag.

8. <img />

The image tag let's you put an image on the page. This is another tag that requires an attribute to work. You need to use the "src" attribute to specify the address of the image. You can also use the "width" and "height" attributes if you need to control the size. If you specify only one of them, the unspecified dimension will scale proportionately. The value of the "height" and "width" attributes is measured in pixels

<img src="http://lo-fi.net/images/picture.jpg" width="100" height="200"/>

This is an inline element and an empty tag.

9. <br />

This is a line break. Quite simply, it places a break in t a line so the text following it appears on a new line.

Lists

Lists are a very important way to present text on a web page. With the nature of short attention spans abounding on the internet, there's nothing like a list to make content easy to digest. In addition, they help tremendously when you need to display information in a hierarchical way.

10. <ul>

This is an Unordered List, or as we typically know it, a bulleted list. This is a block level element in which List Items are placed. The only tag that you can legally put into a <ul> tag is a <li> tag. This is what a bulleted list might look like

<ul>
<li>Fruits</li>
<li>Vegetables</li>
<li>Proteins</li>
</ul>

This is what it looks like
  • Fruits
  • Vegetables
  • Proteins
What's cool about lists is that they can be nested inside each other. A <ul> tag can rest within a <li> tag, which builds a hierarchy, like this.
<ul>
<li>Fruits
<ul>
<li>Apples</li>
<li>Oranges</li>
<li>Lemons</li>
</ul>
</li>
<li>Vegetables
<ul>
<li>Carrots</li>
<li>Broccoli</li>
<li>Beets</li>
</ul>
</li>
<li>Proteins
<ul>
<li>Beef</li>
<li>Salmon</li>
<li>Chicken</li>
</ul>
</li>
</ul>

This is what it looks like
  • Fruits
    • Apples
    • Oranges
    • Lemons
  • Vegetables
    • Carrots
    • Broccoli
    • Beets
  • Proteins
    • Beef
    • Salmon
    • Chicken

11. <ol>

The more organized sibling to the Unordered List, is the Ordered List. It works the same way as the unordered list does, but it appears on the page with numbers instead of bullets. You can nest these within each other as well. You can even mix an ordered list with an unordered list. Check this out.

<ul>
<li>Top Fruits
<ol>
<li>Apples</li>
<li>Oranges</li>
<li>Lemons</li>
</ol>
</li>
<li>Top Vegetables
<ol>
<li>Carrots</li>
<li>Broccoli</li>
<li>Beets</li>
</ol>
</li>
<li>Top Proteins
<ol>
<li>Beef</li>
<li>Salmon</li>
<li>Chicken</li>
</ol>
</li>
</ul>

This is what it looks like
  • Top Fruits
    1. Apples
    2. Oranges
    3. Lemons
  • Top Vegetables
    1. Carrots
    2. Broccoli
    3. Beets
  • Top Proteins
    1. Beef
    2. Salmon
    3. Chicken

12. <li>

The List Item is an HTML tag that belongs only in a <ul> or <ol> tag. Any place else is just wrong. The content of <li> tag is a little more flexible. They are block level elements, so you can put other block level elements in them -- headings, paragraphs, other lists, and such. You can of course put inline elements in these as well -- anchors, images, plain text, whatever.

Formatting

Sometimes, you'll find it necessary and important to add some visual formatting to your text. Most of the time, it's best to use Cascading Style Sheets (CSS) to do that (which I don't cover at ALL here). However, it is still legal to add some text formatting with HTML tags. Here's 2 common ones

13. <strong> or <b>

Wrapping text in the Strong or Bold tag has the same default effect. This makes the text inside it bold. The main difference is that the <strong> tag is interpreted by screen readers (web browsers for the vision-impaired) in such a way as to raise a voice.

These tags are inline elements, and should only contain other inline elements.

14. <em> <i>

The Emphasis and Italic tags also have the same default effect. These make the text inside italic. The <em> tag has the same analogous interpretation as the <strong> tag by screen readers. It adds some, eh, emphasis to the text.

These tags are inline elements as well, and should only contain other inline elements. Here's an example of something that is both bold and italic

<strong><i>Bold and Italic</i></strong>

Table

The table is one of the most powerful layout elements that HTML provides. This allows you to place content into a grid of columns and rows. To use a table, there are three main pieces involved. A tabular layout will consist of the table container, rows within that container, and cells within each row. The cells are the only thing in the table that can contain any actual content of the table.

15. <table>

The Table tag is the tag that starts the table. Alone, it doesn't do much. In fact, it is not valid to have <table> tag with nothing in it. It simply doesn't make sense to set this up without contents inside. There are only a couple of valid tags that can be direct children of a <table> tag, and they are all specific to a tabular layout.

16. <tr>

One of the main HTML tags that can be a child of a <table> tag is the Table Row. This too requires content to be valid. The content of a table row can only be one of two table cell tags. Those follow

17. <td>

The Table Data cell can only appear within a <tr> tag. However, the <td> tag can contain just about anything it wants to. Other tables, headings, images, plain text, paragraphs -- just about anything that doesn't have any limitations on what it's parent tag is can go in here. Here is a sample table with one row, and two columns:

<table>
<tr>
<td>One</td>
<td>Two</td>
</tr>
</table>

This is what it looks like with a border

One Two

18. <th>

Another tag that can appear within the <tr> tag is the Table Heading tag. The <th> helps to declare what the heading of a table is. Typically, this tag will appear in the top row of a table to indicate the name of the column. However, there are no restrictions on which position they reside in a <tr>. Other than the semantic nuance, a <th> behaves the same way as the <td> tag does.

<table>
<tr>
<th>Letters</th>
<th>Numbers</th>
</tr>
<tr>
<td>A</td>
<td>1</td>
</tr>
<tr>
<td>B</td>
<td>2</td>
</tr>
<tr>
<td>C</td>
<td>3</td>
</tr>
</table>

This is what it looks like with a border

Letters Numbers
A 1
B 2
C 3

Document Structure

Occasionally, it's nice to have a tag just to collect a group of content together, simply for the purpose of putting a boundary around it. For that purpose, and it is a common one, we have a couple tags to help.

19. <div>

The Division tag , frequently referred to simply as a "div", defines a section of the page. That's it. It does not have any significant impact on the display of it's contents other than acting as a block level type of container for it's contents.

The simplicity of a <div> provides a lot of flexibility in structuring the content of an HTML file. As you work on building HTML over time, you'll find yourself using this a lot. Especially when there are a lot of different blocks of content that you want to group together visually.

The contents of a <div> are very flexible. Any tag that doesn't have any restrictions on what it's parent tag can be are allowed here. Tables, other divs, inline elements, etc. The <div> tag is a block level element.

<div>
<h1>Here's a heading</h1>
<p>Here's a paragraph grouped with the heading</p>
</div>

20. <span>

The Span tag similarly wraps content for the sake of grouping content together. The main difference between the <div> tag and the <span> tag is that the span tag is an inline element. That means that it can only contain raw text or other inline elements.

Here's an example that shows nested span tags to group some words together.

<span>Here is some text <span>and this is a sub-group of text</span></span>

Bonus

What you see above represent what I consider the essentials to building an HTML document. Much of the other parts of HTML (and there are many) are more specialized. For example, we didn't touch form elements or some more advanced table features. However, what's above will give you what you need to get started.

There are a couple items that are worth noting, as a bonus.

21. <!DOCTYPE >

The first bonus is the Document Type declaration. This is a line that goes at the very top of the page to help the browser determine what how to read the rest of the HTML that you wrote. Believe it or not, there are a couple different flavors of HTML, and each has slightly different rules. The Document Type helps to tell the browser what rules your HTML adheres to. Using a document type is not a requirement, but it is a very good idea. People who write good HTML code use doctypes.

The doctype for HTML that uses the HTML5 rules is refreshingly simple:
<!DOCTYPE HTML>

The doctype for HTML that uses the XHTML Strict rules is a little more verbose. I don't know anyone who has it memorized:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

An HTML document with a proper HTML5 document type declaration would look like this
<!DOCTYPE HTML>
<html>
<head><title>HTML 5 page</title></head>
<body>This is an HTML 5 page</body>
</html>

22. <!-- Comments -->

Last but not least, the comment is something you should be aware of. The comment tag allows you to add comments to the code you're writing, which the browser will not show. They can be helpful in making notes to help you understand the HTML you write. This is what a comment inside a Paragraph would look like.

<p>I love to write HTML <!-- as long as someone is paying for it --></p>

In that example, the only thing that the end user would see is the "I love to write HTML". Everything inside the <!-- ... --> does not show. As you can see, it is a helpful way to communicate between people writing the code.

So that's it! You should be off to the races now. Be careful though. Once you get started with this, it's hard to stop. And once you get into using javascript to add interactive behavior, and CSS to control your visual style, it's nearly impossible.

Tuesday, October 20, 2009

Upgrade to Snow Leopard Freezes at Boot -- FIXED!

A couple of weeks ago, I decided that I'd do a standard upgrade to Mac OS X Snow Leopard. I was wary because I have a fairly customized installation of Leopard. I've done a good deal of tweaking in the Terminal to get things set up for the sake of web development. However, having faith, I went ahead and did it any way. I figured that it would go smoothly.


It did not.

Right away when booting in to my account the system would hang. I'd get the spinning beach ball, and the magnifying glass for Spotlight appearing in the top right corner. Nothing else. No dock. No menu bar. Nothing. Frozen. I could safe boot in to the system with my account (holding down shift button when starting) but a standard log in would not work.

At that point, I decided that I'd revert with a complete time machine backup and try again some other day. I shifted my strategy to do a clean install.

A week later, my adventure with a clean install began. Until last night, I was quite pleased with the progress. Happy with the installation and configuration of the system, I started transferring files. Then I started with the fonts. I copied the contents of the ~/Library/Fonts directory from the leopard disk to my clean snow leopard disk. It took a lot longer than it should have. I copied the contents of the ~/Library/FontCollections directory in the same way. I was immediately suspicious. I then un-did those copies. Removed all of the user fonts. Removed the new Font collections. Something just didn't seem right. Curious but content, I moved on.

I then started up an instance of Eclipse. And it crashed. I checked the log, where I saw a NullPointerException which mentioned this:
at org.eclipse.swt.graphics.Device.getFontList(Device.java:369)
Very interesting.

I then rebooted the machine, and found the same problem that I had when I did the normal upgrade. System hang. Frozen. The spinning beach ball of death. Defeated, I went to bed.

Thinking that the problems I had were probably related, I did a search to see if clearing the font caches might work. Honestly, I didn't even know if there was such a thing. Apparently there is, and this is where I found the details about clearing a font cache in Mac OS X.

The good news is that clearing the font cache worked! I've managed to fix the problem and boot in to Snow Leopard without hanging or freezing. This is what I did:

  1. Consider removing all of your user fonts and font collections -- I don't know if this is necessary.
  2. Reboot, holding down the SHIFT button as the system starts - this boots into safe mode
  3. Log in to your account from the log in screen
  4. Open the Terminal (Applications/Utilities/Terminal)
  5. At the command line, use aprutil to clear the font cache type this:
    atsutil databases -removeUser

    If you want to remove font caches for all users (I did), type this:
    sudo atsutil databases -remove

    Since you're using sudo to execute this command, you will need an administrator password.
  6. Reboot the machine, and you should be good to go. At least, if you have the same problem I did.

Monday, December 29, 2008

Gratuitous family media

I feel that I'm just not doing a good job as a Dad unless I blog about my kids now and then. For those far flung, here's a set of recents.

It's impossible to resist giggling along with this one of Nolan laughing hysterically at the frog blowing in his face



And representing for the Badgers in the apron Grandma sent, here's Gideon drawing with his markers.



A few family shots.

My favorite people in the world.


Gideon demonstrating the laws of physics.


Nolan, grinning as always.


Yours truly making sushi. We found a good deal on some yellow fin, but had to make due with sub standard, non-sushi rice -- which explains the look on my face.


One of Gideon's favorite video games is "Photoshop." He picks out the colors and the brush. Then I hold down the mouse button of a laptop while he moves his finger around on the track pad to do the drawing. Tons of fun!



Tuesday, December 16, 2008

Bailout your bicycle

If there's a silver lining to the $700 billion bailout it's legislation about giving bicyclists a tax break.

As a year round commuter facing sub-zero temps and snow this week, I was excited to see this news. Really, $20 / month doesn't cover a whole lot in bicycle expenses, but hey, I still think it's great news.

Tuesday, September 02, 2008

Prophecy? Europe?

Oh yes, Europe and prophecy go together more than you might think.

This Sunday, September 7th, 2008, if you happen to be within ear-shot of Fort Collins, you should consider checking out a lecture about the role of Europe in light of Biblical prophecy. Norbert Link will be presenting a message that I think is significant in the scope of world history. I'm not even exaggerating.

By connecting the evidence of current events and secular history with prophecy, the news reported today from around the world becomes absolutely magnified in significance. I don't know all of the details about the content of the lecture, but I do know that you can expect to hear about the prophetic emergence of the European Union to global power. Right now, the EU is in its infancy and might not seem like a global super power, but I believe it will be. Power has already begun to shift in significant ways. Merely seeing that the Euro is gaining greater influence as the currency of choice in international trade, because of the instability of the dollar, with increasing momentum is an indication of the power shift. I'm not an expert economist, nor am I informed of all the intricacies of global politics, but it doesn't take much to notice that the EU is gaining influence quickly. As the EU becomes more organized and better at making decisions, they will become more powerful. And, by joining so many disparate peoples and populations, the European Union will become the statue with feet of iron and clay mentioned in Daniel 2. At least, that's what I believe the Bible teaches.

You'll also likely hear something interesting about the removal of blessings from the United States and United Kingdom. Essentially, the premise is that these countries are the inheritors of the birthright from Jacob in Genesis 48, becoming a "great people" and "multitude of nations" respectively. Of course, since it is a lecture about the teachings of the Bible, you may hear about the many reasons why these birthright blessings are being withdrawn as well.

Ultimately, the shift in global power we're seeing right now is all part of the plan that the Bible records. And that's a good thing. However, what's shocking is that it doesn't take much imagination fill in the gaps between current events and Revelation events.

What you won't hear will be requests for money, a devotional altar call, nor a feel-good "just love the Lord" message. It will be a much more sobering set of content. What you will hear, even if you don't agree with it all, is an observation and analysis of current events and history that will blow your mind, if you take the Bible seriously.

I challenge you to open your mind and check it out.

Tuesday, June 10, 2008

...and Baby Makes Four

About three weeks ago my wife, Shana and I arrived home carrying our newborn baby boy Nolan from the hospital. This is certainly a long overdue post, but bringing a newborn into the household tends to force some re-prioritization. Blogging fell pretty far down the list. So, without further adieu, a photo or 2. Introducing, Nolan.






I also figured that this would be a good place to record some of the details. At least before I forget them.

Over the weekend of May 17-18th, Shana noticed some different activity going on in her body. She had plenty of Braxton-Hicks contractions throughout the pregnancy, and what she was feeling was definitely more serious. So, I managed to scramble getting some things together Friday night, expecting that we might have to make a quick getaway. That was not the case. Things settled down completely. But we were warned.

Monday (May 19th) morning we woke up, and almost immediately became aware that we were going to be parents to a new child that day. The real contractions were regular and definitely stopped Shana in her tracks once in a while. To make things more interesting, I had an appointment with a recruiter that morning to talk about my job search -- I had actively started looking for a new job a week earlier and needed to find something fast. With things relatively stable at home, I figured that I'd take a calculated risk and go to the meeting. While Shana was at home, in labor, I was sitting at a coffee shop waiting very impatiently for the recruiter to show up. After ten looooooong minutes, and no show by the recruiter (communication mix up) I decided to leave. I'm glad I did.

I got home around 10:30 am and called up Shana's brother, Robb, to arrange a pickup for our two year old, Gideon. He stopped by around 11 am and picked him up, to deliver to Granny and Papa. Everything was pretty well under control at that point.

Contractions were still relatively mild, so in order to encourage them along, we decided to go for a walk around the neighborhood. It certainly worked. When we arrived back home an hour later, Shana was having contractions anywhere from 5 to 6 minutes apart. Right on track.

Our plan was to allow Shana to labor as much as possible in the comfort of our home before arriving at the hospital for the delivery. We had been through it once before, taking Bradley method classes, so we had a pretty good idea of what to do. Shana immediately laid down to get some much needed rest while the contractions did their work. I think she may have even gotten a little bit of sleep.

While she was resting and allowing labor to naturally progress, I was tediously filling out a job application, hunting down history and contact information. I had a potential job offer in the works, and didn't want to take too long to respond. I'm sure they would have been understanding about any delays, but to me it was baggage that I could clear from my head. It also gave me something to do as an outlet for all the nervous energy. So, I did as much as I could, and kept as much job seeking momentum as I could.

Around 3 pm, while I was doing some scanning, Shana mentioned, in a tone that could not be ignored, that she was going to need some attention soon. Scanning could wait.

From that point on, things happened pretty rapidly. She was struggling to find the most comfortable position to be in while the contractions strengthened. Hands and knees? Nope. Sitting on a therapy ball at the end of the bed? Nope. Kneeling on the floor, resting on the bed? Nope. The most comfortable position wound up being a side-lying position on the bed. Good enough for me. I tended to her, trying to massage as much as I could to relieve the pressure. I then called the midwives to let them know that we were in active labor and that they could expect to see us later that day.

Continuing to labor, more intense, deep moaning turns out to be unbelievably helpful for Shana. In the back of my head, I was thinking to myself that the first time we had a baby, the moaning was quickly followed with pushing -- hmmmm. Time to pay close attention. Shana, to her credit, was extremely well composed, especially in retrospect. She looked relaxed, and there was no screaming in pain, but she was definitely working pretty hard. Cool towels were what she needed most. At that point, contractions were anywhere from 5 minutes to 3 minutes apart.

4:00 pm. Shana and I decide that it's time to start moving to the car to get to the hospital for the delivery. I call the midwives to let them know we're on our way. While I'm on the phone, Shana cries out, "I feel like pushing!!!" I really didn't want to hear that. Both of us panic slightly because we KNOW that we stayed home too long. I call the midwives back. "Shana feels like pushing, we're going NOW!"

Then began our lengthy venture down the stairs. Wow, it took some time. Trying to convince a laboring woman, who feels like pushing that she needs to start moving down stairs is like, well, just what it sounds like. It took 30 minutes to get downstairs. And, about half way down, her water broke.

PANIC!

Her pitch rises in fear. In a moment of idiotic diplomacy, I ask her if she wants to ride in the car, or if I should call an ambulance. I definitely didn't need to burden her with something as serious as a decision. Anyway, while I scramble to grab all of our bags in my arm, she found enough strength to make it half way across the front yard before another contraction hits. Remember, she feels like pushing. I hold her up to support and notice that she's crossing her legs at the knee. I nearly freak out. OK, that one's over, let's get her in the car.

She manages to get into the car, but there's absolutely no way she's going to actually sit. She knelt on the front seat, butt towards the windshield, hugging the headrest, while I drove as swiftly as possible to the hospital.

12 minutes later, Shana hasn't given birth yet, and we arrive at the hospital emergency room meeting our midwife at the entrance. They get a gurney, and try to decide whether to deliver the baby in the emergency room or in the actual birthing room. Shana decides that she can make it to the birthing room. Good thing too. I don't get the impression that ER folks enjoy delivering babies.

Up the elevator we go, and get into the room at 4:49 pm. A push or two later, the midwife says, "I think he's coming on the next push." I am completely overwhelmed with emotion, laughing and crying at the same time, as I watch our son Nolan gracefully enter the world. At 4:53 pm.

9lbs 8 oz, 20.5 inches long. Not chump change!




Postscript:

The following day, Tuesday, I managed to get some paperwork faxed to an employer, and by lunch time, I had a favorable job offer from them. What an absolute amazing 24 hours.

Monday, April 21, 2008

Multi-threaded Socket Server in Java

I have always been curious about how to make a multi-threaded server in Java, and it turns out to be pretty simple to get something basic up and running.

My goal was to create a program that would listen for incoming connections from a client, and repeat whatever is sent to that server. You can see this server work using a telnet session on port 5000.


telnet localhost 5000


Then, whatever you type will be echoed back to you. If you want to quit, just type exit.

Here's the code, consisting of 2 classes.


package sockets;
import java.io.*;
import java.net.*;

/**
* Includes main method to get things going
* Otherwise, this just prepares a new ServerSocket that
* listens for new connections
* and starts a new thread for each connection
*/
public class EchoServer {
public void go(){
try{
ServerSocket serverSocket = new ServerSocket(5000);
while(true){
System.out.print("Listening for connections on port 5000... ");
Socket client = serverSocket.accept();
Thread t = new Thread(new EchoClientHandler(client));
t.start();
System.out.println("Connected - "+client.getInetAddress());
}
}catch(Exception e){
e.printStackTrace();
}
}

public static void main(String[] args) {
EchoServer server = new EchoServer();
server.go();
}
}

/**
* The Runnable job that takes in the new Socket
*/
class EchoClientHandler implements Runnable{

private final BufferedReader reader;
private final PrintWriter output;
private final Socket socket;
private static final String MESSAGE = "ECHO... [?]\r\n";
private static final String EXIT_MESSAGE = "Sad to see you go. Goodbye.\r\n";
private static final String WELCOME_MESSAGE = "Welcome to the Echo Server. Type something to see it echoed back to you!\r\n";

public EchoClientHandler(Socket incomingSocket) throws IOException{
socket = incomingSocket;
output = new PrintWriter(incomingSocket.getOutputStream());
reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
}

public void run(){
try{
output.write(WELCOME_MESSAGE);
output.flush();
String line = null;
while((line = reader.readLine()) != null){
boolean quit = false;
output.write(MESSAGE.replaceAll("\\?", line));
if(line.trim().equalsIgnoreCase("exit")){
output.write(EXIT_MESSAGE);
quit = true;
}
output.flush();
if(quit){
break;
}
}
}catch(Exception e){
System.err.println("OUCH! "+e.getMessage());
}finally{
try{socket.close();}catch(Exception ee){}
}
}
}


Here's how it works.

When the EchoServer starts up, it opens a server socket that listens for incoming connection requests. When it gets a request, it creates a new handler instance, taking the Socket as an argument. The handler is a Runnable class, and used to start a new Thread. The result is that the EchoServer can handle more than one connection at a time -- just like a good socket server should.

To expand on this, it would be a good idea to implement some means of managing the threads and connections. Using the java.util.concurrent API would be a good thing to do to implement some means of thread pooling in the server instead of using naked Threads. Thread pooling is an important thing to implement because each new persistent connection requires a new thread. Too many connections would cause some real resource problems. However, if there are limits to the amount of connections the server will allow, you need to manage connections. Therefore, some intelligence might need to be added to a Client program, so that a connection need only stay alive for a certain amount of time before becoming disconnected. Then, a well designed client might seamlessly create a new connection to the server.

Thursday, April 03, 2008

Social Networks are the Next Commodity

When I need to fly I typically treat myself to a copy of the Economist. In my opinion, it's got some of the best news available in the world. Last week, on a trip to San Diego, I picked up a copy for myself to enjoy.

The March 22 issue had an interesting and compelling article about the future of social networking sites. Essentially, the premises state that social networking is something that will become pervasive and a feature that people come to expect on a site. There's no question that social networking is becoming ubiquitous. You could make the argument that social networks are already a commodity, in the way that because they are everywhere, and cheap or most likely free to participate in, social networking is already a commodity.

OK, what does that mean? It means that the only way to make any money on a primarily social networking platform is to increase volume. Indeed, it's the page views, not the amazing amounts of revenue that make Facebook so highly valued. What I found interesting about the article in the Economist was the part that mentioned how difficult it is to create any sort of solid revenue model based on the high-traffic, social network, advertising only business model. There are some serious limits to the amount of money a business can make with this kind of structure. And it gets worse. Since most social networks don't to anything more useful than poke, attack, or leave a message on a page for a friend, there's not much value for a user to remain loyal to a site he or she is a member of. That means declining page views once the buzz is gone. You can see attempts to maintain buzz by sites like myspace and linkedin constantly adding new features, but in the end, it just makes for a more complicated we application, with a diluted purpose.

So, what's next?

Email for one. The fore-mentioned article makes a point of explaining that email is the best way to really build a rich social network for the sake of networking. That's right, email is the next killer app. Check out Xobni. They're building what I believe is a real and genuine social networking app with purpose. And they integrate it with your email client. I also expect that we'll see some pretty amazing things, with some genuine utility, hitting our mobile phones very soon. When I mention utility, I'm not talking about ridiculous pillow fights or zombie attacks either. With the android platform, and the iPhone SDK, developing real social networking applications that tie into real people doing real things in real time becomes much more of a possibility.

What about social networking sites? I believe that we'll see somewhat of a shake down in the realm of social networks. They will be on plenty of sites, and the smart ones will use some means of identity sharing between them. However, I believe that the social networking destinations will need something of real value to offer their users. Otherwise, with nothing invested, and nothing returned, there's not much reason to build a profile. Eventually, social networking will become the byproduct of something more useful.

Thursday, February 07, 2008

February New Technology Meetup - Boulder

Tuesday, I had the opportunity to present one of the sites I've been working on in the past year - ReferenceVault. I was trying to break the record for the number of slides presented in the span of time I had. In 5 minutes, I went through 54 slides, and did a 90 second demo of the site. Pretty fun.

Here's a picture of me requesting a reference captured by one of the BrightKite guys.


Tuesday, January 22, 2008

Leopard for the Web Developer - Running Tomcat as a Service

In my experimentation with configuring multiple virtualhosts with SSL, I stumbled upon the magic of launchd within mac os x. I use it to make a call to ifconfig when I start up to create a new loopback interface, and it works splendidly. Knowing that it would work on startup, I thought I'd apply the principles to Tomcat.

The process of setting up Tomcat as a service in Leopard is extremely simple. It goes something like this:

  1. Download Tomcat
  2. Unpack Tomcat where you want it (/usr/local/tomcat is a good spot)
  3. Create a lauchd plist configuration to point to the tomcat executable
  4. Place that configuration file someplace where launchd will find it.
  5. invoke launchdctl to install the new service
Once you do steps 1 and 2, it's time to create the launchd plist file. Here's what mine looks like -- I'll explain what's going on following

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>

<key>Disabled</key>
<false/>

<key>EnvironmentVariables</key>
<dict>
<key>JAVA_HOME</key>
<string>/System/Library/Frameworks/JavaVM.framework/Home</string>
</dict>

<key>Label</key>
<string>org.apache.tomcat.tomcat6</string>

<key>ProgramArguments</key>
<array>
<string>/usr/local/tomcat6/bin/catalina.sh</string>
<string>run</string>
</array>

<key>RunAtLoad</key>
<true/>

<key>ServiceDescription</key>
<string>Tomcat 6 Server</string>

</dict>
</plist>

OK, here's what's happening. The plist defines a dictionary data structure instructing launchd how it should work. You'll see a <key> followed by a value of some sort. I'll go key by key.

  1. Disabled - a boolean value.
    If you want to have this active, set the value to false, as it is here. If you want to disable the service without uninstalling it, just change the disabled value to true.
  2. EnvironmentVariables - a (sub)dictionary value.
    This is just a set of name value pairs defining environment variables that you might need. In our case, Tomcat needs to know what JAVA_HOME is. You can set more if you want by adding more <key> and <string> pairs
  3. Label - a String value.
    This one is really important. It needs to be a unique identifier for the launchd process. launchd keeps track of all the things it starts and stops with this Label value. Just make sure that it's unique. It's common practice to use the reverse-domain syntax that you see here (org.apache.tomcat.tomcat6). Incidentally, it's also common practice to name this plist file with the same label (org.apache.tomcat.tomcat6.plist)
  4. ProgramArguments - an array of strings.
    Think of this as what you would type at the command line. Basically, anything you can do at the command line can be placed in a ProgramArguments value. The first string in the array is the executable program that you wish to run. Anything following is an argument that you would pass to that command. In our case, this merely does the following command:
    /usr/local/tomcat6/bin/catalina.sh run
  5. RunAtLoad - boolean value.
    This is what makes this a service, telling OS X that this should run when starting up.
  6. ServiceDescription - String value.
    This helps in the console to figure out what's running. It should just be some sort of description identifying the process. In this case, Tomcat 6 Server.
And that's it for the configuration file. Go ahead and save it as org.apache.tomcat.tomcat6.plist on your desktop, or somewhere else obvious. We'll move it to where it needs to reside next.

Launchd looks in a couple of places for these kinds of configuration files. From the man pages of launchd:

~/Library/LaunchAgents         Per-user agents provided by the user.
/Library/LaunchAgents Per-user agents provided by the administrator.
/Library/LaunchDaemons System wide daemons provided by the administrator.
/System/Library/LaunchAgents Mac OS X Per-user agents.
/System/Library/LaunchDaemons Mac OS X System wide daemons.


Since I want tomcat to start up as a machine process, not a user one, I place it in /Library/LaunchDaemons. If I wanted to make it a user process, I put it in ~/Library/LaunchAgents. A couple notes about this. First, if you put your file in /Library/LaunchDaemons, the plist file needs to be owned by root. The easiest way to do this is to open Terminal and do a "sudo cp org.apache.tomcat.tomcat6.plist /Library/LaunchDaemons/". This will make root own the file so it can start up as a system process. Second, if you decide to place the file in ~/Library/LaunchAgents, you don't need root ownership, but you do need to make sure the directory exists. By default, Leopard does not have a "LaunchAgents" folder in the user Library. So, you might have to make that directory before you copy your file there.

Final step, you'll need the Terminal. It's install time.

If you placed the plist in /Library/LaunchDaemons, do this

sudo launchctl load /Library/LaunchDaemons/org.apache.tomcat.tomcat6.plist


If you placed the plist in ~/Library/LaunchAgents, do this

launchctl load ~/Library/LaunchAgents/org.apache.tomcat.tomcat6.plist


That should do it. You now have Tomcat installed as a service on Leopard.

Friday, January 18, 2008

JSON Recursion -- Making a Self Reference

I have been working on a simple JSON library in Java which will allow me to serialize a JSON string. I'm pretty satisfied with the results so far, and I intend to release the code, however, until today, there was one thing that threw me for a loop. Writing JSON including a self reference. Here's the problem

When you write the following JSON syntax:

{"me":this}

You expect that when you access the 'me' property, it would give a reference to that object. However, what you get instead is a reference to the Window object. This happens because the closures that javascript has assigns the 'this' to the Window because during the construction of the new object, the new object doesn't yet exist, and 'this' still refers to the Window. Not what we wanted.

Here's the fix:
{
"me":function(){
this.me = this;
return this;
}
}.me()

Instead of assigning the 'me' attribute to 'this' right away, we construct the object, setting the 'me' attribute to a function. The 'me' function re-assigns its own value, and in effect, kind of self-destructs. Finally, we make the 'me' function return a reference to 'this'. 'me' is now assigned a reference to itself.

This method works within an eval as well. It also nests pretty well too. Here's a more complicated example, with a sub-object containing a self reference, as well as multiple self-references:
{
"me":function(){this.me = this; return this;},
"alsoMe":function(){this.alsoMe = this; return this;},
"subObject":{
"subMe":function(){this.subMe = this; return this;}
}.subMe()
}.me().alsoMe()

Friday, December 21, 2007

Two arms, two legs, and 140 bpm

Today Shana and I went to have an ultrasound done. The baby we're expecting is healthy and doing well. According to the measurements, we're probably a little ahead in our estimates for the due date. The baby might be a week older than we thought. Nevertheless, we're both extremely happy, thankful and blessed to have another healthy baby on the way.

I was pleasantly surprised when we got the dvd in our hands and it was an actual movie. And now, here it is for the world to see.

Oh, and what about the sex? You'll have to watch and see for yourself. And if you like, leave some naming suggestions in the comments. We're open minded, but yes, picky too :-)

Wednesday, November 14, 2007

Leopard for the Web Developer - Multiple Virtualhosts with SSL in Apache

The goal is simple but lofty -- configure Apache for multiple SSL virtualhosts in Mac OS X Leopard.

In practice, this gets a little complicated. Here are the basic set of steps to take:

  1. Configure domain name resolution for the development host names
  2. Configure distinct IP address aliases for those host names (critical for multiple SSL Virtualhosts)
  3. Create the self-signed SSL certificate(s)
  4. Enable the correct modules and configuration files for Apache.
However, before we begin, lets do a little bit of preparation. The first thing you'll want to do is determine which host names you're going to use. For example, let's say you have 2 development domains -- local.lo-fi.net and dev.lo-fi.net -- each of these will be a different development project, pointing to different resources on the file system. Once you know which host names you'll be configuring your environment for, you need to choose the distinct IP address to give them. For the record, distinct IP addresses aren't important if you don't plan on using SSL. However, if you do need SSL on these domains, a distinct IP address is critical. I don't know all the details, but, from experience I can tell you that an SSL certificate somehow binds to a single IP address. If you're a little lost, don't worry, more details about the SSL stuff follow. The point is, you need to decide which IP addresses you want to use for the host names.

For my purposes, I want my host names to work much like "localhost" works. I just want a host name to point to my local computer. Basically, here's what I want:

host: localhost = ip: 127.0.0.1
host: local.lo-fi.net = ip: 127.0.0.2
host: dev.lo-fi.net = ip: 127.0.0.3

Now that you've made this decision, you can move forward.

Configuring Domain Name Resolution for the Development Host Name

This is the easiest part, by far. Simply open /etc/hosts with your favorite text editor, and add a few lines. The following is what mine will look like.


##
# Host Database
#
# localhost is used to configure the loopback interface
# when the system is booting. Do not change this entry.
##
127.0.0.1 localhost
255.255.255.255 broadcasthost
::1 localhost
fe80::1%lo0 localhost

#Development domains
127.0.0.2 local.lo-fi.net
127.0.0.3 dev.lo-fi.net

All of the "localhost" lines should already exist for you. The 2 lines that are relevant to you are the ones showing the desired ip addresses with the development domains. After you save this, if you try pinging "local.lo-fi.net", your computer will try to connect to the ip address "127.0.0.2" However, that IP address doesn't exist yet. That's next.

Configuring IP Aliases with ifconfig and launchd

Since I want to have my host names act like localhost does, I'm going to add aliases to the loopback network interface. You can do this in the terminal by typing:

sudo ifconfig lo0 alias 127.0.0.2 netmask 255.255.255.0
sudo ifconfig lo0 alias 127.0.0.3 netmask 255.255.255.0
Now, when you ping "local.lo-fi.net", your computer tries to contact 127.0.0.2, and you get a result. Great! This is exactly what we want -- well, kind of. When you log out or re-boot, this configuration is lost. What we really want is for this to happen at startup, so we don't have to re-configure ifconfig every time we start our computer.

Making this happen is one of the coolest things in this process -- at least, that's what I think. Before I get to the decided solution, I'll back up just a bit. In previous versions of Mac OS X, you could edit the /etc/iftab file, consisting of lines with the arguments you'd send to ifconfig (eg. lo0 alias 127.0.0.2 netmask 255.255.255.0), and this would get picked up and work when starting up. However, in Leopard iftab is gone. What's a developer to do? One solution I found leveraged Automator, but I figured out something much more elegant.

Launchd to the rescue!

Launchd is a daemon running in OS X that is responsible for lots of process management. It's designed to be a powerful replacement for other types of service management tools like inetd, rc, and even cron. What's neat is that you can create a plist configuration file pointing to the executable file you want to run, put it in a specific place, and the system executes it at the right time. What we're going to do is create a plist file for each of our network aliases. These plist files will actually execute ifconfig with the arguments we need, and do it as the privileged root user without any manual intervention.

We're going to create 2 plist files:

/Library/LaunchDaemons/net.lo-fi.local.ifconfig.plist
/Library/LaunchDaemons/net.lo-fi.dev.ifconfig.plist
OK, here's the content of one of these files (net.lo-fi.local.ifconfig):

<plist version="1.0">
<dict>
<key>Label</key>
<string>net.lo-fi.local.ifconfig</string>
<key>ProgramArguments</key>
<array>
<string>/sbin/ifconfig</string>
<string>lo0</string>
<string>alias</string>
<string>127.0.0.2</string>
<string>netmask</string>
<string>255.255.255.0</string>
</array>
<key>RunAtLoad</key>
<true/>
</dict>
</plist>

I won't go into the nitty gritty about launchd plist files, but basically this file does 3 things.
  1. Declares a unique Label name (net.lo-fi.local.ifconfig)
  2. Declares the program to run (ifconfig), as well as the arguments that follow
  3. Tells launchd to run this at load time
Finally, these files need to be owned by root. So, if you haven't already, do this:
sudo chown root:wheel /Library/LaunchDaemons/net.lo-fi.local.ifconfig.plist
sudo chown root:wheel /Library/LaunchDaemons/net.lo-fi.dev.ifconfig.plist
Now, if you re-boot, these files will execute ifconfig with the arguments you need. It's so simple, it's beautiful.

Self Signed SSL Certificates

I have to admit, I followed the instructions for creating a self signed certificate here, with splendid results. If you're interested in the details about how creating a self signed certificate works, it's worth your time to read it. If you don't care, and just want something to work, you probably won't need more than what I show you below. However, here's the high level overview of what I'm about to do.
  1. Create a certificate for our own personal signing authority
  2. Create a certificate request for a domain
  3. Sign the certificate signing request, and generate a signed certificate
  4. Make a copy of the signed certificate that doesn't need a password when apache starts
I did this all in a "ssl" directory I created in /etc/apache2

sudo mkdir /etc/apache2/ssl
cd /etc/apache2/ssl


1. Generate your own Certificate Authority (CA). Make sure to remember the passphrase you're prompted for. This is what you use to sign certificates.

sudo openssl genrsa -des3 -out ca.key 4096
sudo openssl req -new -x509 -days 1825 -key ca.key -out ca.crt

2. Generate a server key and request for signing (csr). When prompted for the Common Name (CN), enter the domain name you want the certificate for. In my case, the Common Name would be "local.lo-fi.net"

sudo openssl genrsa -des3 -out local.lo-fi.net.key 4096
sudo openssl req -new -key local.lo-fi.net.key -out local.lo-fi.net.csr


3. Sign the certificate signing request with the self-created certificate authority that you made earlier

sudo openssl x509 -req -days 1825 -in local.lo-fi.net.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out local.lo-fi.net.cst

4. Make a key which doesn't cause apache to prompt for a password.

sudo openssl rsa -in local.lo-fi.net.key -out local.lo-fi.net.key.insecure
sudo mv local.lo-fi.net.key local.lo-fi.net.key.secure
sudo mv local.lo-fi.net.key.insecure local.lo-fi.net.key


Repeat steps 2 through 4 for each distinct domain you want to create a certificate for. Another thing that you can do, is name wildcards for your common name. For example, if I wanted a certificate that I could use an all subdomains of lo-fi.net, I can enter a Common Name of "*.lo-fi.net"

Just to review, here's what you should have in your directory

$ ls /etc/apache2/ssl
ca.crt
ca.key
dev.lo-fi.net.crt
dev.lo-fi.net.csr
dev.lo-fi.net.key
dev.lo-fi.net.key.secure
local.lo-fi.net.crt
local.lo-fi.net.csr
local.lo-fi.net.key
local.lo-fi.net.key.secure


Now, you have everything you need for setting up the virtualhost for your domains.

Here's what you've all been waiting for! Configuring multiple virtualhosts with SSL.

Here's the high level review of what we need to do:
  1. Configure virtualhosting
  2. Configure mod_ssl
  3. Add virtualhost configurations for our new hosts.
The first step to take is to tell Apache to include some files. The specific files we need to have included are the ones designed for virtualhost and ssl configuration. By default, these are not included. To include them, open /etc/apache2/httpd.conf, and go to the bottom of the file. Around lines 461 amd 473, you'll have the opportunity to un-comment the relevant include lines. Here's what it should look like once you're done.
# Virtual hosts
Include /private/etc/apache2/extra/httpd-vhosts.conf
and
# Secure (SSL/TLS) connections
Include /private/etc/apache2/extra/httpd-ssl.conf

Once that is done, you'll need to edit these files somewhat. httpd-vhosts.conf configures virtualhosts running on port 80, designed to apply name-based virtualhosting. I include it here, because I want to test sites on both port 80 and port 443 (https). Using name-based virtualhosting is actually pretty nice for domains when ssl isn't required. All you have to do is create a new <virtualhost> entry, with a "ServerName [whatever.com]" line, and you have a new virtualhost. However, for this file, I'm just going remove the dummy virtualhosts that are in this file as examples, and set a default. Here is what I like to use.

#
# Use name-based virtual hosting.
#
NameVirtualHost *:80

#
# VirtualHost example:
# Almost any Apache directive may go into a VirtualHost container.
# The first VirtualHost section is used for all requests that do not
# match a ServerName or ServerAlias in any <VirtualHost> block.
#
<VirtualHost _default_:80>
ServerAdmin eric@mac.com
DocumentRoot "/Library/WebServer/Documents"
ServerName localhost
ErrorLog /private/var/log/apache2/error_log
CustomLog /private/var/log/apache2/access_log common
</VirtualHost>

This configuration does 2 things, it names a wildcard virtualhost for port 80, and it defines a virtualhost that will be used for everything other than a name-based virtualhost that we might define later. That does it for the httpd-vhosts.conf file.

Next up is the mod_ssl configuration in the httpd-ssl.conf file. The modification for this should be pretty simple. This file does 2 things. First, it sets up the basic configuration for the ssl module. Second, it contains virtualhost configuration for a default virtualhost for port 443. The easiest way to deal with this file is to comment out the default virtualhost configuration (which starts around line 75). This configuration is designed to give you an ssl virtualhost for any host that isn't matched by another specific virtualhost. If this is something you'd like to do, all you have to do is make sure that you have a valid certificate and a key. Look for these lines (line 99 and 107):
SSLCertificateFile "/private/etc/apache2/server.crt"
and
SSLCertificateKeyFile "/private/etc/apache2/server.key"
If you want to enable this default ssl virtualhost, adjust them as necessary, such that they point to a certificate and key that you have created. OK, now save that file and you're good to go.

The final step is to create some virtualhost files for your domains. I create one per domain, and place them in /etc/apache2/other. Any file with a ".conf" extension is picked up by apache when it starts up. I like to name my files with the domain I'm configuring.
local.lo-fi.net.conf
dev.lo-fi.net.conf


Finally, we can configure the virtualhosts. Here is what mine look like:

local.lo-fi.net.conf


<VirtualHost *:80>
ServerName local.lo-fi.net
DocumentRoot /Users/eric/WebApps/local.lo-fi.net/webroot
ServerAdmin eric@guesswhere.net
<Directory "/Users/eric/WebApps/local.lo-fi.net/webroot">
AllowOverride All
Options
Order allow,deny
Allow from all
</Directory>
</VirtualHost>

#Note the loopback ip address we set up for this host
#local.lo-fi.net = 127.0.0.2
<VirtualHost 127.0.0.2:443>
ServerName local.lo-fi.net
DocumentRoot /Users/eric/WebApps/local.lo-fi.net/webroot
ServerAdmin eric@guesswhere.net
<Directory "/Users/eric/WebApps/local.lo-fi.net/webroot">
AllowOverride All
Options
Order allow,deny
Allow from all
</Directory>

# SSL Configuration
SSLEngine on
SSLCipherSuite ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP
SSLOptions +FakeBasicAuth +ExportCertData +StdEnvVars +StrictRequire

#Self Signed certificates
SSLCertificateFile /etc/apache2/ssl/local.lo-fi.net.crt
SSLCertificateKeyFile /etc/apache2/ssl/local.lo-fi.net.key
SSLCertificateChainFile /etc/apache2/ssl/ca.crt

#DON'T DO ANY INTENSIVE SSL OPERATIONS UNLESS THE FILE IS html OR php
<Files ~ "\.(html|php?)$">
SSLOptions +StdEnvVars
</Files>
SetEnvIf User-Agent ".*MSIE.*" nokeepalive ssl-unclean-shutdown downgrade-1.0 force-response-1.0

</VirtualHost>


dev.lo-fi.net.conf


<VirtualHost *:80>
ServerName dev.lo-fi.net
DocumentRoot /Users/eric/WebApps/dev.lo-fi.net/webroot
ServerAdmin eric@guesswhere.net
<Directory "/Users/eric/WebApps/dev.lo-fi.net/webroot">
AllowOverride All
Options
Order allow,deny
Allow from all
</Directory>
</VirtualHost>

#Note the loopback ip address we set up for this host
#dev.lo-fi.net = 127.0.0.3
<VirtualHost 127.0.0.3:443>
ServerName dev.lo-fi.net
DocumentRoot /Users/eric/WebApps/dev.lo-fi.net/webroot
ServerAdmin eric@guesswhere.net
<Directory "/Users/eric/WebApps/dev.lo-fi.net/webroot">
AllowOverride All
Options
Order allow,deny
Allow from all
</Directory>

# SSL Configuration
SSLEngine on
SSLCipherSuite ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP
SSLOptions +FakeBasicAuth +ExportCertData +StdEnvVars +StrictRequire

#Self Signed certificates
SSLCertificateFile /etc/apache2/ssl/dev.lo-fi.net.crt
SSLCertificateKeyFile /etc/apache2/ssl/dev.lo-fi.net.key
SSLCertificateChainFile /etc/apache2/ssl/ca.crt

#DON'T DO ANY INTENSIVE SSL OPERATIONS UNLESS THE FILE IS html OR php
<Files ~ "\.(html|php?)$">
SSLOptions +StdEnvVars
</Files>
SetEnvIf User-Agent ".*MSIE.*" nokeepalive ssl-unclean-shutdown downgrade-1.0 force-response-1.0

</VirtualHost>


And there you have it. SSL for multiple virtualhosts in Apache for Mac OS X Leopard. Once you restart Apache, you should be up and running, sending the correct Self Signed certificates to the browser.

Monday, October 29, 2007

Leopard for the Web Developer - installing mod_jk

Today I was pleased to get a few comments from a fellow programmer anxious to set up his Mac so Apache could connect with Tomcat with the help of mod_jk. He came looking for info, found none, and kindly came back later to reveal his findings. Here's billo's instructions about how to install mod_jk on Mac OS X Leopard (for an intel Mac).



He explains in some pretty good detail why it fails out of the tar-box, so I won't go into it. However, what I will do is give you a line-by-line for how to make it work. I had to fill in a couple gaps after finding out what the problem was. Here's what you need to do.



1. Download and unpack the source of mod_jk (I installed version 1.2.25)



2. Make your way into the source directory (tomcat-connectors-[version]-src/native)


$ cd tomcat-connectors-1.2.25-src/native


3. Edit the apache-2.0/Makefile.apxs.in file with billo's fix. This is the solution that fixes the build. What you need to do is replace these lines:


mod_jk.la:
$(APXS) -c -o $@ -Wc,"${APXSCFLAGS} ${JK_INCL}" "${JAVA_INCL}" "${APXSLDFLAGS}" mod_jk.c ${APACHE_OBJECTS}

with these:


mod_jk.la:
$(APXS) -c -o $@ -Wc,"${APXSCFLAGS} -arch x86_64 ${JK_INCL}" "${JAVA_INCL}" "${APXSLDFLAGS} -arch x86_64 " mod_jk.c ${APACHE_OBJECTS}

The tab at the beginning of the $(APXS) line is very important! Don't remove it.



4. While you're in the [src]/native directory, configure the build files


$ ./configure --with-apxs=/usr/sbin/apxs


5. Change directory into apache-2.0 and get ready to build.


$ cd apache-2.0


6. Make the module using apxs as your compiler


$ make -f Makefile.apxs


7. Install the module


$ sudo make install


From there, you're on your own getting it configured for Apache. But the documentation for configuring mod_jk is  abundant.

Leopard for the Web Developer - Restoration Stategy

One of the goals I have for installing Leopard is to start with a clean installation, so I can use it to restore if I should ever mess things up sufficiently, as to require starting over. My intention was to install a clean OS onto an external hard drive, then create a disk image of that prefect system so I can use it to restore from. I was inspired with this idea after reading this fantastic set of instructions for backing up a Mac, and reading the man pages of asr and hdiutil. With these feathers in my cap, I wrote up a VERY CRUDE shell script to do it all, being the nerd that I am. Here it is:


#!/bin/bash

# This is a script designed to build a restorable disk image
# from a specified volume

# set up the variables.
method=$1
diskImage=$2
theVolume=$3
volumeName=$4

# Help method
help(){
echo "This is the help"
}

# This is the create method
create(){
image=$1
volume=$2
volname=$3
tempImage=$image"_temp"
#if [$volname] ; then
#echo $volname
#else
# volname="Mac Restore"
#fi;
#1. use hdiutil to create the image - make it a read write version
echo "hdiutil create $tempImage -ov -format UDRW -nocrossdev -srcfolder $volume -volname $volname"
hdiutil create $tempImage -ov -format UDRW -nocrossdev -srcfolder $volume -volname $volname

#2. mount the image
echo "hdiutil attach $tempImage.dmg"
hdiutil attach $tempImage.dmg

#3. Clean it up manually
echo "rm -f /Volumes/$volname/var/db/BootCache.playlist"
rm -f /Volumes/$volname/var/db/BootCache.playlist
echo "rm -f /Volumes/$volname/var/db/volinfo.database"
rm -f /Volumes/$volname/var/db/volinfo.database
echo "rm -rf /Volumes/$volname/var/vm/swap*"
rm -rf /Volumes/$volname/var/vm/swap*

#4. unmount the volume
echo "hdiutil detach /Volumes/$volname"
hdiutil detach /Volumes/$volname

#5. Convert the image into a read only compressed version
echo "hdiutil convert -format UDZO $tempImage.dmg -o $image"
hdiutil convert -format UDZO $tempImage.dmg -o $image

#6. Delete the temp image
echo "rm $tempImage"
rm $tempImage

#7. use asr to build the checksums so I can use the image to do a restore
echo "asr -imagescan $image.dmg"
asr -imagescan $image.dmg
}

# Default method restores the image $1 to the volume $2
restore(){
image = $1
volume = $2

echo "asr restore --source $image --target $volume --erase"
}

case $method in
create)
create $2 $3 $4
;;

restore)
restore $2 $3
;;

help)
help
;;
esac

The only problem is that it didn't work for me. I'd run this, saving the image file to a location on another partition of my external harddrive, and it would fail every time. Thinking that I was a little too ambitious and amateur to build my own shell script to handle it, I thought I'd try Carbon Copy Cloner, which is a fabulous backup software. In various configurations, it too failed every time. As a last resort, I tried using the DiskUtility app that ships with OS X. Once again failure.

What's interesting is how each of these approaches fail. Each time, creating an image file failed when the file size approached 4 Gigabytes. That was my key. It turns out that the partition that I use to do my backups on the external harddrive is formatted with a FAT32 file system. This is unfortunately required because I need my wife's PC to access the drive as well. After doing a little research, I found that FAT32 has a file size limit of just under 4 Gigs. Drats!

Now, my strategy for creating a perfect restorable disk image must change. I can't save the image on the backup drive as I intended. Instead of creating a restorable image, which I just think would be super cool, I think I'm going to have to do something else. I'll probably just restore from one disk to the other, and figure out how to save a disk image later. I'm thinking that I might just save it to a server on the network. I just have to set up the server :-)

Instead of focusing on the image creation, I think I'll push forward with the set up and install.

Up next: Apache, MySQL and PHP customization in Lepoard.

Wednesday, October 24, 2007

Leopard for the Web Developer

I did it. I pre-ordered Mac OS X Leopard. I'm looking forward to getting it for lots of reasons, but primarily because I plan on setting up a system that's just super righteous for a web developer (mostly java and php related).

In the posts to come, I'll list the steps involved in installing and configuring various features. My ultimate goal is to set up a disk image that contains the righteous set-up, so that I can restore it to my hard drive when I need to. I'll do this by installing Leopard onto an external drive before I actually install it on my Mac. This will afford me the luxury of making a disk image that's totally clean and uncluttered of the personal stuff, and allow me to continue work as usual while I perfect the Leopard install.

Stay tuned! Among the things I plan on doing include:

  • Configuring Apache Virtualhosts to handle custom domains under development.
  • Setting up the hosts file for those domains
  • Running PHP4 and PHP5 on the same apache install - both as a module!
  • Install Tomcat 5.5 and Tomcat 6 - maybe to run as a service
  • Connect Apache web server to Tomcat installations with modjk
  • Create at least one self-signed SSL Certificate for testing Secure domains in Apache
  • Install Eclipse as well as various plugins
  • Install Maven
  • Install Subversion
  • Install MySQL
  • I haven't played with it yet, but it seems like a glaring omission to leave out a Ruby on Rails set up. I may do that if I get inspired.
  • Install virtualization software. I have Parallels 2 now, but I'm considering a move to VMWare's Fusion. It's really a matter of dedicating the dollars. An upgrade to Parallels 3 is almost the same as buying Fusion outright.
So there it is! I expect that I'll get rolling with the details this weekend.

Tuesday, October 16, 2007

Respect the Barista

This year, on the dates of Sept 26th through October 4th, I celebrated the Feast of Tabernacles. It was established by God to be observed as a "statute forever in your generations" (His words, not mine -- Leviticus 23:41). For those who are unaware, essentially, the Feast of Tabernacles is the last set of holy days of the year in the Bible. This particular feast looks forward to the establishment of God's Kingdom on Earth -- really, this is the fulfillment of God's whole plan, the meaning of life. If you're interested in learning more, check out this fantastic literature about God's Holy Days, and this one about the Fall Holy Days.

All this is to give you a little context. One of everyone's favorite scriptures involving the Feast of Tabernacles is Deuteronomy 14:26, which says:

"And you shall spend that money for whatever your heart desires: for oxen or sheep, for wine or similar drink, for whatever your heart desires; you shall eat there before the Lord your God, and you shall rejoice, you and your household."

Of course, that doesn't mean that I should go to Vegas and spend it all on sin. But it does say that I can spend the money I save all year for whatever my heart desires.

Well, this year, my heart desired a good caffeine buzz. We got the Rancilio Miss Silvia espresso machine and the Rancilio Rocky espresso grinder through Jellyfish. So far, so good. With this set up and some killer local coffee beans, my 'spro rivals the best coffee shops in town. Check it out!




That's right. 25 second shots. Mmmmmmmm, good!

Wednesday, July 25, 2007

Struts 2 Security Update

A couple of weeks ago, a remote exploit was demonstrated for applications using Struts 2.0.8 and below. It's a scary one. Like System.exit(0) scary. In some ways I can't believe that it got this far because it's such a simple one.

Anyway, if you're using Struts 2 below verson 2.0.9, or if you're using WebWork below version 2.0.4, do yourself a favor and UPDATE your jars.

Easy way: just update your xwork jar file (download the full lib here)
Better way: update to Struts2.0.9

Sunday, July 22, 2007

Social Networking is Candy

I have some opinions about the current trends I've been seeing with new and emerging web sites. It seems that every single day, tech crunch posts something about a new social networking site getting seven figure venture capitalist investment. It makes me shake my head. This is why.

The underlying goal of social networking sites is communication with other people. And that's cool. We human beings love communication. I believe it's one of the core human needs. If you think of the major leaps in technology, many of them relate to advancement in communication methods. And if not directly, indirectly. Many advances help us to communicate with others better. The same is true with websites.

I can't help but notice a couple challenges facing a new social networking business model though.

1. Maintenance.

Keeping up with them numerous accounts on various sites is challenging at best. Just as it becomes increasingly time consuming and burdensom when you have multiple phone numbers, or multiple email addresses, belonging to many social networking sites requires overhead. I believe that Facebook is right on with adding applications, though, because this will allow it's users to pool their needs to communicate in one place. The need to belong to another type of social networking site, which has a specific purpose, becomes less gravitational. The more a user has invested in a single site, with a single account, the more reason there is to stay at that one place. This means that the flood of social networking sites we see today with specific purposes may become overshadowed by Facebook, simply because users don't want to keep up with an account in too many places at once.

2. Longevity.

Remember Friendster? What about MySpace? Facebook has grown immensely in the past year, simply because its the next thing, and facilitates communication in a slightly different way. And yes, unlike another popular site, it helps that it actually looks OK. MySpace is certainly not dead, but it's not the buzz that it was a year ago. I can't help but notice how trendy these sites are. It doesn't take a rocket scientist to figure out that soon a new site will launch, with a new twist on networking, and will take over as the place to keep in touch with people. If I may make a prediction, I'll say that the next big site will do something amazing related to integrating our cellphones and portable devices (on and off line).

3. Utility.

Sites that have longevity have something in common. People DO something with them. They use them. There's an investment involved. Flickr has all your photos, Hotmail / Gmail has your email, Ebay is your source of income, Wikipedia is your source for information, and Google is your oracle. Does Myspace or Facebook _have_ your friends? Not really, that's just where you hang out virtually. What does it DO for you? The answer? These sites give you a place and a medium to communicate. But the nature of communication is ethereal. It exists, and then it's gone. It has an expiration date. With the exception of time, there's little to no investment from an account holder at purely social networking sites. There's just the convenience of being in the same virtual place at the same virtual time with your friends, and adding customizations to your profile. This is not to say that facilitating communication is not useful. What I'm saying is that the value of that communication on social networking sites is mostly trivial. How many MySpace pages have endless streams of "LOL" and "Dude, how's it goin'?" conversations?

4. Excitement.

One of the best parts of signing on with a social networking account, is the process of building your account, loading it with connections to friends. It's really exciting when it's new, because so much happens so fast. However, once all of your close friends are signed up, the pace of growth slows down, and the thrill is gone. This alone makes for a short term life span.

Now, I'm not saying that there's no place for a social networking business model. It works for a specific purpose. It facilitates communication. But, we communicate in so many various ways, that one place on the internet to do it all just isn't lasting. We love new and novel means of communicating too. It gets easy to cut our losses when we leave an account at one site for another site because any communication through these sites has already served it's purpose. It's only of archival purpose once it exists. Much like a new car, the value of a communicated idea decreases at a dramatic pace (the IDEA communicated, on the other hand, is of some value... sometimes)

Social networking is candy. Lots of fun, but of no real nutritional, lasting value. I have to add as a disclaimer to all of this that I don't do much on social networking sites. They bore me. I love to communicate with people who I know and whom I don't know, but if I want to communicate something important, I have SO many ways to do it that work better than a website.

What does this mean? I believe that social networking sites are a flash in the pan, a gold rush if you will. It's not lasting though. Just exciting. As someone who is investing the future of his career in the industry, I just hope that the hype doesn't get out of hand, like it did in our recent past.

Monday, June 04, 2007

Imperial Stout via Batch Sparge

My brother-in-law and I recently started brewing beer. Being in Fort Collins, amongst some top-class breweries, we thought we'd be in good company.

Robb's got extensive experience in the craft, having brewed scores of quality beers, meads and wines. On the other hand, I have done very little. After making 2 or 3 batches in the dorm kitchen about 10 years ago, I just gave up. I found it much easier to run down to the corner for a sixer after I became of the age to legally purchase. Nevertheless, I love making my own stuff, and having a discriminating palette, I've always wanted to get back into making beer. With summer nigh upon us, and plenty of "Yeah, dude. We gotta brew!" conversations through the past year, Robb and I finally jumped in head first making beer.

Our last batch was a pale ale using Crystal hops exclusively. It turned out to be pretty good. A little light in body, cloudy, and not quite bitter enough, but Mmmmm tasty. One of the best things about home brew is that you get a chance to make more if it's not quite right -- and if it's perfect for that matter too.

Yesterday, we set out to build an Imperial Stout. We used an award winning recipe from Robb's stash, with a full 18lbs of grain for a ~5 gallon batch (Yowza!). We decided to omit the 10 lbs. of raspberries it called for, as neither of us have the garden, nor the budget for such an extravagant adjunct.

We started at about 8 in the morning with some donuts, coffee and a wee bit of mead Robb happened to find hibernating in a forgotten Corny keg. The mashing went a little less than controlled. We started with water that was about 4 degrees outside of the envelope of enzymatic activity we wanted, and semi-frantically (only as frantic as home brew allows) tried to cool it down, as you would a hot bowl of oatmeal. Then we went in for some breakfast. When we got back out, it was way too cool, by about 10 degrees F. I hypothesize because it was sitting on the concrete. We decided to put it back on heat for a bit until the temp got to where it needed to be.

I was in charge of the re-heat. I stirred while the pot was over the flame, and watched the thermometer closely. It rose pretty slowly, until I gave it a good stir. And suddenly it was like 20 degrees too hot. Real nice. With any enzymes completely fried that would help us out with any starch conversion, we decided to check the status. Fortunately our starch converted. Whew!

After a discussion with the friendly owner of the local home brew shop, we decided to batch sparge our mash. I didn't quite understand the process at first, but it turns out to be pretty simple. Instead of letting the grain sit while spending an hour sprinkling hot water over it, you go through a process of draining the mash at full speed, stirring in the sparge water in a couple batches until you have your desired volume. The best instructions for batch sparging, we found at brew365. There's lots of other articles about the technique, but few make it seem as simple as it is.

After that, everything went as planned. We got the gravity reading we were hoping for too (with 18 lbs of grains we BETTER). It should be quite a stout stout.

Robb just sent me a movie of the fruits of our labor. She lives!