So, I had a heart attack and bypass surgery

Hey y’all. So, I had a heart attack and bypass surgery. Here is the full story.

Friday (3/31) and Saturday (4/1) nights I had chest pain that I thought was acid reflux. On Sunday morning, the pain returned. I checked my blood pressure. It was 170/103. I took some anxiety meds, gas x, and aspirin. An hour later it was still high.

So we went to the ER. Blood work showed troponin in my blood. “When heart muscles become damaged, troponin is sent into the bloodstream. As heart damage increases, greater amounts of troponin are released in the blood.” I was then admitted for observation and further testing.

On Monday (4/3) morning they performed an echocardiogram. There were some abnormalities. They then performed a heart catheter. I had 90% blockage in at least one artery. And blockages in several others. I was immediately transferred to UAB hospital.

Later that day I met with a surgeon. After discussing it with him, we decided to do bypass surgery. The long term success rate with this surgery at my age is better than the alternatives. Surgery was booked for Thursday, April 6.

On Tuesday (4/4) and Wednesday (4/5) I just hung out at the hospital. I could have another heart attack at any moment. Going home was not an option. Friends and family visited. I had some hard conversations with family about what to do “just in case”. Those conversations don’t phase me. And the family I spoke to were very practical about it as well.

Early Thursday morning, before dawn, I broke down a little bit. The reality that I could not wake up was hitting me. I knew it was not likely. These procedures are done every day. My doctor would probably do several that day alone. Still, it could have happened. It’s normal for me to have these emotional outbursts alone. The first time I remember it happening was with my great grandmothers death when I was 15. It’s been the same with all my other grandparents’ deaths as well. It’s just how I deal with it.

Then it was time to go. The family that was there followed us down to the waiting room. Once I was in pre-op and settled they said I could have one person come back. They let two coke back. The nurse said we seemed like solid people. I don’t remember a lot about that time. I do remember Deedra deciding to read my chart. Haha. The staff walking by was confused. Then I was off. While still rolling me in, I started to feel woozy. And then black.

I wake up very confused with some voices I know and others I don’t know. I understand their instructions but don’t know how to follow them. I need to breath. Ok. There is something in my mouth. Oh it’s the ventilator of course. They can’t remove it until I breath. There are two people I know there. My ex wife, and mother of my six children, Robin, coaching me on what to do. Good I need that right now. And Amy, my platonic life partner, speaking to me softly and encouraging me to breath. Man, I really need that approach too. If you had asked me what two people I would want in that moment, I would probably not have chosen either of them. And yet, they were the perfect combination at that time. Some (I assume) nurse said “good job” and out came the ventilator. Based on when I knew I went into the OR and how long the surgery took, I would say this is around 2pm. People say they visited with me in recovery. I believe them. Still, I really don’t recall much until 5AM on Friday morning.

Friday was confusing. It’s like my mind was still trying to figure out what happened to my body.

Between Friday and Tuesday (4/11) I had good times and bad times. I eventually got to go home. That is where I am now. My strength has slowly been recovering. The last device attached to my body came off yesterday. It will be several weeks of very limited activity. Mostly I just can’t lift things or drive. Slowly that will be allowed more and more. Then once all restrictions are removed, I can start building up my strength again.

Who am I to call anyone a racist?

Recently, on Facebook, I was asked "Who are you to call anyone a racist?". To be clear, I did not call anyone a racist. But, really, let's say I did call someone a racist? Who am I to call anyone a racist? After all, I am a 47 year old, white, middle class man. I am, quite possibly, in the absolute sweet spot of my life for white privilege.

 

As a child, I heard older family members say racist things. Luckily, my parents made it clear to me that they were wrong and I should ignore them. So I have for 40+ years. Some of those racist things were said about my childhood best friend, who is black. Were they nasty, ugly, hateful remarks? No. They didn't use the "N" word. It was subtle things that made me question if I should have a best friend that is black. They found it confusing. They found it odd. It was clear they did not approve.

 

I was fortunate to have lived in a very diverse neighborhood in Huntsville, AL as a child. My next door neighbor was two years older than me. He was my best friend. I don't know if I was his best friend but he was definitely mine. And like I said, he is black. His father pulled the first tooth I lost. I spent so much time at his house as a child and he spent time at mine. We liked his house better because his parents had converted their two car garage into an awesome den/music hall. I was young and innocent as they say. I didn't know any different. I am so glad that was the case. I have not seen him in years as I moved away from Huntsville when I was eleven years old. A year or so ago, I did find his mother and sisters on Facebook and was able to reconnect with them online. He has a career in the Air Force. I am very proud to have called, and still consider, him my friend.

 

