Acts of God

I am writing this post from an airport hotel in Irving, Texas, which is near the Dallas/Fort Worth Airport. I have been in Texas for the last two days and I don’t anticipate being able to leave for another few days, at the earliest.

I am booked through American Airlines. I usually book through Delta and have found them to be very good and reliable, but this was a business trip. I did not pay for my flight and so I didn’t really get to complain about not getting on the carrier of my choice.

I arrived in Dallas yesterday evening. My flight to Madison was supposed to leave at 8:20 in the evening. 8:20 came and went. The passengers asked a lot of questions and they were not answered for a considerable period of time. The flight kept getting pushed back hour by hour.

After it was pushed back to 10:30 we were told that there was a maintenance issue with the plane and they were waiting for a crew to come and fix it. They said they were bringing a second plane in case the first one wasn’t fixed in time.

The second plane arrived and we were told that the second plane also had maintenance issues. We had two broken airplanes and no idea about when we would get to go home.

Around 11:30 the flight staff announced that if we wanted to rebook our flights for the next day, they would do it for free!! BUT… we would not get a voucher for hotel, food, or transportation if we chose to do this. Unsurprisingly, no one took them up on this offer.

At 12:30, our flight was officially cancelled. We were told that the first plane had been fixed, but that they didn’t have the right paperwork to certify it was fixed and so the plane could not be used.

The stranded passengers were scattered to three local hotels. Many of us were placed at the Super 8. We were told to call a number and a shuttle would come to get us. We called the number and were told that the shuttle stopped going out at midnight and that we needed to take a cab. Half of us were given cab vouchers and half were not. I was among those who was not.

After finally getting to the hotel, I had about six hours to sleep before I had to go back for my rebooked flight. When we got up in the morning the shuttle was actually working, so I didn’t need to line up a cab to get back to the airport.

When we woke up, it was raining cats and dogs (sadly, not men). It was seriously pouring outside. We all had a sinking feeling that we were not going to be going home on time today. We sadly piled into the shuttle back to the airport and hoped for the best.

We found a bunch of people from our flight the day before waiting around the airport. Their flights had been cancelled and they were rebooked on our flight.

Every hour or so for the rest of today we would hear that we had a gate change. We all picked up our bags and hiked from gate to gate so many times we lost count.

We finally settled down at the gate that we were at last night. We all hoped and prayed that things would be different this time.

Our flight got pushed further and further back. We watched hopefully as we saw planes landing and flying away. There were a lot fewer of them than we would have liked, but we held out hope that we would get home.

This was not to be.

Seven hours after my flight was supposed to leave (and ten hours after others were set to leave) our flight was cancelled. We frantically tried to speak to representatives both in person and on the phone. When I called, I was told that the earliest they could fly me out was Tuesday morning, which is the day after tomorrow. I asked what I was supposed to do until then. The representative told me that she would help me find a hotel and give me a special rate, but that since the flight was cancelled due to weather that I would not be given another voucher. I asked if I could get my checked bag. I was told I could and to talk to the baggage service representatives. She said if I went to them they would have my bag brought out.

One reason I took the train a lot a few years ago was because I went through a similar situation to this in 2008. I was stranded at O’Hare because much of Wisconsin had flooded and no one could fly into any of the airports there. At that point I could take a bus from O’Hare to Madison. That isn’t really the case here. I knew at that point that I probably couldn’t get a flight into Wisconsin for love or money, so instead of flailing and trying to fight with everyone else to try and book the last flight to Wisconsin, I just accepted that my best option was to take the Tuesday flight and stay at the hotel. The hotel would be much cheaper than any other flight I would book before then anyway. I work remotely and I can work anywhere. I asked if the hotel had WiFi and since it did I was happy.

I was happy until I found out I couldn’t get my bag. I have been wearing the same clothes for two days. I didn’t take my contacts out yesterday. I had no toothpaste or deodorant. The idea of keeping my contacts in for another two days was unbearable. I grudgingly realized my best option was to get a Lyft from the hotel and pick up all the stuff I needed. I was pretty sure I could find clean underwear and hopefully another shirt.

I am laying here in my room after this ordeal and I wanted to go over the personal cost of this situation to myself and to the other people on this flight.

My Personal Costs

Here is an itemized list of my personal expenses incurred by this situation:

Hotel: $130

Since I can’t get on a flight until the day after tomorrow, I had to book a room for two days. Other people from my flight looked into finding flights on other airlines. One person found one for $230. Another friend said he found one that he cashed his loyalty points into that would have cost $730.

I work remotely and have people to watch my pugs. I would like to be home, but I can work anywhere. This was the cheapest option.

I do not know if this is a reimbursable expense. When my business trip was arranged this was not part of the budget. I am working under the assumption that I am responsible for this expense.

Lost Gift: $30

When they cancelled our first flight, we were taken to a nearby hotel. I forgot that earlier in the day I bought a gift for my mother at the San Jose airport. I found some vinegars that were from a local vineyard. I wanted to show her how much I appreciated her watching my pugs and I hadn’t had a chance to go anywhere to find something special for her.

I was super happy that I found something unique that I could give her that was thoughtful. I like to give people thoughtful gifts that I think will delight them.

I got pinged by the TSA this morning because I forgot about the bottles. I couldn’t put them in my checked luggage because it was trapped somewhere in the bowels of the airport.

I was told that I could check my backpack, but I don’t want to check a MacBook Pro and an iPad Pro just to try and save my vinegar. I was told that they are going to dump the vinegar down the drain. These bottles are hermetically sealed and still in the packaging from the airport.

I understand the issue with bringing liquids through airport security, but I honestly wish that I had been given some kind of option to save my gift for my mom because it wasn’t my choice to leave the airport and have to go through the line again.

I am hoping if I go back to San Jose I can find it again.

Toiletries: $40

When our second flight was cancelled and I called to find out when I could go home. They said the earliest I could get out was Tuesday. This is Sunday.

I figured it would be okay. I was told I could go get my checked bag. I packed too many clothes, so I had a few fresh outfits to wear along with deodorant and toothpaste. When I went to the baggage help desk (that I had been told would give me my bag) I was told that they would not give me my bag. I was told it was still on the plane and that it would not be taken off and would be at my destination.

Considering that my flight was not until Tuesday, I am highly skeptical that they are not going to have a flight tomorrow or before I am flying on Tuesday.

I have been wearing my contacts for the last two days. I can’t wear them for another two days. So I had to find a drug store near my hotel.

I had to buy the following items:

  • Contact lens solution and container
  • Deodorant
  • Toothbrush and Toothpaste
  • Another Shirt
  • Underwear

If I had been allowed to take my bag like I was told I would be able to do, these days would have been a lot less unpleasant.

Transportation: $60

The first night I got a hotel voucher, but I was not given any transportation vouchers. I was told the hotel would send a shuttle, but the hotel we were placed at did not send shuttles after midnight.

We were told that we could not share cabs with people who had been given vouchers. We were told it counted as a separate fare and would cost $48 a person to go to our free hotel.

I said fuck that and contacted Lyft. I was able to bring three other unfortunate people without vouchers for one fare. Even with a large tip, it was only about thirty bucks. I tried to just cover it, but people gave me cash.

Since I wasn’t allowed to get my checked bag, I had to get a Lyft to and from a drug store to pick up necessities for the next few days.

Higher Costs Paid By Others

This situation has been an annoyance to me. I don’t get to be home with my pugs or cook my own food.

But I have a lot more flexibility than most people do. I can work remotely. I can work tomorrow as easily from my hotel as I can from my house. Even if my current contract doesn’t reimburse me for this situation, it’s not going to affect me financially that much. It just means I dip further into my savings and I will be annoyed.

There are a lot of other people on my flight who were affected far worse than I was.

The pilot from the first cancelled flight didn’t get paid for the time he was at the airport. He only gets paid if he flies. Since neither plane was flight worthy, he didn’t get paid last night. While the rest of us passengers got varying degrees of vouchers, he was on his own for providing his own hotel. I heard him calling around trying to find a hotel room and negotiate a better rate.

There was a man there who was missing his parent’s 50th wedding anniversary. He kept looking at his watch saying around 4:00 that the party they were holding was wrapping up about now.

The absolute saddest story I heard the last two days was from a soldier who is stationed in Korea. He was taking 17 days of leave to come home and see his wife. He hadn’t seen her in six months. Today is her birthday. We was supposed to be home last night. If he is in the same situation that I am in, he won’t get to go home until Tuesday. He potentially has burned a quarter of his leave hanging around a fucking airport/hotel trying to get home to his family.

If he had known that he would not be able to fly out until Tuesday, he could have rented a car this morning and been home tomorrow. He could have driven to another airport and tried to get home sooner that way. Instead, he was given false hope that home was just around the corner. It’s just another hour, then you can go home.

The man whose parents had their 50th anniversary will never get to see it because it only happens once. The soldier will never get those days back. This man is representing our country and I felt he was treated very badly.

