Lukas Z's Blog

What Bitcoin and Communism Have in Common

This is basically a shower thought. Let me explain..

In a way Bitcoin is a huge brake, like a brake that stops a car, that we are building to reach our ideal of a decentralized democratic digital currency. Why is it like a brake? Because we have to spend energy, a very large amount of energy, to prevent something to happen that is natural. Just like it’s natural for the wheel of a car to continue spinning, and for the car to continue to move forward, we need to spend energy to apply a counter force to slow it down again.

So spinning is natural for the wheel, but what is natural for computers? The answer: Copying data. And performing operations on it. With just a little imagination and the right tools, anyone can make a computer do anything. (Remember Steve Jobs’ “Bicycle for the mind” metaphor.) The state of computers in malleable. So much so, that we invented error correcting codes, checksums and hashes to ensure that the data is unchanged. (These techniques of course play an important part in the technology that is Bitcoin.) But fundamentally, the computer remains a very malleable thing. It’s boundless and anarchistic in nature. Because the basic material it works on is information itself. And information seems to want to flow, just as a river wants to flow downstream. (For example, remember the last time you had to exercise willpower so you don’t tell a juicy secret to someone else?)

Bitcoin relies on having a lot of people agree on one set of data and for that data to be unchangeable (plus some other interesting qualitites). For this to work a mechanism called Proof of Work was invented, but in my metaphor it’s just a huge brake that prevents data from changing. And just as the brake on the car gets hot when it slows down the car by applying pressure and causing friction, the big Bitcoin brake of course also get’s hot and produces all that heat caused by CPUs and GPUs and other hardware calculating all those hashes, which, essentially results in more CO2 in the atmosphere. You just can’t cheat the laws of physics (unless you are Neo in the Matrix).

So what about the Communism? Well it’s similar. It’s a great idea with a lot of appeal at first, for example it seems to empower the little guy in the short term, but in the long term it fails because it opposes what is natural. In the case of Communism certain liberties that were a given in the west, had to restricted, to uphold the assumption that all people are equal (or something like that). What did they end up doing? They had to build huge brakes that prevented the people from leaving. They build sophisticated border walls and fences to contain the people. And on top of it an immense amount of bullshit, lies and brainwashing, had to be applied as well. Just so it worked. But it only worked for a while.

So Communism had to construct a big brake (or many brakes depending how you look at it), because it tried to do what was not natural for people. And Bitcoin has a big brake to prevent from happening what is natural to computers and information in general. Will it also remain a nice utopia that eventually failed because of the upkeep of that brake? Or will it change the rules fundamentally?

For me computers always have been about this nimbleness, this “think it and just do it”-ness, with ever faster CPUs and ever lower barriers to do more and more stuff. Bitcoin seems doomed to do the exact opposite. By making “mining” (Proof of Work) harder and harder (and, arguably, by spending more effort on convincing people that it’s good), it will use more and more energy, and thus it will always be an uphill battle. While computers get faster and faster and, perhaps, more people start asking: Why bother?

Having said all that: I own Bitcoin (and some Ethereum) and I’m happy that the mini amount I have now can buy a car or is worth a very luxurious holiday. So a part of me certainly doesn’t want it to fail.

And yet..

Onboarding Idea for New Employees

Working for a client I noticed that after weeks I still had gaps in my knowledge about the product roadmap. And I wasn’t the only one. I felt that in meetings people did not dare to ask questions because they didn’t want to be the person that is out of the loop. The one that didn’t do their homework.

Well since I belive that appearing stupid is a risk worth taking if it helps me to delete some ignorance, I usually ask. And often afterwards others dare to ask their questions, too. Many knowledge gaps get closed this way.

But usually some well informed people (,sometimes just the one person presenting something) wonder why we don’t know. Then a link to a wiki page or offers to forward a helpful PDF are given.

But in reality the people simply have not been properly briefed. Or, in the case of new employees, the on-boarding process was lacking. Instead they were too quickly given their first task to they can slowly learn the ropes. Fast forward a few months and they only know the bits they’ve been working on well.

Here’s what I would suggest instead: Any new employee, after setting up his computer and accounts, is paired with a QA person. QA people know the product well. They know the details of requirements, even old ones. And they do regression tests regularly.

The idea is simple: Have the new guy or gal perform a regression test with the QA person. Preferably a full regression test. Those should occur often enough. Or just have him or her observe as the regression test is performed.