After living in Tuscumbia, AL for four years where racial topics were basically not discussed despite there being a neighborhood named Richman Hills where the road leading into it was named White City Drive, I moved to a suburb of Birmingham, AL. I have lived in the Birmingham area, including some years in the city proper, for all but two years of my life since I was 15 years old. This is the city where police turned fire hoses and dogs on protesters during the Civil Rights movement.

 

I found things in Birmingham different than they were in Huntsville. The Birmingham area was and still is highly segregated. It's not by law or force. It's mostly white flight which is itself a form of socioeconomic racism. It was a strange thing for me to realize as I grew older. I found the history of racial injustice to be just below the surface in Birmingham. I did not witness any overtly racist behavior in public. But, it was there, kind of like that subtle language my elders used when I was young. There was a lot of use of the words like "those people" or "they" when referring to black people. Again, I ignored the people saying these things and was silent.

 

Shortly after President Obama was elected, I was in a barber shop. It was not a local place. I travel for work between Birmingham and Huntsville very regularly. A small town between here and there had a barber shop. It was very convenient for me to stop in there on my way to Huntsville. I had been in there four or five times with little to no issues. Then one day, I am getting my haircut and a customer comes in. He and the barber seemed to know each other socially. They did not seem to be great friends, but they knew each other's names. At some point, the customer says, "You know what Lincoln, Kennedy, and Obama have in common?" I could think of nothing. The barber said "I don't know." The customer says "Nothing yet." I took a minute or so for it to sink in. He was saying that Obama would be assassinated. I was stunned. That was the most overt racism I had faced in years. The barber didn't seem too happy about it, but he didn't say anything about it either. I never went back to that barbershop. Now though, I regret that I ignored it and was silent.

 

During President Obama’s tenure, I saw posts on Facebook from friends and family, people I shared a meal with, that blamed him for all their problems. I unfollowed some of them. I ignored others. And, I was silent.

 

In the last three and a half years, I have seen many of those same people post things supporting President Trump and his agenda to divide this country. I unfollowed some of them. I ignored others. And, I was silent.

 

I have done my best to be a good example to my children the same way my parents were to me. The other day, I told my youngest child “I don’t think I need to say this, but I am going to.  Racism is wrong.” His response was “Of course Dad, I know that.” I wanted to be sure I said it out loud though.

 

I am done being silent. My silence has not helped the world.  Who am I to call anyone a racist? I am a 47 year old, white, middle class man. I will not ignore them and I will not be silent any longer.

Masks in Design and How They Relate to HTML/CSS

I have always struggled understanding the use of masks in design tools like Photoshop, Illustrator, and Sketch. I recently had to work on translating some creative from Sketch into a responsive design. I realized that a mask in these tools is like a containing element in HTML with overflow hidden and the contents being absolutely positioned.

This is not something you would want to do a lot of as there is a lot of the image being loaded that not being shown. But, it is useful in responsive designs.

See the Pen How masks in design tools translate to HTML by Brian Moon (@brianlmoon) on CodePen.

New Responsive Design

I have not blogged in over a year. Shame on me. I think part of the reason was because my blog template had become quite dated. I tweaked it a bit to make it semi-responsive a while back. But, I have never been happy with it.

So, I decided to build a new, mobile first template from scratch and use lots of modern (relative to my old template) CSS and responsive web design techniques. Things like rem for sizing things, flexbox, text-shadow, and background-size (for the header image). I know it is nothing ground-breaking. And, at the same time, it was nice to shed all the old compatibility layers and work with the code without worrying about fall backs.

For the font, I chose the super-popular Open Sans after reading "Serif or Sans Serif?" by Danielle Stone. I looked at many sans serif fonts. Open Sans just looked the cleanest to me.

I opted to go with an easy to read black text on white background after reading "How the Web Became Unreadable" by Kevin Marks. One great nugget in that article is where Kevin quotes Adam Schwartz:
A color is a color isn’t a color……not to computers…and not to the human eye.
I found this very interesting. I often look at my "black" SUV and think "my car looks kind of brown today".