Acts of God

I know that airlines don’t control everything. Stuff happens. I just feel that things could have been handled better and they were not because of the desire by the airline to try and not spend money.

The regional carrier model of transporting people from smaller airlines like Madison to regional hubs like Atlanta and Dallas is a cost savings measure. Regional carriers are usually owned by companies other than American and Delta. I have read a lot of bad things about this business model that I can’t directly cite and therefore do not feel comfortable referencing. Based on those things, I was not really surprised that there were maintenance issues and I was honestly a little worried about the plane even before they told us that it had broken.

Rather than telling us that we would not be able to fly out last night, they tried to con the passengers into rebooking the flight on their own rather than being up front with the fact that we were probably not going home.

Had we known that we were not going home earlier in the day, we could have found other ways to go home. Once people determined that there were no American Airlines flights until Tuesday, people scrambled to find another way home. People could have rented cars to try and get to other airports outside of the affected area.

It would have made a huge difference to me to be able to have access to my checked bag while I am stuck out here. I have no idea why I didn’t get access to it, but I think there should have been a way for me to get it.

Most of all, I think it’s terrible if we can’t do better by soldiers who are serving our country. I am incredibly upset that this man missed his wife’s birthday and possibly won’t get to go home until Tuesday. I know that we all feel like our own personal perspective is the worst, but I would like to think that someone could have taken a few extra steps earlier in the process to make sure this man got home.

All day yesterday and today, I felt like we were collectively treated like cattle. We were herded from one end of the airport to the other. We were seen as a collective herd and treated as such by the airline.

We’re not a herd. We’re people. We all have stories. A lot of people have been inconvenienced this weekend, but a number of them missed precious moments of their lives that they will never get back again.

Signal Flow and the Art of Motorcycle Maintenance

Last year I worked at a hardware company where our primary product was robotics and not software. This is an experience I don’t think most software developers get to have. Most of us are stuck writing esoteric applications communicating with a server or a cloud where you’re not programming something you can touch and feel.

When I was in school I never got to take any shop classes because they scheduled them opposite the college prep classes. My grandfather was a builder and I remember growing up wandering around building sites watching people pouring concrete. Even with that experience, I still had a mental block that working with hardware or power tools was something for other people.

I don’t think that working with your hands has to be divorced from working with your head. I think if you physically touch and see the things you are working with, it helps you think about what you are actually doing.

When I was going to school for audio engineering they made us write signal flow documents for how the sound travels from the microphone to the recording device. I found it incredibly frustrating because I just wanted to go and play with the sound board and I didn’t think it mattered about how things worked under the hood.

That experience really helped me a lot with programming. When I write a program I think through the signal flow of my code. I think about the sequence of events that happens when things are triggered. I don’t know if other people do this too. I know that I have trouble dealing with code where people ask me about something that happens in the middle of the signal flow. To me, it’s almost a narrative thing where a story happens between when the user interacts with the app, or it launches, or whatever the triggering event is and the events that happen afterwards.

I really want to do more with hardware. I find just working with software to be very existential. I feel like I am not doing anything. But I also know that I don’t have the requisite skills to do the things I want to do.

I have enough skills to have a good career as an iOS developer, but it isn’t just about money for me. I want to work on things I find emotionally fulfilling. People keep telling me that jobs are supposed to be soulless and boring, otherwise people would do things for free. I don’t think that’s the case. I think there are a lot of unexplored avenues with iOS that require specialized skills. I think that working with Bluetooth and micro controller devices has a lot of potential, but that requires knowing stuff besides Swift.

How I Learned Programming

I have been incredibly disorganized about trying to learn electronics. I bought a bunch of electronics kits partially to learn soldering. I have a good handle on soldering, but I didn’t do the stuff I intended by figuring out the signal flow of the projects I was working on.

I bought the Make: Electronics book, but I didn’t work through the projects while I read it. I was reading it in the bath tub and before bed, like I was reading my programming books.

I burned myself out reading technical books where you’re supposed to work through a project or look at code while you are working through it.

I know, but keep consciously forgetting, that code, like anything, is a skill. When I learned programming, I sat down between 60 and 80 hours a week working through the Big Nerd Ranch iOS book over and over again.

My teacher Eric Knapp told us that programming is like playing the piano. You need to practice a lot. The first time I typed a project in the book, it would make no sense. It would just be something that worked like magic. The second time I typed it, things wouldn’t be much different. By the third time, I would start to make mental connections about how the project worked. I was starting to form a signal flow document mentally about how an object I created in one place would pull information from another object and result in an output. By the fourth time I understood how the whole program would work.

One thing I had to get over was the idea that somehow doing a tutorial wasn’t really programming. I thought if I didn’t create the code in my head then I wasn’t really learning.

That isn’t the case at all.

It’s like practicing scales on the piano. If you do something over and over again and you do it a lot, your brain starts to make mental connections that it wouldn’t if you didn’t work with something a lot.

It’s like how if you play through Mario Brothers for the first time, you probably die in the first world. If you watch someone who’s been playing since 1987, you think they’re a genius because they know where the short cuts are and where they keep dying. They didn’t start out that way. Either they found them by playing it a lot or someone clued them into where the short cuts were.

How I Want to Learn Electronics

One thing I keep hearing from people is that you need a project to really learn something. I would agree to that to some extent. When I was trying to learn GLSL I didn’t make any progress until I found a project I wanted to do. I found a filter I wanted to write and it gave me enough focus to go in and write the code and add it to the framework.

However, I was only able to do that because I had enough of a base of knowledge about basic programming in order to do that. If I tried to jump in and write that shader before I wrote “Hello, World!” then I would have been hosed.

I think there are two levels of learning a new skill. There is the grunt work of learning the basics, like terminology and “signal flow”. You have to have a good grasp of these things before you can move on to doing your passion project.

I was trying to jump into my passion project without putting in the grunt work I put into learning programming. I have to work through a bunch of basic electronics projects like making an LED light up before I can design an analog synthesizer or a beacon to find my dog when she runs away.

I want to start the Make: Electronics book over again, but I want to do it properly. I have an electronics workshop in my basement, but like everything else in my life, it’s super disorganized.

I bought the component packs for that book. I want to organize my space and learn electronics the same way I learned programming. I want to set aside a decent amount of time and actually touch components and build things. I am not going to skip over the grunt work and “scales” of electronics because if you don’t build a good foundation of knowledge, you won’t get anywhere.

What I am Not Going to Do

I am going to stop trying to read programming and electronics books for fun. I felt guilty for the last few years doing anything that was not related to programming. I burned myself out and created a lot of frustration trying to force myself to learn in a way that was unnatural.

At RWDevCon, James Dempsey talked about the importance going away from keyboard. If I am not in front of my computer actively working on a programming project, I am not going to read a programming book or tutorial. I want to be fully away from the computer.

There is a Buddhist concept of ”Be Here Now”. Don’t worry about the past because you can’t change it and don’t worry about the future because it hasn’t happened yet. The only thing that is important is the moment that is happening right now. If you’re off the clock, be fully off the clock. Disengage. Don’t check Twitter and email. Don’t read programming books. Don’t feel guilty about not working.

I am hoping to document my progress on the blog. I am not going to be inventing the wheel here. I am doing my scales and working through my programming tutorials over and over again. It’s going to be some basic stuff and figuring out how everything works together. I want to get back to how I worked in my audio engineering classes by understanding my signal flow. You can’t build a castle on a swamp, and you can’t generate great innovations without a strong technical foundation.

Hobbies and Hand Grenades

One of my goals for 2016 is to try and be more mentally healthy.

I have written before about the guilt I feel when I am not working, or doing something that feels like work. I take programming books to the bath tub. I haven’t taken a vacation in three years. I have a panic attack if I don’t check my email once an hour.

I deleted Twitter and Facebook from my phone about two weeks ago. I was going to try and stay off of Twitter completely for like a month, but my blog was hacked and enough people expressed concern about it that I felt it was necessary to explain on Twitter what was going on. I am now checking it periodically, but I am trying not to be on it for more than five minutes at a time and no more than three times a day. BTW, the battery life on my phone has increased to three days from about twelve hours, so #winning.

I am starting back up with reality in a week. I was hoping to get some things resolved during this break so that I could get back to work all refreshed and recharged. I always had this idea that if you took like a day off that it would undo all the damage you’ve done to yourself for the last three years. It doesn’t quite work that way.

Wanted to do an assessment of where I am at before I start my last full week of being AFK.

Tired

I am exhausted. I was still running on some nervous energy before I went to RWDevCon, which explains why I have actual programming posts on my blog from that time.

I tried to make some attempts at working on a project so that I would not just fall off the wagon while I was off, but I gave up on that last week Wednesday. I found myself staring at my screen not able to do much, so I turn off my work computer and left my office and decided to try and find something to do that was relaxing so that I could really make an effort to recharge. It’s been really hard.