This can take a while of course, but consider how much time would be saved later on.

How to Redirect HTTP and HTTPS Requests Using Namecheap and AWS

This is a mini writeup for a very specific case.

Let’s say we have a domain name, ourcooldoma.in. And for some reason we want to redirect all traffic to somecool.org. And the following things also apply:

  • ourcooldoma.in is registered at a hoster like Namecheap.
  • somecool.org does not belong ot us at all.
  • we want to redirect ourcooldoma.in and www.ourcooldoma.in.
  • we are already using AWS.

(Told you it was specific..)

Then we can do this:

  1. Set up an empty S3 bucket at AWS and make it public.
  2. In the properties of the bucket use the Static Website Hosting feature in Properties and define a redirect to somecool.org. Take note of the Endpoint value in the Static Website Hosting box.
  3. Because we support HTTPS use ACM to create a certificate that matches ourcooldoma.in and www.ourcooldoma.in (or *.ourcooldoma.in).
  4. Create a Cloudfront distribution that uses that bucket’s Endpoint as origin and is valid for the domains www.ourcooldoma.in and ourcooldoma.in. Use the certificate from the step before.
  5. Configure ALIAS records at Namecheap for www and @ pointing to the domain name of our Cloudfront distribution.

Done!

Now every request to ourcooldoma.in will result in a DNS query that returns the ALIAS entry (though I believe ALIAS is not a standard key but a technicality provided by Namecheap and others to circumvent the restriction of CNAME, which one would normally use, but which cannot be used with @ unless you are ok with masking your MX and other subdomain records).

So our request will be actually fired against the IP address at Cloudfront but the client still expects a valid SSL certificate for ourcooldoma.in. Cloudfront provides that (created in step 3) and we can finally get to the (cached) bucket, which only does one thing: 301 redirect the client to somecool.org.

How to Include Binary Vendor Frameworks in Xcode With and Without Cocoapods

Sometimes we have a closed source binary library that we want to include in our iOS project. To do that Xcode needs to do the following things:

  • Find the framework (via defaults or the Framework Search Paths setting).
  • Embed the framework in the bundle and sign it.
  • Link against the framework during build.
  • Strip any architectures from the framework binary that are not required (or even forbidden: You cannot for instance ship a binary that contains code for x86_64 through AppStoreConnect).

I want to add another complication, which is of course optional: The framework is only included for some configurations, for example DebugWithFramework. It should not be included in all other configs.

First I will show how to do it manually and then I will show the Cocoapods way, which, in my humble developer opinion, is superior.

Approach 1: The manual approach

So let’s say we want to do the above steps manually.

For the optional “only some configurations” requirement make sure the configurations have been created.

Step 1: Add the Framework

We can just pull the binary framework into our file tree in Xcode and we’re done. However, if we only want to include it in some configurations we should uncheck the target membership of the framework and add it manually.

Step 2: Framework Search Paths & Linker Setting

We need to tell our build system about our Framework. I believe this is already done for us if we add the Framework to our target and/or if we drag the Framework into the “Embedded Frameworks” box in settings.

But this part of the post is about the manual approach, with inclusion for only certain configurations, so we need to do two things: Set the Framework Search Path and tell the Linker.

But this is easy:

In Build Settings look for Other Linker Flags and add two lines for the configurations that matter (you may need to click the drop down arrow first): “-framework” and “CoolFramework” if “CoolFramework” is the name of your framework, otherwise please substitute the correct value.

Finally in Build Settings look for Framework Search Paths. Again select the configurations that you care about and add a new line below $(inherited) that looks something like this:


$(PROJECT_DIR)/Frameworks/MyCoolFramework/debug

And you should be good to go.

At this point your app probably compiles but at runtime it crashes complaining that it can’t find the Framework.

That’s because it’s not in the Bundle yet. For that you need the next step:

Step 3: Embed & Sign

If it’s supposed to be included for all configs we can just add it by dragging it into the Embedded Frameworks box in our project settings (assuming it’s not already there). Then make sure the option is set to “Embed & Sign” and you’re done.

It gets slightly more complicated if we include it manually. For that we can add a custom script build phase in our Build Phases tab that looks somewhat like this:


if [[ -z ${SCRIPT_INPUT_FILE_0} || -z ${SCRIPT_OUTPUT_FILE_0} ]]; then
    echo "This Xcode Run Script build phase must be configured with Input & Output Files"
    exit 1