With the help of the love of my life, Deedra, I found the header graphic, bought it from iStockPhoto and then played with the hue a bit to get it just right.

While testing, I found myself reading my old blog posts. It felt good. I really need to do this more.

Don't say ASAP when you really mean DEADIN

I have found that people tend to use the acronym ASAP incorrectly. ASAP stands for As Soon As Possible. The most important part of that phrase to me is As Possible. Sometimes, it's only possible to get something done 3 weeks from now due to other priorities. Or, to do it correct, it will take hours or days. However, some people don't seem to get this concept. Here are a couple of examples I found on the web.

The Problem with ASAP

What ‘ASAP’ Really Means

ASAP is toxic, avoid it As Soon As Possible

ASAP

It's not the fault of those writers. The world in general seems to be confused on this. Not everyone is confused though. I found ASAP — What It REALLY Means which does seem to get the real meaning.

At DealNews, we struggled with the ambiguity surrounding this acronym. To resolve this, we coined our own own phrase and acronym to represent what some people seem to think ASAP means.

DEADIN:
Drop
Everything
And
Do
It
Now

We use this when something needs to be done right now. It can't wait. The person being asked to DEADIN a task needs to literally drop what they are doing and do this instead. This is a much clearer term than ASAP.

With this new acronym in your quiver, you can better determine the importance of a task. Now, when someone asks you to do something ASAP, you can ask "Is next Tuesday OK?" Or you can tell them it will take 10 hours to do it right. If they are okay with those answers, they really did mean ASAP. If they are not, you can ask them if you should "Drop Everything And Do It Now". (Pro tip: It still make 10 hours to to right. Don't compromise the quality of your work.)

Apple Says My Screen Is Third Party

I have always had the utmost respect for Apple. Even before I used Macs and before the iPhone came out, I knew they were a top notch company.

I have had five iPhones. I have had 6 or 7 MacBook Pros. My kids have Macs. My kids have iPhones. My parents use iPads. I think a lot of Apple products and service... until today.

We took my daughter's hand me down iPhone 5 in to have the ear piece and top button fixed. It's been in the family the whole time. It was never owned by anyone other than family. Last year, I took it in for the Apple Store Battery Replacement Program. That is the last time anyone had it open. In fact, that may have been the last time it was out of its case. More on this later.

After we dropped off the phone today, we were told it was going to be an hour. No problem, we could kill some time. We came back an hour later and the person brought us the phone out and tells us that they refused to work on it because the screen is a 3rd party part. Whoa! What? I tell her that the only place it was ever worked on was in that exact store. She goes to get a manager. I thought, OK, the Apple customer service I know and love is about to kick in. They are going to realize their mistake and this will all be good. Or, even if they still think it's a 3rd party screen, he will come up with some resolution for the problem. Um, no.

He says the same thing (almost verbatim) to me that the previous person said. I again tell him it has only been opened by them. He offers to take it to the back and have a technician open it up again. He was not really gone long enough for that. He comes back, points at some things on the screen and tells me that is how they know it's a 3rd party part. I again, tell him that only the Apple Store has had it open. His response is a carefully crafted piece of technicality that can only come from lawyers and businessmen. It was along the lines of "At some point, this screen has been replaced with a 3rd party screen. I am not saying you are lying. I am not claiming to know how it was replaced. I am only stating that this is a 3rd party screen." What?

So, OK, what now? I mean, it wasn't under warranty. I did not expect to get a new free phone. I was going to pay to have it fixed. Nope. They won't touch it with a ten foot pole. It has a 3rd party part on it. He claims, that because they base their repair fees on being able to refurbish and reuse the parts they pull off of the phone (the phone I own and paid for by the way), they can't offer to repair a phone with parts they can't refurbish. I can't even pay full price, whatever that is. He never gave me a price to pay for a new screen with no discounts.

At this point, I realized I needed to leave. I was so furious. I was furious it was happening. I was furious that the manager had no solution for me. I was furious that he was speaking in legalese.

Just to be clear, I could buy my daughter a new iPhone 6. I am not trying to get something for nothing. I just wanted the phone to work again. One of the things I love about Apple products is how well they hold up. Sure, you have to have some work done on them sometimes. Batteries go bad. Buttons quit working. But, let's be real. My daughter uses this thing for hours a day. I have the data bill to prove it. So, I like that I can have an Apple product repaired when it breaks and it gets a longer life. The alternative is to throw it away.

How did I end up here? I can only come up with one scenario. And the thought that this is what happened upsets me even more. When we took it for the battery replacement last year, they kept it longer than their initial estimate. And the store was dead that day. When they brought it out, the case would not fit on the bottom of the phone. It was like the screen was not on all the way. The person took it back to the back again. They came out later and it seemed to work fine. And I was fine with all of this because it's Apple. I trust(ed) Apple. But, what if, they broke the screen? What if the tech that broke it was used a screen from some returned phone that did have a third party part and no one caught it? Or what if, Apple was knowingly using third party parts?

If I had not just had the battery replaced last year, I would think maybe there was some shenanigans in the shipping when the phone was new. We bought this phone brand new when the iPhone 5 came out. It would not come as a surprise if some devices had been intercepted and taken apart along the shipping lines. Or even in production. But, we just had it serviced at the Apple Store last year. They had no problem with the screen then other than the one they caused when they had to put it back together a second time.

This all sounds too far fetched right? Sadly, there seems to be a trend of Apple denying service to people. All of these people can't be lying. They can't all be out to get one over on Apple.



While waiting for our appointment, I overheard an Apple Genius telling a woman she "may" have had water damage. She didn't tell her she did. She did not claim the woman was lying. She thought she "may" have water damage. I don't know if she did or not. What struck me was the way she told her she "thought it could be" water damage. She told her she had seen lots of bad screens, but none of them (really? not one single screen?) had vertical lines in it like this. It's like she was setting her up to come back later and say "Darn, the tech says it is water damage." Sadly, I find myself doubting that conversation now. It makes me want to take a phone in with horizontal lines and see if I get the same story.

Of course, I know what many, many people will say to this. You will say that if I am really this upset, I should not buy anymore Apple products. And you are right. That is the American way. The free market is the way to get to companies. The thing is, if I bought a Samsung Galaxy, where would I get it fixed? Would my experience be any better? There is not Samsung store. There are no Authorized Samsung repair facilities. So, what would that get me? A disposable phone? Maybe that is what Apple wants. Maybe that is their goal. Deny service to people in hopes it will lead to more sales and less long term use of their devices.

And you know what makes this all even more crappy? One of the reasons he says he knows it is a third party screen is that the home button is lose. It wasn't lose when we brought it in! I was using the phone myself to make sure a back up was done just before we handed it over to the Apple Store. They did that when they opened the screen and decided it was a third pary part. So, now, my daughter's phone not only has no working ear piece and a top button that works only some of the time. Now, her home button spins around. Sigh.

Using socket_connect with a timeout

TL;DR

I was having trouble with socket connections timing out reliably. Sometimes, my timeout would be reached. Other times, the connect would fail after three to six seconds. I finally figured out it had to do with trying to connect to a routable, non-localhost address. This function is what I finally ended up with that reliably connects to a working server, fails quickly for a server that has an address/port that is not reachable and will reach the timeout for routable addresses that are not up.

I have put a version of my final function into a Gist on Github. I hope someone finds it useful.

Full Story

So, it seems that when you try and connect to an IP that is routable on the network, but not answering, the TCP stack has some built in timeouts that are not obvious. This differs from trying to connect to an IP address that is up, but not listening on a given port. We took a Gearman server down for maintenance and I noticed our warning logs were showing a 3 to 7 second delay between the attempt to queue jobs and the warning log. The timeout we had set was only 100ms. So, this seemed odd.

After a lot of messing around, a coworker pointed out that in production, the failures were happening for an IP that was routable on the network, but that had no host listening on the IP. I had been using localhost and some foreign port for my "failed" server. After using an IP that was local to our LAN but had no host listening on the IP, I was able to recreate it on a dev server. I figured out that if you set the send and receive timeouts really low before calling connect, you can loop while calling connect. You check the error state and timeout. As long as the error is an acceptable one and the timeout is not reached, keep trying until it connects. It works like a charm.

I found several similar examples to this on the web. However, none of them mixed all these techniques.

You can simply set the send and receive timeouts to your actual timeout and it will return quicker. However, the timeouts apply to the packets. And there are retry rules in place. So, I found that a 100ms timeout for each send and receive would wind up taking 500ms or so to actually fail. This was not what I wanted. I wanted more control. So, I set a 100 microsecond timeout during connect. This makes socket_connect return quickly. As long as the socket error is 115 (in progress) or 114 (already trying), we keep calling it. Unless of course our timeout is reached. Then we fail.

It works really well. Should help for doing server maintenance on our Gearman servers.

Most epic ticket of the day

UPDATE: I should clarify. This ticket is an internal ticket at DealNews. It is about what the defaults on our servers should be. It is not about what the defaults should be in MySQL. The frustration that UTF8 support in MySQL is only 3 bytes is quite real.

 This epic ticket of the day is brought to you by Joe Hopkinson.

#7940: Default charset should be utf8mb4
------------------------------------------------------------------------
 The RFC for UTF-8 states, AND I QUOTE:

 > In UTF-8, characters from the U+0000..U+10FFFF range (the UTF-16
 accessible range) are encoded using sequences of 1 to 4 octets.

 What's that? You don't believe me?! Well, you can read it for yourself
 here!

 What is an octet, you ask? It's a unit of digital information in computing
 and telecommunications that consists of eight bits. (Hence, __oct__et.)

 "So what?", said the neck bearded MySQL developer dressed as Neo from the
 Matrix, as he smuggly quaffed a Surge and settled down to play Virtua
 Fighter 4 on his dusty PS2.

 So, if you recall from your Pre-Intro to Programming, 8 bits = 1 byte.
 Thus, the RFC states that the storage maximum storage requirements for a
 multibyte character must be 4 bytes, as required.

 I know that RFCs are more of GUIDELINE, right? It's not like they could be
 considered a standard or anything! It's not like there should be an
 implicit contract when an implementor decides to use a label like "UTF-8",
 right?

 Because of you, we have to strip our reader's carefully crafted emojii.
 Because of you, our search term data will never be exact. Because of you,
 we have to spend COUNTLESS HOURS altering every table that we have (which
 is a lot, by the way) to make sure that we can support a standard that was
 written in 2003!

 A cursory search shows that shortly after 2003, MySQL release quality
 started to tank. I can only assume that was because of you.

 Jerk.

 * The default charset should be utf8mb4.
 * Alter and test critical business processes.
 * Change OrderedFunctionSet to generate the appropriate tables.
 * Generate ptosc or propagator scripts to update everything else, as needed.
 * Curse the MySQL developer who caused this.

Keeping your data work on the server using UNION

I have found myself using UNION in MySQL more and more lately. In this example, I am using it to speed up queries that are using IN clauses. MySQL handles the IN clause like a big OR operation. Recently, I created what looks like a very crazy query using UNION, that in fact helped our MySQL servers perform much better.

With any technology you use, you have to ask yourself, "What is this tech good at doing?" For me, MySQL has always been excelent at running lots of small queries that use primary, unique, or well defined covering indexes. I guess most databases are good at that. Perhaps that is the bare minimum for any database. MySQL seems to excel at doing this however. We had a query that looked like this:

select category_id, count(*) from some_table
where
    article_id in (1,2,3,4,5,6,7,8,9) and
    category_id in (11,22,33,44,55,66,77,88,99) and
    some_date_time > now() - interval 30 day
group by
    category_id

There were more things in the where clause. I am not including them all in these examples. MySQL does not have a lot it can do with that query. Maybe there is a key on the date field it can use. And if the date field limits the possible rows, a scan of those rows will be quick. That was not the case here. We were asking for a lot of data to be scanned. Depending on how many items were in the in clauses, this query could take as much as 800 milliseconds to return. Our goal at DealNews is to have all pages generate in under 300 milliseconds. So, this one query was 2.5x our total page time.

In case you were wondering what this query is used for, it is used to calculate the counts of items in sub categories on our category navigation pages. On this page it's the box on the left hand side labeled "Category". Those numbers next to each category are what we are asking this query to return to us.

Because I know how my data is stored and structured, I can fix this slow query. I happen to know that there are many fewer rows for each item for article_id than there is for category_id. There is also a key on this table on article_id and some_date_time. That means, for a single article_id, MySQL could find the rows it wants very quickly. Without using a union, the only solution would be to query all this data in a loop in code and get all the results back and reassemble them in code. That is a lot of wasted round trip work for the application however. You see this pattern a fair amount in PHP code. It is one of my pet peeves. I have written before about keeping the data on the server. The same idea applies here. I turned the above query into this:

select category_id, sum(count) as count from 
(
    (
        select category_id, count(*) as count from some_table
        where
            article_id=1 and
            category_id in (11,22,33,44,55,66,77,88,99) and
            some_date_time > now() - interval 30 day
        group by
            category_id
    )
    union all
    (
        select category_id, count(*) as count from some_table
        where
            article_id=2 and
            category_id in (11,22,33,44,55,66,77,88,99) and
            some_date_time > now() - interval 30 day
        group by
            category_id
    )
    union all
    (
        select category_id, count(*) as count from some_table
        where
            article_id=3 and
            category_id in (11,22,33,44,55,66,77,88,99) and
            some_date_time > now() - interval 30 day
        group by
            category_id
    )
    union all
    (
        select category_id, count(*) as count from some_table
        where
            article_id=4 and
            category_id in (11,22,33,44,55,66,77,88,99) and
            some_date_time > now() - interval 30 day
        group by
            category_id
    )
    union all
    (
        select category_id, count(*) as count from some_table
        where
            article_id=5 and
            category_id in (11,22,33,44,55,66,77,88,99) and
            some_date_time > now() - interval 30 day
        group by
            category_id
    )
    union all
    (
        select category_id, count(*) as count from some_table
        where
            article_id=6 and
            category_id in (11,22,33,44,55,66,77,88,99) and
            some_date_time > now() - interval 30 day
        group by
            category_id
    )
    union all
    (
        select category_id, count(*) as count from some_table
        where
            article_id=7 and
            category_id in (11,22,33,44,55,66,77,88,99) and
            some_date_time > now() - interval 30 day
        group by
            category_id
    )
    union all
    (
        select category_id, count(*) as count from some_table
        where
            article_id=8 and
            category_id in (11,22,33,44,55,66,77,88,99) and
            some_date_time > now() - interval 30 day
        group by
            category_id
    )
    union all
    (
        select category_id, count(*) as count from some_table
        where
            article_id=9 and
            category_id in (11,22,33,44,55,66,77,88,99) and
            some_date_time > now() - interval 30 day
        group by
            category_id
    )
) derived_table
group by
    category_id

Pretty gnarly looking huh? The run time of that query is 8ms. Yes, MySQL has to perform 9 subqueries and then the outer query. And because it can use good keys for the subqueries, the total execution time for this query is only 8ms. The data comes back from the database ready to use in one trip to the server. The page generation time for those pages went from a mean of 213ms with a standard deviation of 136ms to a mean of 196ms and standard deviation of 81ms. That may not sound like a lot. Take a look at how much less work the MySQL servers are doing now.

 

mysql graph showing decrease in rows read

The arrow in the image is when I rolled the change out. Several other graphs show the change in server performance as well.

The UNION is a great way to keep your data on the server until it's ready to come back to your application. Do you think it can be of use to you in your application?

Parenting When Your Kid Is "An Adult"

When I dropped out of college at 19, I came home to my parents' house. My parents had moved since I had left home. There was no room for me in the new house. I was not there to claim one when they moved in. My Dad and I put up a wall with paneling on it to enclose part of the garage. We cut a hole in the air duct that was in that space. Tada! That was now my bedroom. My room consisted of a concrete floor, three walls with paneling, one concrete block wall, a twin bed (I had a king size when I left 15 months before), and maybe a table. I was not happy. But, that is what was offered to me. I kind of held a grudge about that for a while.

As of right now, my oldest son is 18 years old. He starts college in the fall. I am so very proud of him. He was accepted to an honors program. His grades and testing earned him scholarships. His future is very bright. For this summer, though, he is still home. He has no job. Our attempts to get him to get one have fallen short. He is not motivated to do so. I refuse to go find him one. So, I am giving him one. In exchange for room and board, gas for his car, his car, his car insurance and whatever money is left after those expenses are paid going into his pocket, he will be my assistant. He will fetch his siblings from various places, run errands for me, do extra chores around the house, and anything else I need. To earn his car, he has been doing the "personal driver" service for a while for me. I am expecting more of him this summer though. This arrangement has its good days and bad days.

Today, I suddenly realized why my parents put me in that basement. The bad news for my son is that our basement is darker, dirtier, hotter and a lot less comfortable than the one I lived in at 19 years old. Let's hope I don't get to the point where I want to put him down there.