Publicly Available Information

Okay, I am probably going to get a lot of flack for this blog post, but I am writing it anyway and I don’t really give a damn. If someone can give me a compelling reason to think I am wrong, I am happy to hear it.

So, yesterday I posted a few pictures of packages I have received on Twitter. I had several of my friends reach out to me to ask me if I meant to post my address on Twitter.

I didn’t post it on purpose, but I didn’t think that it was that big of a deal. I understand that one of the big things that tech feminists have been mentioning people doing to terrorize them is to “dox” them by posting their phone numbers and addresses on malicious websites where people who mean them harm can see them.

I am not in any way discounting how terrifying that can be and they have every right to be upset by that behavior, but this is my take on things…

Back in 1985…

Back when I was growing up we had these things called “phone books.” They were large books that arrived in the mail each year that had a listing of the names and addresses of every person who lived in your county. If I wanted to look up a classmate’s phone number, I could haul this stupid large book out and look up their last name. Sometimes there were a few people that all had the same name and you would have to call a few of them to find the right person.

We didn’t have caller ID, so you never knew who was calling you. You couldn’t block malicious numbers, but most calls weren’t malicious. More often than not it was a telemarketer and you learned after a while that if you picked up on the first ring and there was a long pause it was probably a telemarketer and you hung up on them.

Having your address and phone number publicly available didn’t used to be a big deal.

The new phone books are here! The new phone books are here!!

The new phone books are here! The new phone books are here!!

Today

My address is publicly available. Wisconsin (for now) has open records. I went through a divorce last year and never moved. You can go to the Wisconsin Circuit Court access and look me up and find out where I live.

Back when I was starting out I was really stupid and printed my home address on my business cards. I handed these out for a while before I realized this was a really stupid fucking thing to do and got new ones printed that only had my personal phone number on them. Then I just started handing out pug stickers with no identifying information whatsoever on them.

Point is, if someone wants to find out where I live, it’s not hard.

I know there is an outside chance that someone I don’t know will show up at my door and do something to me, but that possibility doesn’t worry me very much. I live in a town in rural Wisconsin that has no public transportation. Most of the developers I am aware of who live in my area live in downtown Madison because it means they don’t have to have a car. In order to get out to where I live they have to find a car and drive half an hour to where I am. My parents live closer than that and even they don’t like to drive to where I live. That’s just the people who live here. If you’re some asshole in The Bay Area you would have to fly and drive out here to mess with me.

Every one of my neighbors has a gun. I have had my neighbors call my parents when my ex husband and I got home early from a trip and they saw someone moving around in my house.

If someone intends to harm me, it would take a lot of trouble and money for them to do so. My not publicly posting my address somewhere is not going to prevent someone who is intent on harming me from doing so. I also will not hesitate to call the cops if someone shows up that I don’t know and didn’t invite.

Risk Assessment

Of all the things I worry about, having a stranger show up at my house is pretty low on my list.

I worry about my house burning down while I am at a conference. I worry about my pugs choking on something and dying. I worry about losing my job and having to relocate to San Francisco because no one will let me work remotely.

I am willing to accept the possibility that at some point in the future someone could show up at my house with the intention to harm me. Someone could send a bomb in the mail to hurt me and my pugs. Any number of things could happen.

I just think the odds of that happening is so unlikely that I don’t think it honestly matters that much if I inadvertently post a picture of my address on Twitter.

I don’t want to spend every waking moment of my life worried that someone out there is out to get me.

My personal experience with this community has been that it has been incredibly supportive. I wrote several blog posts recently during a bout of depression and I had at least five people reach out to me personally via phone and email to support me and give me helpful advice.

I know a number of people have been poorly treated by strangers on the internet and I empathize with them. I know that a well known female developer in Madison was stalked by another developer in Madison and that was completely not okay. She went to a lot of trouble to hide her address, which was not publicly available, and had it revealed by the police to someone who had presented a clear and real danger to her. I am not trying to discredit her experiences by saying that because nothing bad has happened to me so far that her fears are irrational.

I took down the photos because enough people seemed worried about it. But I just find it strange that a bunch of people acted like I posted my social security number and my credit card number on Twitter and just trusted people to not steal my identity or show up at my house and murder me. I have found 98% people to generally be decent and respectful. I would prefer to focus on that percentage rather than judge on the smaller number who make life difficult. If I am proven wrong I will be the first to admit it. But I would like to give people the benefit of the doubt that they are not planning to attack me just because they can find out where I live.

Self Destructive Tendencies

I have a problem and I am writing about it because I want to know if anyone else has the same problem.