Today I woke up for a few hours and then had to go back to bed. I have people who want me to go and do things with them, but I know if I do that then I’ll be completely worthless in the following days.

I feel horrible for not taking this time to deep clean my house or drop all the stuff I have boxed up to give away that is cluttering up my basement. I also feel guilty for not working on anything. I feel like I have this opportunity to do something for myself that I am squandering by just sleeping all the time because I am exhausted.

I tried socially drinking at conferences and I just don’t think I can do it anymore. Drinking makes me feel sick. I feel like I am being poisoned. Eating food I didn’t make for myself makes me sick too. I am slightly worried about the business trips I need to make over the next month and I am hoping I can find a way to maintain some physical health while I am away from my house.

I am giving up alcohol completely for at least six months. At this point it doesn’t feel like much of a sacrifice. I feel lousy all the time. I was treated for migraines about a decade ago and they’re coming back and being persistent. My therapist told me that a lot of the abuse I have put my body through doesn’t just resolve itself overnight. It takes time for my body to detox and recuperate. I am hoping that the steps I am taking right now are a step in the right direction so that I can go back to feeling okay again.

Bored

So since I am not programming and it’s too tiring to leave my house, I have been trying to find something to do with my day.

I picked up some of my hobbies that I haven’t done since I started programming.

I picked up cross stitch again. I brought out a project I have been working on for years because I just stopped doing it a while ago.

It was really weird to pick it back up again. I felt rusty and clumsy and slow. After a few days it got better. The things I learned over two decades of doing this came back pretty quickly.

I also started reading non-programming books again.

I have a box of random science fiction books that a friend lent me. I pulled a few books out of that box. I also read through a few books that I had been meaning to read but didn’t get around to.

One reason I got off of Twitter was because I would bring these books to the tub to read but I would only get a few pages in before getting bored and then going on Twitter for hours. By removing Twitter from my phone and just not having it near me when I am reading, I have been better able to stay focused and actually get through books.

I have been doing this for the last five days and it’s getting kind of boring and repetitive. There is only so long that you can do something until it gets boring. I don’t really know what to do from here. I am taking my dog for a walk most days because I need to get out of the house and she needs exercise, but I don’t know what to do to alleviate the boredom. All of the other hobbies I have, like working with electronics, are all very mentally intensive. I talked to a person about helping them build an airplane, but after I went out for a day to see what it involved I was spent for several days.

It’s very aggravating and frustrating to want to do things but not being able to do them. I am trying to continue to rest because I know that exhausting myself at this point is counter productive, but the temptation to just mindlessly graze on Twitter is great.

Lonely

The last bit is that, since I am not on Twitter, it gets somewhat lonely.

I am living alone. I have my pugs, but they’re not people. I know that I have a lot of friends who would love to see me and do things with me, but I can’t make myself do anything with them right now.

It’s weird. I am lonely, but the desire to be with people is far less than the desire to just be left alone. I didn’t think it was possible to feel both things at once.

I am hoping that the fact that I have nothing to do right now is the source of many of these feelings. I am hoping that because I have nothing else to do besides dwell on all this garbage that when I am actively engaged in a project again that a lot of this stuff will go away. Part of me is terrified that it won’t.

My goal in the future to avoid this is to try and figure out how to disengage and do things that help me relax mentally. I would like to find a way to incorporate my hobbies back into my work life. I want to set up my electronics workshop in the basement so that when I can’t deal with being in front of my computer for a while I have something I can do. When I get done with work I don’t want to just leave my desktop computer in my office to go to my laptop computer in my living room. I don’t want to fritter away my time on worthless Twitter drama. I either want to be fully engaged or fully disengaged.

My goals for 2016 are to begin learning electronics and C++. I need to structure projects for those so that I can be engaged with them, but I will not do that until I am done with this coming week. This is the last time I have to do whatever the hell I want, and right now I just want to be left alone to wallow in my own sense of self loathing and apathy.

Elementary

I have been taking some time off recently and catching up on some much needed rest. Part of my regime has been finding a bunch of TV shows I have been meaning to watch and going through them.

One of those shows is Elementary. I am a huge Sherlock Holmes addict. The recent versions with Benedict Cumberbatch and Robert Downey Jr. have been interesting, but Jeremey Brett will always be my Sherlock.

Besides updating to modern times, one of the big selling points of Elementary has been gender switching several of the more prominent characters in the Holmes canon, namely the role of Dr. Watson.

I want to talk a bit about something I feel that they did right with this that I would like to see more of in the future.

Mentorship

In the original Holmes stories, Watson is Sherlock’s roommate and side kick. He acts as the reader’s eyes and ears reporting what a “normal” person would see and generally most of the resolutions in the crimes come as a surprise because Watson does not observe what Sherlock does, which makes it difficult to guess what the resolution of the stories will be.

CBS_ELEMENTARY_406_LOGO_IMAGE_702765_640x360In Elementary, Watson starts out as a sober companion for Sherlock, but eventually transitions to being his protégé. He sees potential in her and he helps her cultivate it.

This Watson is a dynamic character. Her skills grow and evolve. This is different than the static Watson character in the original stories who is purposely kept somewhat dumb to allow the reader to enjoy the story.

A lot of this dynamic spoke to me on a personal level.

Programming is a rather new field that is primarily male-dominated. All of my mentors have been men. I often wonder if men ever get to be mentored because there is an inherent social dynamic that seems to make it easier for men to mentor women. Our society assumes that women take a subordinate role and it’s simply easier when you are a woman to approach a man and ask for help and for guidance. This can have a pleasing feeling for both people because the man feels important because he gets to instruct and train a subordinate and the woman feels important because someone she respects and admires has chosen to take time out of their life to pass on knowledge and wisdom to them that they aren’t passing down to anyone else.

When you’re first starting out, this can be a very comfortable and emotionally rewarding relationship. However, like all things, this can’t last.

Partnership

At some point, the protégé starts to bump up against the edges of the relationship. The protégé wants to be acknowledged. They want to have their new skills be recognized and leave the nest and be seen as an equal.

This can make the mentor very uncomfortable. Their entire relationship is predicated upon being the source of knowledge. Once the protégé catches up to the mentor, it can cause a lot of issues.

Elementary-season-3-promo-watson-holmesIt can make the mentor feel very upset because they feel they’ve lost their identity as the person who knows everything. Sometimes the mentor succumbs to the urge to try and cut their protégé down to keep them in the subordinate role because that is where they feel comfortable.

Other times the mentor can become upset that the protégé wants to be seen as an equal. The mentor has spent decades honing their craft and this upstart person wants to be seen as an equal without putting the work in.

This relationship is very reminiscent of a parent/child relationship. At some point you realize your parents don’t know everything. Our relationships with our parents change as we get older because they must. Sometimes our parents cut us down to try and maintain the control over us that they have gotten used to. They want us to succeed, but not too much because it threatens their sense of self worth.

A mentorship relationship is more fragile than a parental relationship because of two reasons. One, our parents will always be our parents. As much as we might argue and fight with them, there is a blood tie that can’t be broken. The second is the one I mention at the beginning of this post, the gender thing.

Professional Respect

One thing that I respect Elementary for is the fact that, as far as I have gotten, there has been no effort to force Sherlock and Watson into a romantic relationship. All of their conflicts have been able to explore the mentor/protégé relationship without having to stoop to the cliche of putting them together in a romantic relationship.

I greatly admire the fact that the writers have been able to craft a compelling story about the mentorship conflict in a completely platonic context.

1355273194905.cachedAs the person who has been in the protégé role, I want my mentors to see me as an equal. I want to show them that they were right in sharing their wisdom with me and I would like to show I can manage on my own without being dependent on them. Joan Watson is similar. She wants to be a detective in her own right.

Sherlock doesn’t want her as an equal. He wants to keep her as a subordinate. They fight over her need to be her own person and not an extension of him.

Both characters have had romantic relationships with other people, so this isn’t a generic, Aspie asexual stereotype. The relationship between Sherlock and Watson is based on professional admiration and respect. Watson gets frustrated when Sherlock won’t give her the professional respect she feels she has earned.

I have found it incredibly compelling to watch this relationship being explored. It’s a painful situation for both Sherlock and Watson. Both of them are right. Both of them have been hurt by their evolving relationship. But it’s a necessary pain for them to experience so both of them can grow and change.

Lessons From Sherlock

I spoke about mentorship at CocoaLove 2015. I wanted to give advice to both mentors and protégés. I want to reiterate some of it now.

If you are a protégé, at some point you need to step out on your own. It’s comfortable and safe to be under the wing of someone with a lot of experience, but at some point you need to succeed or fail on your own. You will stumble a lot, but that is how your mentor learned. They stumbled and have given you advice about how to avoid the same stumbles they took. You will learn best through your own stumbles than you will hearing stories of your mentor’s stumbles.

If you are a mentor, please understand that this is a temporary situation. Don’t become so attached to the idea that you have to know everything that it creates a situation where you lash out at your protégé when they want to be seen as an equal. Your protégé has a lot of affection for you that can quickly turn into a toxic situation if you put them down in an effort to keep them subordinate to you.

