Sunday, January 15, 2017

AWS IoT Button and TP-Link Smart Plug

A TP-Link smart plug is inserted into a standard electrical outlet and is controlled by the Kasa smartphone app to turn on and off the power to whatever device, for example a lamp, that’s plugged into it. It can also be controlled by voice commands when paired with an Amazon Echo. I wanted to experiment with Amazon Web Service (AWS) Internet of Things (IoT) services using my purchase of an Amazon Programmable Dash Button to control the TP-Link. The design point was that any click (single, double or long press) of the button would turn the power off if it’s currently powered on, and vice versa. That required querying the current device status, parsing the data returned and issuing the proper on/off command. Even the most simple projects, when dealing with unfamiliar technology, leads to lots of challenges and learning, which I’ll share in this blog.

I split the project in two parts, dealing first with controlling the TP-Link from a known environment, namely my MacBook Air on my home wireless network. There is no documented API for the TP-Link, but thanks to a Google search turning up a shell script on George Georgovassilis’s Techblog, I had a starting point. Commands are sent to TCP port 9999 on the TP-Link, which requires a statically-defined, internal IP address so it doesn’t move around, and I defined that on the wireless router. Executing the shell script from a Terminal prompt worked without issue. Knowing that I would be issuing those commands from the Internet (AWS) side of things and not having the ability to statically define the external IP address of my home’s Internet connection, I created a dynamic DNS name using the DYNU (www.dynu.com) service. Now when my home IP address changes, that gets sent to DYNU and they update DNS. I opened port 9999 inbound on my firewall to just the TP-Link, connected my Mac outside my home network via my Android phone’s hotspot capability. Testing was successful and the first part of the project was complete.

The second part dealt with understanding the parts and flows of AWS. When the IoT button is clicked, a message is sent to AWS which is mapped via a Simple Notification Service (SNS) message to one or more AWS Lambda functions. These functions can be written in Python 2.7 or Javascript (Node.js), but not the shell script I’d used so far. Deciding on Python, a language I had never used, I took a short crash course to learn its general syntax and converted the shell script, including updating the script’s netcat calls to standard Python socket calls. After several rounds of additional learning, I had a syntactically proper program and testing began. I was surprised to find that the data returned when querying the TP-Link was slightly different than before, and used a print statement to log the new string and modified the Python program to match. The final hurdle was learning that the socket needed to be closed and a new one created after the query and before the on/off command sent.

So now I have a working IoT button, but two factors limit its usefulness in this purpose. First, it takes about five seconds between clicking the button and the TP-Link changing its power status. Second, the IoT button is limited to about one thousand clicks before its power runs out with no way to charge or replace its battery. Turning lights on and off once a day would drain the button in a little over a year. Turning Christmas lights on and off once a day during each December would be a more suitable, and handy, use case.

Below is the code, with the only required change is updating DNS name (or IP address) in the two bolded connect statements,

AWS Lambda Python 2.7 Function

import socket
import base64
#
def lambda_handler(event, context):
  on = base64.b64decode(bytes('AAAAKtDygfiL/5r31e+UtsWg1Iv5nPCR6LfEsNGlwOLYo4HyhueT9tTu36Lfog=='))
#
  off = base64.b64decode(bytes('AAAAKtDygfiL/5r31e+UtsWg1Iv5nPCR6LfEsNGlwOLYo4HyhueT9tTu3qPeow=='))
#
  query = base64.b64decode(bytes('AAAAI9Dw0qHYq9+61/XPtJS20bTAn+yV5o/hh+jK8J7rh+vLtpbr'))
#
# Query the TP_Link for its current power status
  s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  s.connect(('YOUR IP OR DNS NAME', 9999))
  s.send(query)
  reply = base64.b64encode(bytes(s.recv(1024)))
  reply = reply[:7]
  s.close()
#
# If the TP_Link is off, turn it on, and vice versa
  s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  s.connect(('IP OR DNS NAME', 9999))
  if reply == 'AAACPND':
      s.send(on)
  else:
      s.send(off)
  s.close()

Friday, December 16, 2016

IT is Disappearing