fi

echo "Embed ${SCRIPT_INPUT_FILE_0}"
if [[ $CONFIGURATION == 'DebugWithFramework' || $CONFIGURATION == 'ReleaseWithFramework' ]]; then
      FRAMEWORK_SOURCE=${SCRIPT_INPUT_FILE_0}
        FRAMEWORK_DESTINATION=${SCRIPT_OUTPUT_FILE_0}
        DESTINATION_FOLDER=`dirname ${FRAMEWORK_DESTINATION}`
        
        mkdir -p ${DESTINATION_FOLDER}
        cp -Rv ${FRAMEWORK_SOURCE} ${FRAMEWORK_DESTINATION}

        CODE_SIGN_IDENTITY_FOR_ITEMS="${EXPANDED_CODE_SIGN_IDENTITY_NAME}"
        if [ "${CODE_SIGN_IDENTITY_FOR_ITEMS}" = "" ] ; then
            CODE_SIGN_IDENTITY_FOR_ITEMS="${CODE_SIGN_IDENTITY}"
        fi

        BINARY_NAME=`basename ${FRAMEWORK_DESTINATION} .framework`
        codesign --force --verbose --sign "${CODE_SIGN_IDENTITY_FOR_ITEMS}" ${FRAMEWORK_DESTINATION}/${BINARY_NAME}
        echo " ✅ Embedded successfully"
    else
        echo " ❌ Non MyCoolFramework build detected - do not embed"
    fi

Script phases have input and output files (extra input text fields), and in our case we can set it to the following values:


$(SOURCE_ROOT)/Frameworks/MyCoolFramework/debug/MyCoolFramework.framework

for the Input and


${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MyCoolFramework.framework

for the output.

So the output specifies where the binary goes in the compiled bundle.

Disclaimer: This code is a slightly modified snippet from Github. If I find it, I’ll link to it later.

Step 4: Strip Unnecessary Architectures

The app may run fine now in your Simulator or even on an actual iPhone or iPad, but if we want to submit our app to the AppStore we need to do one more thing: Remove architectures that are not used by the target devices.

Quick sidenote: What are architectures?

Well if you write source code it eventually gets compiled into machine code. Zeroes and Ones that are actually instructions (opcodes + arguments) for the CPU. But CPUs are different, they have different architectures and each architecture has different opcodes. (Simply speaking.) Until Apple switches to Apple Silicon, your mac (and your iOS Simulator) most likely has a x86_64 Intel CPU. And your iPhone most likely has a armv7 CPU.

If you have a binary framework that you did not compile yourself it must have the binary code for correct architectures already included. And the best case is that it has the code for _all_required architectures.

So what do we do before uploading to the AppStore?

We get rid off all binary code that is not for iPhone and iPad.

And we do it using a command line tool called lipo.

Now remember, Xcode does all this for you automatically, usually, but we are handling a custom case here where our framwork is binary.

Here’s the build script phase for that:


if [[ $CONFIGURATION == 'DebugWithFramework' || $CONFIGURATION == 'ReleaseWithFramework' ]]; then

  FRAMEWORK="MyCoolFramework"
  FRAMEWORK_EXECUTABLE_PATH="${BUILT_PRODUCTS_DIR}/${FRAMEWORKS_FOLDER_PATH}/$FRAMEWORK.framework/$FRAMEWORK"
  EXTRACTED_ARCHS=()

  for ARCH in $ARCHS
  do
    lipo -extract "$ARCH" "$FRAMEWORK_EXECUTABLE_PATH" -o "$FRAMEWORK_EXECUTABLE_PATH-$ARCH"
    EXTRACTED_ARCHS+=("$FRAMEWORK_EXECUTABLE_PATH-$ARCH")
  done

  lipo -o "$FRAMEWORK_EXECUTABLE_PATH-merged" -create "${EXTRACTED_ARCHS[@]}"
  
  rm "${EXTRACTED_ARCHS[@]}"
  rm "$FRAMEWORK_EXECUTABLE_PATH"
  mv "$FRAMEWORK_EXECUTABLE_PATH-merged" "$FRAMEWORK_EXECUTABLE_PATH"
fi

This can be changed a bit to work for all frameworks I guess, but here it’s the special case in which we have one framework, MyCoolFramework, and two configurations DebugWithFramework and ReleaseWithFramework.

Step 5: Using the Framework in our code

Just briefly I want to mention how you can prevent compilation errors by using an #if clause in your code. Consider this Swift code:


#if canImport(MyCoolFramework)
import MyCoolFramework
#endif

You can use these if-blocks liberally everywhere in your Swift code.

Conclusion & Open Questions

I think we’re done. (If not please write a comment so I can fix it. I don’t have a lot of time to double check everything I’ve written here. Thanks.)

As you can see the manual approach is tiresome but at least we learn somehting about how Xcode builds apps for us!

I want to mention one more complication that can and probably will occur: What if our Framework has dependencies, for example Cocapods that must be present? They can be added in the Podfile but if we need to restrict the inclusion to certain configurations then we must take extra steps.

That’s why we should use Cocoapods all the way in the first place! ;)