The best way for a mentor/protégé relationship to go is if both parties go in wanting the protégé to become independent. If you’re a mentor and your protégé doesn’t seem to want to walk on their own, try to push them to take risks and fall and learn from their experiences.

Above all, remember that part of the reason you both entered into this relationship was because you like and respect one another. Just because your relationship changes as the protégé grows in experience doesn’t mean those feelings go away.

Twitter Detox

I have been taking some time off recently. I don’t really want to talk about the circumstances surrounding it because that isn’t the point of this post.

Since I have had time to work on slides and projects, I figured I would be super productive. I have been kind of productive, but not as much as I would like.

I have noticed I have no attention span. It’s gotten worse over the last two years or so.

I was on my flight to CocoaConf San Jose and I nearly had a panic attack that I couldn’t tweet the four hours or so I was on the plane. When I go to take a bath I bring a bunch of books and even video games to consume in the tub but I wind up spending all of my time on my phone chatting with people on Twitter. I get bored playing video games because they don’t move fast enough and that revelation really disturbs me quite a lot. I used to cross stitch and doing anything for more than a few minutes at a time is incredibly difficult.

There has been some question about the rise in cases of ADHD. I think that some people, like my teacher Eric Knapp, were born with it. But I also think that we can train our brains to mimic symptoms of it and that the massively connected world we live in has not been good for this.

I will wake up in the middle of the night and not be able to get back to sleep until I check Twitter and my email. This is really unhealthy.

I have no idea when this started getting really bad, but this is the first time I have noticed it.

Twitter has been really good at helping me establish and maintain connections with people I might only meet once at a conference. I know that a lot of people have gotten to know me and my pugs through my tweets.

I am just at a point where I am concerned about my long-term ability to function and be productive and I would like to break this cycle of thinking.

So I am going to delete the Twitter app from my phone. I am going to close the tab I have open for Twitter on my laptop.

I will answer email. There should be enough places online for people to find my email without me having to put it in this post. I will be on Slack channels. I will try to write on my blog more. I am not trying to make myself unreachable, I just need to disconnect from The Matrix for a while and relearn how to pay attention and focus so I can do things I think are important.

At this point I am planning to do this until the beginning of May. I want to give myself a good detox period.

I think that by doing this I will spend less time on my computer when I am not working. I will be more productive when I am on my computer. I think that I waste hours each day just chatting with people on Twitter and if that outlet isn’t there anymore I will be less likely to zone out in front of my computer for hours each night.

I hope that my decision is respected and I plan to write about my observations of the changing state of my focus on this blog. I am interested in seeing how my focus changes over the next month or so.

Thank you.

Caesar Cipher

I have been trying to do more programming exercises recently. One thing that I think is incredibly important when you are an engineer is to have an understanding of the problem you are trying to solve. If you’re not solving a problem, you wind up with Clever Code, and that’s just bad for everyone.

I have a casual interest in cryptography. It’s one of those things that always fascinated me but I never realized I could actually learn and apply to things.

I couldn’t sleep last night and I looked around for a book to read. I found my copy of The Code Book by Simon Singh.

I found a bunch of really interesting cryptographic methods that looked like they would be interesting code projects.

I am going to go through and do some of these in order of complexity and age. The older the method, the simpler it is. This makes sense because new cryptographic algorithms are only created in response to the most recent one being cracked.

I will be adding all of my projects to a Github repository.

I’ll probably hit a wall at some point where I can’t continue to do this, but for now I have a few that I can do and I am looking forward to figuring out how to implement these.

Working Caesar Cipher

Working Caesar Cipher

What is a Caesar Cipher?

A Caesar Cipher is an encryption technique where each letter of the alphabet is shifted by a certain offset and all the letters are substituted.

For example, if your offset is 3, then every time you have an “a” in your text that you are encrypting, it would be replaced by a “d.” “b” would be replaced by “e” and so on. Once you get to the end of the alphabet, you start at the beginning. “z” would be replaced by “c”, “y” would be replaced by “b”, and so forth.

This cipher was used for several hundred years, but it was vulnerable to being easily broken. In fact, there is a daily cryptographic puzzle that no one ever looks at published in the paper next to the comics.

Even though this specific cipher is fairly easy to break, it provides the basis for some more complex ciphers being used, which is why I am starting out with this one. I can build off of this one to work on more complicated problems.

What are our Requirements?

In order to implement a solution for this problem, it’s helpful to think through what this application has to do.

  1. Take in a string
  2. Choose an offset
  3. Check each letter in the string
  4. Shift the letter by the offset
  5. Return an encrypted string

The first part is easy. We simply use the built-in UI elements in iOS to create a text field that can contain the input text and the encrypted string.

Since we’re dealing with an offset where one letter will be substituted for another, it mades sense to use arrays. There should be a constant array that simply contains the entire alphabet with each letter constituting an element.

The second array is a little more tricky. We need to shift the elements in the array by a variable offset. You use the offset to figure out what the first element in the new array is.

After you get both arrays, you find the index of each letter in the first array and replace it with the correlating letter in the second array.

Implementation

I like to keep as much code as possible out of the view controller as possible, so I only have one line of code:

@IBAction func encryptText(sender: AnyObject) {
    encryptedText.text = encryptedString(inputText.text)
}

I have a helper function that takes the text input as a parameter and outputs the encrypted string and some other parts to the text output. Everything else is in a separate file of stand alone functions.

First thing I wanted to create was my immutable alphabet array:

let alphabet:[Character] = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]

Next up, I need my offset. I could make that something the user inputs, but it was easier to just have it be a randomly generated number:

func randomNumber() -> Int {
    return Int(arc4random_uniform(25) + 1)
}

I want this to return a number between one and twenty-five. Since the array starts at zero and a zero offset means no encryption, it makes sense to have the lowest number be a one. Since the alphabet is always going to be 26 characters long, having a hard-coded value of twenty-five makes sense in this scenario.

I would like to unit test this method, but I don’t know how to do that. Since the output is random, I don’t really know how to generate a useful unit test. At this point I have to just have faith that this piece of code won’t return a number that is outside of the index of my array.

I don’t like leaving things to chance, so in my code to create my encryption array I deal with this possibility to avoid making my app crash:

func encryptArray(var offset:Int) -> [Character] {
    
    if offset < 1 {
        offset = 1
    }
    
    if offset > 25 {
        offset = 25
    }
    
    var array = alphabet
    let slice = array[0.. < offset]
    array.removeRange(0.. < offset)
    array.appendContentsOf(slice)
    
    return array
    
}

The last few lines of code are copying the range at the beginning of the array, hacking it off of the front, the pasting it to the back.

I feel like there should be a more efficient way of doing this, but it works for now, so huzzah.

One of the things I really wanted to do was figure out a way to use map(). So far I have not found a good reason to use it. I have seen clever code from people that is longer than mine but more functional. I really wanted to find a situation where mapping a function made sense. Generating an array of characters that are offset by a certain fixed amount from another array of characters fits this to a tee.

Before I can use map(), I need to set up the function that is going to be mapped to the array:

func encryptCharacter(input:Character, encryptedArray:[Character]) -> Character {
    
    if alphabet.contains(input) {
        let index = alphabet.indexOf(input)
        return encryptedArray[index!]
    } else {
        return input
    }
}

One case I had to handle was if the character was not a letter. We’re dealing with spaces, commas, periods, etc… I do a check to make sure that the array contains the character being passed in. If it doesn’t, then it is one of the other characters we are returning directly.

Now that we have our processing function, and all of our other functions, for that matter, it’s time to pull it all together:

func encryptedString(stringToEncrypt:String) -> String {
    let lowercaseStringToEncrypt = stringToEncrypt.lowercaseString
    let offset = randomNumber()
    let encryptionArray = encryptArray(offset)
    let array = [Character](lowercaseStringToEncrypt.characters)
    
    let encryptedArray = array.map({encryptCharacter($0, encryptedArray: encryptionArray)})
    
    let encryptedString = String(encryptedArray)
    
    return "(encryptedString)
 The offset was (offset).
 (alphabet[0]) = (encryptionArray[0])"
}

This isn't working quite right...

This isn't working quite right...

The first time I ran this project, I realized that my analysis is case sensitive. I had letters that would fall through and be returned directly because the algorithm did not catch that they were letters. I resolved this by forcing all of the characters to be lowercase so that they would be processed. I think I could have made another array of upper case letters and add more complexity to the encryption process, but I didn’t feel like it. This was a simple fix.

Capital letters don't get no respect.

Capital letters don't get no respect.

I am creating variable to hold the results of all of my helper functions. Where necessary, I am passing in the results of some of these function to the functions that follow. We have a nice line of parts that all connect to one another in only one way.

In order to pass each character in, I need to create an array of characters from the string input in the view controller. There is a nice handy function that makes this process somewhat easy.