Things disappear because either you can’t see them anymore or they become so familiar and pervasive you just totally ignore them, effectively disappearing into the background noise of life. Both of these are happening with information technology and if you’re in this field you might feel that you’re not appreciated the way you’re accustomed to, and that change is quite unexpected, given the explosion of the Internet, mobile devices, home automation technology, 4G cellular networks, driverless cars, ultra-thin laptops and hoverboards. But this isn’t a viewpoint of reality, it’s just about how people perceive the world.

Back in the “good old days”, computer rooms filled entire floors of office buildings, often viewable through thick glass windows revealing rows of big boxes with flashing lights, spinning tapes and technicians in white lab coats. Thick black coax cables connected your steel-cased terminal, with its indestructible keyboard, to secured wiring closets that routed the cables through bored out holes in floors on their way to those multi-million-dollar mainframes. You had special printers, usually large and noisy, that consumed their own special paper, boxes of continuous, green-and-white forms. If you were lucky, you had a special “knife” to separate one output from another. Those heydays changed in the late 1980’s and early 1990’s as the personal computer became popular and getting your new 486 or Pentium system with its huge boxy system unit and LCD monitor was a day to cherish. Printers morphed into sleek ink-jet and lasers, 8.5”x 11” cut-sheet wonders and loading the right drivers was a right of passage. Then starting at the end of century, things started going in reverse.

Intel-based servers, occupying a fraction of a mainframe’s space, came into fashion. That eventually led to virtualization and hyper-convergence, further shrinking its footprint until an entire room became a couple racks of equipment, hardly impressive as it stood there without a blink, a spin or a technician. Then we moved it to an outsourced data center and now we’re moving it to “the cloud”.

So servers have disappeared.

All the coax cable was removed and your office technology moved over to the same wires as your telephone. Wireless networks removed even the cord and we buried the wireless access points in the ceiling for the best coverage and even if you let its antenna hang from the ceiling, most humans don’t look up all that often, a fact I used to my advantage when hiding Easter eggs from my children. If it was above eye level, they couldn’t find it, even after they knew that’s what I was doing. Faster networks dissolved those irritating slowdowns and everyone has multi-megabit Internet at home.

So networks disappeared.

The PCs are still there, but instead of a thirty pound monster we have two pound laptops with solid-state disks to deliver ten times the performance. But we also have our smartphone and tablets almost making the need for a laptop moot. Executives routinely leave their laptop in their office while traveling, packing their instant-on, less-than-a-pound, all-day-battery iPad, most likely one they bought with their own money. The special printers are gone, consumed by the office copier. Instead of loading serious gobs of software, we access services on the Internet.

So the PCs, while not invisible yet, are fading fast.

The Help Desk has largely become faceless as tickets are entered and problems are resolved, most times without two humans conversing, much less seeing, each other. While useful, productive and necessary, it further removes the connection between people, and the human element is largely disappearing.

So the people join the PCs, not invisible totally, but again, fading.

To further compound the issue, technology is so pervasive it’s disappearing in front of our eyes. I have technology in every pocket. My car key has technology, my smartphone is technology personified, my credit cards have chips and my watch has sensors and a bluetooth connection. I have a smart TV combined with a Roku, Apple TV, Chromecast and cable box. My TV is way smarter than me. My washing machine senses its load, the dryer the its dryness and the outdoor lights sense when someone is near. The car talks to satellites, connects bluetooth and senses the key in my pocket. It was once magical, and now it’s all so familiar I take it for granted.

So it’s all around us, all the time, and we notice it about as much as the air we breathe.

It’s no wonder that the question of “What’s the value of IT” comes up more frequently. We’re disappearing and what people don’t see they naturally question. In my opinion this is not one question, but two. First portion is asking us to make visible all those things they no longer see, or at least used to see parts of. We need to realize that all these things are largely invisible these days for the variety of reasons stated above and take steps to make them real again. Something as simple as making a list of software available in your company, a major systems diagram or the number of PCs being upgraded this year can go a long way.

The second part is asking what are the people in the IT department actually doing. That question can make us very defensive, but it shouldn’t, because if we really think about it, we deliver the changes our business’s require, fix their issues and protect IT assets from a variety of threats. We need to communicate those with a non-defensive posture, using a common language and with a sense of excitement. We should take notice of whole industries that provide mostly invisible products like banking and car insurance, and learn how they convey their value to customers.

Or bury yourself in your cube with your do-not-disturb sign. Your choices will determine your fate.

Wednesday, July 20, 2016