When I start a new project I get really overwhelmed.

My dream project for the last few years has been to write a synthesizer application. Every time I start to think about writing this application I get incredibly overwhelmed by a lot of things:

  • How much math do I need to know how to do?
  • What kind of synthesizer do I want to write?
  • Oh shit, everything is in C++. How much C++ do I need to know?!
  • Can I use this audio programming book that’s in C++ if everything in it assumes you’re using Windows?
  • How do I do the user interface?
  • How do I fit all these little elements on an iPhone? Can I lay it out differently?
  • Do I need to know OpenGL to do a decent user interface?

So I get super overwhelmed and I sit down to try to figure out one of these things.

I sit down to learn C++ so I can read the book on audio programming.

I figure out that I don’t understand the math and I get freaked out and I try to learn the math.

Then at a certain point I get overwhelmed, feel stupid, and curl up on the floor crying because I am stupid and will never amount to anything and I should just give up on programming because I am a failure and should just go back to working at Target.

This doesn’t just happen with my personal projects. Sometimes this happens at work too.

At my previous job I had to learn a bunch of stuff about network programming. I have never done network programming and I honestly never want to do it ever again. I had people telling me to play with Paw to learn network programming. I don’t know what Paw is supposed to do. If I don’t know what it is doing, how do I play with it? I have no context for anything I am doing, so I wind up in this creepy, paralyzing mental mode where I am grappling with a bunch of unfamiliar terminology that has no context and if I can’t do my job I will get fired and I can’t pay my mortgage and I will be homeless and it makes me curl up on the floor breathing into a brown paper bag.

How do I avoid this?

Learn by Doing

I know from my own personal experience that I learn better by doing.

For a really long time I learned by doing a lot of tutorials. The first time I would do a tutorial I would have the overwhelming paralyzing feeling of not knowing what I was doing, but then I would do the tutorial over and over again a few times until I got the feel for what I was doing.

Back when I was a full time student and had the luxury of time, I could do this 60-80 hours a week. It was kind of magical about how by the third or fourth time I totally understood what I was doing.

Then I went out into the job market and started to mentally feel like I couldn’t do this and have tried to find ways around it. I used to keep trying to do tutorials, but I would only have time to do them once and I would be stuck in the paralyzed overwhelming stage, so I stopped doing that.

The only way to learn and grow is to write code.

You start with a blank project and you ask yourself how to make something work. That gives you the first step you have to take to find your answer.

I know this. I have experienced this. So why does it always take me by surprise when I figure this out for the fortieth time??

Lazy Information Initialization

I noticed I tend to get overstimulated and unfocused when I have to start on something. I tend to shave yaks.

I think that I can read a book on math for 3D graphics programming and learn all about that before I start a project rather than going in and just learning what I need to know to do what I need to do.

I do things that seem like work but aren’t actually productive.

I know on some level that trying to learn this difficult way by reading math books in the bath tub is not helpful and actively causes me mental harm. But I feel guilty if I am not working and I have adopted a lot of destructive behaviors that feel like work and make me feel like I am being productive that are making me less productive.

As I have gotten more and more burned out I have worked harder and harder on these self destructive tendencies because I haven’t known how to break out of them.

I have noticed at most of my jobs there is an implicit feel that working on code that does not directly go into a project is considered wasteful. Saying I am going to set up a sample project to learn a concept sounds unproductive and people would really rather that you work directly on the code base or read documentation. (Except when I worked for Brad. He did this stuff all the time and this is where I got this idea from and I finally started getting it through my thick head.)

In my experience, those things don’t work nearly as effectively.

I am trying to be better about asserting what I need to be a productive programmer even if it’s not what people want to hear. It’s not enough to just say “I need to do these things.” I also have to put them into practice.

And part of putting those into practice is to stop doing these destructive behaviors that make me feel like I am doing something when I am actually destroying my ability to function.

I think it’s important to understand how we learn and to stick to it even when other people don’t want to hear about it. It’s really easy to do a bunch of things that make you feel busy but aren’t getting you anywhere.

I am sick of feeling tired and burned out all the time because I am doing things that I know don’t actually help me. I am trying to figure out how to be a more productive person because my career and my mental health depend on it. This is too important to ignore and wait to resolve itself.

So I am not going to exhaust myself reading programming and math books with no context. I am going to do more sample projects and I will only learn what I need to know to solve a problem with my code. I am not going to expel a lot of energy on something that causes mental friction and generates heat that burns me out. I will only use energy on things that are actively productive. I will be less tired and less hurt this way.

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)\n The offset was \(offset).\n \(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.