I was able to effectively use my nice map() function to process each character in the array of characters.

After going through and encrypting each character in the array, we can bring it back together again in a String.

Lastly, I wanted to include some information about the encrypted string beyond just the string. I wanted to include the offset and show what the first element in the encrypted array was.

Conclusion

I am not certain how to write unit tests for two of my stand alone function. They have randomly generated outputs. I think there must be a way to prove these work, even if it isn’t with unit tests. If anyone has suggestions about how to proceed with this I would appreciate it.

Overall, this was a nice little project to work on before heading off to RWDevCon. I have a larger independent project I would like to work on that I didn’t want to start when I would be gone for a week.

I find encoding and data processing to be fascinating. I would like to work on more stuff like this, even if it is just for my blog. I am hoping to have a more complicated encryption project on here soon.

How to Add A New Shader to GPUImage

Last year I wrote this article about image processing shaders.

I explain how several shaders in GPUImage work and what the point of a vertex and a fragment shader are. But since this has come out, I have realized there is a lot more to this than I was able to go into in this article.

In spite of the fact that I worked for Brad Larson for a year, I never wrote a shader for GPUImage. When I started trying to figure it out, it became incredibly intimidating. There was a lot of stuff going on in the framework that I was less than familiar with. I also knew there was a lot of stuff he and I spoke about that was not really made available to the general public in the form of documentation.

So, in this blog post, I would like to extend that post somewhat by talking specifically about GPUImage rather than shaders in the abstract. I want to talk about the internal workings of GPUImage to the point that you understand what components you need to connect your shader to the rest of the framework. I want to talk about some general conventions used by Brad. Lastly, I would like to talk about how to construct complex shaders by combining several more primitive shaders.

I am sending this blog post to Brad for tech reviewing to ensure that everything in this post is factually correct and to ensure that I am not propagating any false information. If there is something I am missing here, I would appreciate having someone reach out to me to ask about it so I can include it here.

Fork GPUImage

If you want to contribute to GPUImage, you must create a fork of the repository. I am actually using this post to recreate all of my work because I didn’t fork the repo, tried to create a branch, and it was turtles all the way down.

I had a fork that was two years old and 99 commits behind the main branch. I am only using my forks to create projects to contribute to the framework, so I destroyed my old fork and created a new one. If you’re better at Git than I am and can keep pulling in the changes, then awesome. My Git-fu is weak so I did this, which is probably making a bunch of people sob and scream “WHY?!?”

Adding Your New Filter to the Framework

There are two different instances of the GPUImage framework: Mac and iOS. They both share a lot of the same code files, but you need to add the new filter to both manually.

My Solarize filter is one that modifies the color, so I dragged and dropped my filter into the group of color modifying shaders. The source files go into the Source folder in the Framework folder in the file you clone from GitHub.

Where the shader files go

Where the shader files go

While you are looking at your .h file, you need to make sure that it is set to Public rather than Project. If you don’t do that, it won’t be visible for the next step in this process.

This is the wrong privacy setting for the header file.

This is the wrong privacy setting for the header file.

This is the correct privacy setting

This is the correct privacy setting

Next, you need to go to the Build Phases of the GPUImageFramework target of your project. You need to add the .h file to the Headers in the framework and the .m file to the Compile Sources.

I had some trouble doing this. When I would click on the “+” button at the bottom of the filter list, I would only be able to find the opposite file. So for example, when I tried to add my header to the Headers list, I would only be able to find the solarization implementation file. The way I got around this was to drag the file from the list and drop it into the build phases target.

Drag the file from the left to the correct build phase on the right.

Drag the file from the left to the correct build phase on the right.

Lastly, you need to add your filter to the GPUImage.h header file so that the framework has access to your shader. (By the way, wasn’t C/Objective-C a pain??)

The GPUImage.h is different for the Mac and the iOS project, so if you want your filter to be available on both platforms, you need to remember to add it to both GPUImage.h header files.

Adding Your New Filter to the Filter Showcase

First off, want to warn you to only use the Swift version of the Filter Showcase. I had a lot of stuff that I was adding in here to try and get the Objective-C version working. That was the main reason I split this into two blog posts. It is a pain in the ass and it was made far simpler in the Swift version of the filter showcase.

When you open the Filter Showcase, you will be asked if you want to update to the recommended project settings. Don’t do this!

The only place you need to make a change is in the file FilterOperations.swift. This file is shared between both the iOS and the Mac Filter Showcase apps, so you only have to change this once. Huzzah!

You need to add your new filter to the filterOperations array. There are a few things you need to set in your initialization:

FilterOperation (
        listName:"Solarize",
        titleName:"Solarize",
        sliderConfiguration:.Enabled(minimumValue:0.0, maximumValue:1.0, initialValue:0.5),
        sliderUpdateCallback: {(filter, sliderValue) in
            filter.threshold = sliderValue
        },
        filterOperationType:.SingleInput
    ),

I looked at the parameters used in the GPUImageLuminanceThresholdFilter initialization because my shader was primarily based on this code. As such, your filters might have different parameters than mine did. Look around at other instances to get an idea of how your filter should be initialized.

When you build and run the Filter Showcase, you might encounter an issue where the project builds but doesn’t run. You might see this pop-up:

Update the what now??

Update the what now??

If this happens, don’t update anything. Xcode is trying to run the wrong scheme. Look up at the top of Xcode near the “Play” button and check the scheme. It should say Filter Showcase. If it says GPUImage instead, then you need to change the scheme and it should work okay.

Wrong schemes are full of fail.

Wrong schemes are full of fail.

GPUImage Style Guide

I am going to go through my Solarize filter to make note of some style things that you should keep in mind when you are writing your own filters to try and keep things consistent.

The entire implementation file for shader is represented in this section, but I am showing a chunk at a time and explaining each part.

#import "GPUImageSolarizeFilter.h"

As with all C programs, you need to import the header for your shader in the implementation file.

#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
NSString *const kGPUImageSolarizeFragmentShaderString = SHADER_STRING
(
 varying highp vec2 textureCoordinate;
 
 uniform sampler2D inputImageTexture;
 uniform highp float threshold;
 
 const highp vec3 W = vec3(0.2125, 0.7154, 0.0721);
 
 void main()
 {
     highp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);
     highp float luminance = dot(textureColor.rgb, W);
     highp float thresholdResult = step(luminance, threshold);
     highp vec3 finalColor = abs(thresholdResult - textureColor.rgb);
     
     gl_FragColor = vec4(finalColor, textureColor.w);
 }
);

Since GPUImage is cross platform, you need to check if your shader is running on an iOS device or not. Since iOS uses OpenGL ES and not just plain OpenGL, there are a slight difference that you need to take into consideration.

Notice how a bunch of the variables are described as highp. In OpenGL ES, since you have more limited processing power, if you don’t need a lot of precision, you can optimize your code by lowering the necessary precision. You do not do this in the Mac version of the shader:

#else
NSString *const kGPUImageSolarizeFragmentShaderString = SHADER_STRING
(
 varying vec2 textureCoordinate;
 
 uniform sampler2D inputImageTexture;
 uniform float threshold;
 
 const vec3 W = vec3(0.2125, 0.7154, 0.0721);
 
 void main()
 {
     vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);
     float luminance = dot(textureColor.rgb, W);
     float thresholdResult = step(luminance, threshold);
     vec3 finalColor = abs(thresholdResult - textureColor.rgb);

     gl_FragColor = vec4(vec3(finalColor), textureColor.w);
 }
);
#endif

One last thing I want to point out is the use of NSString *const kGPUImageSolarizeFragmentShaderString = SHADER_STRING. It is a convention to take the name of your shader, add a “k” at the beginning (“k” for “constant”, get it?), and follow it with “FragmentShaderString.” Use this convention when you write your own shaders.

In each shader that you create for GPUImage you need to remember to include the textureCoordinate and the <>. These two variables receive the exact pixel you are going to process, so make sure you have those in each of your shaders.

Now we move on to the implementation:

@implementation GPUImageSolarizeFilter;

@synthesize threshold = _threshold;

I have a public facing variable, threshold, that I need to get access to in order to implement the shader, so it needs to be synthesized. Again, this is a throw back from C/Objective-C that you might not be familiar with if you just started with Swift.

#pragma mark -
#pragma mark Initialization

- (id)init;
{
    if (!(self = [super initWithFragmentShaderFromString:kGPUImageSolarizeFragmentShaderString]))
    {
        return nil;
    }
    
    thresholdUniform = [filterProgram uniformIndex:@"threshold"];
    self.threshold = 0.5;
    
    return self;
}

All Vertex shaders will look similar to this. They all have an initializer that attempts to initialize the fragment shader from that string you created back at the beginning of the if/else statements.

If you have a public facing variable like threshold is here, you need to set that up before you finish your initialization.

#pragma mark -
#pragma mark Accessors

- (void)setThreshold:(CGFloat)newValue;
{
    _threshold = newValue;
    
    [self setFloat:_threshold forUniform:thresholdUniform program:filterProgram];
}