Guessing Games

I have three simple rules for constructing passwords. They must be easy to remember, hard to guess and quick to type. Inspecting this a bit closer, the “easy” and “quick” are about me, and I can decide what is and isn’t. But the most important, “guess”, is not about me, it’s about the person trying to hack my account. So I can’t decide if my chosen password is “hard” until I get into the thoughts of the hacker. Since that is literally quite impossible, we’ll have to substitute a little research, and a little deduction, to come up with some ways they might approach their guessing. Then we can match a chosen password against these methods to see if they stand a good chance of succeeding. If they might, find another password. If they can’t, sleep easy.

For this analysis, we’ll assume the password needs to be 8 characters in length and contain at least one letter and one number. That results in 2.8 trillion possible combinations, the result of each position having 36 potential (a-z, 0-9) characters.

The most obvious method, but also the most useless, is to programmatically generate guesses. We’ll call this one “random”. Each attempt to guess has a probability of 1 divided by 2.8 trillion, or roughly ten times less likely than winning the Powerball Jackpot (1 in 292 billion) with one ticket. If your thief can try one million guesses every second, it will take about two years to try all the possibilities. So while it’s highly improbable this method could work, it’s also the only method that nobody can protect against, no matter what obscure 8 characters you pick. But this is also the method the “experts” want to make harder by making the password longer, include a capital letter or some special character. Ludacris, in my opinion. 2.8 trillion choices is tough enough.

Since most people think in similar ways, it’s not surprising that they tend to pick similar, simple passwords. We’ll call this one “popular”. Trying only a few thousand of these passwords will likely let a hacker into someone’s account. If your password looks anything even close to “password”, “12345678”, “baseball”, “football”, “superman”, “trustno1”, “sunshine”, “whatever” or “startrek”, stop reading this and change your password now. Anything you use that looks simple is a bad choice. And that rule, “not simple”, is really the only thing you really need to remember.

If a hacker is specifically targeting you, they have the time and motivation to research your life to formulate likely guesses. We’ll call this “targeted”. If you’re a big Bob Seger fan, they might try “bobseger”. If you’re Donald Trump, they might try “melania1” (his wife’s name). If you’re password is built around your personal information or interests, change it now.

The final method is based upon my observations of passwords I’ve encountered, which are very often based on a dictionary words or people’s names, followed by a number, normally “1” unless they are forced to change periodically, then between “1” and “9” (only geeks use “0”) . This final method we’ll call “dictionary”. While the English dictionary contains a little over a million words (who knew?), only 3,000 or so are commonly used. And a fraction of them are seven characters long. And while fewer in number, that’s still true for baby names. If your password starts with a 7-character name or word, again, change it now.

Based the above, and while I don’t claim it’s perfect and will always be a work in progress, it’s a good place to start, and we now have six objective tests to compare our password against. Given the way I construct my passwords, here is my score.

Easy to remember - pass
Quick to type - pass
Popular Attack - pass
Targeted Attack - pass
Dictionary Attack - pass
Random Attack - fail (but everybody fails)

So yeah, I sleep well. I hope you do too.

Sunday, June 26, 2016

The Best

According to the dictionary, “best” is defined as something that is “better than all others”. Seems simple enough and we throw the word around all the time without necessarily appreciating all the various flavors of “best” there is, and if we’re really using it properly.

At the very heart of defining “best” in more detail, I think it’s a good starting point to divide “best” into its objective meaning versus its subjective meaning. The objective form means that you can clearly state your objective, for example, that you’re looking for the most profitable solution or producing a product at the least cost. The second part is developing a means to achieve that objective that others can review and agree that it indeed results in the optimum answer. For example, at work we have a model that processes customer orders, dates needed, transportation costs and machine capacities to produce a solution that maximizes profit within those constraints. That model uses a branch of mathematics, linear programming, that will produce the optimal answer. Not saying that the inputs themselves are always right or that our model might not have room for improvement, but I can reasonably argue that we get the “best” answer. Room for debate exists, but not all that much.

