<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Ezri on Medium]]></title>
        <description><![CDATA[Stories by Ezri on Medium]]></description>
        <link>https://medium.com/@zerostride?source=rss-bee51bc4260------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*QKG4LiJX-nRnpi3nvrSQRA.png</url>
            <title>Stories by Ezri on Medium</title>
            <link>https://medium.com/@zerostride?source=rss-bee51bc4260------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sun, 15 Nov 2026 18:44:17 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@zerostride/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[Updating Your NFA Tax Stamps After a Name Change]]></title>
            <link>https://zerostride.medium.com/updating-your-nfa-tax-stamps-after-a-name-change-c8a8f47dc1a1?source=rss-bee51bc4260------2</link>
            <guid isPermaLink="false">https://medium.com/p/c8a8f47dc1a1</guid>
            <category><![CDATA[firearms]]></category>
            <category><![CDATA[atf]]></category>
            <category><![CDATA[nfa]]></category>
            <category><![CDATA[transgender]]></category>
            <dc:creator><![CDATA[Ezri]]></dc:creator>
            <pubDate>Fri, 18 Nov 2022 17:06:30 GMT</pubDate>
            <atom:updated>2022-11-18T17:06:30.298Z</atom:updated>
            <content:encoded><![CDATA[<p>If you do a legal name change, for any of the various awesome reasons (including, because I felt like it) you will need to update lot of things in a long, excruciating, and sometimes humiliating process.</p><p>But that’s not what this post is about. This post is about what is possibly the easiest-to-deal-with thing on your name change list…</p><h3>Updating the Tax Stamps for Your NFA Items</h3><p>In order to update your tax stamps, you will need:</p><ul><li>Your existing tax stamp</li><li>A picture (or scan) of the court order for your name change</li></ul><p>You will then compose a letter which contains:</p><ul><li>The name on the tax stamp (your old name)</li><li>The Dealer’s name</li><li>The Serial number</li></ul><p>Then <strong><em>SIGN IT BY HAND</em></strong>. I did it by just signing the PDF with MacOS, you may wish to use a different method, but it needs to have a signature on it.</p><h4>Sample Email</h4><p>This is the text of the email I sent to update the name on the tax stamp for my Dead Air Mask:</p><blockquote>To whom it may concern,</blockquote><blockquote>My legal name has been changed, via court order (see attached),<br>from ‘[OLD NAME]’ to ‘[NEW NAME]’.</blockquote><blockquote>I have a tax stamp for [ITEM TYPE] with serial number [SERIAL],<br>a [MODEL] model, from manufacturer [MANUFACTURER NAME] in<br>[MANUFACTURER LOCATION], which was approved on [DATE OF TAX STAMP].</blockquote><blockquote>The transferor’s name and address (box 3a) on this form is:</blockquote><blockquote>[THE CONTENTS OF BOX 3a]</blockquote><blockquote>Please let me know if there’s any other information I need to provide.</blockquote><blockquote>Sincerely,<br>[SIGNATURE] [DATE]</blockquote><blockquote>[YOUR PRINTED NAME]</blockquote><p>Then you will attach the picture or scan of the court order, and email it to <a href="/service/mailto:nfafax@atf.gov">nfafax@atf.gov</a></p><h4>Following Up</h4><p>In about a week or so, give them a call just to make sure it was received; this doesn’t take very long and it’s worth doing just to make sure.</p><p>Then in a little while you’ll get a letter, via the post office, from the ATF addressed to your new name, that is a printed-out copy of the letter you sent with a little stamp on it that says:</p><blockquote>Requested Adjustments made to the National Firearms Registration and Transfer Record.</blockquote><h3>And that’s it! You did the thing!</h3><p>You will not get a new tax stamp, the record is now just updated and I opted to keep the paper copy from the ATF along with my tax stamp.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=c8a8f47dc1a1" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Analog Input Processing]]></title>
            <link>https://zerostride.medium.com/analog-input-processing-d420ddf26c71?source=rss-bee51bc4260------2</link>
            <guid isPermaLink="false">https://medium.com/p/d420ddf26c71</guid>
            <category><![CDATA[virtual-reality]]></category>
            <category><![CDATA[game-development]]></category>
            <category><![CDATA[mobile-game-development]]></category>
            <dc:creator><![CDATA[Ezri]]></dc:creator>
            <pubDate>Sat, 10 Aug 2019 16:41:01 GMT</pubDate>
            <atom:updated>2019-08-10T16:41:01.120Z</atom:updated>
            <content:encoded><![CDATA[<blockquote>This post originally appeared on #AltDevBlogADay on June 16, 2011</blockquote><p>Analog input devices are becoming more and more prevalent in the gaming landscape. We’ve gone from just using gamepads and joysticks, to accelerometer data, swipe gestures, and pretending we have gamepads by using touch screens. Analog controls are all about conveying a feel to the user in order to connect them to their avatar, and deepen the play-experience. There are several tricks for this that can be employed with fantastic results to deliver controls that feel great.</p><p>Let <em>μ</em> be a normalized input value from an analog device. Many analog devices will provide input as an integer. For the purposes of this discussion, it is assumed that all input values have been normalized.</p><h3>Deadzone</h3><p>Analog input is, by its nature, noisy. It is critical to ensure that the values you are getting from the device are the result of intentional user manipulation, and not simply background noise. The ‘deadzone’ is the range of input values which can be generated without any intentional user input.</p><p>Let <em>λ</em> indicate a constant, below which input value for the analog device are indistinguishable from background noise. An input value should be rejected if <em>|μ| &lt; λ</em></p><p>The next key is what you do after a value exceeds <em>λ</em>. Pick up a console adventure game, and very slowly move the control stick until your character begins moving. Does your character unnaturally lurch into motion once the deadzone has been exceeded? If not, well good for you. Many games suffer from this problem, though, and it is because input values have not been re-scaled after the deadzone. To put it another way, your character goes instantly from having a movement value of 0, to <em>λ</em> causing them to lurch into movement. In order to smooth this movement, we compute <em>μ′</em>.</p><p><em>μ′=sgn(μ)*(|μ| — λ)/(1 — λ)</em></p><p>We now have a linear, continuous range of normalized input values, without any ‘lurching’.</p><h3>Non-Linear Inputs Have More Fun</h3><p>Having linear input values is good; it puts you well above a good number of released games, but we can do better. Consider the steering for a racing game, controlled by an accelerometer device. When the user wants to make a small turn, they will turn the device only slightly; when they want to make a more dramatic turn, they will drastically turn the device. We want to prevent over-correction, because it makes the user feel as though they do not have good control over their experience.</p><p>Let <em>μ″=ƒ(|μ′|)*sgn(μ)</em> where <em>ƒ(x)</em> is continuous over the interval <em>[0, 1]</em> and <em>ƒ(0)=0</em> and <em>ƒ(1)=1</em>.</p><p>Analog input must be tuned to the purpose of the input. In Marble Blast Ultra I observed that, I wanted very fine control over the input with small stick-movements, but wanted drastic changes when the control stick was near its extents. To do this, I used <em>ƒ(x)=x^e</em> [<a href="https://www.wolframalpha.com/input/?i=plot+%7C+x%5Ee+%7C+x+%3D+0++to++1">plot</a>] on the movement input, and <em>ƒ(x)=x^3.2</em> [<a href="https://www.wolframalpha.com/input/?i=plot+%7C+x%5E3.2+%7C+x+%3D+0++to++1">plot</a>] for the camera. I found these values by playing the game, tweeking, and playing some more. It was easy to conceptualize what I was trying to do by looking at a graph of the function, but as this is about the feel of the input, it is critical that enough time is devoted to playing the game with the altered input.</p><p>I strongly suggest that you grab a graphing calculator, and mess around with some functions. You’ll probably settle on some variation on <em>e^x</em> or <em>x^C</em>. Your input needs may call for something like<br><em>ƒ(x)=max(0, ln(x)+1)</em> [<a href="https://www.wolframalpha.com/input/?i=plot+%7C+max(0,+ln(x)%2B1)+%7C+x+%3D+0++to++1">plot</a>]<br>which I have yet to use, but think it could work fantastically for an analog stick input of some sort.</p><p>The ultimate goal of processing analog values is to make the input more visceral, than the raw values reported by the analog device.</p><h3>Squaring the Circle</h3><p>Take a look at the analog sticks on a game controller, or better yet: take apart a game controller. What you’ll find is a the analog stick seated in a square component, which is made into a nice circle by the plastic shell of the controller. You should also observe that the extents of the square component are only reachable by the control stick in four precise locations. That means that, under normal circumstances, you will only see <em>|μ| = 1</em>when the stick is either at the exact top, bottom, left, or right.</p><p>Why do you care? Well if the magnitude of movement is based on the analog input, you will not get the full range of values. Further, it means that players can obtain an unfair advantage in your game by taking the shell off their controller, and cutting the circular housing for the control stick into a square, allowing them to reach magnitudes that other players can not. We learned this the hard way, in Marble Blast Ultra.</p><p>I had to dig out some old code, but this was our solution:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/0d400b28a9937e6ce37afd68ae4ed8e5/href">https://medium.com/media/0d400b28a9937e6ce37afd68ae4ed8e5/href</a></iframe><h3>Going Further</h3><p>Analog input is a representation of actions a player wants to perform in the game. Instead of simply slaving your code to the values sampled by the hardware, I encourage you to use those values to interpret the desires of the user to create a better play-experience.</p><p>I recently worked on an Android racing game and did some experimentation with trying to detect when a user was trying to swerve to avoid an obstacle. To do this, I kept a sliding window of input values, μ, on the relevant accelerometer axis. I used this to compute several averages over segments of time, in essence, doing a kind of piecewise differentiation on the input. I then intended to experiment with adjusting the tire-grip to try and assist the user in swerving.</p><p>While I ended up running out of time for this experiment, it’s something I’d like to mess with a bit more in the future. I think there is a lot of ground to be gained by treating input as an expression of the users desires, instead of a direct input to game values. It is important to not cross over into creating non-deterministic situations for the user; where they feel as though the input they are generating does something different each time they perform an action.</p><h3>Consider the Surface Scratched</h3><p>I haven’t seen these issues addressed in any other places, and I don’t feel as though this is really a complete treatment. I developed the techniques I shared through trial and error, with a dash of OCD. It is my hope that I have introduced the concept that interpreting and processing analog input is a viable option, as opposed to simply feeding it directly into your kinematics. Analog input processing is an opportunity to make the user feel connected to the game-experience by making their manipulations of game objects feel more natural. Help them perform fine-grained movements when needed, and react more drastically to dramatic inputs.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=d420ddf26c71" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Psychic Hot-lines are Evil]]></title>
            <link>https://zerostride.medium.com/psychic-hot-lines-are-evil-c777815c7af9?source=rss-bee51bc4260------2</link>
            <guid isPermaLink="false">https://medium.com/p/c777815c7af9</guid>
            <category><![CDATA[gaming]]></category>
            <category><![CDATA[game-development]]></category>
            <dc:creator><![CDATA[Ezri]]></dc:creator>
            <pubDate>Sat, 03 Aug 2019 16:36:01 GMT</pubDate>
            <atom:updated>2019-08-03T16:36:01.017Z</atom:updated>
            <content:encoded><![CDATA[<blockquote>This post originally appeared on #AltDevBlogADay on March 18, 2011</blockquote><p>Recently upon a midnight dreary, I was watching Futurama and saw a commercial for a psychic hotline. As I wearily pondered what kind of weak-ass reasoning someone would use to justify paying $3.99 a minute to talk to a “real psychic,” it struck me like a raven hitting a plate-glass window: psychic hot-lines are evil!</p><h4>Social Games Are Evil!</h4><p>At least that’s according Jonathan Blow, creator of Braid, because they aren’t Dwarf Fortress, and the customer can’t be responsible for knowing what’s good for them. They’re eroding game developer’s ability to get paid, and causing them to work long hours; if you believe Satoru Iwata, President of Nintendo. They’re “doing something shitty” said Jeff Roberts, an owner of RAD Game Tools.</p><p>They’re exploiting people, they’re not real games, they’re cow clickers, and I think Muammar al-Gaddafi also claimed they’re responsible for recent protests in Libya.</p><h4>Video Games as a Culture</h4><p>What does it mean to be a gamer? Or more accurately, what did it mean to be a gamer? Games were counter-culture. If you played video games (back when they were real games I mean, of course) you would dedicate weekends to grinding out levels to beat a boss fight in Final Fantasy on the NES. You trudged through Ultima Underworld with a notebook of scribbled clues of things you needed to remember. You eagerly awaited the next issue of a gaming magazine because the bundled CD’s were the only ways to get demos. You were part of a secret club.</p><p>Getting to hang out with a fellow gamer was like meeting a countryman in a foreign land. You could talk about the same movies; have arguments about the current/next/previous game console. The other gamer likely shared similar motivations and desired play-experiences with you. You could vent common frustrations, exchange tips, suggestions of other games to try.</p><p>Being a gamer meant, upon meeting another gamer, you could form an instant connection with them.</p><h4>The Beginning of the End</h4><p>Then came Farmville…well actually casual games came before that, and everyone bitched &amp; moaned about ‘bubble poppers’ too, but let’s stay focused, people. This is a new crisis in gaming, and it’s not like any other previous crisis because this time it’s actually going to ruin gaming and we’re burning righteous indignation here. Geez, it’s not like this pattern of behavior has repeated itself throughout human history, and could be categorized and identified by common elements or something.</p><p>Now where was I…oh right, Facebook, evil, Farmville…cows, those horrible cows.</p><p>So along came Facebook and about a bajillion people said, “Wow this looks like a good place for me post pictures of myself in mirrored sunglasses, or with a martini in my hand. I can destroy gaming while I’m at it!” right? Well part of that is true, at least. There were web-based games before Facebook, like Kingdom of Loathing, Travian, and many more, but they didn’t get nearly the type of exposure that was just around the corner.</p><p>Late 2006 Facebook had just recently started their development platform, and opened up registrations to all comers. They ended that year with about 12 million users. By April of 2007, that number had almost doubled to 20 million. In May, the Facebook Platform launched with 85 applications. By October, there were over 50 million users. Overnight, it became possible to spread, virally, the ability to use a 3rd party application to slap, poke or wink at someone.</p><p>Soon came getting bit by Vampires, getting invited into someone’s Mafia, and the cows…</p><h4>Nouveau Riche</h4><p>So what actually happened amidst the deluge of wall-spam, and shady offers? The gaming population grew; massively. In the span of less than a year entire demographics of people, who were previously uninterested in any kind of interactive play-experience offered to them by things with screens, were playing games. They became motivated by intangable, electronically stored, rewards. They integrated the need to dedicate time to play games into their daily schedule. They wanted to make the numbers go bigger. They wanted to demonstrate, and advertise their prowess at virtual tasks.</p><p>They became gamers, and gamers lost their secret clubhouse.</p><p>Zynga became a game developer.</p><p>The industry reeled. This was not of our doing; this had to be a fad. This was Gatsby showing up to the Buchanan’s mansion. We alone had the lineage needed to carry the torch of gaming into the new millennium. We, the gaming elite, had the integrity, the honor, and of course the moral high ground. These scammers, these spammers; these ill-bred rakes…dey tuk our jerbs!</p><p>Or to quote Theognis of Megara, “In former days, there was a tribe who knew no laws nor manners…These men are nobles, now, the gentlemen of old are now the trash.” He was bitching &amp; moaning about this very thing back in 600 B.C.</p><h4>Rampant Butt-Hurt</h4><p>So by this point, you should probably be picking up on the fact that I think the social-game detractors, and their fanatical following (hint: yeah I probably do mean you) are a bunch of mindless, change-averse, dimwits who couldn’t identify an anthropological pattern if it showed up on their Facebook wall and asked them to help build a barn.</p><p>We denounce, as ignorant, every mis-characterization of…whatever is the latest game Fox News has talked about. We bring out facts and statistics every time some dipshit with a PhD claims, baselessly, that video games cause violent behavior. Exasperated, we take refuge in our belief that the mainstream doesn’t understand us; they just don’t get it.</p><p>Hardcore gamers, and game developers are a minuscule minority. We like this when we are up late at night perfecting our split-second reactions in PixelJunk Shooter, but when faced with any of the implications of this minority standing, we cry foul. In fact the only thing we whine more intensely about is the mainstream trying to understand, and join us.</p><p>Gamers, and game developers bitch &amp; moan about any expansion of the gaming demographic. Table-top war gamers hate Magic: the Gathering players. Console gamers think anyone who can’t make headshots in HALO while twitching like a rabbit-on-meth isn’t worthy of the gamer title. PC gamers think anything without a mouse and an upgradeable video card is low-brow. Nintendo complains that everyone should still go to a store and buy a $40 cartridge to get a new play-experience. Pen &amp; paper die-hards think all of this technology stuff just dilutes the concept. We rail against anything new, with no recollection of the last battle fought.</p><p>Don’t want to believe me? Watch Warren Spector’s PAX 2010 keynote:</p><blockquote>“We spent 20 years trying to convince the public how amazing games are, and we’ve won. …we have to get past not wanting to let more people in the club.”</blockquote><h4>Psychic Hot-lines Are Evil</h4><p>So what is this psychic hot-line crap, and what does it have to do with social games? The psychic-hotline does not appeal to us; it has no application to the things we consider important, and does not hold a valid position in our world-view. It’s a scam, and any customer of this kind of service must not actually know what they want, or what is good for them. Right?</p><p>The psychic hot-line represents an experience we understand neither the desire-for, nor the benefit-of. It doesn’t appeal to our demographic, our needs, or our sensibilities. Does this make the psychic hot-line ‘wrong’, or more apropos ‘evil’?</p><p>The first recourse for which you should reach is not the easily-shouldered mantle of moral superiority; but instead that of logistics. Simply put, if there existed no market, the product wouldn’t be viable. At least some people must feel this service to be useful; enough people to maintain a staff of “psychics”; enough to buy air-time; enough cash left over to make it lucrative for owners.</p><p>Go ahead, attempt to justify your righteous indignation for this idea by marginalizing the number of people this could possibly appeal to; I’ll wait. While I do, though, I’d just like to mention that a recent poll found that, within a 3% margin of error, 14% of Americans answered ‘yes’ to the question, “Do you think Barak Obama is the anti-Christ?” So, at least 30–50 million people in the United States believe that. In contrast only 11 million PS3’s have been sold in America, and 35 million world-wide.</p><p>We back yet? Or does that last factoid still hurt? Go get a glass of Scotch; I can wait a bit longer. Want to know the number of Americans that don’t believe humans evolved? No, probably not; I’ve abused your brains with enough statistics for this blog entry, I think.</p><p>Why is the desire-for, or the value-of the psychic hot-line experience inherently less-valid than another experience? Why do only some markets deserve to be served, and others do not? At what point are opinions no-longer fact-based, and instead become shields the mind erects to protect itself from information it doesn’t like? That’s probably out of scope for this discussion, I suppose.</p><h4>We Don’t Need No Justification</h4><p>So more than 1% of the population of the world has played Farmville. What’s that mean? Are people leaving Call of Duty, in droves, to go click on some cud-chewing cows? No probably not. Are some percentage people who play Call of Duty playing Farmville as well? Seems statistically likely. So the game industry is experiencing non-cannibalistic growth.</p><p>What about the converse? Will people who play Farmville start parking their chopper-gunner over my spawn point? Probably not, but there will be overlap into the more traditional game industry for certain. As entire new demographics of people discover that gaming can offer them a play-experience which is enjoyable, they will seek-out new play experiences. As social gaming matures, quality expectations will rise. It is inevitable. Do you still see web-pages covered with animated gif’s and horrible tiled background images? Do we still use the &lt;blink&gt; tag in HTML?</p><p>So who will lead this improvement of quality in the social games space? Veteran game developers who haven’t cemented their heads inside their asses, mostly. Zynga, who gets accused of simply exploiting people with optimized metrics, shared one of the secrets they discovered by way of Brian Reynolds at Austin GDC 2010, “Fun monetizes well.” Will they dedicate themselves to fun, though? Or simply collect data and use that to drive future game-play? I will paraphrase Brenda Brathwaite, “If you use metrics to optimize hockey, you end up with boxing.” Not everyone likes boxing. Not everyone even likes hockey.</p><p>So lets stop “justifying” social games. The burden of proof is no longer on the proponents of social gaming as a viable medium for fun. The detractors, you nay-sayers, start proving your case. You can start by examining the patterns of logic and reasoning you are applying to this argument, and taking a look at with whom you share philosophy.</p><h4>So In Conclusion…</h4><p>Mexican immigrants cause unemployment, comic books aren’t art, homosexuals destroy the sanctity of marriage, and psychic hot-lines are evil.</p><p>Apply the critical thought processes our industry values so highly in all your endeavors.</p><h4>Afterword</h4><p>There will doubtless be discussion in the comments; I will likely not feel the need to wade into it. I brushed on politics, religion, and other issues to illustrate a subtle point: the debate surrounding social games is no longer objective. I write with the full knowledge that the reader, no matter which side of the debate they are on, will only walk away having their viewpoints re-enforced in their own mind (if this does not describe you, congratulations, you are a statistical anomaly in the human landscape).</p><p>I will simply close with the words of one of my favorite authors,</p><p>“There are three classes of intellects: one which comprehends by itself; another which appreciates what others comprehend; and a third which neither comprehends by itself nor by the showing of others; the first is the most excellent, the second is good, and the third is useless.”</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=c777815c7af9" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[The Gambler]]></title>
            <link>https://zerostride.medium.com/the-gambler-d1d488ca21c7?source=rss-bee51bc4260------2</link>
            <guid isPermaLink="false">https://medium.com/p/d1d488ca21c7</guid>
            <category><![CDATA[game-development]]></category>
            <category><![CDATA[startup]]></category>
            <dc:creator><![CDATA[Ezri]]></dc:creator>
            <pubDate>Fri, 26 Jul 2019 16:16:02 GMT</pubDate>
            <atom:updated>2019-07-26T16:16:02.832Z</atom:updated>
            <content:encoded><![CDATA[<blockquote>This post originally appeared on #AltDevBlogADay on March 3, 2011</blockquote><p>Every few months a game studio closes, and there are largely two reactions: ‘genuine shock and outrage’, and ‘feigned shock and outrage’. The people in the second group feign shock and outrage mostly because they simply don’t want to argue with people in the first group.</p><p>Before I go any further, I’ll lay out the requirements for being in the second group, so you can stop reading now if you want. You are going to have to pull your head out of whatever “mission critical code” you are writing, every once in a while, and pay attention to all of that “irrelevant shit” that goes on at other levels. You’re going to have to investigate politics; you’re going to have to think about logistics; you’re going to have to talk-to (and worse, listen-to) people you think are useless. Yes, I am suggesting that you stop thinking about how to squeeze just one more instruction out of that shader, for as much as maybe an hour a week.</p><p>Too much to ask? Then stop reading. You are a drone.</p><p>That piss you off? Good. Want to keep on reading so you can post snarky comments at the end? Mission accomplished.</p><h4>An Earnest Business</h4><p>Your team does not exist in a vacuum. Your company does not exist in a vacuum. The company that owns/funds your company does not exist in a vacuum. We’ll keep it at just three levels, for the purposes of discussion, even though it’s frequently more complicated.</p><p>Given those three levels, you likely have no fewer than: a producer, who reports to an executive producer, who oversees several projects and reports to a manager, who still can’t find the ‘any’ key and reports to an executive, who is subservient to a C-level but also deals with the equivalent of a producer at the company which owns/funds your own, who hands down edicts to please their superior, who really hopes the Board of Directors doesn’t find out about the latest multi-million dollar fuck-up they oversaw.</p><p>None of these layers are irrelevant. You’d really like to think that they are. You’d like to think that if you just put your head down, and make good games, that everything will work out for the best. That may very-well be true, but developing situational-awareness in the game industry will not only let you know when to start sending out your resumé, it will make you a better developer.</p><h4>Two Levers Move Man</h4><p>While decisions may seem to be handed down, from on high, by faceless committees in corporations, they are made by people. These people are driven by the same two motivating factors that drive you: fear, and self-interest (yeah go ahead and argue against that point … you’re wrong; moving on). When you know what motivates people, you can more easily encourage them to take mutually beneficial action.</p><p>Your first task is to figure out who has skin in the game. Figure out what those individuals, as well as their group has got on the line. Did they go to bat for this project/company? How much stock do they have (See ‘They Have Boats?’ below)? What’s the company culture with regard to under-performing projects? What kind of returns do they generally expect on investments? What else do they have going on outside this project this quarter? This year? What do they want more: profit or write-offs?</p><p>It is important to note, at this point, that these are questions you are asking of yourself to try and focus your analysis of the information you have collected. This is a practice of deduction, and it works in likelihoods, not certainties. The more specific you try to get, the more inaccurate the analysis will be. At the end you will distill everything down to what is essentially a guess, and a confidence level in that guess.</p><p>When in doubt, bet on fear, and accounting.</p><h4>The Use of Spies</h4><p>The more people with which you have relationships in each layer of management, the more informed you will be. Do you drink? Drink with them. Do you smoke? Smoke with them. Do you have no vices what-so-ever? Find the ones that have no vices and ride around on high-horses together. You just need a foot-in-the-door; you don’t want to be a sycophant, that doesn’t accomplish your goal (also it’s kind of lame). In short: you need in-roads from which you can obtain information to which you wouldn’t otherwise be privy. These in-roads are people. You are recruiting spies.</p><p>You must now keep your spies, and grow your network. The easiest way to stunt the growth of your network is to blab information you’ve been given. You aren’t on a mission from god; your task is not to “save” your less-informed piers. Just know when to show up with beer, and what kind is the favorite. Eventually you will discover with whom you can talk about different information. This isn’t gossip time, it is information exchange. Never discuss the source of information, or put someone in the spot about their sources, and be wary of people who do.</p><p>You are not trying to construct the one, true picture of what is going on. You will never get the whole picture. That is because nobody has it. Your task is to collect as much information as you can, filter out unreliable information, and then look for inconsistencies. You’re a developer, a nerd, this is what we’re good at. The patterns of thought that you use every day to design, to code, to make art are the same patterns of thought that will help you make the most of your spies.</p><blockquote>“Be subtle! be subtle! and use your spies for every kind of business.”</blockquote><h4>They Have Boats?</h4><p>You likely have far more information available to you than you think about the people at higher levels outside, or even inside, your company. Is the company publicly traded? If so, and you are in the United States, than the Securities and Exchange Commission has your back. Mandatory SEC filings will tell you (among other things) who has how much stock, and from that you can extrapolate how much money is really on the line for individuals (start with Form 10-K filings). You can also compare your salaries to theirs, and weep bitter tears.</p><p>You can find out many useful things, for example: “Oh my! It appears that the general councel for this company is on the board of directors and has a metric-assload of shares. I bet this could be used to our advantage.”</p><p>Why is this important? If you want insight into the minds of the people with the purse-strings, than you better damn well know what’s been going on with their company. If you want to provide a compelling reason to continue funding your studio, get advanced warning about when they may decide to stop funding your studio or help them to understand how not seeing things your way could lead to very bad things, read SEC filings.</p><h4>Lies, Damned Lies, and PowerPoint</h4><p>Some of the most successful games in history were almost axed. The lists and anecdotes are out there, just look. This is because, at some point the people who wrote the checks looked at them and said, “Too much risk.” (Remember when I said, “bet on fear and accounting?” Bet on fear and accounting.) In contrast, some of the dumbest games ever conceived have thrown millions of dollars down the drain. There are (in)famous examples of this, as well as ones only discussed in hushed tones over beer. How can this be?</p><p>So why do bad things happen to good games; or good things happen to dumb games? At some point, it all comes down to somebody standing in the front of a room with PowerPoint. The person in the suit does not want to hear about what you hope will work. They do not give a shit about your game design. They want to hear and see one thing: “It’s a slam dunk!” You can tell them this, but it’s the connotations of the bullet points and mock-up shots that either scream “slam dunk” or, “risk”. Games that look similar to successful games appear ‘less risky’ than new looks. Games that are rehashes of successful games seem ‘less risky’ than trying to introduce new play experiences.</p><p>So, what, are you just supposed to pitch the same re-hashed garbage that everyone else tries? No; hell no. Have you been paying attention? You need to know to whom you are pitching, to whom they have to pitch, and include appropriate content. You need to review your pitch docs, mock-ups, screenshots, and any other communication with a fine-toothed ‘risk’ comb. You want to deliver a pitch that compels someone who plays games, but include enough content that they can then turn around and use to pitch to the person in the suit. Tailor your deliverables so that, at each step, it is more lucrative for the person passing them up the chain to deem them a “slam dunk” rather than a “risk”, and then ensure that the deliverable contains the material they need to pass it to the next link of the chain.</p><p>Why is this relevant? Because a project that is deemed sufficiently ‘risky’ will be presented, at each layer, with the presenter trying to distance themselves from any potential future failure to later spin as, “I told you so.” If the project is presented properly, it will instead be backed by the person presenting it, because they want to take credit for its success. When a project that is backed by self-interest comes under fire, those people in suits will throw additional money at the problem, in an attempt to validate their support of the project. In contrast, when a project that has been deemed as ‘risky’ hits the skids, the person in the suit will axe it to validate their initial assessment, and be seen as cutting costs.</p><blockquote>“Men are moved by two levers only: fear and self interest.”</blockquote><h4>Know When To Walk Away, and Know When To Run</h4><p>Few, if any, game companies exist in a steady-state. Exceptional companies are exceptional. Company life-cycle could be imagined as a Koch curve described by, and made up of Freytag’s pyramids. Projects are introduced, rise, reach a climax, wind-down, and are resolved. At the same time, the company, as a whole, is either in it’s foundation, it’s growth, it’s climax, or stagnation/decline (the accountants do the dénouement part).</p><p>Different people are motivated by various parts of this lifespan. It is up to you to know yourself, and what fuels your creativity. Do you need to have your hands in all aspects of development? Can you only do work that you feel is meaningful when things aren’t on fire? Do you want to only focus on specific bits of specific projects? Do you need to be flying by the seat of your pants to be interested in what you are doing? Do you just want to come in, and write code from 9–5?</p><p>You do not work at the company which your company once was. You do not work at the company which your company can become. You work at the company as it exists. Making games is hard (Valve said so), so don’t mistake hardship for badness. If everyone around you pines for the company it once was, it may be time to walk away. If a guy walks in, says, “Hey I’m the new CEO. At my last company I moved everyone to Los Angeles, and laid off half the staff because it got me more money,” laughs and then says, “We’re moving the company!” it may be time to run.</p><p>Ultimately you are the one who is responsible for the the direction, sustainability, and satisfaction of your career. Understanding the issues that surround your daily tasks, and keeping your ears open will allow you insight into the processes at play, and give you foresight into what will happen next.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=d1d488ca21c7" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Care and Feeding: Accountants]]></title>
            <link>https://zerostride.medium.com/care-and-feeding-accountants-f0fb16894c38?source=rss-bee51bc4260------2</link>
            <guid isPermaLink="false">https://medium.com/p/f0fb16894c38</guid>
            <category><![CDATA[game-development]]></category>
            <category><![CDATA[startup]]></category>
            <category><![CDATA[accounting]]></category>
            <dc:creator><![CDATA[Ezri]]></dc:creator>
            <pubDate>Fri, 19 Jul 2019 16:06:01 GMT</pubDate>
            <atom:updated>2019-07-19T16:06:01.110Z</atom:updated>
            <content:encoded><![CDATA[<blockquote>This post originally appeared on #AltDevBlogADay on February 16, 2011</blockquote><p>Accountants, along with lawyers, are the primary professional service providers with which you will interact as a small game studio. Accountants are very different from lawyers, but with both professions an ounce of prevention is worth a pound of cure (or 0.028kg of prevention is worth 0.4536kg of cure). In order to garner the full benefit of your accountant, you must be aware of what you are doing ahead of time, and you must help them to understand the differences between the business of game development, as opposed to the more traditional business dealings with which they are likely familiar.</p><p>This discussion will be in the context of the United States tax code, however the concepts mentioned should be broad enough that you can consult your tax professional about specifics. This post is not intended as financial, or tax advice, and can not be used as such.</p><h4>About the Accountant</h4><p>Accountants do not make you money. Accountants help you keep money that you have made. The accountant does not know your business, they know accounting. You should explain to your accountant, in general terms, how your company makes money, how your company spends money, and how you expect to make money in the future.</p><p>Accountants generally like organization, and dislike unexpected surprises. You can make your accountant happy by delivering monthly bank/credit card statements and letting them put things in order incrementally. You will likely make them unhappy if you hand them a disorganized pile of papers at the end of the year, and then wonder why your tax forms aren’t done quickly.</p><p>Accountants are accustomed to working with people who largely go against the suggestions made in this discussion. Most clients of theirs will shove off their books, and talk to them once a year during tax time. This may result in your accountants being caught flat-footed by questions you ask. It is not unreasonable to expect them to do the foot-work, but do at least a cursory investigation of your own. It’s your money, not theirs. If you find yourself with an accountant that repeatedly does not have good answers for you, and does not find those answers and get back to you, it may be time for a new accountant.</p><h4>Confusing your Accountant</h4><p>Game development is not a standard case for accounting. Sure money comes in, and money goes out, but that is where most of the similarities end. As game developers, we do not make physical goods. We make ideas, data, and we build value in our studios through these things. An accountant is likely familiar with businesses in which value is based around physical properties, not intellectual. If you want to confuse an accountant, or a banker, simply tell them that your industry has no concept of ‘unit cost’ — a measure of total cost incurred to put one unit of product into the hands of a retailer/consumer. Not only does game development have no real way to quantify what a ‘unit’ is, there would be no deterministic way to assign that a value.</p><p>Now that you have a confused accountant on your hands, you can further throw them for a loop by telling them that acquisitions of game studios are largely equity deals. This will cause more confusion because they will be thinking in terms of physical goods, liabilities, and other traditional business concerns. I explain it like this:</p><blockquote><em>When you buy a game company, you are buying brains; you are buying the intellectual property developed by that studio, and the brains that make it valuable. You are doing an equity deal, because the brains have equity. If the brains aren’t happy, you got nothin’.</em></blockquote><p>This matters because the accountant has many things on their mind with regard to the structure of your studio. When, say for example, a manufacturing business is sold, the original owners likely keep their equity; the new owners do not want it. It gets them nothing but liability. Making your accountant aware of the differences of an intellectual-property-based industry is important.</p><p>Making your accountant aware of the specifics of the game industry is important for discussions about company structure. In the United States most studios are organized as either an LLC, s-corporation or c-corporation. These different types all have advantages and disadvantages, and you may revisit your decision. It is very easy to start an LLC, and you have the option of converting to a corporation at any point in the future. However, once you make the election to convert to a corporation (s-corp, or c-corp, it does not matter) you can not “switch back” to just being an LLC. Having a discussion with your accountant or tax professional about structure, when they hold untrue assumptions about the nature of your business, is counterproductive. They don’t know your business, they know numbers — you know your business, so help them understand it.</p><h4>Saving Money with your Accountant</h4><p>Your accountant/tax professional can save you money, but likely only if you know what you are planning to do ahead of time. For example: in the United States, qualified research &amp; development activities are eligible for a tax credit. Salaries, expenses, even some contracting may be things that the government will give you money to do. There is a catch (Lesson 1: with tax law, there always is) — these must be done in the proper way, and with supporting evidence. With programming, we have the advantage of…version control software! Want to prove that qualified research activities took place, exactly what they were, and when they happened? Well you have a commit log! But you need to make sure that you are going about the research in the right way. Informing your tax professional about your plans, and asking questions is important.</p><p>Asking questions is important. Your accountant can’t steep themselves in your business — you need to understand a bit of their world to gain the depth of their knowledge. Do you need to buy hardware? That’s a capital asset, ask what kind of options are available for accelerated depreciation. You may be able to write off the entire cost of that new server this year. Are you hiring employees? Ask what kind of hiring incentives are available at the state and federal level. Are you considering offering, or currently offering health care (I hope so)? There are possible tax credits available in the United States for doing so — ask your accountant!</p><p>Talk to your accountant, and corporate attorney about your structure. Share with them your goals for the structure, your future plans, and what you would like to provide for your employees. Be aware that their recommendations are not made in a vacuum; they are based on their experience, so do your own research as well. You write the checks, not them. They may see the balance in your company bank account, but you are the one that will feel it. So do your homework.</p><h4>Get your Mind on your Money</h4><p>At the end of the day, it is up to you to use your money wisely. Accountants can help you to do more development, provide better benefits for your employees, and help you make best use of your resources, all while helping your bottom line. Accountants will not make you money, but they can help you do smart things with it.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=f0fb16894c38" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Care and Feeding: Lawyers]]></title>
            <link>https://zerostride.medium.com/care-and-feeding-lawyers-abd45f1bbbd5?source=rss-bee51bc4260------2</link>
            <guid isPermaLink="false">https://medium.com/p/abd45f1bbbd5</guid>
            <category><![CDATA[game-development]]></category>
            <category><![CDATA[law]]></category>
            <dc:creator><![CDATA[Ezri]]></dc:creator>
            <pubDate>Fri, 12 Jul 2019 07:39:55 GMT</pubDate>
            <atom:updated>2019-07-12T07:39:55.187Z</atom:updated>
            <content:encoded><![CDATA[<h4><em>“it is a common defect in man not to make any provision in the calm against the tempest”</em></h4><blockquote>This post originally appeared on #AltDevBlogADay on February 1, 2011</blockquote><p>At some point in your career in game development, you will likely encounter the lawyer. The lawyer is a misunderstood creature, not so unlike the developer. Lawyers solve problems. Like developers, you need to be able to understand, and communicate with the lawyer in order to reach a resolution for your problem. Your ability to understand enough about law to communicate with the lawyer is directly proportional to the value which you will receive.</p><p>This discussion will be from the perspective of United States law, though the concepts, and not the specifics, are my intent. I am not a lawyer, and this post is not legal advice. It is my hope that I can bring some of my experience to the developer community, from the perspective of a developer.</p><h4>About the Lawyer</h4><p>At all times it is important to recognize the lawyer’s first priority: they are advising you with regard to what is legal. You may be concerned about your bottom line; about your production schedule; about creative issues — those are not their priorities. They shouldn’t be their priorities, and the lawyer knows this. When dealing with a lawyer, you are also inevitably dealing with an opposing lawyer. That other lawyer also has one priority: they are advising their client, your opposition, what is legal. The opposing parties lawyer can be one of your best allies because of this. It is crucial that you understand this mindset. It will cause you frustration if you don’t, but can be a great asset if you do.</p><p>The lawyer gets paid whether you get the result you want, or not. You will likely sign something to this effect as part of your engagement. You may be required to give them a retainer; a sum of money which will be used to pay expenses. This is their way of saying, “I am going to need to do a lot of work on this, and I’m not going to just assume you can pay me.” This isn’t a vote of no confidence, it simply reflects the lawyer’s experiences with people: they do, and say stupid things which get them sued. The lawyer gets paid, end of story. Just budget-for, accept, and understand this.</p><p>The lawyer is a creative thinker. The lawyer, and the developer, are not so different. The lawyer must think abstractly, and then apply that thought into a very rigid set of terms and rules. Legalese reads like legalese because the specific terms and phrasing have defensible meaning, not to create some kind of arbitrary barrier to entry. The law is comprised entirely of abstract concepts which have been recorded in a precise language, with the intent of eliminating ambiguity. Do not short-change yourself by thinking that legalese is just some useless, syntactic garbage (or (you (will (not (get good-value (from your-lawyer)))))).</p><p>The lawyer hates having their time wasted. The single most valuable resource to a court, or a lawyer, is time. For example: They sent you their red-line on a 5-page contract two days ago, and you walk into a meeting having not read it, they will not be pleased (but they’ll still bill you). Remember, it’s your name that will be signed to that contract, not theirs. They will tell you if a clause in a contract is legal, but they may have no way of knowing if it will screw up your development plan. Your ass is on the line, so read contracts like your studio depends on it; because it just might someday.</p><p>The lawyer understands that you do not know the law. If you go in with a highlighted copy of that same 5-page contract and say, “I don’t understand these parts,” they will respect you. If you are in a meeting, and they use a term you don’t understand, ask them about it. If that term seems important, go home and look up more information so you can better understand the concept.</p><h4>Key Terms</h4><p>This is by no means a complete list of terms or concepts, but they are probably the top three that will keep you out of trouble.</p><p><strong>Discovery</strong> — Not as thrilling as it sounds. This is where the opposition asks the judge to make you hand over information they feel is relevant to their case. If you are having conversations that you don’t want found by someone in the future: don’t do them in written form. If you are thinking about texting your buddy something funny that someone would consider evidence: don’t. The time to think “oh shit that would look bad” is not after you get the subpoena; it’s before you make the communication. There are exceptions, and information which is protected from discovery, as well as ways to challenge requests, but if you don’t want something found during discovery, the time to think about it is before you put pen-to-paper (in this case, the pen can be electronic).</p><p><strong>Attorney-client privilege</strong> — Stuff you say to your lawyer isn’t subject to discovery. There are exceptions, as always, but the one thing I want to highlight is this: this is communication between you and your lawyer. If you get an e-mail from your lawyer, and forward it to someone else in the company, you have likely made that e-mail subject to discovery. If you get a detailed itemization of time spent from your lawyer, and you stuff that into the folder to send to the book-keeper, you have made the details on how the lawyer spent their time subject to discovery. You should always, always, always ask your lawyer any questions you have about attorney-client privilege before you engage in the communication about-which you have questions.</p><p><strong>Indemnification</strong> — If Alice indemnifies Bob, this doesn’t mean that Bob is free-and-clear should some feces be on an incoming trajectory. All it means is that Alice will defend Bob to the extent of their resources. That last bit is important. If Mallory comes along and sues Bob, and can out-spend Alice…Bob is still going to be in trouble. Indemnification from Alice may be no more protective than a wet paper-bag.</p><h4>Meeting Your Lawyer</h4><p>So you need a lawyer. The best time to choose a lawyer is when there is no pressing need, but I’ll be realistic about things: you need a lawyer; you needed one last month. This means you are soon headed to some sort of meeting which will likely be held around a gigantic wooden table. If they offer you water or coffee, for the love of god use the coasters which will be placed conveniently nearby. The chairs will be comfy.</p><p>This first meeting is important. It will set the tone for your relationship with your lawyer. Your preparation is key. You are walking into a meeting with someone who likely knows little, or nothing, about your business. It is your responsibility to explain to the lawyer your business in terms of the business they understand: the law. I will say that again because it is important: the lawyer does not know your business better than you do; they can’t. The lawyer has several clients, and they get paid whether you get the outcome you want, or not. You are a team with your lawyer, they are not a one-man show.</p><p>They will want to see relevant documentation: contracts, milestone requirements, communication logs, and the like; but you probably guessed this. What you forgot was that those contracts are for a game; those milestone requirements are written in ‘developmentese’; and those communication logs have conversations assigned to people they don’t know. So do some extra work: write a list of terms, abbreviations, acronyms that are used in the documents. List out who is who in communication logs; what is their position, how are they related to the case, and anything else that is relevant to the context of the communication. When they are re-reading these items later, that extra work will pay-off in spades.</p><h4>Go Forth, and do Great and Legally Defensible Things</h4><p>You are a team with your lawyer, and the effectiveness of your team is directly proportional to your ability to communicate. The burden of understanding is on you. They will likely keep practicing law even if your studio goes out of business. Don’t enter into the arrangement thinking that you handed the lawyer some information and they’ll take care of it all. Understanding is key to communication. Look for the common ground between your professions, welcome your new ally, and work with them for the betterment of your studio.</p><p>Above all else, address potential legal issues before they are crises, and you will prevail.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=abd45f1bbbd5" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Who’s Lib is it Anyway?]]></title>
            <link>https://zerostride.medium.com/whos-lib-is-it-anyway-88d8b4d047aa?source=rss-bee51bc4260------2</link>
            <guid isPermaLink="false">https://medium.com/p/88d8b4d047aa</guid>
            <category><![CDATA[android]]></category>
            <category><![CDATA[firebase]]></category>
            <dc:creator><![CDATA[Ezri]]></dc:creator>
            <pubDate>Tue, 05 Feb 2019 19:33:12 GMT</pubDate>
            <atom:updated>2019-02-06T00:48:25.077Z</atom:updated>
            <content:encoded><![CDATA[<p>Working with Android SDKs can be a bit like inviting someone to store their vintage land-mine collection in your back yard (and then paying them for that convenience).</p><p>I recently needed to answer, “Who’s the asshole bringing in these symbols?” and this is how I found out.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/3a6dfc1fc5f4a7cb971ba8a5d11601e5/href">https://medium.com/media/3a6dfc1fc5f4a7cb971ba8a5d11601e5/href</a></iframe><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/07e26503bb5447cb797ca51dddac25b1/href">https://medium.com/media/07e26503bb5447cb797ca51dddac25b1/href</a></iframe><p>These commands are looking for ‘android.arch.lifecycle’ symbols, so replace that with whatever it is you are looking for.</p><h3>headdesk</h3><p>This functionality is also available in the <strong>headdesk blame </strong>command, starting in version 0.11.0.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*WsGbc0OI7unqBTxfbrXlhQ.png" /><figcaption>headdesk blame android.arch.lifecycle</figcaption></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=88d8b4d047aa" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Building Deterministic Zip Files with Built-In Commands]]></title>
            <link>https://zerostride.medium.com/building-deterministic-zip-files-with-built-in-commands-741275116a19?source=rss-bee51bc4260------2</link>
            <guid isPermaLink="false">https://medium.com/p/741275116a19</guid>
            <category><![CDATA[git]]></category>
            <category><![CDATA[zip]]></category>
            <category><![CDATA[aws]]></category>
            <category><![CDATA[circleci]]></category>
            <category><![CDATA[aws-lambda]]></category>
            <dc:creator><![CDATA[Ezri]]></dc:creator>
            <pubDate>Fri, 25 Jan 2019 20:24:09 GMT</pubDate>
            <atom:updated>2019-01-25T21:06:03.729Z</atom:updated>
            <content:encoded><![CDATA[<p>Zip files are not deterministic by nature, and this can cause some problems when you’re trying to do what you gotta do.</p><p>One specific use-case (my use case) was knowing when our continuous integration should deploy a new version of our AWS Lambda functions.</p><h3>Why Aren’t Zip Files Deterministic</h3><p>Non-determinism in zip files is not due to any of the underlying algorithms, but due to the other elements involved in building the zip file.</p><h4>“Extra Information”</h4><p>By default, zip will include “extra information” in the zip file. This depends on OS and such, but can include owner, creation time, access time etc.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/89e72234ddb147bb5cff7b5e7d55da6d/href">https://medium.com/media/89e72234ddb147bb5cff7b5e7d55da6d/href</a></iframe><p>The md5s are different, even though the files are the same.</p><p>To correct this part of the puzzle, use the <strong>-X</strong> (or <strong>--no-extra</strong>) flag.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/1083c8b682a20167f588cf9489bc7190/href">https://medium.com/media/1083c8b682a20167f588cf9489bc7190/href</a></iframe><h4>Permissions</h4><p>The permissions on files, with identical contents, will create different zip files.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/a752c4ed1d3bf389fcd8355c56c5d798/href">https://medium.com/media/a752c4ed1d3bf389fcd8355c56c5d798/href</a></iframe><h4>Timestamp</h4><p>The <strong>-X</strong> flag still includes the timestamp of the file, so two files with the same contents, but different timestamps, will create different zip files.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/df7d37e48f0b8ab2678d3ce75cc582f3/href">https://medium.com/media/df7d37e48f0b8ab2678d3ce75cc582f3/href</a></iframe><p>In order to create a deterministic zip file, we need to make sure that the timestamp of each included file stays the same.</p><p>To do this we <strong>could</strong> simply set the timestamp of all the zipped files to a constant value.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/f85e531310dfbdd2e34507d7993c26fe/href">https://medium.com/media/f85e531310dfbdd2e34507d7993c26fe/href</a></iframe><p>But in my case, I needed something a bit more clever, and I suspect you will as well…</p><h3>Generating Meaningful Timestamps with Git</h3><p>Setting the timestamp to a constant value does solve the problem of generating a deterministic zip, but it’s not very meaningful. What if we could get the timestamp for the most recent modification to an included file.</p><p>We can with git! (Probably other version control also, but that’s left as an exercise for the reader).</p><p>This uses the <strong>ls-files</strong> git command, pipes the output to the <strong>log</strong> git command and formats the output to just output the author date.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/0227ef33c4481a812d75052a1c1791ee/href">https://medium.com/media/0227ef33c4481a812d75052a1c1791ee/href</a></iframe><p>We now need to format the date into something we can sort, and provide as input to<strong> touch -t</strong>.</p><p>(Using the <strong>--date</strong> flag requires git version 2.6 or higher.)</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/50ba83b6f903fc738f1cbed23dc881c0/href">https://medium.com/media/50ba83b6f903fc738f1cbed23dc881c0/href</a></iframe><p>We can now put this together with <strong>touch</strong>.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/b23074406c05712b8db3b126135eaf42/href">https://medium.com/media/b23074406c05712b8db3b126135eaf42/href</a></iframe><p>This will recursively set the timestamp of all files to the timestamp of the timestamp of the last change in git.</p><h4>Reusable Command for CircleCI</h4><p>Here is the code as a <a href="https://circleci.com/docs/2.0/reusing-config/">reusable command forCircleCI</a>.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/88b0604f2b89f412e271da5fbc6aaf09/href">https://medium.com/media/88b0604f2b89f412e271da5fbc6aaf09/href</a></iframe><p>This command also sets the timestamp of the resulting zip file to the timestamp of the last changed file that it contains.</p><p>This makes it easy to use the <strong>aws s3 sync</strong> to update only when there is an update to the contained code.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/7de14b48ffa9fa68f695db4f1f3e5490/href">https://medium.com/media/7de14b48ffa9fa68f695db4f1f3e5490/href</a></iframe><p>I included how to update git on the (very old) version of Debian that CircleCI uses, since that’s a headache.</p><h3>Learning!</h3><p>I hope this helped demystify the process of creating zip files, and some of the reasons why they can be non-deterministic.</p><p>If it didn’t, well, write your own damn blog.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=741275116a19" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Automated Detection of Common APK Issues]]></title>
            <link>https://zerostride.medium.com/automated-detection-of-common-apk-issues-1197a5a6424a?source=rss-bee51bc4260------2</link>
            <guid isPermaLink="false">https://medium.com/p/1197a5a6424a</guid>
            <category><![CDATA[android]]></category>
            <dc:creator><![CDATA[Ezri]]></dc:creator>
            <pubDate>Wed, 16 Jan 2019 22:57:11 GMT</pubDate>
            <atom:updated>2019-01-16T23:43:10.284Z</atom:updated>
            <content:encoded><![CDATA[<p>Part of my day-to-day tasks at <a href="https://teak.io/">Teak.io</a> is developer support.</p><p>I have seen some of the same issues show up again, and again on a monthly (if not weekly) basis.</p><p>After writing some scripts to allow me to address support requests more quickly, I decided the ideal application would be to make a tool that could be integrated into build systems as a kind of “unit tests for build output.”</p><h3>Introducing ‘headdesk’</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/454/1*jSCUWiDkqrQkSSKB2YpLeA.gif" /><figcaption>Because we’ve all been there with Android.</figcaption></figure><p><a href="https://github.com/GoCarrot/headdesk"><strong>headdesk</strong></a> is a Ruby Gem which unpacks an Android app (APK), processes the contents, and then runs checks on it.</p><p>Each check is like a unit test for the output of your build system. It will pass, fail, or be skipped. It will also export information relevant to that check so that you can easily see the values it was looking at, and even do further processing.</p><p>Each time I get a support request, I now write a check that would catch it.</p><h4>Feature Requests</h4><p>The current battery of checks is based on my support requests for Teak.</p><p>If <strong>headdesk</strong> doesn’t do what you need it to do, <a href="https://github.com/GoCarrot/headdesk/issues/new">make an issue on GitHub</a> and I’ll see what I can do!</p><h3>We Need Tools</h3><p>After a few years of doing this, let’s just say I’ve seen things…</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*lHvt11P3mtNkPX7cDGuEAw.jpeg" /></figure><p>One of the biggest sources of issues, across all projects that I’ve seen, is build configuration management. It is very easy to neglect a build system, and just as easy to ‘lose’ how it works.</p><p>Blindly-trusting the output of a build process will bite you in the ass. You need to make sure that you are shipping the thing you think you are shipping.</p><p>I’ve seen builds get shipped that crash with references to SDKs that were removed. Release builds with debug credentials, or the Facebook App Id of a different game.</p><p>We need tools that will automate checking for these issues.</p><h3>Use Cases</h3><p>There are three major categories where <strong>headdesk</strong> will help your build process.</p><h4>Build Configuration Validation</h4><p>Mobile games use a crapload of SDKs, each of which wants credentials. Then there’s url schemes, configuration files, and all of this is compounded by having your dev, QA, and release versions.</p><p>It’s important to know that each environment has the proper configuration, and the only way to do this is to verify the final product.</p><p><strong>headdesk</strong> will export the data which it analyzes as JSON. One of the built in checks is for <a href="https://github.com/GoCarrot/headdesk/blob/master/docs/teak/configuration.md">GCM and Teak configuration</a>.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/0abc71e2a52adec5ebc50a2ba389c5d9/href">https://medium.com/media/0abc71e2a52adec5ebc50a2ba389c5d9/href</a></iframe><p>You can test these exported values to make sure they are correct for your dev/QA/prod build.</p><h4>Early Deprecation Warning</h4><p>Old SDKs, Google Play Store requirements, unsupported OS versions are all pain points that every game I have worked with has felt.</p><p>Late last year (Nov. 2018), Google said all Google Play apps needed to target API 26. This caught teams by surprise.</p><p>Facebook only guarantees that their APIs and SDKs will work for two years. This is easy to forget.</p><p>Google is deprecating the GCM libraries in favor of FCM, and you need to update by April 11th.</p><p><strong>headdesk</strong> checks for these cases, and warns you. This lets you make plans to update your SDKs, instead of being a surprise a week before a release.</p><h4>Common Crash Detection</h4><p>In the chaos of updating multiple SDKs, or switching from one vendor to a better vendor, simple things get overlooked.</p><p>Runtime dependencies can get removed, and cause crashes with seemingly mysterious reasons.</p><p><strong>headdesk</strong> detects some of these cases and warns you.</p><h3>Let’s Ship Better Games</h3><p>No automated tool can catch all issues, but let’s stop working without a safety-net.</p><p><strong>headdesk</strong> will help you ship better games.</p><p>I will help you, whether you are my customer or not.</p><p>Let’s ship better games, together as an industry.</p><h3>Technical Details</h3><p>The remainder of this post will be focused on the technical aspects of the tool.</p><h4>Usage: Command Line</h4><p>On the command line, <strong>headdesk</strong> will output nicely colored and formatted output, and you can <strong>⌘ + double-click </strong>on the URL to open the docs for a check.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*cliap3lkGYGn6xnix9avmA.png" /></figure><p>It can also output JSON, and that’s where you can read status, flag a build as failing, or use the exported data (more on this later) to do further analysis.</p><p>See <a href="https://github.com/GoCarrot/headdesk">the docs</a> for full usage instructions.</p><h4>Usage: Hosted</h4><p>I’ve also made it available as a web API, so you can use it from anywhere with a simple cURL command.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/1b8ac18febe16d0203a79ab8de4a8dfe/href">https://medium.com/media/1b8ac18febe16d0203a79ab8de4a8dfe/href</a></iframe><p>The hosted version will return JSON.</p><h3>Writing Checks</h3><p>I wanted writing a check to be like writing Rspec. As such there’s a handy DSL which makes it easy to access the decompiled bytecode, the resources, and the AndroidManifest.xml of an APK.</p><p>My goal was that any time I got a support request, I’d write a check to automate finding the issue.</p><h4>Docs</h4><p>I took inspiration from a Ruby tool called <a href="https://github.com/troessner/reek">reek</a> and so each check includes a documentation page which describes the reason the check exists, what causes it to fail, if it will be skipped, and what it will export.</p><h4>Writing Checks</h4><p>A very common issue that I’ve seen in the , “Why does my app crash?” department is: the developer changed their build configuration, or removed an SDK without removing the <em>&lt;receiver&gt;</em> in the <em>AndroidManifest.xml</em>.</p><p>When an event is received that is picked up by that receiver, the app crashes.</p><p>The <a href="https://github.com/GoCarrot/headdesk/blob/master/docs/receiver.md"><strong>receiver</strong></a> check detects these cases. It will iterate over all <em>&lt;receiver&gt; </em>blocks in the <em>AndroidManifest.xml</em>, gets their ‘name’ property (which specifies the Java class that will be instantiated) and then makes sure that that class is present in the code.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/0db166acbf9472126f76fb592d1429b2/href">https://medium.com/media/0db166acbf9472126f76fb592d1429b2/href</a></iframe><h4>Accessing Resources</h4><p>From a check, you can easily access Android resources that have been parsed and put into an object which uses <strong>method_missing</strong> to let you sloppy-access whatever you are looking for.</p><p>You can specify an API version as well, to examine values in the same way that the app will see them on different Android versions.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/66e09463a38252209efc1d1a572904c1/href">https://medium.com/media/66e09463a38252209efc1d1a572904c1/href</a></iframe><p>As of this blog post, the resource types supported are: <strong>string</strong>, <strong>integer</strong>, <strong>color</strong>, <strong>bool</strong> and <strong>drawable</strong>.</p><h4>Decompiled Java</h4><p>Checks can easily access decompiled Java code to pull out constant values, validate library support, or whatever else you can do with bytecode (I’ve…done some things).</p><p>Here is some code which is used by the <a href="https://github.com/GoCarrot/headdesk/blob/master/docs/facebook.md"><strong>facebook</strong></a> check, to read out the version of the Facebook SDK</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/e38ca281440c41b5d703bab6a74339f0/href">https://medium.com/media/e38ca281440c41b5d703bab6a74339f0/href</a></iframe><p>This uses <strong>find_class</strong> and <strong>method</strong> to get the bytecode for the ‘getSdkVersion’ method of the Facebook SDK, and then parses out the constant containing the SDK version with a regular expression.</p><h4>Exports</h4><p>Checks don’t just pass or fail, they will also export the data that will help you debug problems, or use for your own testing.</p><p>This is example output from the <a href="https://github.com/GoCarrot/headdesk/blob/master/docs/facebook.md"><strong>facebook</strong></a> check, which will check the version of the Facebook SDK you are using, and make sure it was released within the past two years (which is Facebook’s deprecation cycle):</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/58dc853c18ca3eaa41d61467b754cc27/href">https://medium.com/media/58dc853c18ca3eaa41d61467b754cc27/href</a></iframe><h3>Source Code</h3><p><strong>headdesk</strong> is MIT Licensed, and available on GitHub.</p><p><a href="https://github.com/GoCarrot/headdesk">GoCarrot/headdesk</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=1197a5a6424a" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Get Your Shit Together]]></title>
            <link>https://zerostride.medium.com/get-your-shit-together-6ccbfd6bb755?source=rss-bee51bc4260------2</link>
            <guid isPermaLink="false">https://medium.com/p/6ccbfd6bb755</guid>
            <category><![CDATA[programming]]></category>
            <dc:creator><![CDATA[Ezri]]></dc:creator>
            <pubDate>Tue, 01 Jan 2019 20:03:40 GMT</pubDate>
            <atom:updated>2019-01-01T22:33:23.708Z</atom:updated>
            <content:encoded><![CDATA[<p>Many years ago there was #AltDevBlogADay which <a href="https://medium.com/u/c8b369cca97b">Mike Acton</a> started, and asked me to contribute. I agreed, under the condition that I could write about the business of programming, and not write about code things.</p><p>The rest of you can write about code things and, let’s be honest here, you’re probably better at it than I am. Even if you’re not, you’re certainly louder.</p><p>It is now, with some reluctance…and some nice rye whisky, that I weigh in on the C++20 thing.</p><h3>So What’s the Problem?</h3><p>The story so far: In the beginning, the C++ standards committee was created. This has made a lot of people very angry and been widely regarded as a bad move.</p><p>Yes, the syntax is bullshit. The compile time of “modern C++” vs C is bullshit too.</p><p>The errors suck, it’s nearly unreadable, it’s miserably debuggable, and it’s certainly not desirable.</p><p>That is the entirety of the fucks that I will devote to that part of the problem.</p><h3>The Game Industry Does Not Use C++</h3><p>The game industry does not use C++. We use, I guess, C with “namespaces”, also some vtables, because sometimes-that-makes sense-right-up-until-it-doesn’t-oh-god-why.</p><p>So, with that in mind…</p><p>Why the fuck are you yelling at the C++ standards committee?</p><p>The game industry does not use C++, so it’s not the job of people who teach C++, or people who determine the direction of C++ to cater to the whims of the game industry.</p><h3>The Job to be Done in the Game Industry</h3><p>Put down the pitchforks, and get your shit together.</p><p>You need to hire. You need to grow your team, and that means junior developers.</p><p>You can make including Boost a fire-able offense (not…totally unreasonable).</p><p>You can rant about the C++ standards committee (again, not unreasonable).</p><p>But you need junior developers, and you need to grow your junior developers into senior developers, so they can step up when the time comes.</p><h3>Re-stating the Problem</h3><p>Let me show you a different perspective:</p><p><em>“We can’t effectively run our engine development teams, unless a standards committee we have ignored for 30 years does what we want it to do,” </em>is a problem so large that the SEC would make angry noises about it not being disclosed to investors.</p><p>And as it stands right now, your CEO would be trying to bullshit a statement to shareholders that wasn’t, “Our most experienced developers are handling this by getting into flame wars on Twitter.”</p><h3>Get Your Shit Together</h3><ol><li>Join the standards committee.<br>It’s unlikely to solve anything right now, but if you want a seat at the table…literally sit down at the table.</li><li>Communicate expectations clearly to your teams.<br>If the only way a developer can find out not to use Boost is an old joke about getting fired for using Boost, your communication sucks.</li><li>Automate checking those expectations.<br>Run a CI server, compile with -std=c++98. Grep for &lt;boost&gt; or maybe even do code reviews!</li><li>Try some technical leadership.<br>It’s this crazy thing where a senior developer stops programming all the time, and instead uses their knowledge and experience to make everyone on the team more effective.</li><li>Mentorship. Just do it.<br>Yeah it sucks when people you spent a year or more training just churn out and go somewhere else. Want people to not quit? Maybe try a legit incentives structure, opportunities for advancement, and invest time into helping them grow their professional goals (and give them space for their personal goals as well).<br><a href="https://hbr.org/2018/01/why-people-really-quit-their-jobs">Read</a>. <a href="https://www.forbes.com/sites/valleyvoices/2017/02/22/dont-be-surprised-when-your-employees-quit/#31657bd6325e">Some</a>. <a href="https://medium.com/@checkli/why-employees-quit-20-stats-employers-need-to-know-b921c253f767">Fucking</a>. <a href="https://www.inc.com/marcel-schwantes/why-are-your-employees-quitting-a-study-says-it-comes-down-to-any-of-these-6-reasons.html">Literature</a>.</li></ol><h3>For Advanced Players Only…</h3><p>Want to really make a difference? Get together and talk about the core knowledge required, with the goal of putting together some kind of open coursework on unlearning “modern C++” and learning game engine C(++).</p><p>You know what that would mean?</p><p>You could <strong>tell applicants what they need to know</strong>, and be at least reasonably proficient with the material in that coursework before applying.</p><p>You could have a <strong>template for skill development</strong> once someone is hired.</p><p>You could have a solid <strong>path for advancement</strong> within companies, for employees to move into engine code from other disciplines.</p><p>You could use it as a <strong>guideline for acceptable coding practices</strong> for your teams.</p><p>You could <strong>create opportunities for people</strong>, anywhere, to learn the basics and create <em>new pools of talent</em> in places where there currently exists none.</p><p>And you want to know what is even better?</p><p>You could actually talk to universities in a language they understand, and provide a framework for them to not just teach what the game industry needs, but to understand why we need it.</p><h3>We Can Fix It</h3><p>The problems that people are voicing about C++20 are legitimate. The difficulty of hiring, training and retaining developers is real. It’s ok to feel frustrated and angry.</p><p>The good news is that the solutions for keeping the code clean, on-boarding new hires, and <em>not needing to care what’s in C++20</em> are all things which will make life better for everyone.</p><p>You will make better tech, make better games, make a better workplace, and feel better about it.</p><p>These are your teams.<br>These are your code bases.<br>These are your companies.<br>This is our industry.</p><h4>Get your shit together.</h4><p><em>Special thanks to: Alex Scarborough, Ben Garney, Robert Blanchette, Tom Forsyth, Mike Acton, and Kat Miller.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=6ccbfd6bb755" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>