@end

Lastly, if you have a public facing variable, like we do with the threshold, you need an accessor for it.

Copy/Paste Coding

I normally really do not condone “Copy/Paste” coding, but did want to mention that there is a lot of repetitive stuff in all of the shader programs. This shader only has like five lines of code that I changed between the Solarize filter and the Luminance Threshold filter.

Generally speaking, copying and pasting code is bad, but looking through a piece of code and figuring out what everything does while you are learning and being able to process how to do this on your own in the future isn’t always the worst thing in the world. I could have written my shader without having an understanding of how the two contributing filters worked.

So, use these as learning materials and there’s nothing wrong with looking at how they’re put together until you feel comfortable with the process on your own.

Wrapping Up

I know that trying to start something unfamiliar can be really intimidating. Especially if there are a bunch of esoteric steps that you’ve never done before and you don’t want to have to ask about it because you feel stupid.

I went back and forth with Brad a dozen times while writing this blog post and none of my questions were about the actual shader code. It was all about how to add this to the framework, why my shader wasn’t showing up in the header, etc…

This stuff is not intuitive if you haven’t done it before. This might be familiar to older Mac programmers who had to do this stuff all the time, but if you primarily work with Swift where everything is just there and you don’t have to add things to build phases, then this can be extraordinarily frustrating.

I hope that this is helpful to those who have wanted to contribute to GPUImage but got frustrated by the hoops that were necessary to jump through to get something working. I hope that this means that people have a resource besides Brad to get answers to common questions that aren’t really available on Stack Overflow.

How to Write a Custom Shader Using GPUImage

One of my goals over the last year or so was to do more coding and to specifically do more GLSL programming. You learn best by actually working on projects. I know that, but I have had some trouble making time to do things on my own.

I want to go over my thought process in figuring out a filter I wanted to write, how I was able to utilize the resources available to me, and to hopefully give you an idea about how you can do the same.

You can clone GPUImage here.

Solarize Image Filter

One thing I had trouble with in GPUImage is the fact that it is too comprehensive. I couldn’t think of an image filter that wasn’t in the framework already.

So I started thinking about Photoshop. I remembered there was a goofy filter in Photoshop called Solarize.

Since I knew that Brad was more concerned with things like edge detection and machine vision, I figured that it would not have occurred to him to include a purely artistic filter like that. Sure enough, there was no solarization filter. Jackpot!

After figuring out something that wasn’t there, the next question was how to create one. I initially was going to use this Photoshop tutorial as a jumping off point, but I wondered if there was a better way. I Googled “Solarize Effect Algorithm” and I found this computer science class web page that gave an agnostic description of how the effect works.

What is Solarization?

Solarization is an effect from analog photography. In photography, one important component of a photograph is its exposure time. Photographers used to purposely overexpose their photos to generate this effect. When a negative or a print is overexposed, parts of the image will invert their color. Black will become white, green will become red.

There is a threshold where any part that passes that threshold will receive the effect.

One of the things Brad told me about GPUImage was that many of the filters in GPUImage are composed of many smaller filters. It’s like building blocks. You have a base number of simple effects. These effects can be combined together to generate more and more complex effects.

Looking at the algorithm for solarization, I noticed it requires two things:

  • An adaptive threshold to determine what parts of the image receive the effect
  • An inversion effect on the pixels

I opened up GPUImage to see if there were already filters that do those things. Both of these functions already exist in GPUImage.

Now I needed to figure out how they work so that I could combine them into one, complex filter.

GPUImageColorInvertFilter

Since the color invert filter is the simpler of the two filters, I will be looking at this one first.

Since this is a straightforward filter that does one thing without any variables, there are no publicly facing properties in it’s header file.

Here is the code for the vertex shader that we see in the implementation file:

NSString *const kGPUImageInvertFragmentShaderString = SHADER_STRING
(
 varying highp vec2 textureCoordinate;
 
 uniform sampler2D inputImageTexture;
 
 void main()
 {
    lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);
    
    gl_FragColor = vec4((1.0 - textureColor.rgb), textureColor.w);
 }
);

These two lines will exist in every vertex shader in GPUImage:

varying highp vec2 textureCoordinate;
uniform sampler2D inputImageTexture;

These lines are the lines where you are bringing in the image that is going to be filtered and the specific pixel that the fragment shader is going to work on.

Let’s look at the rest of this:

void main()
{
   lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);
   gl_FragColor = vec4((1.0 - textureColor.rgb), textureColor.w);
}

The first line is simply obtaining the specific RBGA values at the specific pixel that you are currently processing. We need that for the second line of code.

The gl_FragColor is the “return” statement for the fragment shader. We are returning what color the pixel will be. Texture colors are part of a normalized coordinate system where everything exists on a continuum between 0.0 and 1.0. In order to invert the color, we are subtracting the current color from 1.0. If your red value is 0.8, the inverted value would be (1.0 - 0.8), which equals 0.2.

This is a simple and straight forward shader. All of the actual, shader specific logic is in the gl_FragColor line where we are doing the logic to invert the colors.

Now let’s move on to the more complicated shader.

GPUImageLuminanceThresholdFilter

The Luminance Threshold Filter is interesting. It checks the amount of light in the frame and if it is above a certain threshold, the pixel will be white. If it’s below that threshold, the pixel will be black. How do we do this? Let’s find out.

The Luminance Threshold Filter, unlike the color inversion filter, has public facing properties. This means that the header file has some actual code in it that we need to be aware of. Since this one is interactive and depends upon input from the user, we need a way for the shader to interface with the rest of the code:

@interface GPUImageLuminanceThresholdFilter : GPUImageFilter
{
    GLint thresholdUniform;
}

/** Anything above this luminance will be white, and anything below black. Ranges from 0.0 to 1.0, with 0.5 as the default
 */
@property(readwrite, nonatomic) CGFloat threshold; 

@end

Our threshold property will receive input from a slider in the UI that will then set a property we will need to calculate our shader.

NSString *const kGPUImageLuminanceThresholdFragmentShaderString = SHADER_STRING
( 
 varying highp vec2 textureCoordinate;
 
 uniform sampler2D inputImageTexture;
 uniform highp float threshold;
 
 const highp vec3 W = vec3(0.2125, 0.7154, 0.0721);

 void main()
 {
     highp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);
     highp float luminance = dot(textureColor.rgb, W);
     highp float thresholdResult = step(threshold, luminance);
     
     gl_FragColor = vec4(vec3(thresholdResult), textureColor.w);
 }
);

This has a few more components than the color inversion code. Let’s take a look at the new code.

uniform highp float threshold;
const highp vec3 W = vec3(0.2125, 0.7154, 0.0721);

The first variable is the value we are receiving from the user for our threshold. We want this to be very accurate because we’re trying to determine whether a pixel should receive an effect or not.

The second line has what looks like a set of “magic numbers.” These numbers are a formula for determining luminance. There are explanations for it here and in the iPhone 3D programming book by Philip Rideout. We will use this constant to map over the current value of the fragment in the next bit of code.

void main()
{
    highp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);
    highp float luminance = dot(textureColor.rgb, W);
    highp float thresholdResult = step(threshold, luminance);
     
    gl_FragColor = vec4(vec3(thresholdResult), textureColor.w);
}

The first line does the same thing as it did in the color inversion filter, so we can safely move on to the next line.

For the luminance variable, we’re encountering our first function that doesn’t exist in C: dot(). dot() takes each red, green, and blue property in our current pixel and multiplies it by the corresponding property in our “magic” formula. These are then added together to generate a float.

I have tried hard to find a good explanation of why dot product exists and what it does. This is the closest thing I can find. One of my goals with this series of blog posts is to take things like dot product where you can explain what it does, but not why you are using it and what functionality it fulfills. For now, hopefully this is enough.

Next up, we have the threshold result. This is where we are doing our only conditional logic in the shader. If you recall, this shader makes a determination if each pixel should be white or black. That determination is being made here.

The step() function evaluates two different floats. If the first number is larger, then the threshold result is 1.0 and that particular pixel is bright enough to pass the threshold requirements. If the second number is larger, then the pixel is too dim to pass the threshold and the result is 0.0.

Finally, we map this result to our “return” statement, the gl_FragColor. If the pixel passed the threshold, then our RGB values are (1.0,1.0,1.0), or white. If it was too dim, the then RGB values are (0.0,0.0,0.0), or black.

GPUImageSolarizeFilter

According to the algorithm that describes the solarization process, you use a luminance threshold to determine if a pixel receives an effect or not. Instead of the effect of making the pixel either white or black, we want to know if the pixel should be left alone or if it’s color should be inverted.

The only line of code that the color inversion filter has that the threshold doesn’t have is a different gl_FragColor:

// Color inversion gl_FragColor
gl_FragColor = vec4((1.0 - textureColor.rgb), textureColor.w);