On the other side of “best” is its subjective meaning, and that’s open to the wide variety of human opinion. Where is the “best” city to live? Who was the “best” basketball player ever to play the game? What is the “best” wine to serve with chicken on a cool spring evening? You have your choices, and I’ll have mine. But if you ask a million people and tally up all the results for that wine recommendation, you’re more likely to follow the advice of the crowd and not my particular taste for Viognier. I look for the crowd’s opinion of “best” all the time on amazon.com, routinely searching only for products with at least a 4-star rating. But I also read some 5-star and 1-star reviews in detail, looking for some reason a particular product would not fit my particular purpose. The power of collective opinion in helping decide “best” is most useful indeed, as it rarely steers me wrong.

But what really irritates me are people that throw around “best” and can’t explain if they’re using the objective or subjective form, or the type and breadth of peer review defined above. They simply want me to accept their “best” designation without any level of substantiation. When pressed they deliver their finest “deer-in-the-headlights” look. It would be comical if it wasn’t so sad.

So the next time you hear the term “Best practice”, just think “Their favorite pizza”, and you won’t be far off.

Wednesday, June 1, 2016

Phone Stories

In a recent blog I wrote about improving the Corporate pocket phone directory and challenging the status quo. That isn’t the only story from my 1992-1998 stint leading the Network Services group, which the phone systems group was a part. Here are a couple of my favorite phone stories.

In those days phones had a paper insert between the five left-side and five right-side sets of programmable buttons. Each button was defined a function, for example “Call Forward”, a direct dial extension for a frequent contact or other purposes. The practice had been to use a typewriter to create these inserts and cut them out to fit. But then this thing called a laser printer appeared on the scene and could be programmed to print all sorts of fonts and sizes. So I created a mainframe program that would accept ten phrases and print out large, high-quality inserts. Not always accepting of change, my folks thought I was loony and didn’t understand why I would bother. At least until the senior executives commented that they loved these new inserts because they could see them without putting on their reading glasses. It’s a great lesson in seeing a situation through your customer’s eyes instead of your own.

I inherited a large closet full of unused phones, mostly phones without the small display that could tell you who was calling you, a useful feature to make sure you answer your boss’s call but ignore the pesky salesperson. The display phones were more expensive, so the previous phone system replacement tried to keep costs down by limiting the number of people that got the nicer phone. That backfired as IT buckled to reason and pressure (mostly pressure) and purchased more display phones to replace those destined for the aforementioned closet. The phone system needed another upgrade in the mid-1990’s and I was determined to learn from past mistakes. So I simply decreed that the new system would have two phone options, a normal-size, beige display phone and a larger, beige display phone for customer service and administrative assistants. The response, from my voice folks, was adamant in that I just didn’t understand my customers. They wanted, no, demanded choices, many models and colors to choose from. Executives expected to color coordinate their phone with their office furnishings. I would be forced into the “that’s the way we’ve always done it” cornucopia of choice. But, typical of me, I insisted that I knew my customer also. First they all wanted display phones, so when they would see their two choices, they would be thrilled they wouldn’t have to argue again for a display phone. The executives, in my opinion, were largely men that wore blue suits, white shirts and ties their wives picked out for them and would accept the color-neutral beige phone without a second thought. So we setup the two choices in a conference room and invited everyone in the building to come see the choices and make their decision. The result? Happy customers, much to the surprise of the IT group. If you ask what people what they want, they will come up with lots of choices. When you give them two to choose from, they will happily make that choice also. Another lesson learned. Sometimes is just better not to give people too much choice.

Phone systems are engineered, not designed, that’s very clear to me, even to this day. I have my phone number taped to my phone. An engineer would think that’s stupid, I should know my own phone number. A designer would walk around, see numbers taped to lots of phones and add that feature to the phone’s display. The designer would also have a color graphics display, not the not-quite-black on a not-quite-white background text-only display I put up with. Sadly, I think these are the same engineers that build remote controls for TV sets. It took a design-driven company to give us the phone we truly wanted, even if we didn’t know that we did. Can you imagine what the smartphone would have looked like if engineers created it? Like a really big flip phone. Thanks, Apple, for saving us from that fate.

Saturday, May 21, 2016

The Best Thing I Never Learned

The best thing I never learned was that I couldn't do something. It just doesn't occur to me that I can’t do something, particularly if it involves a computer. I’ve embarked on a number of projects over the years convinced that I would get them done one way or another, and a few of them ended up being pretty challenging. Which were, of course, also the ones I learned the most from. I also really hate to lose. Fueled by fearlessness to begin and a stubbornness not to give up, I share three of my fondest memories.