Ok let’s look at how that’s done in the second part.

Approach 2: Using Cocapods

Now we will make our own Cocoapod that simply includes our vendor framework. Now why do we want to do that? Because Cocoapods takes care of all the steps above for us!

That’s right, the batteries are included. Let’s start.

Btw. I assume you are already using Cocoapods and your project already has a Podfile. (If not, please add Cocoapods now and run pod init in your project folder.)

Step 1: Writing a gemspec file

A pod is defined by a gemspec file that instructs the pod binary what to do when installing. I’ll keep it brief and just paste you own for our case. But there are more options which may be required. Especially if you are also having swift and objective c files in there somewhere that must be compiled. Our case is actually simpler because the framework is binary.

We’re writing a local pod by the way. You could have it remotely in some git repo and you could even publish it in the cococapods repository but our case here it’s local only and it’s in the same git repository as our app. It’s basically just in a subfolder.

Here we go:


Pod::Spec.new do |spec|
  spec.name         = "MyCoolFramework"
  spec.version      = "0.0.1"
  spec.summary      = "Podspec wrapper for the MyCoolFramework framework."
  spec.authors      = { "Lukas Zielinski" => "http://www.lukaszielinski.de" }
  spec.homepage     = "http://www.lukaszielinski.de"
  spec.platform     = :ios, "12.0"
  spec.source       = { :http => 'file://' + __dir__ + '/MyCoolFramework.framework.zip' }
  spec.public_header_files = "MyCoolFramework.framework/Headers/*.h"
  spec.ios.vendored_frameworks = "MyCoolFramework.framework"

  spec.dependency 'RxSwift', '5.1.0'
  spec.dependency 'RxCocoa', '5.1.0'
  spec.dependency 'RxDataSources', '4.0.1'
end

The gemspec should be in the same folder as they framework and the framework folder should be zipped. Cocoapods will unzip the archive during installation.

There’s also a speciality here: Our framework has dependencies, it requires the RxSwift pod to run. I’ve added this to show you to demonstrate that it’s easy to add dependencies now and also to show a peculiarity about Cocoapods below.

Step 2: Adding our brand new pod

Let’s see how our Podfile looks now:


target 'App' do
  pod "MyCoolFramework", :podspec => "Frameworks/MyCoolFramework/debug/", :configurations => ["DebugWithFramework, "ReleaseWithFramework"]

  pod "RxCocoa", "5.1.0", :configurations => ["DebugWithFramework, "ReleaseWithFramework"]
  pod "RxDataSources", "4.0.1", :configurations => ["DebugWithFramework, "ReleaseWithFramework"]
  pod "RxSwift", "5.1.0", :configurations => ["DebugWithFramework, "ReleaseWithFramework"]
  # explicit dependency for RxCocoa:
  pod 'RxRelay', '~> 5.0', :configurations => ["DebugWithFramework, "ReleaseWithFramework"]
end

And if we don’t care about configurations it’s just this:


target 'App' do
  pod "MyCoolFramework", :podspec => "Frameworks/MyCoolFramework/debug/"
end

Now we can run pod install and we’re good to go! We can run the app and even submit it to the AppStore, because Cocoapods takes care of all the steps from the manual approach for us!

There’s one thing that you should look out for regarding the configurations. As you see in the Podfile examples, it gets much more verbose when we want to restrict the pod to be included in certain configurations only. That is because Cocoapods requires us to also specify all the dependencies and the dependencies’ dependencies (transitive dependencies) explicitely IF we want to restrict them to some configurations.

Consider this:


target 'App' do
  pod "MyCoolFramework", :podspec => "Frameworks/MyCoolFramework/debug/", :configurations => ["DebugWithFramework, "ReleaseWithFramework"]
end

Here our framework is not included in the “Debug” stage, however it’s dependencies are. This is something to look out for.

Protip: Build and afterwards look inside your compiled app’s package. There’s a frameworks folder there. You should only see pods that are dependencies of our framework in apps build with those configurations.

Final words

That’s it, I hope this helps someone. Please send me any corrections or comment below. Thank you!

New Blog

I have decided to stop posting non work related content here after all. I think it could send a confusing message. After all I am a freelacne software professional and posting about storytelling might put prospect clients off.

For now, you can find “the blog where I randomly ramble about stuff” here.

Story Ideas 1

I write here to get better at writing, but let me also train my creativity muscle for fun.

In any case the Stephen King book which I’ve read recently has inspired me to come up with story ideas.

Maybe what I will type in a few seconds will be really bad, but hey, this is just a quick blog post. The fun part is that I will just start writing the first sentence and then, hopefully, the rest of the idea will write itself.

Let’s try.

Here we go:

The elected president of Ireland is fed up with superstition. He and his party ban all folklore from the school curriculum. As a matter of fact, a new law is passed: If you talk about elves and Leprechauns and so forth in public places such as bars or on Youtube, you can be fined up to 200 euros. Some however won’t have it. They rely on their folklore to sell their merchandise to tourists. So they come up with guerilla tactics that bring back the folklore into the mainstream. So they sabotage public holidays, paint fantasy graffiti and so on. They also uncover something very troubling about this president. He is not a human but an actual Leprechaun. So they are real after all! However, in order to survive the fantasy creatures need humans to forget about them. After this is discovered by the souvenir guerilla activits they face a choice to follow their profits or to protect the actual magical people. They split in two, a very angry leader decides to wipe them out once and for all, so he can forever sell the souvenirs. But through some magic and with the help of some children and a drunk (sorry for the clishee) old storyteller they manage to defeat him somehow. In the end the 21st century begins, everyone is a mobile phone zombie, constantly staring at Instagram and Tik Tok, but it is good. The fairtale creatures can at least live in peace for now.

Ok this has two weaknesses. One: I know nothing about Irish folklore and should definitely research before writing such a story. Also the alcohol clishee is bad. As a matter of fact, if I made such a story I would actually have no one drink in it at all. Secondly, it misses the explanation why the fairytale creatures want to be forgotten.

And where do the children and that old storytelling guy come from?

So many questions. But at least it’s a start.

Anyway, this is fun. I really just started with the first sentence and the rest wrote itself. I’ll do that more often to relax. Fun times. ☘️

It’s Not for You

You don’t like my blog? No problem, it’s not for you.

If it were, you would like it. At least some parts of it.

Seth Godin writes in one of his books that the spelling errors in Nigerian email scams serve a purpose. They filter out the smarter, arguably more difficult, readers. If you are put off by the spelling and the grammar you won’t reply to the email. Good, they don’t want you to. Because you most probably will be wasting their time. Others will be better victims. The Nigerian Prince email is not for you. [1]

And so it is with everything else.

Liberating, isn’t it? Suddenly we don’t need to make everyone happy with our art and our product. We can’t make everyone happy anyway, because different people have different preferences. But now we don’t have to feel so bad about it.

Another example: You approached a girl on the bus? And she rejected you harshley? That’s fine. You’re not for her.

Isn’t it useful to know that? To know it early?

Footnotes

[1] I doubt it’s always on purpose. I think some of that fraud spam is just 14 year old kids writing.

Our Surroundings

The place I live in, my car, my clothes, they all tell a story about me and it’s not random. What I am is reflected in my surroundings which are influenced by my preferences.

For instance there are some things I care less about. Other things irk me and I need to fix them. Maybe I need my car to be practical and maybe my clothes send out hints about my profession.

It’s all about harmony. This will sound a bit esoteric but I feel that we all have something surrounding us that is akin to a magnetic field.

(Or, just as valid: It’s just a little metaphor that we can employ to ramble about random things on our blogs.)

When we place a magnet on top of a surface with metal filings they will arrange in a certain way. In physics class, this is how teachers make the invisible magnetic fields visible.

In a similar way, if we put a person in a place and let some time pass, the place will be transformed according to the person.

For example, if a Zen monk from Japan moved into a German home, and he remained a Zen monk, the place would probably change for the better (I’m biased.). It’s a clishee but let’s say the house would be cleaner and the garden would appear very well looked after. At the same time he would be affected by his new life in Germany. Perhaps he would start eating bread or he would begin expressing his annoyance with German trains who are embarrasingly often late. So in reality it’s an interplay. It goes both ways.

The magnetic field doesn’t just affect things. It works with everything including people. We become more like the other humans we spend the most time with and they become more like us. The latter I believe is perhaps generally underrated. We may feel that we are drifting along and that the world is pulling us in a certain direction. That we are merely sentenced to react passively. But actually we too affect the others. By expressing ourselves we make an impression on other people and change their behavior, if ever so slightly. (We always do it regardless if it’s intentional.)

Perhaps a good example is when we become parents. The child is constantly exposed to our field and cannot help but absorb it. It’s the same with our friends. Just like the mental filings in physics class, we adjust. And they do, too. This creates a shared view of life and a sense of belonging.[1]

“Expressing ourselves” seems like such a new thing though. It’s probably more of an ideal of the west and rather foreign in the east. But no matter to which hemisphere we belong, there is some sort of mainstream culture, some great story that is shared by most. So in addition to all the smaller fields there are some bigger ones, shared between members of nations or regions of the earth.

And some shared by all humans.

The more time passes the more the differences between cultures will disappear. Despite a loss of influence by mainstream media the mainstream culture seems stronger than ever. For some reason. Maybe it’s some unifying power inherent in capitalism, which influences us all. Or it’s a fear of a loss of orientation after losing the mainstream narrative.

Perhaps, eventually, some really nice patterns will emerge between all the metal filings, the people, on this big surface we call Earth.

Let’s hope that there will be enough variety left.

Like someone once said: “Imagine the traffic jams if all people liked the same thing.”

Footnotes

[1] But what happens if someone changes? Will there be a force that is invested in keeping him the way he was? You bet.

What Precedes and Follows

Epictetus, a Stoic philosopher, says about our goals and dreams: “In every affair consider what precedes and follows, and then undertake it. Otherwise you will begin with spirit; but not having thought of the consequences, when some of them appear you will shamefully desist.”*

I suppose this is very good advice. Something that Jordan Peterson may say.

And yet, and yet.. how often have people succeeded at something because they overestimated their odds (and underestimated the difficulties)?

Perhaps luckily, they weren’t very imaginative and didn’t know what else to try. Perhaps they werent very impulsive, and their problems weren’t enough to trigger a flight reponse in them. Or they were just very stubborn. In any case, they sticked around. They tried some more and, eventually, everything worked out in their favor. And they got the treasure.

Sometimes what reads like disadvantages can be just what is required.

* = Link to a translation of the Enchiridion by Epictetus See paragraph 29 for the quote mentioned here.

Everyone Misunderstands the Mazda MX-5 Luggage Rack

I’m a big fan of the Mazda MX-5, which is also called Mazda Miata. I had one a few years ago and I still miss it. I think this is the perfect car. Unless you need a third seat or luggage space..

Speaking of luggage. What fascinates me is that virtually everyone installs the luggage rack the wrong way!

The only exception is the third gen Miata where it’s usually done right, and despite the fact that we all see the 3rd gen on the road most of us still don’t get it.

Here is what I mean:

Miata NB

The rack on this beautfiul 2nd gen should be rotated by 180 degrees. The short sticking out part should be towards the front, not back.

Why?

Because its function is to prevent your luggage from chopping your head off if you crash into something. It’s not there to prevent your luggage from falling down because of the crazy acceleration of the Miata.

Because, let’s face it, the Miata doesn’t accelerate that quickly.

3rd gen (“NC”) owners get it usually right, because the luggage racks are shipped with a brake light, since the rack obscures the 3rd brake lamp. So there’s just one way to install it, the correct way, the way that prevents your bags from killing you.

Or not just you. Everyone else that is unlucky enough to be crashed into by a Miata!

Just saying.

(Fanboy disclaimer: Luckily, this is a mostly theoretical discussion. The Miata handles awesomly. It’s rare that you would loose control and crash.)

But still.. I wonder, what else in life is obviously wrong, that we, the average people who never thought too much about it, don’t get?