// Luminance Threshold gl_FragColor
gl_FragColor = vec4(vec3(thresholdResult), textureColor.w);

I am embarrassed to say how long it took me to figure out how to combine these two filters. I thought about this for a long time. I had to think through all of the logic of how the threshold filter works.

The threshold filter either colors a pixel black or white. That is determined in the thresholdResult variable. This means that we still need the result in order to figure out if a pixel receives an effect or not, but how do we modify it?

Look at this part of the gl_FragColor for the color inversion:

(1.0 - textureColor.rgb)

Where else do we see 1.0 being used in the threshold shader? It’s the result of a successful step() function. If it fails, you wind up with 0.0. We need to change the gl_FragColor from the color inversion filter to have the option to return a normal color or an inverted color. If we subtract 0.0 from the texture color, then nothing changes.

This is the final code I came up with to implement my Solarize Shader:

NSString *const kGPUImageSolarizeFragmentShaderString = SHADER_STRING
(
 varying highp vec2 textureCoordinate;
 
 uniform sampler2D inputImageTexture;
 uniform highp float threshold;
 
 const highp vec3 W = vec3(0.2125, 0.7154, 0.0721);
 
 void main()
 {
     highp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);
     highp float luminance = dot(textureColor.rgb, W);
     highp float thresholdResult = step(luminance, threshold);
     highp vec3 finalColor = abs(thresholdResult - textureColor.rgb);
     
     gl_FragColor = vec4(finalColor, textureColor.w);
 }
);

This is primarily composed of the same code to create the luminance threshold shader, but instead of mapping each pixel to be either black or white, I am using that result to check to see if I am inverting my colors. If the colors need to be inverted, then the thresholdResult is 1.0 and our formula moves forward as usual. If thresholdResult is 0.0, then our texture color remains the same, except now it is negative, which is why I wrapped it in an abs() function.

Completely solarize shader. Will try to get a better picture later.

Completely solarize shader. Will try to get a better picture later.

Takeaways

One of the big things I keep harping on with this blog the last year or so is that to be a good engineer, you must have an understanding about what you’re trying to accomplish.

Breaking down a shader that you want into an algorithm helps you to tease out what pieces of functionality you need to get the result you want. In a lot of cases, the smaller pieces of functionality are already out there in the world somewhere and you can reuse them to build more complex things.

You also need to be able to read through those shaders to figure out how they work so you can know where the pressure points are to change the code. Since shaders are so small, you can usually take one line at a time and break down what it does. If there is a function being used that you’re unfamiliar with, Google it. You don’t always need to understand all of the why something is being used in order to implement it, such as I did with the dot() function. I was able to have a good enough grasp of what it did to understand why it was needed in my shader which was all I really needed.

This stuff can be intimidating, which is why it’s important to spend some time figuring out why something works and, more importantly, figuring out what YOU want to do with it.

I will be following this post up tomorrow with instructions for how to add a shader to the GPUImage framework, including some other parts of the shader code that I did not go over here.

Exercises for Programmers: Exercise 4- Mad Libs

The fourth exercise in Exercises for Programmers is to create a Mad Lib.

Mad Libs are a game you play when you’re a kid and you’re trying to learn different parts of speech. You name random nouns and verbs to fill in the blanks in a story you can’t see until you are finished.

This project continues with the theme of making the exercises more and more complex as you go along.

This project requires you to ask for four different user inputs and to create a story around them. If any of those inputs is missing, you want to alert the user rather than output a story with half the words missing.

As usual, I have uploaded this project to GitHub.

What this looks like when successful

What this looks like when successful

Data Structures

Since I want to unit test my application, I want to move as much of the programming logic outside of the view controller as possible. I need to grab the four user input responses and I want to pass those into another function.

I thought about making this into an array of strings, but I liked the idea of being able to have keys and values for the user input. I want to be able to tell the user which field they forgot to fill and that is a lot easier when you bundle the name of the field along with the input instead of just counting on things being in the right order. Having an array of random words with no indication about what they represent seemed like a recipe for disaster.

In the @IBAction for the Enter button, I created a dictionary of all of the user input values:

let userInput:[String:String] = [
    "noun":nounTextField.text!,
    "verb":verbTextField.text!,
    "adjective":adjectiveTextField.text!,
    "adverb":adverbTextField.text!
]

Now that I had a data structure and I knew what types were going into it, I could start working on the output logic.

Set up

Set up

To Map(), or not to Map()

One reason I wanted these values to exist in a data structure was because I wanted to use Map().

This seemed like a good time to use Map(). I had to iterate through a data structure, check to see if the input was empty, and if it was I had to do something.

Taking this approach really tripped me up and cost me a lot of time.

When I worked with Brad at SonoPlot, he used protocols and flatmaps to iterate through a collection of data we were writing to and getting from the NSUserDefaults. I thought I would set up a function that returns an optional string that would check each string to see if there was anything in it. If there wasn’t, I could return a nil and filter them out.

func isStringEmpty(input:String) -> String? {
    if input.characters.count != 0 {
        return input
    } else {
        return nil
    }
}

I started to realize this wasn’t really helpful to me. Here is why:

Let’s say my user forgets to specify a verb. I can flatmap my dictionary using this function that will give me an array with three values. I won’t know which value is missing. I can’t tell the user which value they forgot to enter.

I spent a bunch of time trying to figure out how to map my isStringEmpty() function to my dictionary. In order to try and figure out how to optimize this, I wrote it in the most inefficient manner I possibly could so I could see what code I was repeating:

func output(input:[String:String]) -> String {
    
    var outputString = String()
    
    let noun = isStringEmpty(input["noun"]!)
    let verb = isStringEmpty(input["verb"]!)
    let adjective = isStringEmpty(input["adjective"]!)
    let adverb = isStringEmpty(input["adverb"]!)
    
    if noun == nil {
        outputString += "Please enter a noun! 
"
    }
    
    if verb == nil {
        outputString += "Please enter a verb! 
"
    }
    
    if adjective == nil {
        outputString += "Please enter an adjective! 
"
    }
    
    if adverb == nil {
        outputString += "Please enter an adverb! 
"
    }
    
    if noun != nil &&
       verb != nil &&
       adjective != nil &&
       adverb != nil
    {
        outputString = "Do you (verb) your (adjective) (noun) (adverb)?"
    }
    
    return outputString
}

Clearly I am repeating my calls to isStringEmpty() for every input in my UI. This is really inefficient.

I am also constantly checking if something is nil. Since the variable I am checking has the same name as the type of word that I need to tell the user to enter, this could probably be more generic.

I optimized this from that monstrosity to the following:

func output(input:[String:String]) -> String {
    var outputString = String()
    
    for (key, value) in input {
        let checkValue = isStringEmpty(value)
        
        if checkValue.characters.count == nil {
            outputString += "Please enter a (key)! 
"
        }
        
    }
    
    if outputString.characters.count == 0 {
        let noun = input["noun"]!
        let verb = input["verb"]!
        let adjective = input["adjective"]!
        let adverb = input["adverb"]!
        
        outputString = "Do you (verb) your (adjective) (noun) (adverb)?"
    }
    
    return outputString
}

I tried for a bit to use a map() function rather than the for-in loop, but it felt just easier to do it this way. I would still like to get more comfortable using map(), but I also don’t want to create an “If you give a mouse a cookie” problem where I am adding a bunch of garbage to my code to try and force a square peg into a round hole.

If anyone can give me a good explanation about how I could have used map() more efficiently than using for-in I would greatly appreciate it. I have seen it used in other people’s code but I don’t process how I can implement it myself because I have not tried to solve a problem with it yet.

Lastly, I realized that my efforts to cram the flatmap() into the code was causing me to use the isStringEmpty() function even though there really was no point in doing so.

I condensed down all of my programming logic into one function:

func output(input:[String:String]) -> String {
    var outputString = String()
    
    for (key, value) in input {
        
        if value.characters.count == 0 {
            outputString += "Please enter a (key)! 
"
        }
        
    }
    
    if outputString.characters.count == 0 {
        let noun = input["noun"]!
        let verb = input["verb"]!
        let adjective = input["adjective"]!
        let adverb = input["adverb"]!
        
        outputString = "Do you (verb) your (adjective) (noun) (adverb)?"
    }
    
    return outputString
}
Completely empty response

Completely empty response

Limit to User Input Optimization

One thing that bothered me about this project was the fact that I couldn’t procedurally deal with every instance of pulling out the nouns, verbs, etc…

No matter what I do I have to spend four lines of code pulling out the user input and then another four lines doing something with them.

Those lines of code cause me to be bothered because I don’t like hard coding things. I was happy I could do the for-in loop because there could be forty elements or two and either way it was flexible. Having things hard coded isn’t flexible.

However, I do not think there is a way around this in this project. I believe that any time you are doing anything that touches the user interface, there is a limit to how far you can optimize it.