Gothic was the name of a computer program that would read a single input card and print it out on a old-style mainframe impact printer, transforming each character into many rows of asterisks that formed a large, gothic-font representation of the character. Those printers used boxes of paper that were one long continuous page, with perforations that allowed different printouts to be separated, so the Gothic program could print large, long banners, perfect for a “Happy 30th Birthday” sign. Gothic was written in Assembler language for a DOS (IBM, not Microsoft, the PC hadn’t been invented yet) operating system, but Wright State University used MVT and Gothic needed to be modified to run. I really wanted Gothic available, so I decided to figure out how modify it. The only problem was I didn’t know assembler language and it was totally Greek to me. Little by little I learned that a BALR was a Branch-And-Link-Register and that mainframes has 16, 32-bit registers. An MVC was a Move-Character and an S was a Subtract. And those translated exactly to machine instructions and that meant most of the program would work on MVT without change. That was a relief. I also figured out that there were only three things that had to change, the beginning of the program where control was passed from the operating system to the program, the end where control was passed back, and several operating system-specific inclusions which I learned were called macros. All those changes totaled perhaps a dozen lines of code, but a wealth of knowledge to me. And a bit of pride each time I saw a Gothic banner taped to a wall.

COBOL, an acronym for COmmon Business-Oriented Language, was one of the required programming languages to learn way back then, and Wright State used an interpretive version from the University of Waterloo named WATBOL, which was more efficient for student use. My final program of the quarter kept giving me errors and as much as I looked, I couldn’t spot what was wrong. One trusty way to debug a program was to insert PRINT statements at key places to verify the program was moving through its logic as expected. After much trial and error, I found that if I included a single PRINT statement at a specific spot, the error went away, which pointed to an error in WATBOL itself, not in my code. That’s a pretty hard conclusion to sell to your instructor, so I offered another solution. I would do all the work necessary to convert my program to real COBOL and convert all the input and output files from WATBOL format to regular operating system format, not really knowing if that was possible. And I would do it all in the week break between quarters. He agreed to delay my final grade for that week and another intense learning experience began. I had to learn enough JCL (Job Control Language) to create files and execute the COBOL compiler, find some utilities to do the file conversions and make the minor code changes due to the differences between WATBOL and COBOL. I was helped by having all the other students on break and no contention for computer resources. By the end of the week I had everything converted and successfully ran my program, without the PRINT statement, and turned in my completed assignment.

Years later, somewhere in the mid-90’s, I was taking a graduate-level Operations Research class where we were learning optimization techniques like Linear and Integer Programming and I needed an idea for a final project. At the same time I was managing the Network Systems group at The Mead Corporation, and they were in the process of acquiring a distribution business to add to their Mead Merchants group. My group had to plan and execute a networking solution for 30 new locations located all over the United States at the lowest cost while delivering good performance. Networks back then consisted of multi-drop lines, where you started a circuit at your data center, added a drop in an office in one city, added another drop in a second city, etc. We engaged AT&T to design a network for the new locations based on three rules. To deliver good performance, the expected busy-hour line utilization for each line could not exceed 50 percent (based on sales volume and line usage from existing Merchant locations) and a maximum of four cities per line. For high availability at the large regional offices, they had to be connected to two different lines. AT&T was given these specifications to feed into their world-class INOS design tool. And it occurred to me that this might make a good final school project. Took me a week to figure out that I would need to design an Integer Program consisting of 30 rows, each one representing an office and a large number of columns, each one representing any valid line given the performance constraints. The regional offices would just look like two locations with one-half the expected load each. The total distance from the data center to all the locations on a potential line would be used as an estimation of its cost. Add a few other constraints and solve for the lowest cost. In my head, it was possible, but a problem vastly too large to commute by hand, as we learned in class. But Mead had MPSX, a mainframe-based program for solving Integer Programs like this, so I learned enough about its syntax before writing two PL/1 programs to generate the matrix, which turned out to have over 20,000 columns. That completed, I submitted the batch job to run overnight before leaving for home, not knowing how long it might run. To my shock, it was still running the next morning. All this work and my final project was in danger. I cancelled the job and began trying to figure out what had happened. I noticed that most of the job’s activity was constant reading and writing to MPSX’s matrix disk datasets, so I changed the JCL to keep those datasets in memory and again submitted them for overnight execution, which it did, barely. I was at the edge of how large a problem MPSX could handle. Over the following week several changes were made and a final solution was given to AT&T to price and compare to INOS’s solution. I won by $100 per month, a small but decisive victory, and earned an A+ from my instructor.

Now that’s what I call having fun.


Monday, May 16, 2016

The Pocket Directory Story

Back in the 1990’s I managed the Network Services team with responsibility for all voice and data communications. The team installed and upgraded phone systems, ran coax cables, installed hundreds of LAN switches from Austria to Japan. It was an exciting time as this thing called “The Internet” started to gain some traction and mobile phones started fitting in the palm of your hand. Then one day, along with all that, the CIO asked (OK, told) me that I now had responsibility for the fixing and reprinting, asap, the small, pocket-sized, Corporate phone directory which had been totally and embarrassingly messed up. That part was easy, but now that I had this in my control, and I really hated this little thing, I had my team carve out some time to make it better … way better. We discussed its shortcomings (I’m being polite), came up with ideas and asked other local companies how their’s looked. The following documents the highlights and shows what refusing to accept status quo and embracing change can fix, even with something as pedestrian as a phone directory.

1. We changed from glossy to uncoated paper

One constant in life is change and that certainly is true for people and telephone numbers over the yearly life of this directory, so writing updates is a common practice. But glossy paper is hard to write on and easily smears. Sure, it looks all pretty and shiny, but this isn’t an advertising brochure. Switching to uncoated paper solved this, and was less expensive.

2. We changed from a glued back to a spiral binder

What does one do with a telephone directory? Not a trick question, you look up phone numbers. Why do you look up phone number? To call someone. Can you remember a 10-digit phone number? You are in the minority if you can. I’m with the majority who can’t. The old directory had a glued back to it, so you had to hold it in one hand while holding the phone another one hand and dialing with your third hand. Oops, ran out of hands. So you held the phone under you chin and dialed. That was comfortable (not). The other option was to break the glue so the directory would lay flat. That led to pages falling out. Switching to a spiral binder solved all that nonsense.

3. We changed from portrait to landscape

The old portrait layout resulted in multiple lines per person and generally a messy looking layout. Switching to landscape permitted a person’s name, title, work and home telephone numbers to fit in a single line, and we switched to a consistent 10-digit phone number format. Improved the readability at least ten fold. We also made it a little larger, but still kept it under the size of a standard dress shirt pocket.

4. The entire network team did a QA check

Unlike many IT departments, the network team knows people and had visited about everywhere in the company. The biggest source of recurring errors in the content of the the directory was the process used to collect the data. The old process was basically just send us your department’s updates and we’ll print another book. No updates, we’ll print last year’s. Hence any errors in content was someone else’s fault. I just wanted to make the best directory possible, not cover my backside when mistakes were made. So after the first draft of the new directory was ready we sat down over pizza and soda’s to look for mistakes, over the objections that we would be wasting our time. Page one, the Board of Directors. A must-get-it-right page in any large corporation. Yep, first error found. “But they said it was OK!”. It wasn’t a blame game any more. My favorite was when we got to the Hawai’i office and Charlie jumped up exclaiming “That’s not the right main office number, I just know it!”, ran to phone dialed it with his expected result, then dialed what he knew was right, had a brief conversation with the Hawai’ian receptionist, and gave us the correction. We spent two hours and made it half way through the directory that day. Before we published, we must have fixed hundreds of mistakes. The quality had never been better.

5. We delivered a printed copy to the print shop

Since the root cause of my group picking up this responsibility was a breakdown between the previous owner and the internal print shop, we knew we had to get this right. At the heart of the breakdown was the technology difference between the two groups, and could easily cause future problems. After much discussion we settled on an unexpectedly simple solution. We would give them a printed copy of the directory, one-sided and on full-size 8 ½ by 11 paper and they would shrink and print it double-sided. Really hard to mess that process up.

6. We surveyed our customers

I think it’s pretty obvious that we were excited by the changes and the quality of our final product. But what did everyone else think? What other good ideas had we not thought of? So I asked that a short survey be sent out. “Why in the world would we do that?” was the general response from the team. But I insisted and we got some ideas and some praise. My favorite was “It’s obvious that whoever designed the new directory was a traveler!”.

Spot on.