When I was going to write the unit tests, I had the urge to see what would happen if I sent a value that wasn’t noun or verb or if one of those was missing. I know that in this project that is impossible, but it still really bothers me because of how inefficient it feels. It had code smell. I think there is nothing I can do about it, but that won’t keep me from driving myself crazy trying to think of a way around it.

Partially empty response

Partially empty response

Takeaways

Initially, I thought this project would have a lot more programming logic than any other project before this, but it actually had the least amount.

I left my less efficient code in the project to show how much I was able to refactor the project.

I think a major takeaway that I want to bring up is the idea of rewriting your code a lot.

One issue I have had with working with other people on programming projects is that sometimes, as I did here, it’s easier for me to write some really crappy, inefficient code that just works so that I can get a better handle on how to make it better. When I am working on something and someone randomly demands to see what I have so far, it is incredibly upsetting to have to show that I did this really terrible code. There are probably ways around this, but it can be super demoralizing to show the early part of my process to someone when it is something I am still actively working on and trying to make better.

If you are a decent programmer, you will rewrite your code a few times. You will get a better idea about what problems you are trying to solve and how your current approach isn’t what you thought it would be. My final code is about a third of what it was initially because the way I thought I needed to do this was different than the way I actually needed to do it. I could have kept adding more and more junk to the code to try and force it to work, or I could change my perspective on how to approach the problem.

I firmly believe in writing bad code to get the garbage out of your head. Not every line of code needs to be a line from Shakespeare. Writing a lot of bad code helps you figure out how to write better code more quickly.

Why I am Trying to Give Up Drinking

Anyone who follows me on Twitter or knows me in real life knows that I am quite fond of my evening glass of wine. It’s at a point where it’s almost a personality trait, along with my pugs.

I am vaguely aware of the fact that it’s not really a good thing to be known as the person who drinks a lot. I had the problem of thinking that people like Dorothy Parker and Lucille Bluth are super cool and have lead me to attribute this as a positive personality trait.

I wasn’t always like this.

How I Started Drinking

The first time I ever got drunk was at my bachelorette party. It was a very interesting experience for me. It felt like having a migraine only it didn’t hurt. It put me into this weird, almost meditative state that I found very stimulating.

I never partied when I was in high school or college. I used to spend my Saturday nights watching public TV with my parents. When I was in college I would spend all night alone in my apartment doing cross stitching while watching Law & Order marathons.

I felt kind of like I missed out on my youth and I wanted to make up for lost time. I figured I would get tired of it and I didn’t worry about it too much.

I went back to school to learn programming. I had a lot of anxiety about how I was going to find a job because I knew that the tech industry was very youth-centric. I knew as a woman in my 30’s with no experience it would tricky to break into the industry. I knew my best chance was to work my ass off and try to increase my skills as fast as possible. I stopped cross stitching and doing all the things I used to do to relax. The easiest way to get myself to relax was to drink. I half heartedly tried quitting a few times, but I was so stressed out that I figured I would deal with it later.

Then my marriage started falling apart.

The last year I was married I gave myself alcohol poisoning five times. Two weeks into my first job I was out for New Year’s and I drank so much so quickly that I could not keep water down for a few days. I didn’t want to tell any of the young guys at my job that I got so drunk I couldn’t keep water down, so I just kind of got through it.

After I left that job I worked from home and worked on a book. I used to keep boxes of wine outside where they would freeze overnight. I would bring them in and by the time noon rolled around the wine was thawed enough for me to drink it.

After the divorce I went through a massive depression that I did not expect to go through. I had to commute sixty miles a day to and from my job. By the time I got home I was so spent that all I could do was open a bottle of wine and drink in the bath tub. I deluded myself into thinking I didn’t have a problem because I stopped giving myself alcohol poisoning.

I am painfully aware that these behaviors that I am describing are really unhealthy. But I was stressed out and depressed and this wasn’t at the top of my list of things to worry about.

Why I Am Going to Stop

I am honestly trying to remember what triggered this most recent decision.

The last few months I haven’t been able to go for walks because of the weather. I used to walk 45 minutes a day. It was therapeutic. I wasn’t doing it to lose weight, it was just to get away from the computer and try to clear my head.

I hit 34 and started noticing things like lines around my eyes. I feel like I have put on a bunch of weight over the last few months. I bought larger jeans that used to be loose that are now not anymore.

I recently was able to start doing my walks again recently. I realized that even though I was jogging two miles a day I probably wasn’t going to lose any weight because of my drinking habit.

For some reason, this really bothered me. I don’t want to be a person who is obsessed with losing that last ten pounds, but I am at the point where a bunch of this crap is really bothering me.

I have cleared out enough other emotional baggage from my queue that I now want to deal with this.

I don’t want to feel this way anymore. I have had enough periods of my life where I was out of shape and not feeling particularly well. I know that inevitably at some point I am going to be old. It will be harder to lose weight than it is now. My joints will bother me. I can’t keep this from happening, but I can push it off a while longer by making changes now. It’s better late than never.

What I am Trying To Do

My initial thought was that I would do things in moderation. I would limit myself to one glass of wine a night. I then realized that was not going to work. I always think I will have one, but then after the first one I feel really good and the evening is still early, so I have more.

I also decided not to try and replace alcohol with another sweet beverage like fruit juice. I want to be healthier and lose weight, so replacing alcoholic sugar with non-alcoholic sugar was not a great idea.

I am trying to go cold turkey on most sugar.

I did this a few years ago. I drank nothing but water for like two weeks to retrain my palette not to expect everything it encounters to be sweet.

I am restraining my beverage intake to just water, sparkling water, and tea. I am putting some honey in my tea in the mornings because I am also putting lemon in it and I need something to ameliorate it. I know honey is sugar and sugar is bad for you, but I am confining it to that one thing and I have no allusions that it’s healthy, so don’t lecture me.

I am taking this one day at a time. I know from watching people fail at diets that I am going to have bad days. I will have days where I simply can’t deal with it and I will drink. I will not throw in the towel and give up on the experiment. I will just try to do better next time.

Things I have Notice So Far

I am only on my third day of this, so in a few weeks this might be a laughable blog post. But I have noticed a few things so far.

Nights are Boring

My routine used to be that I would finish work, take a bath with a glass of wine, get warm and comfortable, then go to bed.

I can’t do that anymore.

I used to think that after I got done with work, that I was spent for the day. I would basically drug my brain to get it to relax and calm down so I could sleep and work the next day.

The last few days I have realized I can take a bath and be refreshed enough to work on something else that I actually want to do.

It’s really disconcerting. I know I am tired and I need to sleep, but my brain gets a second wind.

This might be a temporary thing and I will probably crash in a few days. At that point I need to figure out a better way to relax. I never thought I would forget how to relax. It was so hard to do any work when I was younger that I never thought I would be stuck in the mind set that I had to work all the time.

Sugar Withdrawal Really Sucks

I think part of the reason I was drinking as much as I did was because I trained my brain to associate sugar with work being over.

I knew that alcohol had a lot of sugar in it, but I didn’t think about the fact that I was slowly increasing my intake over the last few years.

Yesterday I wanted to stab someone for a drink, not because I craved the alcohol, but because I craved the sugar. I ate a few pieces of dark chocolate and I felt better and the craving went away.

The long term goal isn’t to replace one source of sugar with another. I know that cutting back on all sugar is the goal, but it takes some time to get there. At least the chocolate provides some satiation. Alcohol is an appetite stimulant. I will not be hungry, but then I will have a glass of wine and suddenly be famished. Cutting back on the alcohol not only cuts those calories, but also all the ones I would eat after getting the munchies.

I am hoping the cravings get better the longer I stick with this.

Not Exercising Bothers Me

My Apple Watch got pretty passive aggressive with me over the winter because I wasn’t going on my walks. It was annoying, but I didn’t feel super compelled to do anything about it.

The last few days I have been crawling the walls if I can’t do some kind of exercise.

I wanted to go for a walk yesterday and I almost jumped out of my skin trying to find a time I could get out of here. It was too cold to walk, so I did a strength training exercise for half an hour and even that didn’t feel long enough.

Sitting at my computer today drove me crazy. I am going to try to find a way to do a standing desk of some kind. It’s harder to do with the retina iMac than it was with the laptop and the robotics boxes.

Moving Forward

For me, the biggest test of how this will go is when I got to my first conference this year in two weeks, RWDevCon. I need to decide if I am going to forgo drinking altogether at that event or try to limit myself to one drink. If it were right now I would forgo it completely, but I will see how I feel then.

I wish I could see this in an optimistic light. Yay, I can work on side projects after work. I can work out and lose weight and be healthier. This is going to be super awesome.

But I can’t think of it that way. This is going to be a huge and difficult adjustment. I know I used to live quite happily not doing this every night and I can probably do that again. But it’s going to take some time and effort to relearn how to relax so I don’t burn myself out. I feel like I have taken the fail safes off of myself that kept me from doing too much. I knew I could force myself to relax by basically drugging myself. Now that I am choosing not to do that anymore, I am not sure how I am going to function. I guess I will find out.