Heather B-Log
These are the words that I've had to say in the past whenever. Go ahead and consume them.
2022-06-17T00:00:00Z
Heather B-Log
heather booker
Learning SSH etc
2022-06-17T00:00:00Z
https://hboo.ca/posts/2022-06-17-learning-ssh-etc/
<p>I am job searching! Fun times. I also have a weirdly high proportion of friends simultaneously job searching, which is cool because we can discuss interview stuff. This is exactly what led me down the road labelled "learn SSH" - my friend and co-job-searcher behind <a href="https://www.heyheatheritsmeagain.com/">Hey Heather, it's me again</a> mentioned that an interviewer asked "If you needed to get some files onto a remote server, how would you do that?", and my response was externally a cool, blank stare, and internally a spiral-of-doom-panic. đ
</p>
<p>But my friend knew! They answered "scp", and then the interviewer added "sure! or rsync.". And then I asked this question to a different friend, who answered "ssh". So now I had 3 things to learn about! I had heard of all of these, and I know my team at my previous job used <code>rsync</code> for our deployments.</p>
<p>So, I got together with my friend who went through the interview, and we started slowly chewing through the many topics we had on the menu. The main objective was: "Use each other's computer as a remote server, and try to get some files onto it!"</p>
<p>We started by listing what we already knew (or <em>thought</em> we knew):</p>
<ul>
<li>FTP: An antiquated way to transfer files (this "knowledge" came from me using it several years ago to make a website for someone.).</li>
<li>SSH: How to use another computer's command line remotely.</li>
<li>SCP: SSH, but just for copying files.</li>
<li>rsync: Another way to copy files???</li>
</ul>
<p>Unfortunately, (or perhaps fortunately? the more learning, the better?), the explanations of what these things are always references other unknowns, and so on and so forth until you have unraveled a giant tangle of things-you-don't-know, and suddenly it's not looking like a one-day project anymore. It reminds me of this type of dictionary definition which I cursed just recently:</p>
<blockquote>
<p><strong>heretical</strong>:<br />
Of or relating to heresy or heretics.<br />
Characterized by, revealing, or approaching departure from established beliefs or standards.<br />
Containing heresy; of the nature of, or characterized by, heresy.</p>
</blockquote>
<p>Two thirds of those definitions just mean you need to learn MOAR DEFINITIONS. (As defined when <a href="https://duckduckgo.com/?t=ffab&q=heretical&ia=definition">searched via DuckDuckGo</a>.)</p>
<p>And so it is that we learned many things that day. Mostly that everything internet-protocol-y (IP-y!)<sup class="footnote-ref"><a href="https://hboo.ca/posts/2022-06-17-learning-ssh-etc/#fn1" id="fnref1">[1]</a></sup> is badly named:</p>
<ul>
<li>
<p>SCP's original implementation was flawed, so now, under the hood, calling <code>scp</code> just gives you a secure version of FTP: SFTP, which is FTP over SSH.<sup class="footnote-ref"><a href="https://hboo.ca/posts/2022-06-17-learning-ssh-etc/#fn2" id="fnref2">[2]</a></sup></p>
</li>
<li>
<p>TLS/SSL has both in the name because SSL was essentially under copyright, but SSL was the well-known name for the protocol, so TLS was just a fancy new name given to the new version of SSL. Except people kept jamming the names together because nobody knew what TLS was, so it needed SSL to hold its hand while it got famous too, and now the pair of names has stuck. <a href="https://tim.dierks.org/2014/05/security-standards-and-name-changes-in.html">Read about the meeting that decided this</a> (and the actual details, because "copyright" is the wrong word).</p>
</li>
</ul>
<p>I also ended up reading some of Julia Evan's zines, specifically the <a href="https://wizardzines.com/zines/http/">HTTP</a> and <a href="https://wizardzines.com/zines/dns/">DNS</a> ones. Reading the HTTP zine made me think: I really oughtta memorize HTTP response codes. Because while I definitely laugh a socially appropriate amount at any HTTP status code jokes, I don't actually remember which one is which, and that's a bit strange for a web developer. No problem though, because <a href="https://httpstatusdogs.com/">HTTP dogs</a><sup class="footnote-ref"><a href="https://hboo.ca/posts/2022-06-17-learning-ssh-etc/#fn3" id="fnref3">[3]</a></sup> are here to help me (and you!) learn while LOOKING AT CUTE DOGGIES đ.</p>
<p>Here they are, grouped by the 100:</p>
<ul>
<li>200: OK</li>
<li>300: Redirect</li>
<li>400: <em>You</em>, the user, did a booboo.</li>
<li>500: <em>They</em>, the server, did a booboo.</li>
</ul>
<p>And for a bonus level, we can get into specific codes:</p>
<ul>
<li>403: "permission denied"</li>
<li>404: a crowd favouriteâ"not found"</li>
</ul>
<p>While looking at this graphic of the parts of a URL (from <a href="https://wizardzines.com/comics/how-urls-work/">https://wizardzines.com/comics/how-urls-work/</a>):</p>
<p><img src="https://hboo.ca/img/url-wizard-zine.png" alt=""parts of a url" from wizard zines" /></p>
<p>, I discovered the "port" is a part of the URL that we don't usually see when browsing the web, but you can sneak around and try putting it in the URL to see what happens -<code>:80</code> for <code>http://</code> sites and <code>:443</code> for <code>https://</code> sites. I found that some sites (stackoverflow over https) loaded just the same, but others (I forget what, over http) did not appreciate having the port specified. XD Or perhaps it was that we specified <code>:80</code>, the port designated for HTTP, while having typed <code>https://</code> at the start of the URL? I'll admit I forget. Please do try it out and write me with your results.</p>
<p>Once we figured out how to get each other's IP addresses -</p>
<p>Oops, time for a sub-lesson!</p>
<p>I used <code>ip address</code>, which spits out a lot of output, and the <em>first IP that isn't localhost (127.0.0.1)</em> you see is the useful one. (I don't know what the others are. MOAR THINGS TO LEARN! đ)</p>
<p>It seems that I get a new IP depending on which router I am connected to, which makes sense, because I only exist on the internet when I am connected to it, and I have to connect through the router, and how else would other internet devices find me, if not by starting at my router? I just found it cool to see how the IP of each device connected to that router shared almost the entire IP address, and only one portion was incremented, ie (these are all fake IPs):</p>
<p>172.666.1.9 - my friend's computer!<br />
172.666.2.9 - random other wifi-connected device, say, a smart thermostat<br />
172.666.4.9 - my computer!</p>
<p>I admittedly couldn't remember whether the second-last digit should be incremented, or the very last digit; while trying to find the answer, I unearthed one hundred billion more questions, like do I have a public <em>and</em> a private IP?! (No, I have a private IP that my router knows, and my router has a public IP that the rest of the internet knows.), and how do <a href="https://www.signal.org/">Signal</a> messages get to me if I don't have a public IP?! (The internet can never initiate sending things to me; I must always ask for it. Messages can get to me by the app leaving a TCP connection open, or by sending requests for updates frequently, by example.) There's also a thing called NAT traversal, or Network Address Translation traversal, which is a way of cutting out any middle parties, to decrease the overall bandwidth used. NAT traversal is often used for video calls among other things. Sorry for mentioning it and basically teaching you nothing specific about it; have fun looking it up yourself! ;D</p>
<p>It also seems that the router reserves some number for devices which are intermittently connected. I say this because we used <code>nmap</code> to see which devices were on the network, and it showed that no devices had the number 3, but that the router gave me an IP address with the digit 4 when I connected to the network. <code>nmap</code> is a magical and spooky tool that can tell you which other devices are connected to the same network. It can tell you their IP, their MAC address; it can guess which OS they are running, and it can tell you the device's name. This is just one terrifying part of what we will later find out amounts to a significant argument for never working in a café again.<sup class="footnote-ref"><a href="https://hboo.ca/posts/2022-06-17-learning-ssh-etc/#fn4" id="fnref4">[4]</a></sup> To return to the IP addressing: we couldn't identify my friend's phone as any of the devices that nmap found on the network; it turned out that the phone disconnected from the wifi while it wasn't in use, and once a browser tab was opened, the phone now showed on the nmap output, with the skipped IP address! I'd like to know how it manages this; surely it can't keep addresses reserved for offline devices forever, or else I would have gotten a much higher number than 4 (it was actually 6, I thought I could get away with simplifying things!).</p>
<p>Now that I've typed "router" 20 times, I'm feeling self-conscious about the difference between a router and a modem. Should I have been saying "modem" this whole time?! I can't look it up because firefox keeps crashing today. Too bad! đ</p>
<p>So, as I was saying, once we figured out how to get each other's IP addresses, I started a tiny server on my computer using the npm module http-server, in a directory with just a dog.txt file containing this adorable ascii dog (<a href="https://ascii.co.uk/art/dog">source</a>):</p>
<pre class="language-txt"><code class="language-txt"> ,--._______,-. <br /> ,',' , . ,_`-. <br /> / / ,' , _` ``. | ) `-.. <br /> (,';'""`/ '"`-._ ` \/ ______ \\ <br /> : ,o.-`- ,o. )\` -' `---.)) <br /> : , d8b ^-. '| `. ` `. <br /> |/ __:_ `. | , ` ` \ <br /> | ( ,-.`-. ;' ; ` : ; <br /> | | , `. / ; : \ <br /> ;-'`:::._,`.__),' : ; <br /> / , `- `-- ; | <br /> / \ ` , | <br /> ( ` : : ,\ | <br /> \ `. : : : ,' \ : <br /> \ `|-- ` \ ,' ,-' :-.-'; <br /> : |`--.______; | : : <br /> : / | | | \ <br /> | ; ; ; / ; <br /> _/--' | -hrr- :`-- / \_:_:_| <br /> ,',',' | |___ \ <br /> `^._,--' / , , .) <br /> `-._,-' </code></pre>
<p>And my friend typed my IP address into the URL bar on their computer, followed by <code>:8080</code>, and saw a link to that dog.txt, and clicked it, and saw the dog! And voilĂ , just like that, we have succeeded at transferring files between computers - an excellent first step to our interview mission. We then followed up with me running my development server for my blog which is configured to port <code>:8080</code>, and my friend could see that too!</p>
<p>Now this suddenly seemed very terrifying, because when you do an nmap scan, it also gives you a list of ports in use on each device, meaning that a stranger in a café could see that a computer with X IP was serving something on Y port, and then they could access it just like my friend just did - without my realizing, without my meaning to.</p>
<p>Naturally, we tested this out in the other direction too: with me trying to type 172.666.my-friend-IP:friend-port in my browser's URL bar, but I couldn't see anything! I forget which kind of "access denied" page it was; I think it just says something like "unable to connect". Unfair!! Why can't I spy on a website about me?! đ</p>
<p>More investigation reveals that my friend's blog uses Jekyll, my blog uses 11ty, and the dog art server I just made uses http-server. They have different default ports too - at first I read something that indicated <code>:8080</code> is for public use, and since my blog was using that port, I suspected this was the explanation. However, using all sorts of different ports on the dog art server did not prevent my beautiful dog art from being accessed right out from under my watchful eyes. Yet more investigation reveals that setting the default host address to <code>0.0.0.0</code> makes a server accessible from other IPs, while <code>127.0.0.1</code> keeps it private - for <code>localhost</code> only. The help page for http-server indicates how to change this, but I have yet to figure it out for Eleventy which is the framework my blog uses. It's wild to me that something that seems so significant could be so...undocumented? Un-obvious? I mean, admittedly http-server lists it as an option in the help dialogue, but it's not in the readme and I had a hard time searching for it. I admit I have a fear of man-pages and help-dialogues...they just have...</p>
<p>SO MANY WORDS.<br />
SO LITTLE TIME.<br />
MUST CONTROL-FIND.<br />
đ</p>
<p>Side note, now that I'm reading about these IPs, I'm just garnering more and more questions, like how can a host have multiple IPs? That's gonna have to be more questions for another day.</p>
<p>So that was a significant aside, but we eventually got back to our main squeeze, putting a file on a server. (Servers don't tend to have web browsers or care about ascii art, but maybe they should...?)</p>
<p><code>rsync</code> is purportedly also a handy tool for getting files onto a server - my friend read the wikipedia intro paragraph and proclaimed "It's like git, but for transferring files". This comparison is because they both use delta encoding<sup class="footnote-ref"><a href="https://hboo.ca/posts/2022-06-17-learning-ssh-etc/#fn5" id="fnref5">[5]</a></sup>. Delta encoding means that instead of copying the whole file every time, it checks which parts changed, and sends (in the case of rsync) or saves (in the case of git) only those parts. In a massive app like the one I used to work on, rsync could mean significant bandwidth savings. But if I have the updated files on my computer, and the server has an old set of files, how does rsync know what the diff is, without first sending one of the versions to the other? I suppose it could use a sort of hash? This is conjecture, I need to do a part 2.</p>
<p>Moving on for now to <code>ssh</code> and <code>scp</code>. It seems to me that <code>ssh</code> only helps insofar as you can use a <code>scp</code> command from the server, rather than using the same <code>scp</code> command but with arguments (file_from, file_to) reversed but from the computer that you're sshing from. So:</p>
<pre><code>computer has dog.txt
server wants dog.txt
start in computer shell:
computer$ ssh into_server
server$ scp remote_file to_local
or
start in computer shell:
computer$ scp local_file to_remote
</code></pre>
<p>Again, total conjecture. I used <code>ssh</code> a few times at my old job but was always terrified of accidentally deleting the entire database<sup class="footnote-ref"><a href="https://hboo.ca/posts/2022-06-17-learning-ssh-etc/#fn6" id="fnref6">[6]</a></sup>. All tutorials on the internet indicated that <code>scp</code>ing onto a server should be as easy as</p>
<pre><code>scp dog.txt 192.666.their.ip:/home/directory
</code></pre>
<p>Alas, a solitary computer is not a server, or at the very least it's not a server that wants to be <code>ssh</code>ed into or <code>scp</code>ed onto, because I was rudely "disconnected" several times. It seems that you must set things up, share keys perhaps, and all that is going to need to be a lesson for another time, because we were hungry or maybe hangry and that was the end of our lesson.</p>
<p>But progress has been made. Many things were learned, explored, examined, and insulted that day, yet our eagerness to answer interview questions more deeply than was ever expected remains strong. Thanks for sticking along for this wild ride of computer learnings, and I hope you're out there having your own fun and asking your own turtles-all-the-way-down questions.</p>
<hr class="footnotes-sep" />
<section class="footnotes">
<ol class="footnotes-list">
<li id="fn1" class="footnote-item"><p>did you know that IP just stands for <em>internet protocol</em>?! Well, I didn't. đ I've been watching the <a href="https://www.youtube.com/watch?v=tpIctyqH29Q&list=PL8dPuuaLjXtNlUrzyH5r6jN9ulIgZBpdo">Crash Course Computer Science</a> videos, and they are just amazing. They explain stuff so simply and are just a joy to watch. That's where I learned what IP and MAC address mean. <a href="https://hboo.ca/posts/2022-06-17-learning-ssh-etc/#fnref1" class="footnote-backref">â©ïž</a></p>
</li>
<li id="fn2" class="footnote-item"><p>SFTP or FTP over SSH is not to be confused with FTPS - FTP over SSL, or the other SFTP - Simple FTP; see <a href="https://en.wikipedia.org/wiki/File_Transfer_Protocol#Derivatives">Wikipedia FTP derivatives</a>). <a href="https://hboo.ca/posts/2022-06-17-learning-ssh-etc/#fnref2" class="footnote-backref">â©ïž</a></p>
</li>
<li id="fn3" class="footnote-item"><p>Oh, the website says HTTP cats came first. Well, my friend knew about the dogs one, and I was too busy admiring those lil cuties to read the fine print. đ <a href="https://hboo.ca/posts/2022-06-17-learning-ssh-etc/#fnref3" class="footnote-backref">â©ïž</a></p>
</li>
<li id="fn4" class="footnote-item"><p>I am certain that I have seen nmap used before, and that in fact someone probably demonstrated exactly how nosy it can be, when I was at the Recurse Center several years ago. Alas, the message didn't stick, and I continue to be obtusely unconvinced to trade convenience for security. <a href="https://hboo.ca/posts/2022-06-17-learning-ssh-etc/#fnref4" class="footnote-backref">â©ïž</a></p>
</li>
<li id="fn5" class="footnote-item"><p>Reading more about delta encoding led me to the idea of <a href="https://en.wikipedia.org/wiki/Delta_encoding#Delta_encoding_in_HTTP">using it for websites</a>, which is quite cool. I'm thinking it would be a cool project to build a...what could you build to simulate this? A website? A package that could be used on any website? Probably not a browser extension. <a href="https://hboo.ca/posts/2022-06-17-learning-ssh-etc/#fnref5" class="footnote-backref">â©ïž</a></p>
</li>
<li id="fn6" class="footnote-item"><p>Which definitely never happened and wasn't a story that got passed around to spread fear into the hearts of innocent developers like me. Nope. <a href="https://hboo.ca/posts/2022-06-17-learning-ssh-etc/#fnref6" class="footnote-backref">â©ïž</a></p>
</li>
</ol>
</section>
I love bixi but -!
2022-05-19T00:00:00Z
https://hboo.ca/posts/2022-05-19-i-love-bixi-but/
<p>BIXI is Montréal's beloved bike sharing system, and I'd like to ask your help, dear readers, in getting their attention.</p>
<p>You see, a few years ago, they added a feature - after you borrow a bike and return it, you can see how many kilometres you traveled, and an estimate of how many calories you burned. I <em>love</em> seeing how many kilometres I biked. I like knowing the distance between spots, and feeling strong that I'm capable of biking so far! But I hate seeing a calorie count. In fact, I hate just <em>seeing</em> the word "calorie". It reminds my brain of all the diet-culture things I've been taught all my life - riding a bike is <em>exercise</em> and exercise is only for <em>burning calories</em> and calories matter for <em>being skinny</em>. This is all pretty toxic messaging that is very hard to avoid subconsciously picking up, and whether you personally agree with the messages or not, I think at the very least, organizations for public good (like BIXI, a non-profit) should avoid subjecting people who struggle with diet-culture to them.</p>
<p>That's why I'm asking BIXI to add a setting: "Show/hide calories". Ideally they don't show calories at all unless you toggle it on; but at the least, let me toggle it off, pretty please! Seeing a calorie count is an even worse trigger for people who struggle with eating disorders, especially when they are trying to recover. We, as a society, should protect our vulnerable, and that includes not shoving triggers in their faces at every turn.</p>
<p>If you agree, please retweet <a href="https://twitter.com/hboo_codes/status/1527296637004959745">my tweet at them</a>, or email them at <a href="mailto:info@bixi.com">info@bixi.com</a> with a quick note that you find the calorie count off-putting or inconsiderate of vulnerable groups.</p>
<p>Thanks so much for reading. This has been a long time coming for me, but I've been too scared to actually do it. Now the time has finally come to be heard and keep our organizations accountable to the people they serve. â€ïž</p>
Learning les chiffres en français
2020-10-16T00:00:00Z
https://hboo.ca/posts/2020-10-16-learning-les-chiffres-en-francais/
<blockquote>
<p>Oh, Miss hboo:</p>
<p>Many years I have waited<br />
For a gift like yours to appear<br />
Why, I predict this project<br />
Could make you a first rate! francophone<br />
My dear, my dear!<br />
I'll write at once to blog readers<br />
Tell them of it in advance<br />
With a tool like this, dear there is<br />
A definish chance<br />
If you work as you should<br />
You'll be making ...goooooooooood đ</p>
<p>Did that really just happen?<br />
Have I actually understood?<br />
This problem I've tried<br />
To ignore or hide<br />
Is a talent! that can be learned...to<br />
Help me use French numbers!<br />
If I work good.<br />
So I'll work good...</p>
</blockquote>
<p>đ</p>
<p>I definitely ripped that off big time from Wicked the musical. And my changes aren't particularly clever, which is fine, because the goal here is:</p>
<p>LEARN YOU SOME NUMBERS IN FRENCH FOR GREAT GOOD.</p>
<p>And not: "Be good at writing song lyrics." We can work on that another day maybe. đ</p>
<p>Anyway, so learning numbers in French is impossibly difficult, at least if you ask me. Which reading my blog is basically asking me, I guess. ÂŻ\<em>(ă)</em>/ÂŻ It's especially difficult because 50 is 50, which is cool, and 60 is 60, which is also cool, but then suddenly 70 is 60-10, and then 80 is: well, what could it be? 60-20? 60-10-10? No, better: 4-20. Ah! Beautiful. Now 90 can follow the 70 pattern, and add 10: 4-20-10. And god forbid you want, for example, 97: 4-20-10-7. -__- Unbelieveable. I know English is impossible too but come on, numbers!! They're so hard!! And so important!! Who cares if you say "I goed" instead of "I went". But we will care if you give us $4.20 when we actually wanted $80, thank you very much!!</p>
<p>Puh. Rant over. So what I really wanted for practicing numbers was just something that would shoot numbers at me again and again, and tell me if I understand them correctly. I found <a href="https://www.youtube.com/watch?v=3rd_haB5V0c">a cute lil video series</a> which was fine for my purposes, except it's only like 20 numbers, and I need to practice like infinity numbers. Eventually I gave up wanting and wishing, and made something myself!! Which I began working on a week or so ago, and then suddenly received a kick in the butt to finish, in the form of a voicemail message that I had to listen to 15 times to get the phone number I needed to call back. I was getting sweaty just sitting there.</p>
<p>So <a href="https://github.com/heatherbooker/pratiquer-chiffres">here's what we've got</a>! A cute little python script that uses the <a href="https://cloud.google.com/text-to-speech">Google text-to-speech API</a> to say numbers aloud in French. The normal (online) mode picks a random number, sends it to the Google API, writes the response to disk, plays the newly-saved file, asks you what number it was, and then JUDGES YOU. The current judgement format of "right vs wrong" is great for me, because I'm slow but usually correct, as long as the number:</p>
<ul>
<li>doesn't start with 8000, and</li>
<li>isn't longer than 4 digits</li>
</ul>
<p>Don't ask, idk, 8000 always confuses me, I always write 1000 instead.</p>
<p>It saves the audio to disk because it seems wasteful to ask Google over and over for 44 (or 709, or 0, or..). That also opened up the ability to add a second mode: offline mode! For when my Google free cloud limit is reached, or the internet is being a potato, or whatever. So for offline mode, it just picks a random audio file from the numbers that have been done previously, and hits me with that. Some other little perks of this offline method include being slightly faster, and also not making my fan spin for 0.5 seconds at a time.</p>
<p>Other interesting things I learned or decided while creating this lil creature:</p>
<ul>
<li>the french equivalent of "uh oh" is "houlĂ "</li>
<li>python has the best interface for getting simple user input</li>
<li>i miss javascripts sneaky conversion between strings and integers, i got bit by expecting that a few times, plus:</li>
<li>i miss typescript telling me that i'm stupidly trying to put a string where an int should be, and vice versa</li>
<li>i used <code>subprocess.Popen</code> instead of <code>subprocess.run</code> for playing the audio, so that for big numbers, i can start typing the answer before it has been fully said đ</li>
<li>you have to specify you are writing bytes to a file (as opposed to writing a string)</li>
</ul>
<p>On the sad side of things, I did not succeed at taking a screen recording of me playing, so I don't get to show you that. đ</p>
<p>On the to-do side of things, I really would like to be able to give the program an answer and then tell it to quit instead of it starting another number. I'm thinking something like</p>
<pre class="language-shell"><code class="language-shell">what numba?<br /><span class="token operator">></span> <span class="token number">42</span> <span class="token keyword">done</span><br />correct and goodbye<span class="token operator">!</span></code></pre>
<p>Because right now it's like</p>
<pre class="language-shell"><code class="language-shell">what numba?<br /><span class="token operator">></span> <span class="token number">42</span><br />what numba?<br /><span class="token operator">></span> <span class="token keyword">done</span><br />correct and goodbye<span class="token operator">!</span></code></pre>
<p>And this stresses me out because I feel like I'm leaving it halfway unfinished<sup class="footnote-ref"><a href="https://hboo.ca/posts/2020-10-16-learning-les-chiffres-en-francais/#fn1" id="fnref1">[1]</a></sup>.</p>
<p>Anyway, <a href="https://github.com/heatherbooker/pratiquer-chiffres">here's the code</a>, have fun, submit issues/improvements, troll, learn, etc. đ Ă la prochaine !</p>
<hr />
<p>PS. I installed a plugin to convert <code>:+1:</code> emoji shorthands into actual visible emojis, which is rad. However, I predict it will make the previous post where I explain that I am using shorthands very confusing, since now they will just be actual emojis. You win some you lose some. đ</p>
<hr />
<hr class="footnotes-sep" />
<section class="footnotes">
<ol class="footnotes-list">
<li id="fn1" class="footnote-item"><p>"Halfway unfinished" is a pretty weird thing to say, but I'm kindof into it. <a href="https://hboo.ca/posts/2020-10-16-learning-les-chiffres-en-francais/#fnref1" class="footnote-backref">â©ïž</a></p>
</li>
</ol>
</section>
Random thoughts
2020-05-19T00:00:00Z
https://hboo.ca/posts/2020-05-19-random-thoughts/
<p>There is a super cool thing a friend of mine did, which I wish to emulate: have an adorable <a href="https://glit.sh/~wesleyac/thoughts/">page of random thoughts</a>. It seems super low pressure, fun as a reader to get a glimpse into someone else's head, and fun as a creator to just collect a mish-mash of glorious tidbits.</p>
<p>The <a href="https://github.com/marenbeam/thoughts">original implementation</a> doesn't involve any manual git-anythings, and makes a nice separate page for these random thoughts. However, I (apparently) am never going to get around to doing that, so a blog post that I update with the thoughts seems good enough. It will be weird, but I am fine with that. đ</p>
<p>19 May, 2020</p>
<p>First thought is this hilarious ad on a website for a local music store that I thought was very cute and saved a few weeks ago, for this exact purpose:</p>
<p><img src="https://hboo.ca/img/steves.png" alt="steves music store - wash those hands!" /></p>
<p>20 May, 2020</p>
<p>I think this format will not do; it is going to make me censor myself more, because this feels like a conversational blog post rather than a collection of random thoughts. But we must try anyway.</p>
<p>20 May, 2020</p>
<p>I am a parasite to humanity.</p>
<p>21 May, 2020</p>
<p><a href="https://hboo.ca/thoughts">I did it!</a> Bye!</p>
<p>23 May, 2020</p>
<p>So! How did I do it? Mostly in <a href="https://github.com/heatherbooker/blog/commit/60a3504cbddbf12fc16e290ea313b8119a7b4f08">this commit</a> (where I have omitted less relevant parts from this post):</p>
<pre class="language-git"><code class="language-git"><br /><span class="token commit-sha1">commit 60a3504cbddbf12fc16e290ea313b8119a7b4f08</span><br />Author: hboo <nope><br />Date: Thu May 21 22:51:00 2020 -0400<br /><br /> Add proper thoughts page!<br /></code></pre>
<p>So exciting! Look at that exclamation mark in the commit message! I had to specially write it in vim because I use zsh instead of bash and it gets confused about the exclamation mark when I use it with <code>git commit -m</code>. (Maybe bash gets confused by <code>!</code>s in quotes too. I don't know.) Anyway! Are you ready for the actual good stuff to begin? It's mostly just jekyll stuff (using <a href="https://jekyllrb.com/docs/collections/">collections</a>):</p>
<pre class="language-git"><code class="language-git"><br />diff --git a/_config.yml b/_config.yml<br />index 58693b8..8235bb6 100644<br /><span class="token deleted">--- a/_config.yml</span><br /><span class="token inserted">+++ b/_config.yml</span><br />@@ -34,6 +34,8 @@ exclude:<br /> - Gemfile<br /> - Gemfile.lock<br /><br /><span class="token inserted">+collections:</span><br /><span class="token inserted">+ - thoughts</span><br /><br /> owner:<br /> name: Heather Booker<br /><br />diff --git a/thoughts.html b/thoughts.html<br />new file mode 100644<br />index 0000000..45572c7<br /><span class="token deleted">--- /dev/null</span><br /><span class="token inserted">+++ b/thoughts.html</span><br /><span class="token coord">@@ -0,0 +1,18 @@</span><br /><span class="token inserted">+---</span><br /><span class="token inserted">+layout: page</span><br /><span class="token inserted">+title: Thoughts</span><br /><span class="token inserted">+permalink: /thoughts/</span><br /><span class="token inserted">+---</span><br /><span class="token inserted">+</span><br /><span class="token inserted">+<div class="thoughts"></span><br /><span class="token inserted">+ <div></span><br /><span class="token inserted">+ {% for thought in site.thoughts reversed %}</span><br /><span class="token inserted">+ <span class="post-meta"></span><br /><span class="token inserted">+ <span class="post-date"></span><br /><span class="token inserted">+ {{ thought.date | date: "%-d %b %Y" | upcase }}</span><br /><span class="token inserted">+ </span></span><br /><span class="token inserted">+ </span></span><br /><span class="token inserted">+ <div>{{ thought.content }}</div></span><br /><span class="token inserted">+ {% endfor %}</span><br /><span class="token inserted">+ </div></span><br /><span class="token inserted">+</div></span><br /></code></pre>
<p>What's next?</p>
<pre class="language-git"><code class="language-git"><br />diff --git a/_posts/2020-05-19-random-thoughts.md b/_posts/2020-05-19-random-thoughts.md<br />index a175619..153c9a4 100644<br /><span class="token deleted">--- a/_posts/2020-05-19-random-thoughts.md</span><br /><span class="token inserted">+++ b/_posts/2020-05-19-random-thoughts.md</span><br />@@ -14,7 +14,7 @@ The [original implementation](https://github.com/marenbeam/thoughts) doesn't inv<br /><br /> First thought is this hilarious ad on a website for a local music store that I thought was very cute and saved a few weeks ago, for this exact purpose:<br /><br /><span class="token deleted">-![steves music store - wash those hands!](/assets/img/steves.png)</span><br /><span class="token inserted">+![steves music store - wash those hands!]({{ '/assets/img/steves.png' | relative_url }})</span><br /><br /> 20 May, 2020<br /></code></pre>
<p>Ack! That path fix shouldn't be in this commit. -_- Darnit, that's what I get for mixing up doing a million things at once >< The paths are a bit more complicated than I was imagining, because the blog thinks it is at <code>/</code> but actually it is at <code>/blog/</code>, so I can't just throw absolute paths around and call it a day. Puh.</p>
<p>Tell the world!:</p>
<pre class="language-git"><code class="language-git"><br />@@ -23,3 +23,7 @@ I think this format will not do; it is going to make me censor myself more, beca<br /> 20 May, 2020<br /><br /> I am a parasite to humanity.<br /><span class="token inserted">+</span><br /><span class="token inserted">+21 May, 2020</span><br /><span class="token inserted">+</span><br /><span class="token inserted">+[I did it!]({{ '/thoughts' | relative_url }}) Bye!</span><br /></code></pre>
<p>Nice.</p>
<p>Next: The original implementation that inspired me strips all newlines, but I want my newlines. However, I don't want the paragraphs to be spaced as far apart as in regular posts - it makes it harder to scan the page. So I take away the margin from every paragraph that <em>follows</em> a paragraph by using the <code>element + element</code> CSS selector. Because the default styling on the blog for paragraphs is to have <code>1.2em</code> both above and below each one, simply setting the <code>margin-top</code> isn't enough - the bottom margin of the paragraph above it is still pushing it away. (Those margins were previously being <a href="https://css-tricks.com/what-you-should-know-about-collapsing-margins/">collapsed</a>.) So it needs a negative margin to overcome that.</p>
<pre class="language-git"><code class="language-git"><br />diff --git a/_sass/pages/_thoughts.scss b/_sass/pages/_thoughts.scss<br />new file mode 100644<br />index 0000000..f2fd639<br /><span class="token deleted">--- /dev/null</span><br /><span class="token inserted">+++ b/_sass/pages/_thoughts.scss</span><br /><span class="token coord">@@ -0,0 +1,5 @@</span><br /><span class="token inserted">+.thoughts {</span><br /><span class="token inserted">+ p + p {</span><br /><span class="token inserted">+ margin-top: -1.2em;</span><br /><span class="token inserted">+ }</span><br /><span class="token inserted">+}</span><br /></code></pre>
<p>And import that style file:</p>
<pre class="language-git"><code class="language-git"><br />diff --git a/_sass/leonids.scss b/_sass/leonids.scss<br />index 225ff25..f338ed7 100644<br /><span class="token deleted">--- a/_sass/leonids.scss</span><br /><span class="token inserted">+++ b/_sass/leonids.scss</span><br /><span class="token coord">@@ -21,3 +21,4 @@</span><br /> @import <span class="token string">"pages/tags"</span>;<br /> @import <span class="token string">"pages/archive"</span>;<br /> @import <span class="token string">"pages/post"</span>;<br /><span class="token inserted">+@import "pages/thoughts";</span><br /></code></pre>
<p>I guess there's no scoping of css to certain pages automatically by jekyll; it has to be done manually. So I actually first released the blog with all the paragraphs being squished together, because I was SO EAGER and didn't double check the other pages. Just the new one. đ It was only afterwards that I addded the <code>.thoughts</code> scope to the <code>p + p</code>. Regression check, my friends!</p>
<p>Last but certainly not least is the glorious thought generator. I largely copied the existing new post generator that I use (<a href="https://hboo.ca/posts/2017-02-28-xiannys-awesome-jekyll-post-generator">by Xianny</a> (who I met!! it was so cool! people are just the best.<sup class="footnote-ref"><a href="https://hboo.ca/posts/2020-05-19-random-thoughts/#fn1" id="fnref1">[1]</a></sup>)), but simpler because thoughts don't have titles, or tags.</p>
<pre class="language-git"><code class="language-git"><br />diff --git a/thought b/thought<br />new file mode 100755<br />index 0000000..ac77be4<br /><span class="token deleted">--- /dev/null</span><br /><span class="token inserted">+++ b/thought</span><br /><span class="token coord">@@ -0,0 +1,19 @@</span><br /><span class="token inserted">+#!/bin/bash</span><br /><span class="token inserted">+# This script creates a new thought in jekyll with pre-filled front matter.</span><br /><span class="token inserted">+# Run `./thought` to generate a thought.</span><br /><span class="token inserted">+</span><br /><span class="token inserted">+FILEDIR="_thoughts"</span><br /><span class="token inserted">+FILENAME="$FILEDIR/$(date +%F-%H-%M-%S).md"</span><br /><span class="token inserted">+</span><br /><span class="token inserted">+echo "---" > $FILENAME</span><br /><span class="token inserted">+echo "date: $(date '+%F %T')" >> $FILENAME</span><br /><span class="token inserted">+echo "---" >> $FILENAME</span><br /><span class="token inserted">+</span><br /><span class="token inserted">+if command -v nvim</span><br /><span class="token inserted">+then</span><br /><span class="token inserted">+ nvim $FILENAME</span><br /><span class="token inserted">+else</span><br /><span class="token inserted">+ vi $FILENAME</span><br /><span class="token inserted">+fi</span><br /><span class="token inserted">+</span><br /><span class="token inserted">+echo $FILENAME</span><br /></code></pre>
<p>Also, the filenames are based on date-time down to the second. I started this paragraph to say that it's not terribly robust, if you generate two thoughts within the same minute the second one will overwrite the first, but then I remembered it is <em>seconds</em> not <em>minutes</em>, and it would be pretty hard to write two thoughts in the same second. So nevermind.</p>
<p>Anyway, so far the whole thing is pretty sweet! You are actually looking at a lot of manipulated git history - I am quite liberal with my interactive rebases and force pushes, which allows me to pretend I wrote everything right the first time, which I definitely did not. ;D</p>
<p>Next up, I made some improvements to this script and the new post generator script.</p>
<p>Every time I would finish editing a post, when I would close it, the path to my editor would be printed in the terminal, because of this line:</p>
<pre class="language-shell"><code class="language-shell"><span class="token keyword">if</span> <span class="token builtin class-name">command</span> -v nvim</code></pre>
<p>That <code>command -v</code> thing checks if <code>nvim</code> is available. But then if it is, it prints the path to nvim, <code>/usr/bin/nvim</code>, which is slightly confusing every time I see it. So the magical world of internet told me I could try appending <code>>/dev/null 2>&1</code> to the end of the check. I don't know what each part of it does, something about not mashing standard error into standard out, but it sends the output into oblivion aka <code>/dev/null</code><sup class="footnote-ref"><a href="https://hboo.ca/posts/2020-05-19-random-thoughts/#fn2" id="fnref2">[2]</a></sup> which is good enough for me! So that line became</p>
<pre class="language-shell"><code class="language-shell"><span class="token keyword">if</span> <span class="token builtin class-name">command</span> -v nvim <span class="token operator">></span>/dev/null <span class="token operator"><span class="token file-descriptor important">2</span>></span><span class="token file-descriptor important">&1</span></code></pre>
<p>I don't really know what <code>/dev/null</code> is, except that it is oblivion. It is where perfectly useless information goes to die, get swept away and cleaned up, and not be accessed or accessible.</p>
<p>The next improvement brought the thought generator closer to that from which is was inspired. Since the original script goes through all of git add + commit + push, I wanted a little taste of that, but with the safety that comes with not pushing things to production automatically every time...since that is a little beyond my comfort level, as a mini control freak. đ</p>
<p>For the thought generator:</p>
<pre class="language-shell"><code class="language-shell"><span class="token function">git</span> <span class="token function">add</span> <span class="token variable">$FILENAME</span><br /><span class="token function">git</span> commit -m <span class="token string">"Think a thought"</span><br /><span class="token builtin class-name">echo</span> <span class="token string">"You thinked a thought! Run 'git push' to tell the world! Or just to get it off your chest."</span></code></pre>
<p>Everything except pushing the thought. Instead a cute reminder to push it.</p>
<p>Also <code>git commit</code> spits some output to the terminal, so you get to see the filename and commit, as a reminder that it really happened. ^^</p>
<p>Whereas for the new post generator, I kept it a little simpler:</p>
<pre class="language-shell"><code class="language-shell"><span class="token function">git</span> <span class="token function">add</span> -N <span class="token variable">$FILENAME</span><br /><span class="token builtin class-name">echo</span> <span class="token string">"New post <span class="token entity" title="\"">\"</span><span class="token variable">$FILENAME</span><span class="token entity" title="\"">\"</span> has been added to git tracked files"</span></code></pre>
<p>I struggled with the right wording for the second half of the message.</p>
<ul>
<li>"is now being tracked by git"</li>
<li>"has been added to the list of tracked files in git"</li>
<li>?????</li>
</ul>
<p>But what I chose seems as good as any. ÂŻ\_(ă)_/ÂŻ</p>
<p>What I wanted for a new post was just for the <em>file</em> to be tracked, but not for the contents to be staged. So I used <code>git add -N</code>, so that I can use <code>git add --patch</code> to manually review the contents that I am about to commit. I also wanted the filename to be printed, so I could remember which one I just wrote.</p>
<p>Anyway, I am pretty thrilled with how things came out! I think writing these little shell scripts is really fun, and I had never done it much before. The thoughts page itself is exactly as heckin adorable as I thought it would be. On the other hand, I am concerned that it is slightly addictive. I find myself thinking of cute one-liners all day long that could go there, and I have to resist the urge to put every thought I ever think on that page. Thanks for joining me on this trip! Make sure to think lots of thoughts today and always. đ (Sorry, this ending feels very sudden and uncoordinated. I hate reading articles like that. Um...bye!)</p>
<hr class="footnotes-sep" />
<section class="footnotes">
<ol class="footnotes-list">
<li id="fn1" class="footnote-item"><p>"people are just the best." Help I sound like a dog !! đ <a href="https://hboo.ca/posts/2020-05-19-random-thoughts/#fnref1" class="footnote-backref">â©ïž</a></p>
</li>
<li id="fn2" class="footnote-item"><p>True story, once while I was at <a href="https://www.recurse.com/">the Recurse Center</a> (or maybe somewhere else, I don't know now that I think about it đ), I was showing someone something, or doing a presentation, and I had some code snippets that I was just playing around with in a folder called <code>~/dev/null</code>, because <code>~/dev</code> seemed like a reasonable location for all my code, and <code>null</code> seemed like a reasonable location for nonsense code. I had never heard of <code>/dev/null</code> and had no idea I was mimicking it, but whoever enlightened me certainly thought it was funny. đ <a href="https://hboo.ca/posts/2020-05-19-random-thoughts/#fnref2" class="footnote-backref">â©ïž</a></p>
</li>
</ol>
</section>
Where to gitignore what
2020-05-02T00:00:00Z
https://hboo.ca/posts/2020-05-02-where-to-gitignore-what/
<p>I downloaded a little plugin the other day; you might use something like it yourself, if you're a super nerd (sorry..): it's called <a href="https://github.com/dpacassi/disable-javascript">disable-javascript</a>. It's a browser addon that I use in Firefox to maximize speed and minimize annoyance when visiting one of the bajillions of overloaded how-to and fake-news and cooking websites, where by "overloaded" I mean there's 999 ads, and auto-playing videos and pop-ups and newsletter subscriptions all vying for my attention when all I want is basic content. However, the addon also breaks many things you may want to use on the interwebs. You've been warned.</p>
<p>Anyway, I was playing around with this addon - first I had it in "default on" mode (meaning JS is allowed), and so when I visited annoying websites, I would add them as an "exception", which would mean they would have javascript disabled. But then I realized that was a losing battle, and it would be much better to use "default off" mode which disables JS everywhere. When I made the switch, however, my list of "exceptions" from phase 1 stuck around, and now they were exceptions in the <em>opposite</em> direction; that is to say, all the websites I wanted to block were now being permitted. It turns out the exceptions list has no concept of whether sites should be blocked or allowed - it just does the opposite of whatever the current setting is. That's a little inconvenient for people like me who can't make up our minds. đ
</p>
<p>Now, what better to do when you find a problem than SOLVE IT?? Indeed dear readers, so I hunted down the <a href="https://github.com/dpacassi/disable-javascript">code</a>, forked the project from Github, and started trying to add a flag for "block" vs "allow" locally. Part of the setup was <code>npm install</code> which generates a local directory <code>node_modules/</code>, full of libraries that you most definitely (probably, except in weird cases, I guess) do not want to track in Git. Generally this would be accomlished by having a row in the project's <code>.gitignore</code>, telling Git not to worry about anything in <code>node_modules/</code>, so that when you do <code>git status</code> it doesn't say that everything in <code>node_modules</code> is untracked, or when you do <code>git add .</code> it doesn't try to add anything in <code>node_modules</code>, etc. But the <code>.gitignore</code> for this project (which existed! that was my first question) mysteriously did not contain any mention of <code>node_modules</code>. Had previous contributors, including the main creator/maintainer, all just quietly and carefully ignored it themselves in their brains?</p>
<p>Idk, I'm not a mind reader (as much as I sometimes try to be). Being the helpful human I am though, I made a pull request to add <code>node_modules</code> to the project's <code>.gitignore</code>. Now, here is where the plot thickens! The maintainer replied to me (very kindly, I must add - I opened a pile of PRs and issues at the same time and the maintainer was very patient with me đ) to explain that, while they agree that <code>node_modules</code> should not be committed, I should actually have it in my <em>global</em> git config to ignore it everywhere. "Best practice!" they said. (Though not actually quite like that, alone as a sentence or with an explanation mark. That is me taking liberties with the editing.) Wow! I thought. I had never heard of such a concept, to centralize things like a python ENV or node_modules to a global .gitignore.</p>
<p>So I searched the internet high and low for "best practices on global vs project gitignores". Just kidding, I searched for 2 minutes<sup class="footnote-ref"><a href="https://hboo.ca/posts/2020-05-02-where-to-gitignore-what/#fn1" id="fnref1">[1]</a></sup>âČ <sup class="footnote-ref"><a href="https://hboo.ca/posts/2020-05-02-where-to-gitignore-what/#fn2" id="fnref2">[2]</a></sup>, before realizing the internet in general was not going to offer trustworthy answers and I had better find a true source of truth, which ended up being <code>man gitignore</code>. The <a href="https://github.com/git/git/blob/master/Documentation/gitignore.txt#L43">relevant lines</a> are there for you to investigate. The section I wanted was about "Which file to place a pattern in", and the most important sections were the first and third ("other repositories" means other developers local copies of the same project):</p>
<pre class="language-text"><code class="language-text"> * Patterns which should be version-controlled and distributed to<br /> other repositories via clone (i.e., files that all developers will want<br /> to ignore) should go into a `.gitignore` file.<br /><br /> * Patterns which a user wants Git to<br /> ignore in all situations (e.g., backup or temporary files generated by<br /> the user's editor of choice) generally go into a file specified by<br /> `core.excludesFile` in the user's `~/.gitconfig`. Its default value is<br /> $XDG_CONFIG_HOME/git/ignore. If $XDG_CONFIG_HOME is either not set or<br /> empty, $HOME/.config/git/ignore is used instead.</code></pre>
<p>I had a <em>real</em> hard time with the first sentence. My problem was interpreting "patterns" to mean "the actual files represented by the patterns". So I thought it meant "Files which should be version-controlled ..(ie, those that all developers will want to ignore)..." which is utterly contradictory. Either you want them version controlled, or you want them ignored. You can't have it both ways people! I thought maybe they forgot a "n't" at the end of "should". I went on a long voyage reading about <a href="https://git-scm.com/community">how to contribute to git using the mailing list</a> so that I could fix the manpage, before eventually realizing that when it says "Patterns which should be ....", "Pattern" literally means <em>the actual plaintext word in the .gitignore file</em> and not the file itself. -__-</p>
<p>Luckily though, now we can go back to business with the disable-javascript project, because I have it on good word that my pull request actually does make sense, and if I love anything, it's being right. đ (Shh, don't tell.)</p>
<p>In summary:</p>
<ul>
<li>text editor-specific or operating system-specific files go in <em>global</em> git config to ignore</li>
<li>project (and therefore language)-specific files go in <em>project</em> <code>.gitignore</code> to be committed and shared with fellow devs working on the same project</li>
</ul>
<p>Cool beans kiddie winks, thanks for hanging around! Also, make sure you know what you're talking about before emailing the whole mailing list of git. Heh, that would have been awkward.</p>
<hr class="footnotes-sep" />
<section class="footnotes">
<ol class="footnotes-list">
<li id="fn1" class="footnote-item"><p>During my 2 minutes of searching I found <a href="https://www.reddit.com/r/node/comments/7i229x/global_gitignore_node_modules/">this reddit thread</a>, which I now wish desperately to answer to help the next me who comes along, but the thread is closed. PUH. đŠ <a href="https://hboo.ca/posts/2020-05-02-where-to-gitignore-what/#fnref1" class="footnote-backref">â©ïž</a></p>
</li>
<li id="fn2" class="footnote-item"><p>Also, can you tell I figured out how to make REAL FOOTNOTES?! Very cool. So much better than my haphazard asterisks system. I might have to go through old posts and fix them up. đ <a href="https://hboo.ca/posts/2020-05-02-where-to-gitignore-what/#fnref2" class="footnote-backref">â©ïž</a></p>
</li>
</ol>
</section>
Glossary
2020-04-25T00:00:00Z
https://hboo.ca/posts/2020-04-25-glossary/
<p>Here's another glorious tidbit from the past, which is actually really exciting because it demonstrates to me that my grasp of French has, in fact, improved in the last few years! đ *</p>
<p>*: Some chat clients (slack, signal? discord, zulip) convert certain terms between colons(<code>:</code>) into emojis! đ becomes the crying laughing face, đ the crying crying face, :lever_les_yeux_au_ciel: the rolling eyes face when you have slack configured to be in French. (My Francophone colleagues especially find it strange and bemusing that I use slack in French - nobody else does, and it leads me to find weird bugs and develop strange habits like referring to "@ici" instead of "@here". But how else will I learn to say "roll your eyes", if not by searching for the emoji in French?!)</p>
<p>Anyway, here's the little stub of a post that doesn't actually explain anything. Apparently I thought a glossary would be useful, which is cute, but like, a lot of maintenance. So, not gonna happen. đ</p>
<hr />
<p>8 MAR 2017</p>
<p>Voici une collection des termes que je pense que soient nEcessaires ou utiles pour comprendre mes postes. J'espEre que cette vous aide. <!--more-->[<a href="https://hboo.ca/posts/2020-04-25-glossary/#c'est-bon">Why is this in French?</a>]</p>
<table>
<thead>
<tr>
<th>Term</th>
<th>Word Class</th>
<th>Meaning</th>
<th style="text-align:right">Notes</th>
</tr>
</thead>
<tbody>
<tr>
<td>IRC</td>
<td>f</td>
<td>f</td>
<td style="text-align:right">f</td>
</tr>
<tr>
<td>RC</td>
<td>c</td>
<td>s</td>
<td style="text-align:right">g</td>
</tr>
<tr>
<td>{:.table}</td>
<td></td>
<td></td>
<td style="text-align:right"></td>
</tr>
</tbody>
</table>
<h4 id="c'est-bon">C'est bon <a class="direct-link" href="https://hboo.ca/posts/2020-04-25-glossary/#c'est-bon">#</a></h4>
<p>The preamble to this glossary is in French because I felt like it. It hopefully translates to "Here is a collection of terms that I think are necessary or useful for understanding my posts. I hope it helps." I like other languages and hope you do too.</p>
<hr />
<p>Back to the present:</p>
<p>So, that was cute, I hope you agree. The capitalized Es in the French part are my shorthand for when I know I need an accent but I'll insert it later. It's adorable to read because now I am amazed that I constructed those sentences and thought they were correct. It's still understandable though I'm pretty sure! I might write a bit more in French in the future; in fact, hopefully a post will come soon to elaborate on a desire that I have to expand the breadth of this blog outside of code. Stay tuned les amis ! đ</p>
<p>In other notes, I guess the random letters in the columns were placeholders while I figured out how to do tables? And also the "Why is this in French?" link is cool, except it links to like 2 lines down, so if you click the link you can't tell it actually did anything, which is less than ideal. ><</p>
<p>ÂŻ\_(ă)_/ÂŻ</p>
<p>Bye!</p>
How to control spotify from the command line
2020-04-19T00:00:00Z
https://hboo.ca/posts/2020-04-19-how-to-control-spotify-from-the-command-line/
<p>Holy buhjeebus the amount of steps. I just want to listen to business casual. Ya know... Let's keep it business. Let's keep it casual. Let's keep it...fun.</p>
<p>So! Here comes, how to listen to spotify from the terminal in fedora. YMMV (Your mileage may vary).</p>
<p>Copy this handy AF simple AF (you're gonna have to look that acronym up yourself...unless you're my mom, then don't worry about it mom) script from this amazing life saving person, that I only found after downloading 298374 other super complicated things that didn't do what I wanted, at all. Like mobify or mobidy or mondiby or something.</p>
<p><a href="https://gist.github.com/wandernauta/6800547">https://gist.github.com/wandernauta/6800547</a></p>
<p>It's just a gist! That's how simple it is! Amazing.</p>
<p>So, wherever you keep your code, maybe in <code>~/code</code>? Start yourself a nice new file called <code>control-spotify.sh</code> and paste the code from that gist into it. Save. Then we'll make a symlink to that script in somewhere that exists in your path, so you can execute this script easily.</p>
<p>Look at the output from <code>echo $PATH</code> - every path between colons (<code>:</code>) is where your computer will look for stuff when you type a command. My path includes <code>/usr/local/bin</code>, so I'm gonna put it there.</p>
<p>There's a couple more puzzle pieces around making the script easy to call. First, what will we type to invoke the script? I want to control spotify by typing <code>sp</code>, as inspired by the original gist title, because that's short and I'm lazy. You might choose <code>spotify</code> or <code>musica_pls_dj</code> or whatever.</p>
<p>So, to symlink the script:</p>
<pre class="language-shell"><code class="language-shell"><span class="token function">ln</span> -s ~/code/control-spotify.sh /usr/local/bin/sp</code></pre>
<p>(PS, I never used symlinks before yesterday. Just in case you think "aw, symlinks, that is magic stuff I'll never understand", since that's what I thought 3 days ago, and every day before that. đ )</p>
<p>Make sure you specify the whole path <code>~/code/...</code> even if you're already in <code>~/code</code> and think you can simply do <code>control-spotify.sh</code>, because the next time you run <code>sp</code>, our friend computer doesn't know that and can't find the script. Sad face. đŠ</p>
<p>Then we want to make the script executable (files ending in <code>.sh</code> are not by default executable! idk why. probably to save us from our dangerous selves):<br />
<code>chmod u+x ~/code/control-spotify.sh</code><br />
I actually used <code>chmod +x</code> (no <code>u</code>), which modifies the permission for everyone; adding <code>u</code> restricts it to the current user, if I understand correctly. I don't really know which one you should use. You do you.</p>
<p>So, now you should be able to do<br />
<code>sp</code><br />
and it should print out a happy little list of possible commands.</p>
<p>Great! Now, I've already taken the liberty of actually putting the script in a directory so I could version control it using git, because</p>
<ul>
<li>I love git</li>
<li>I make a lot of mistakes - I prefer to live fast and crash often đ</li>
<li>I know I will want to make changes, because I can see a lot of comments in the gist</li>
</ul>
<p>The first thing I did was try out each command by having a window open with the help output from running <code>sp</code>, and another window open to run each command. Oh, also, open spotify first. I installed it using <code>snap</code> as recommended for linux. Right, so here I am gleefully rejoicing when <code>sp play</code> and <code>sp pause</code> and <code>sp next</code> all work! But then <code>sp previous</code> doesn't work, it just stops the music, and it won't restart using <code>sp play</code>. Sad face. đŠ On further investigation, it turns out my brain translated <code>prev</code>, which is the actual command, into <code>previous</code>, which is not a recognized command and therefore does not have the intended outcome. Ha. So I made a wee change to the script, adding another alias under <code>sp-prev</code> for <code>sp-previous</code>. And updated the version from <code>0.1</code> to <code>0.2.0</code>, because</p>
<ol>
<li>I like <a href="https://semver.org/">semantic versioning</a> (x.y.z, rather than x.y), and</li>
<li>I added a feature, so it gets a "minor" bump (bug fixes get a "patch" bump and breaking changes get a "major" bump)</li>
</ol>
<p>Next, I can keep trying out commands. Most of them work, which is frankly incredible to me considering so little code. After all the cruft I was wading through before, piling on packages and addons in an attempt to get anything functional. KISS Keep it simple stupid!! â€ïž Some like <code>sp url</code> don't work, which I don't need so I don't care about 8), and some like <code>sp display</code> need additional packages installed, but I don't need to look at album art, so I also don't care about that. đ Whee!!</p>
<p>The big trick though is <code>sp search</code>, which is really what I need - this is how you find songs to play. And spotify has apparently updated their API to require authorization so the original code does squat. D: Let's take the <a href="https://gist.github.com/wandernauta/6800547#gistcomment-2113314">changes @vorbeiei suggests</a> and try those by replacing the <code>sp-search</code> function in the code. (There's a comment just after from someone who made <code>curl</code> silent for a nice clean output, which is great for when it's working, but I want all the details I can get while developing!)</p>
<p>Then we need our client ID and secret - follow the <a href="https://developer.spotify.com/documentation/general/guides/app-settings/#register-your-app">spotify docs to register an app</a>, kindly linked by github user @vorbeiei in their comment. Make your ID. Guess how to insert it into the script, and come back in a couple paragraphs for story time and instructions.</p>
<p>To test, I'm doing a nice easy search for "Moonshine" (by Caravan Palace) - it was on my spotify home page and it's a one word search term, which I assume can only help my cause in getting the search to be successful. It looks like the search syntax is either <code>sp search moonshine</code> or <code>sp moonshine</code>, but neither of them start moonshine playing. They just spit out curl progress, as if things were making good little requests. To debug, we need to drill down into the script a bit more. I took the first <code>curl</code> statement out and started fiddling with it in the command line directly.<br />
<code>curl -H "Authorization: Basic client_id:secret" -d grant_type=client_credentials https://accounts.spotify.com/api/token</code></p>
<p>Are you ready for the aforementioned storytime? First I will tell you how to correctly input your freshly generated credentials. Then I will tell you all the ways you could do the <em>wrong</em> thing, all of which I did. Teehee.</p>
<p>Do do this:</p>
<ul>
<li>copy your client_id and secret from the spotify developer page for the app you registered</li>
<li>stick your client_id and secret together, joined by a <code>:</code></li>
<li>then base64 encode that whole string, without any newlines (<code>base64 -w 0</code>)*</li>
<li>jam the whole thing in the auth string for curl: "Authorization: Basic happily_encoded_stuff"</li>
</ul>
<p>Don't do this:</p>
<ul>
<li>plain old insert your client ID and secret as "Authorization: Basic my_client_id:secret"</li>
<li>nor base64 encode each part seperately, then join them with a <code>:</code></li>
<li>nor base64 encode the whole thing, without removing newlines</li>
</ul>
<p>I don't really know what base64 encoding is, so I just thought the credentials I copied from spotify were already encoded. That was my first problem. The second was trying to encode each part separately then join them with a <code>:</code>. Both of these were leading me to a <code>{"error":"invalid_client"}</code> error from curl. Anyway, it took some noodling as a bash noob, but my eventual process to encode all of this was:</p>
<pre class="language-shell"><code class="language-shell"><span class="token assign-left variable">CREDENTIALS</span><span class="token operator">=</span>dxfjgbjbkjhgfbjhwhatevermyclientidcopieddirectlyfromspotifyis:jbjhkbkjhgbfsdjhgbkjhsfwhatevermysecretcopieddirectlyfromspotfyis<br /><span class="token comment"># make sure it worked</span><br /><span class="token builtin class-name">echo</span> <span class="token variable">$CREDENTIALS</span><br /><span class="token assign-left variable">CREDS_ENCODED</span><span class="token operator">=</span><span class="token variable"><span class="token variable">$(</span><span class="token builtin class-name">echo</span> $CREDENTIALS <span class="token operator">|</span> base64 -w <span class="token number">0</span><span class="token variable">)</span></span><br /><span class="token builtin class-name">echo</span> <span class="token variable">$CREDS_ENCODED</span><br /><span class="token comment"># you should have a single line of 39yijb7hi23h7i!! who doesn't love that stuff.</span><br /><span class="token comment"># now, in the curl command, make the auth string look like:</span><br /><span class="token comment"># "Authorization: Basic $CREDS_ENCODED"</span></code></pre>
<p>Also, I highly recommend adding <code>--verbose</code> as the first argument to <code>curl</code>, so you can see exactly what gets sent once the <code>$CREDS_ENCODED</code> gets evaluated.</p>
<p>The next problem I ran into was a <code>stream was not closed cleanly: PROTOCOL ERROR</code>. I had some suspicion that this was due to the line break in the encoded credentials, but I thought that line break was part of the encoding, so what could I do about it?! Of course, <a href="https://superuser.com/a/1225139">stack overflow to the rescue</a> - It turns out you can pass a flag to <code>base64</code> to "wrap". Sweet! Next problem! đ
</p>
<p>So with that all sorted out, now we're back to <code>{"error":"invalid_client"}</code>, except now the object contains a new key too: <code>{"error_description":"Invalid client secret"}</code> -_-. Gah!</p>
<p>To solve this, since googling the error wasn't getting me anywhere, I searching in the github issues and started checking each one that seemed relevant. Eventually I got to one where somebody responded with <a href="https://github.com/spotify/web-api/issues/1372">very clear instructions</a> to use this site for base64 encoding. Failing other leads, I tried it, and compared the result to my local <code>echo $CREDS_ENCODED</code> - unbelievably, somehow the final character differed, and when I used the web-encoded string, IT WORKED! I got my <code>access_token</code> in the response! No idea what is happening there. None. At all.</p>
<p>Anyway, onwards to moonshine! Add <code> \>> token\</code> to the end of the curl call we were running, then run it again. PS, this is super hacky. You've been warned. ÂŻ\<em>(ă)</em>/ÂŻ Open the token file, delete everything except the token itself, even the quotes around it. Then in the terminal, run <code>TOKEN=$(cat token)</code>, and <code>echo $TOKEN</code> - you should see your token. We are starting to feel like <a href="https://jvns.ca/blog/2017/12/01/new-zine--so-you-want-to-be-a-wizard/">wizards</a> at this point. ;D Now take the second curl statement in the sp script, stick it in the terminal, and replace the authorization <code>$ST2</code> with <code>$TOKEN</code>.</p>
<p>By the way, I would totally just have pasted the token directly into the curl command if I could, but I just re-installed my OS and I haven't figured out how to copy from either the terminal or vi yet. Just saying. đ</p>
<p>In the curl statement, we also have to replace the <code>"q=$Q"</code>, because we don't have a <code>$Q</code> defined. (It is defined a couple lines above in the script - we could just copy that and define Q in the terminal, but I like inlining it for clarity.) So instead, put <code>"q=$@"</code>. Haha, no wait. I tried it and it turns out the q is for query - if you run the curl with <code>$@</code>, you get a "400: no search query" response. That's kindof cool! Did you know that? Now you/I/we know. (Bill Nye reference because he's great.) Ok so back to reality, replace that q bit: <code>"q=moonshine"</code>. Oooh we're so close I can taste it! đ But why doesn't the script work?! If only I could put a debugger in...huh, the internet suggests <code>set -x</code> in the script to debug a shell script, so I put it as the first line in the <code>sp-search</code> function. Ooh, it sure spits out some info, but nothing particularly enlightening. Maybe I will settle for trying to extract each part to a variable, and hopefully that will mean more helpful output.</p>
<p>So, if I use <code>>> token_response</code> after the first curl, then <code>cat token_response | grep -E -o "access_token\":\"[a-zA-Z0-9_-]+\"" -m 1</code>, I do get the access token extracted, so that's cool! It looks like that gets assigned to <code>ST</code> and then <code>ST2</code> becomes characters 15 through 86 of that, so presumably the token itself. That leaves the final <code>grep</code> statement as the final possible culprit, so let's pull it out too and try it in the terminal. (PS, when making hot and sour soup, do cut the daylilies in half. Even short ones are too long. Otherwise you get the spaghetti effect of flinging sauce/liquid everywhere.) Huh, this grep statement seems to work nicely too, returning <code>spotify:track:ID</code>. Does the problem then lie with <code>sp open</code>? Ack! If I take that string, and put it on the end of <code>sp open</code> it works! As a sidenote, I think I am going to discover lots of new music with this - now I am listening to a random song called moonshine that I've never heard before. đ</p>
<p>Oh god, this whole time I thought the bash output produced when I set <code>set -x</code> was masking the credentials variable somehow, but in reality it was just ...nothing. So the first query fails, so everything else fails. Facepalm! Preliminary googling reveals <a href="https://www.digitalocean.com/community/tutorials/how-to-read-and-set-environmental-and-shell-variables-on-a-linux-vps">answers from Digital Ocean</a>...</p>
<blockquote>
<p>We now have a shell variable. This variable is available in our current session, but will not be passed down to child processes.</p>
</blockquote>
<p>D'oh! I need <code>export</code> to make <code>$CREDENTIALS</code> available to the <code>sp</code> script.</p>
<pre class="language-shell"><code class="language-shell"><span class="token builtin class-name">export</span> CREDENTIALS</code></pre>
<p>In the long term, that needs to be exported in my <code>/.zshrc</code>, with the actual base64 encoded string.</p>
<pre class="language-shell"><code class="language-shell"><span class="token builtin class-name">export</span> <span class="token assign-left variable">CREDENTIALS</span><span class="token operator">=</span>jhdfgkjsdbfkugabuyb34ouyfbosdufgyurWHEEEwhatever</code></pre>
<p>Aaaand I'm feeling like a genius, now that it finally works! Thanks for tuning in, friends and countrymice. đ</p>
<p>PS, here's the final version, nicely wrapped up in a repo with condensed instructions! Enjoy!</p>
<p><a href="https://github.com/heatherbooker/spotify-cli">https://github.com/heatherbooker/spotify-cli</a></p>
<p>*Don't do <code>base64 -w 0</code>. I still don't know what it does weird, but...just keep reading.</p>
Choosing an Outreachy project
2020-04-19T00:00:00Z
https://hboo.ca/posts/2020-04-19-choosing-an-outreachy-project/
<p>So, this post was drafted years (no, <em>literally</em> years) ago when I was applying to Outreachy, and it just stayed a draft forever because I guess I thought there was more to it. It turns out, there wasn't, because if there was, it would be there. Ha! I still think it's interesting though, and I want it out of my "untracked files" when I run <code>git status</code>*, so here it comes, in all its overdue glory. đ</p>
<p>*: I could have another branch for this draft, and commit it there. But then I will just forget it exists. Also if I did that and ever actually finished it, it would entail way more git overhead than I want to deal with. So - publish or bust, baby!</p>
<hr />
<p>24 MAR 2017</p>
<p>Oh my goodness. There are so many things pulling me in different directions, making me second guess where I've gone with my application to <a href="https://wiki.gnome.org/Outreachy">Outreachy</a>, and with a few days before the deadline, I still feel like a jumping bean bouncing around between projects and priorities! Here are some of the factors influencing my decisions.</p>
<ol>
<li>How much I stand to learn from participating in this project</li>
<li>How well organized/set up/documented everything is</li>
<li>How helpful the mentor/people involved are to me</li>
<li>How friendly the mentor/people involved are to me</li>
<li>How much autonomy and freedom I think I'll have</li>
<li>Whether my mentor or any of my team members are female (is that sexist? like...this whole thing is gender-based so..?)</li>
<li>The languages and technologies used for that project</li>
<li>How capable I think I will be of completing the project without driving my mentor nutz with questions</li>
</ol>
<p>I'm also kinda worried that people normally just choose and focus on one project to apply to, whereas I have multiple (actually..SO MANY) that I would love to work on and I hope they don't all get lost in space! đą That would be so sad face!</p>
<hr />
<p><strong>Back to the present!</strong></p>
<p>This post is so beautifully typically <em>Heather</em>. Of course there's a whole list of 8 decision factors, qualified with the fact that the 8 are only <em>some</em> of what's influencing my decision. Also, it turns out, I think this is probably also a good list to bring to job interviews.</p>
<p>Except that I would do well to worry less about the last point. If I suck, they can fire me. :angel_face: Realistically though, if I suck, I will get better. That is to say: if I ask a lot of questions, I will learn. And asking questions can highlight existing problems in systems (technical ones or people ones), and make other people feel smart and useful (cool!), and build rapport with colleagues. And if feel that I have too many questions, I can spread them out to the internet, and stack overflow, and other friends. Nice! Now stop worrying. đ</p>
<p>The end.</p>
im not a programmer
2019-12-24T00:00:00Z
https://hboo.ca/posts/2019-12-24-im-not-a-programmer/
<p>Why I don't feel like a programmer:</p>
<p><strong>I use a mac at work</strong></p>
<p>Real programmers don't like Apple.<br />
Real programmers embrace all the manual dirty work they have to do configuring and trouble shooting basic functions on this or that linux distro.<br />
I just want shit to work.</p>
<p><strong>I use package managers</strong></p>
<p>Mac has homebrew.<br />
At home on Fedora, I just use the software manager GUI. If I want something not through it, I have to look up instructions. I don't even know what my package manager is.</p>
<p><strong>I use my mouse</strong></p>
<p>Real programmers only use the keyboard.<br />
Also, they can type without looking.<br />
Not me.</p>
<p><strong>I forget how to use FZF in vim every time my manager shows me</strong></p>
<p>ctrl + p. ctrl + p. This time I'll remember.</p>
<p><strong>I don't know how to write a bash script</strong></p>
<p>Did you know bash doesn't have types? An int and a string are the same thing. What does that even mean? Idk.</p>
<p><strong>Or an awk script</strong></p>
<p>I can't process files fast. Wouldn't that be fun? My coworker is going to make a text editing mini war for us all. Bet I won't succeed.</p>
<p><strong>Or use that JSON processing thing</strong></p>
<p>Like you pipe JSON into it and process it and get answers. In goes JSON, out comes object.key[2]. This was a problem when I wanted to find out if our users ever request a certain field from one of our GraphQL endpoints - I needed to process a lot of logfile. Which reminds me,</p>
<p><strong>I have to copy pasta and double check the steps every time to 1) SSH, or 2) deploy</strong></p>
<p><code>scp</code> is an alien concept. And every other tool that Julia Evans has a cute cartoon explaining. I don't know the syntax or the rules and I'm scared to screw anything up. Maybe that's a good thing, on second thought. At least in some ways.</p>
<p><strong>Or know how to set up a server</strong></p>
<p>It has to like, connect to the internet or something right? And have some software running on it? At least an OS? An operating system counts as software right?</p>
<p><strong>Or know how to explain what a server is</strong></p>
<p>I asked my friend if the software her company uses is just for them, or available for anyone to use. She said, "It's on a server...whatever that means.". I said, yeah I don't know - a computer that does stuff? Maybe without you? Then her roommate explained like a textbook: a server is a specialized computer that whatever whatever I don't know I don't remember, I was busy being sad that I didn't really know what a server was.</p>
<p><strong>I've never managed my own memory</strong></p>
<p>I don't know how a computer works. There's memory and nands and ands and ors and nors. I've never used C or C++ or C# or C- or C%.</p>
<p><strong>I prefer doing to planning</strong></p>
<p>I don't want to think through every possible outcome and option, I just want to make stuff.<br />
That's too waterfall-y. But it means I run up against lots of impossible solutions, and spend time trying plan A then ditching in favour of plan B then returning to plan A. Seems like a waste of time. I'm scatterbrained.</p>
<p><strong>I prefer doing to reading</strong></p>
<p>I don't want to read through the whole React docs every time there's an update, I just want to make stuff.</p>
<p><strong>I don't care much about history</strong></p>
<p>Who is Luna Lovegood? I mean Eva Rotwell? I mean...the girl? The famous one? Who wrote a program, or maybe she didn't?</p>
<p><strong>I use google services</strong></p>
<p>And skype, and whatsapp, and I have a facebook account - multiple facebook accounts.<br />
Real programmers are wary of that stuff.<br />
Real programmers use discord, and signal, and tox, and the onion, and tor, and maybe the onion is actually just the logo for tor, and..?</p>
<p><strong>I'm just a web developer.</strong></p>
<p>I'm just a front end developer.<br />
I don't have an engineering degree.</p>
<p><strong>But I'm a web developer who can't even do CSS.</strong></p>
<p>Isn't that, like, all web developers are good for? CSS?</p>
<p><strong>I don't need long chunks of uninterrupted time.</strong></p>
<p>Real programmers get in a state of flow.<br />
Real programmers need quiet and space to produce genius inventions. I just make forms. No genius required.<br />
I have no right to complain about noise or interruptions.</p>
<p><strong>I don't play video games.</strong></p>
<p>Ack! They all play video games. And chess. And ping pong. I'm an alien! They play chess because they focus and get in flow state and analyse...just like the last point.</p>
<hr />
<p>Anyway.</p>
<hr />
<p><strong>That's better</strong></p>
<p>Anyway, I feel a bit better now. I can still be a programmer if all of the above is true. I'm not static (I can still learn things). I can't learn everything at once (and I'm still fresh enough in programming - 4 years isn't a very long time!) I am just me and I can use my strengths of curiousity and desire to make nice things â€ïž And that's enough!</p>
<p>Buhbye now.</p>
<p>PS - Don't forget to be nice to your less nerdy co-workers. Don't show surprise when they could be about to have a learning opportunity. Make them feel welcome and valued no matter their background and methods. In short, be kind to one another. đ â€ïž</p>
<p>PPS - I picked up a couple <a href="https://adventofcode.com/">advent of code</a> puzzles, because I thought that might be a fun way to feel a little bit more like a programmer again. I think it's working. đ</p>
<p>PPPS - Did you forget the first PS already? Go back to it! đ</p>
Should I stay or should I go now
2018-04-14T00:00:00Z
https://hboo.ca/posts/2018-04-14-should-i-stay-or-should-i-go-now/
<p><strong>: Wherein I discuss the weirdness of half ppl being like "GTFO L8ER !*#$&S", and the other half like "wut where u goin jus chill out"</strong></p>
<p>I am struck by a strange dichotomy of phenomenons that I find in tech job mentalities.</p>
<p>One goes a little like this:</p>
<blockquote>
<p>You've been there 9 months and you're not looking for a new job?! Why not?!</p>
</blockquote>
<p>While the contrary goes like:</p>
<blockquote>
<p>Yeah, this place is good. I can seek out what I need within my company and I am well supported here.</p>
</blockquote>
<p>Perhaps you identify with one or the other mentality. Certainly I found myself happily settling into my workplace, grateful for the autonomy and influence I was given, grateful for the people I worked with, grateful for interesting challenges without undue pressure and unachievable deadlines. But more and more, I felt like the walls were closing in on me - walls of</p>
<ul>
<li>"But you'll never grow if you stay in the same place!"</li>
<li>"You could get a nice big pay bump if you changed companies."</li>
<li>"It's so boring to stay in one place, when are you going to quit?"</li>
<li>"Companies don't care about you or keeping you learning and engaged."</li>
<li>"You'll lose your edge if you don't quit every 9 months."</li>
<li>"You gotta swoop in, write a bunch of shit real fast so you look good, and then move on and leave the shit for some other suckers."</li>
</ul>
<p>And I grew more and more unhappy.</p>
<p>How stupid was I to think I could stay in this job! What a joke to be anywhere longer than a year and a half! A real programmer would never dream of doing such a thing! All the cool people get in and get out!</p>
<p>And worse, thoughts of money haunted me. I didn't ask for enough when I was being hired. I am getting underpaid because I'm a woman. I didn't fight hard enough for a raise. I could get more elsewhere. I'm gonna be stuck at this pay level for the rest of my life. Everyone else is making more than me. The hard work I do is utterly uncorrelated to my compensation. I'll never have enough money.</p>
<p>What absurdity! I am so priveleged to have a job and a salary and all of the wonderful things I have, and life is too short to spend it worrying about how much money I don't make. Alas, it was too late - I was brainwashed by these messages of "more money, shorter jobspans" and becoming rather unnerved by the whole shebang.</p>
<p>As I began to express these opinions in surprise to my fellow humans, I discovered that some for whom I had deep respect had remained at their current jobs - sometimes their first jobs! - for 3 and 5 and 6 years, and maybe even had no plans of leaving.</p>
<p>Incredible! I thought. Unheard of! I mentally pencilled names onto my list of "evidence you don't have to quit every couple weeks".</p>
<p>To counter my anguish around my stagnant position and questionable <a href="https://www.wordreference.com/fren/remuneration">remuneration</a>*, I mentally and emotionally checked out from my job. I spent a while just drifting around, completing projects as required, complaining and commiserating with my dissatisfied colleagues, and half-heartedly considering alternatives, but without taking any action.</p>
<p>Then finally, after one day of roaming the office making snide comments and just generally dumping my newfound negativity on everyone, I was struck by the uncertain reactions of the unfortunate humans on the receiving end of my hostility. I am nothing if not overly sensitive to other peoples' reactions, and I was taken aback by their being taken aback - I had to explain myself multiple times, as if my sass was so unexpected as to be un-understandable. That day, I called my mom. It went something like this:</p>
<p>"Hi Mom. I'm becoming grumpy. I think everyone around me is grumpy. But I don't have to be grumpy. I could keep being happy despite other peoples' grumpy."</p>
<p>"Indeed dearie."</p>
<p>And that was how I came around to realizing that just because other people express distaste for their co-workers or managers or jobs, or just because other people want more more more money, or just because wHATEVER, doesn't mean I have to join their petty and petulant pity parties. I can - and I want to - keep appreciating what I have, respecting those around me, and being content in my life as it is. I know my job is good and that I have rich opportunities where I am, challenges waiting for me to rise up and meet them, and mentorship from others if I only am brave enough to solicit their wisdom and knowledge.</p>
<p>Sometimes it's important for me to be reminded that I can go my own way in life. The choices I make are the right ones, even if there were 1347236572898986397924 other ones I could have made, because any path is a good path if I am on it đ. Other people do cool things and have cool thoughts, but I do too, and if they want to be negative and share that negativity with me, I am sorry to be a nice non-porous metal wall from which they can bounce away to find somewhere else to seep in. I prefer to be a role model of positivity and satisfaction than a sheep of sourness and bitter endings.</p>
<p>With that, I am off to enjoy my life, and practice this principle in all corners of it. I hope you too are reminded to go your own way, but smell the roses along the path - other people can trample their own roses, but don't let them trample yours too! đ</p>
<hr />
<ul>
<li>Note about <em>remuneration</em>: My french-speaking colleague used this word and I wondered if he had erred in his translation from French, but it turns out to be a technically-correct-but-rather-rare-and-generally-with-a-slightly-different-meaning word meaning <em>pay</em>. Presumably in French it is more commonly used. Cool.</li>
</ul>
MobX + React: Can you use this.props in @computeds?
2017-11-27T00:00:00Z
https://hboo.ca/posts/2017-11-27-mobx-n-react-can-you-use-this-n-props-in-computeds/
<p>I am an <code>@computed</code> evangelist when it comes to <code>get</code>ters in the many MobX-React components my team writes for work. I prowl around PRs, hunting for unsuspecting plain ol' innocent getters like this:</p>
<pre class="language-js"><code class="language-js">@observer <span class="token keyword">class</span> <span class="token class-name">Potato</span> <span class="token keyword">extends</span> <span class="token class-name">React<span class="token punctuation">.</span>Component</span> <span class="token punctuation">{</span><br /> @observable frend <span class="token operator">=</span> <span class="token string">'Ms. Beans'</span><span class="token punctuation">;</span><br /><br /> <span class="token keyword">get</span> <span class="token function">grewInTheGround</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> props<span class="token punctuation">.</span>earthlyInfo<span class="token punctuation">.</span>source <span class="token operator">===</span> <span class="token string">'the ground'</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><br /><br /> <span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">return</span> <span class="token operator"><</span>div<span class="token operator">></span> look<span class="token punctuation">,</span> i<span class="token string">'m a paytaytoe { this.grewInTheGround && '</span>from the ground' <span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p>...and POuNCinG on them: "What if we used <code>@computed</code> for that grewInTheGround getter? Check out <a href="https://mobx.js.org/refguide/computed-decorator.html">the docs</a>!"</p>
<p>This was a gleeful pastime of mine until one day I was rudely* interrupted by a co-worker not so easily convinced. They mentioned that for a getter function containing solely MobX observed properties, they would of course also advocate for the use of computed, but <em>this</em> getter relied on only React props from a parent component. They doubted the effectiveness of the decorator in the case where props could influence the getter.</p>
<p>Huh, I thought. (Well actually, first I thought HMPH!, but then I thought better of it and realized ah ha, a learning opportunity!) I hadn't considered the fact that props might not be supervised in the same way other MobX observables are.</p>
<p>Some background:</p>
<ul>
<li>Decorators are like, JS functions with <code>@</code> in front that just magically do stuff to whatever they're applied to.</li>
<li>Mobx is a state management library that is based on observables.</li>
</ul>
<p>So I went straight to the MobX docs and checked if they mentioned props. I checked about computed, and observables, and observer, and React, and optimization, and common pitfalls, and best practices. Result: no. (Sidenote, I wrote the notes for this blog post nearly a month ago now so I am fuzzy on some details, like exactly how much the answer to my question was not contained in the docs. -_-)</p>
<p>Next, to google with variations on 'Can you use this.props in computed mobx'. I found exactly 0 anythings that were helpful. Eventually I migrated my efforts to <a href="https://github.com/mobxjs/mobx">mobxjs/mobx</a> on Github and searched just 'computed props', then opened every issue that looked remotely relevant.</p>
<p>(In retrospect, I should have been looking for whether props are <em>observable</em> and not whether they belong in @computeds, but this did not occur to me because changes in props clearly impacted the render function. Upon realizing this, I decided I had thought that because obviously React was managing the render function. This is also not true because that would totally at least 50% defeat the purpose of using MobX to optimize(minimize) renderings. Whatever.)</p>
<p>I started on one issue, "Discrepancy between re-computation between render and computed", and then found the gold mine <a href="https://github.com/mobxjs/mobx/issues/1075#issuecomment-312801921">in one comment</a>:</p>
<blockquote>
<p>Since 4.0 props are an observable...</p>
</blockquote>
<p>Dammnnnnnnn! Ok to <a href="https://github.com/mobxjs/mobx-react/blob/master/CHANGELOG.md#thisprops-and-thisstate-in-react-components-are-now-observables-as-well">the changelog</a> we go. A sub-header of v4.0 is entitled "this.props and this.state in React components are now observables as well" - bingo!! Well, there you go. The answer is yes, we should use @computed for getters that access props values as well as internal class observed values.</p>
<p>But we can't stop now, we're just getting started. They threw a little teaser into the changelog description there:</p>
<blockquote>
<p>For more details see <a href="https://github.com/mobxjs/mobx-react/pull/136">#136</a></p>
</blockquote>
<p>And whoowee, there's a lot of chattin' in that thread. Also the whole description is "see <a href="https://github.com/mobxjs/mobx-react/issues/124">#124</a>" - #124 is an issue containing discussion leading up to the making of this.props being observed.</p>
<p>At this point I was jumping around between all of these tabs, trying to make sense of it all and answer questions like "what is this HoC they keep mentioning?"(spoiler, higher-order-component) and "wait, so how deeply or shallowly is props observed?".</p>
<p>If we look again at the first example code above, where the computed accesses <code>this.props.earthlyInfo.source</code>, with pre-4.0 MobX, the computed would run if <code>this.props.earthlyInfo.source</code> was modified. Now, the computed also re-runs if <code>this.props.earthlyInfo</code> itself is changed, like if the component was rendered with new data: <code><Potato earthlyInfo={{source: 'kindly neighbour'}} /></code>. Good to know! You can see an example of how this was implemented in <a href="https://github.com/mobxjs/mobx-react/pull/136/files/0bcf70bee3068a1b3df51b1969c28805625b59e5">this PR</a>; it pretty much cycles through props and observes each one.</p>
<p>Pleasingly, I am now able to sleep at night and continue my <code>@computed</code> calling during the day, in full knowledge that I am bettering the efficiency of our code ever ever so slightly. đ</p>
<p>Life is beautiful and birds are singing, as they say.</p>
<p>And hey, a lovely unexpected side effect of this knowledge slurping extravangza was that it recharged my interest in what I was doing at work, at a time when I felt very dulled by menial tasks and repetitve going-ons. It reminds me that sometimes it's important to take some time out of the grind in order to refresh my perspective and remember that Stuff Is Interesting! I really respect that my manager can't resist digging into the internals of everything they touch and I hope to keep channeling that. Props to them and to you and to everyone who doesn't just skim the surface but gets their hands dirty!</p>
<p>SHORT ANSWER IF YOU SKIMMED IN THE HOPES OF JUST FINDING THE FRICK OUT BECAUSE the docs are pretending to be all fancy n whatever but u got sTUFF to do: YA PROPS ARE OBSERVED U can use them in ur @computed đ .</p>
<p>* Note: No offense to the speaker of this statement intended; 'rudely' is merely employed as a figure of speech. đ</p>
Wat the FLIP does Firefox think it's doing with 138% of my CPU power?!
2017-04-21T00:00:00Z
https://hboo.ca/posts/2017-04-21-wat-the-flip-does-firefox-think-its-doing-with-138-of-my-cpu-power/
<p>Oh my bananas, I am having a computer crisis. It all started when I was nOT tOUCHING mY cOMPUTER at all and the only application running (to my knowledge) was Firefox, which had like 4 tabs open. "So what?" you think. "Who cares?" you ask. Well, my fan was going as hard as it could for several iterations of several minutes. I was starting to worry for my baby's health. Also, lately my battery has been dying way too fast for a laptop in its first year of life. So I was concerned.</p>
<p>Let me walk you through my process over the last hour and a half.</p>
<p>I notice the fan going and going and GOING AND GOING AND GOING AND --</p>
<p>I vaguely remember some fabulous new profiling tool I discovered in the last couple days that showed me CPU usage. What was it? Something short...hblot...<code>top</code>!</p>
<p>I forget why I first wanted to check <code>top</code> out. Oh yeah, I was indexing a bunch of stuff in Elasticsearch and my computer was srsly struggling. It was using around 110 - 135% CPU which at first was utterly confusing, because you can't have more than a hundred per cent of a thing, cuz <em>per cent</em> means <em>OUT OF A HUNDRED</em> and THAT'S NOT HOW THAT WORKS. (I've been reading this blog lately with a lot of YELLING...I'm sorry đ)</p>
<p>Anyway, turns out CPU usage is expressed (at least by <code>top</code>, I don't know whether other tools follow the same principle) in usage of one processor.</p>
<p>Right, so Elasticsearch was doing all this (presumably) computationally expensive stuff, dealing with all the data I was giving it with 0 mappings or structure (types? what's a type?), using >100% CPU. The fan was going crazy then too, so the parallels between these situations are not looking good.</p>
<p>I <code>ctrl-alt-T</code> and <code>top</code> and <code>enter</code> and FIREFOX WAS USING > 100% CPU! WAT THA FROCK! I close it, kill the process (why is that necessary? why didn't closing it like a normal person kill it? so many questions.), reopen it, and great, now 20-30% at rest and 60-70% while using.</p>
<p>I mean, small blessings? But to me, that still seems like an awful lot when I want to have Firefox and Sublime and Opera and Vim and Rhythmbox<sup class="footnote-ref"><a href="https://hboo.ca/posts/2017-04-21-wat-the-flip-does-firefox-think-its-doing-with-138-of-my-cpu-power/#fn1" id="fnref1">[1]</a></sup> and a server or two running alongside it. There's not gonna be enough %s to go around, and somebody is going to be left in the dust.</p>
<p>I do some googling, which suggests:</p>
<ul>
<li>My browser is outdated (no.)</li>
<li>I should enable hardware acceleration (no.)</li>
<li>My addons/plugins are being greedy - okay, maybe!</li>
</ul>
<p>I disable <a href="https://www.mozilla.org/en-US/lightbeam/">Lightbeam</a> as my first action, which brings the CPU usage from 60% to 30% while using and 15-20% if I'm not touching it, although all I have to do to cause a 5-10% spike is mouse over it, so that's weird. Maybe it's a coincidence. Sidenote, Lightbeam is a Firefox browser extension made by Mozilla which tracks websites tracking you basically, and all the requests that happen in your browser. I was originally checking it out as a potential Outreachy project. But if it turns out it takes 30% of my CPU, take it away!</p>
<p>Woohoo! Ok, so now we're making progress. Next I disable session manager which saves all my tabs and reopens them next time I open the browser, which Opera automatically does for me and I adore because I am 100% a tab hoarder. Then I try some browsing while keeping an eye on <code>top</code> and NOPE, back at 50-70%. Shucks, turns out Lightbeam wasn't actually doing any insane-o CPU hogging after all.</p>
<p>So I just straight up switch to Safe Mode, which disables all extensions, to see if any other addons or maybe the whole lot of them combined are being sneaky little buggers. I go to Youtube and before I can even click on anything my CPU usage is back at 138%!!!! I wish I could write numbers in capitals. ONE HUNDRED AND THIRTY EIGHT PERCENT!! (No wait, my teacher always told me, if you say "and", it means hundredths. ONE HUNDRED THIRTY EIGHT PERCENT!!! That's better.)</p>
<p>Anyway I google more stuff and checkout Chrome, which has MULTIPLE PROCESSES RUNNING Chrome wtf u think ur doing?! Pff. This makes it really hard to compare with Firefox's one number because I need to add like 4 or 5 numbers and that is toO many numbers friends. TOo many. Also I'd like to point out that I am semi-gleeful at discovering this, because I've heard some negative things about Chrome eating way more resources than is reasonable and I think maybe I have cracked the secret. Next I try my trusty friend Opera which also has multiple processes! Opera! How could you betray me like this!?? I'll just say each process of Opera and Chrome is generally around 20%. Sometimes they'll go up to 45% or 70% or more.</p>
<p>Now I am googling different stuff: "Why does Chrome use multiple processes". I think this will explain all of Chrome's bad behaviour. Ever. What I find is <a href="https://www.google.com/googlebooks/chrome/">this comic</a>, elaborating some interesting thing on the design of Google Chrome (sorry, I just realized I've been saying "Chrome" as if Google Chrome owns that term. How did they get away with using the universal name for a major part of the browser for <em>their</em> browser? Hmph. Making it confusing out here.), including:</p>
<ul>
<li>Each process is a tab!</li>
<li>This means that if one webpage has something silly like an infinite loop, only that tab needs to be killed as opposed to the whole browser.</li>
<li>This system is based on how operating systems open threads for each process.</li>
<li>This also ensures greater security, as each tab is isolated. (I am definitely simplifying here.)</li>
</ul>
<p>This comic is 39 pages long and I am on page 29. I'll get there eventually. Maybe. I do recommend checking it out though if you're interested.</p>
<p>Bonus - remember how I said I don't need to enable hardware acceleration? I decided this because in my settings, the checkbox for "Enable hardware acceleration" is ticked. Seems pretty clear right? Nah, jk. Checking some more advanced settings page tucked away somewhere (as these things always are) exposed that actually, apparently my OS was blocking this from happening. From what I understand, I don't want to force enable this because bad things could happen, ie, something about webby acceleration scripts exploiting OS vulnerabilities, or something. So I'm just gonna not touch that.</p>
<p>To conclude, I learned some stuff about Google Chrome's design, and I solved nothing so my computer is still a minion<sup class="footnote-ref"><a href="https://hboo.ca/posts/2017-04-21-wat-the-flip-does-firefox-think-its-doing-with-138-of-my-cpu-power/#fn2" id="fnref2">[2]</a></sup> to the browsers siphoning as much power as their grubby paws can. Do let me know if you think you are more smarticle than I in this matter and wish to assist. đ</p>
<p>UPDATE OH MY DOG Opera has calmed down while I've been writing and each process is now using under 10% it's a miracle??!!?</p>
<hr class="footnotes-sep" />
<section class="footnotes">
<ol class="footnotes-list">
<li id="fn1" class="footnote-item"><p>"Yo, why the heck you need two browsers and two text editors?!" Whatever, don't judge me! Sometimes one sucks and you gotta switch over but then that one sucks too so...well...NYEH. <em>sticks tongue out</em> <a href="https://hboo.ca/posts/2017-04-21-wat-the-flip-does-firefox-think-its-doing-with-138-of-my-cpu-power/#fnref1" class="footnote-backref">â©ïž</a></p>
</li>
<li id="fn2" class="footnote-item"><p>This line used to read "...my computer is still a slave". I am trying to remove uses of common tech terms that perpetuate white supremacy from 1) my vocabulary and 2) my bubble, starting with blacklist/whitelist and master/slave. <a href="https://hboo.ca/posts/2017-04-21-wat-the-flip-does-firefox-think-its-doing-with-138-of-my-cpu-power/#fnref2" class="footnote-backref">â©ïž</a></p>
</li>
</ol>
</section>
Adventures with Mozilla Con't
2017-03-20T00:00:00Z
https://hboo.ca/posts/2017-03-20-adventures-with-mozilla-cont/
<p>"Con't" is how I used to abbreviate "continued" when I took notes in HS/uni. The good old days. I could never use my laptop even in university (ie when I had one) to take notes in class because the instant I would get even remotely disinterested, I would be totally gone and only tune back in to be hella confused. Dis bad.</p>
<p>Anyway, since deciding that continuing to explore & contribute to Mozilla would be better than trying to (frantically, because that's apparently the <em>only</em> way) apply for other jobs, I have found myself much happier.</p>
<p>Today I set up <a href="https://opensource.com/resources/what-docker">Docker</a>! Holy smokes finally the time has come! It always gets mentioned - even when I told Stanley I wanted to work on Blaggregator (RC's internal blog aggregator...don't you love that name!), he said:</p>
<blockquote>
<p>Oh, talk about a piece of cake! I added a Dockerfile when I was contributing so now it should be super easy to set up!</p>
</blockquote>
<p>Bah humbug, I thought. Well, that's not quite true. I was just surprised that he thought that made it easier. I thought that made it harder - now I had to set up Docker <em>and</em> the actual code. Docker just always seemed like this magical, elusive technology that advanced devs used, and I couldn't justify taking time to explore it myself because I never really <em>needed</em> it.</p>
<p>Also, I think I like to do things the hard way. Sometimes. Sometimes I am trigger happy and I <code>apt-get install</code> like a..whatever, similies are hard. But then I balance that out by sometimes doing everything I can to avoid installing dependencies. For example, I would like to check out BMO, or <a href="http://bugzilla.mozilla.org/">bugzilla.mozilla.org</a>, Mozilla's bug tracker. I first tried just getting it running. Then I relented and turned to Docker, though still resisted using <a href="https://docs.docker.com/compose/overview/">docker-compose</a>, a Docker container management tool. I sleuthed enough to figure out that the <code>docker-compose.yml</code> file contained some tidbits of tasty info, of which I (perhaps erroneously? I still don't know) decided the only important bits were this:</p>
<pre class="language-yml"><code class="language-yml"> <span class="token key atrule">ports</span><span class="token punctuation">:</span><br /> <span class="token punctuation">-</span> <span class="token string">"80:80"</span><br /> <span class="token punctuation">-</span> <span class="token string">"5900:5900"</span></code></pre>
<p>Ah! This means I must bind the port on my machine (host!) to that on the container. I also decided 5900 was the only important one to bind...probably not true, in retrospect. However, the way I tried to get around this was to amend my command to run the container:</p>
<pre class="language-bash"><code class="language-bash"><span class="token comment"># Original:</span><br /><span class="token punctuation">(</span>sudo<span class="token punctuation">)</span> <span class="token function">docker</span> run bmo-dev<br /><br /><span class="token comment"># New attempt:</span><br /><span class="token punctuation">(</span>sudo<span class="token punctuation">)</span> <span class="token function">docker</span> run -p<span class="token operator">=</span><span class="token number">127.0</span>.0.1:5900:5900 bmo-dev</code></pre>
<p>I tried a few other syntaxes (syntacies?) but nothing seemed to be available in my browser đą so I resorted to installing docker-compose.</p>
<p>Also, I aliased <code>docker</code> to <code>sudo docker</code> because it always needs to be run with root privledges and ain't nobody got time to type sudo every time. I decided this is sufficiently innocuous. Please educate me if I am wrong. Also by "time to type" I mean "brain power to remember to type" and "experience to understand that the error message has nothing to do with debugging docker and everything to do with needing MOAR POWER.".</p>
<p>Things I'm learning:</p>
<ul>
<li>In Perl, <code>$</code> identifies a scalar variable (string, num) while <code>@</code> identifies an array</li>
<li><code>127.0.0.1</code> is the magical built-in-to-my-computer Apache server!</li>
<li>Patience.</li>
</ul>
<p>Tune in next time to find out moar things about Mozilla and Outreachy! And maybe life! I talked to a couple mentors lately about their projects and it is making me super excited at the prospect of being fully involved in them! đ)</p>
I applied to Outreachy, and I didn't use my name
2017-03-14T00:00:00Z
https://hboo.ca/posts/2017-03-14-i-applied-to-outreachy-and-didnt-use-my-name/
<p>It's all in the title. I formally submitted my application to participate in the wonderful Outreachy today. If you haven't heard of it, Outreachy is an amazing internship opportunity to be a (paid!) contributor to FOSS (Free and Open Source Software) for underrepresented groups in tech (more details <a href="https://wiki.gnome.org/Outreachy">here</a>). For Outreachy, this means:</p>
<ul>
<li>women: cis and trans</li>
<li>trans men</li>
<li>genderqueer persons</li>
<li>Black/African Americans</li>
<li>Hispanic/Latin@s</li>
<li>American Indians</li>
<li>Alaska Natives</li>
<li>Native Hawaiians</li>
<li>Pacific Islanders</li>
</ul>
<p>Of relevance to me is the first category listed - women. It is awesome that a buncha companies come together to support these minorities getting involved in tech pursuits. I'm so happy this opportunity exists, because gender equality still has a long way to come.</p>
<p>At my first tech meetup, I had just read this article about <a href="https://www.theatlantic.com/magazine/archive/2014/05/the-confidence-gap/359815/">The Confidence Gap</a>. I found it very compelling, and was still thinking about it as I watched the presentations. I signed up that day, in the spirit of the article, to do something I felt underqualified for (some of you, dear readers, may know that this has since been a motto of mine) - give a talk at the next meetup about this very topic. This "Confidence Gap" the authors speak of refers to the statistical truth that women less frequently do all manner of things such as apply for jobs or promotions when they don't meet 100% of the listed qualifications. Unfortunately, the side of this coin that they focus on - women's lack of confidence in themselves - is only half the story, <em>if</em> that. The other half, of course, is the rest of the world discounting and undermining women's abilities and contributions.</p>
<p>I wanted to make sure I tied my talk back to tech - how lucky for me that there was an analysis of Github contributions by gender recently released (<a href="https://peerj.com/preprints/1733/">here</a>, more readable version with more opinions <a href="https://www.theguardian.com/technology/2016/feb/12/women-considered-better-coders-hide-gender-github">here</a>). The findings were that pull requests (PRs) from women were accepted more often than men - across the top 10 languages! Holy smokes! Then comes the twist-ending: women who were socially identifiable as women (typically female names, avatars, etc) had PRs accepted <em>less</em> than men, while women with gender-neutral profiles had PRs accepted <em>more</em> than men.</p>
<p>Ulp*.</p>
<p>Fast forward a few months. I finished my stint at the <a href="https://recurse.com/">Recurse Center</a>, a beautiful programming community where I never had to give a second thought to being a woman. Recently someone I vaguely know shared <a href="https://www.attn.com/stories/15518/creative-sexism-experiment-female-co-worker">this article</a> along with a comment explaining "This is why I go by <uncommon, not-decidedly-gendered name>". This made me think hard about going by a name that wouldn't "obviously" express my gender.</p>
<p>The first problem with this is that I <em>like</em> my name. I don't want to actually be known by and called an alternative name. However, I thought that perhaps I could just change it on Github. Maybe just my @handle. I already changed my IRC nick from <code>heatherboo</code> to <code>hboo</code> (a name which I have since been informed is still decidedly feminine), due to this whole sexism thing, as well as being encouraged by IRC guides (Mozilla's own I believe) to not use a female nick unless I want to be harrassed. Thus, why not change my Github username too? That's what most people see when I go to make a contribution, raise an issue, or comment on anything. I get to know people by their 1) Github usernames and 2) IRC nicks. It should be easy enough to change my username, and maybe even my listed name. Then people would respect me more. They wouldn't mansplain stuff. They would take me more seriously. I wouldn't be "just a dumb girl" or "just a front end developer"**.</p>
<p>Thus I submitted my application to Outreachy with the "male version of my name", Heath. In doing this I discovered the many things intertwined with changing my name - my Google account and email address. My other email address. My resume. Job applications. The degree to which this change felt like it needed to propogate in order to be worth doing began to be more than a tad ominous.</p>
<p>I started writing this article. I consulted a trusted friend in tech about this name-change dilemma. Many important points were raised - including by just re-reading some of the article on Github contributions I linked above. The grand takeaway though, is that continuing to publicly present as a woman is important for solidarity. As a new contributor to Mozilla projects, I gravitate towards working on ones with female main contributors. I look up to them for no reason other than they are <strong>a woman in tech</strong>. Increasing the visible presence of minorities in tech is a cause in-and-of itself, and while it means I give up the chance to masquerade as a man, be given opportuities and credit where I wouldn't otherwise, and then reveal my true identity and "prove" the "real" value of women to people who favour men, it's also incredibly valuable. It also may even have perks of its own - as one woman is quoted in the above article as saying:</p>
<blockquote>
<p>...if my gender has any effect at all, I feel they [the men] go out of their way to support my efforts to learn and make more contributions.</p>
</blockquote>
<ul>
<li>Jenny Bryan, professor at the University of British Columbia and contributor to R</li>
</ul>
<p>This brings us full circle, back to Outreachy - communities may be putting in that little bit of extra resources to support minorities in tech. And that is a beautiful thing.</p>
<p><span class='hboo-vertical-space'></span></p>
<hr />
<p>* <em>Ulp</em>. The sound one makes when swallowing a big ol' ball of fear and dread.</p>
<p>** "just a front end developer" - I remember someone complaining she was sick of going to tech events and having people assume she was "just someone's girlfriend", "just a designer", or "just a front end developer". Ick! Front end development isn't exactly a cake walk as far as I'm concerned. Please inform me if I am just a dumb girl front end developer, and that that must be why I think front end dev is a nontrivial task.</p>
<p>Bonus point, made to me: "If you don't want to work at a place that doesn't like women, isn't the best way to weed them out...to be a woman?" Touché.</p>
<p>**Please excuse my use of terms like "obviously" in regards to gender expression. I know it is not black and white, and I generally try not to engage in binary, traditional gender-appearance assumptions. I hope their relevance in this case is understood, and please feel free to let me know via whatever means you please (if you're looking for a way, <a href="https://twitter.com/hboo_codes">Twitter</a> or perhaps a <a href="https://github.com/heatherbooker/blog/issues">Github issue</a> could be good.) if you disagree with or take issue with anything I said.</p>
Things that seem like they happen in jobs but never in job interviews
2017-03-08T00:00:00Z
https://hboo.ca/posts/2017-03-08-things-that-seem-like-they-happen-in-jobs-but-never-in-job-interviews/
<p>Maybe it's just because I've been setting up wackloads of dev environments and picking projects, but this whole <em>Prepping for <a href="https://wiki.gnome.org/Outreachy">Outreachy</a></em> business is making me think that there's a lot more to jobs than all these job interviews involving little code challenges get at. There's a baloney-ton of:</p>
<ul>
<li>Talking to people</li>
<li>Figuring out what to work on</li>
<li>Stalking channels on IRC</li>
</ul>
<p>Nah, actually I guess this stuff is probably pretty specific to my current situation. (The last one was kindof a joke, except it's definitely true.) I am also spending a ton of time waiting, for:</p>
<ul>
<li>Tests to run</li>
<li>Setup scripts to run / Installs + Downloads to finish</li>
</ul>
<p>like sometimes more than an hour. What! Never in my life have I waited so long for anything.* I guess I sortof also wait for</p>
<ul>
<li>Answers on how to proceed / Help</li>
<li>PR approval / Feedback</li>
<li>Conversations to happen on IRC that I can stealthily glean information from</li>
</ul>
<p>Hopefully once I am more involved in the community and more informed about proper processes and procedures, I will feel less of a need to do that last one.</p>
<p>Anyway, it just feels like I do a lot of "meta" tasks, and less actual "programming" tasks lately. To counter that, I've also been trying to throw a few <a href="https://www.hackerrank.com/heatherbooker">HackerRanks</a> in to keep myself sharp. When I can ignore the hair-rip-out-inducing input forms of these HackerRanks, they are pretty fun lil thangs! I remember some people at RC raving about how addicting they are, and now that I spend all day job hunting (sort-of), they certainly are a tasty treat...I can very much see how one might wind up not wanting to walk away.</p>
<p>Another note - my monitoring of IRC is not good for me. It's like when online-checkins started at RC; I see what everyone else is doing, and how they're interacting with others, and I get sad that I'm not doing that. Let's look at some possible solutions (gee, I hope these fancy new markdown tables I just learned how to build render into HTML (did I use the word 'render' gramatically there?)).</p>
<table>
<thead>
<tr>
<th>Solution</th>
<th>Pros</th>
<th>Cons</th>
</tr>
</thead>
<tbody>
<tr>
<td>Don't lurk on IRC.</td>
<td>Wait, why does this column exist. The pro of all of these is obvi to not get sad.</td>
<td>FOMO! Miss out on: helping people, seeing other people be helped, gossip, internal decision making, bugs, feature and product discussion</td>
</tr>
<tr>
<td>Participate</td>
<td>Ah this has a bonus pro of obtaining more information and potentially making contacts!</td>
<td>May annoy/burden people, takes time, must constantly check because I can't figure out how to get notified, have to pick 0) channel and 1) topic and 2) words</td>
</tr>
</tbody>
</table>
<p>My biggest concern with participating more is that these people already spend a lot of their time managing wannabe contributors and I want to be independent and only ask for help when necessary. At the end of the day, it's probably just like most things - there is no right answer. Just <em>whatever</em>.</p>
<p>This post has rambled. I'm out.</p>
<hr />
<p>* It is definitely a lie that I have never waited more than an hour for anything. Things I have waited more than an hour for include:</p>
<ul>
<li>Flights (to get on)</li>
<li>Flights (for other people to get off)</li>
<li>Bedtime</li>
<li>Dancing</li>
<li>Mail</li>
</ul>
<p>However - when I wrote that, I was reminded of the thought that "Never in my life have I worked so hard for anything.", which is how I feel about programming. This probably deserves to be an article on its own, but it's a truth - never in my life have I worked so hard for anything as I have to learn to code. This is a fact that continues to awe me. Stay tuned for further notes on this matter.</p>
Xianny's awesome Jekyll post generator
2017-02-28T00:00:00Z
https://hboo.ca/posts/2017-02-28-xiannys-awesome-jekyll-post-generator/
<p>Oops, note to self - need to strip special characters such as apostrophes from file names. (Guess how I came up with that one..[1]).</p>
<p>Having got all this Jekyll stuff finally up and running, I was dying from manually formatting all of my posts and their titles. Seriously, typing out the whole date for every post's file name?! Terrible. Also, srsly, what kind of programmer am I if I keep doing something manually. What is even the point.</p>
<p>Unfortunately, shell scripting is <em>not</em> my forte. It is so confusing. I remember one day at <a href="https://recurse.com/">RC</a>, AJ (teehee, two two-letter acronyms, I am Heather-two-two over here) showed me a couple quick things about it and I was amazed. Then I read <a href="https://strugee.net/blog/2017/02/rc-week-7">this blog</a> post where he talks about</p>
<ol>
<li>how he and Aditya solved a Code Dojo with a bash script (!!!), and how</li>
<li>Aditya asked about type-casting in bash.</li>
</ol>
<p>AJ thought that was funny, because bash doesn't have a type system. What?! That explains this one problem I couldn't solve a while back, and why the internet wouldn't tell me how to coerce a string to a number in my shell script... -_-</p>
<p>Anyway, you can see this snippet from my (appallingly large collection of) desktop notes that <em>desperately</em> desires this Jekyll-generating script in my life:</p>
<p><img src="https://hboo.ca/img/post-generator-wanted.png" alt="it has a lot of exclamation points. because i wanted it." /></p>
<p>And then, in checking out the Blaggregator feed (that I finally added myself to! *cue emoji with monkey covering its eyes*), I came upon Xianny's blog post where she wrote the PERFECT SCRIPT! <s>You should definitely <a href="https://journal.xianny.com/2017/02/21/autogen-jekyll-new-post.html">read it</a>! Go. Right now.</s> Link is dead! đą</p>
<p>This was beyond perfect. I am so happy right now.</p>
<p>I made a couple of <a href="https://gist.github.com/heatherbooker/50672cef429e667270b39c0d19f44fe3">tweaks</a>, namely:</p>
<ul>
<li>if <code>-d</code> is passed as a command line option, add <code>draft: true</code> to the front matter[2] of the post instead of adding it to a _drafts dir.</li>
<li>make post titles all lowercase in filenames.</li>
</ul>
<p>This second undertaking involved a very tiny addition, surprisingly.</p>
<pre><code># Before:
# (The - before the $ is not fancy bash shtuff...it's just a dash.)
TITLE+="-$word"
# After:
TITLE+="-${word,,}"
</code></pre>
<p>Not bad hunh?! And now all I did to write this post was type <code>./new "Xianny's awesome Jekyll post generator"</code>!</p>
<p>(Also I had to write the rest of the post and screenshot my note, but...ya know, that was CHILD'S PLAY.)</p>
<p>Thank you Xianny!!</p>
<p>PS - If I forget to fill in the <code>categories</code> field in the front matter, this happens:<br />
<img src="https://hboo.ca/img/fill-me-in.png" alt="nonsense categories on the post" /><br />
because I set it to do that, so I won't forget. It's sorta functional to that end I guess? I am snort-laughing because I tried to help myself but it turns out I am un-helpable.</p>
<p>PPS - If you don't use Jekyll, you may not know why I want to strip apostrophes, or what front matter is.</p>
<p>[1] I want to strip non-alphanumeric chars from titles when they become filenames. I have a feeling they don't belong there.<br />
[2] Front matter is this configuration crap that goes at the top of every post. Stuff like the layout, title, categories, etc.</p>
<p>PPPS - Help, I think I am addicted to writing blog posts.</p>
How to use Heroku Scheduler with Node.js
2017-02-27T00:00:00Z
https://hboo.ca/posts/2017-02-27-how-to-use-heroku-scheduler-with-node/
<p>While there are <a href="https://stackoverflow.com/a/13956024">multiple</a> <a href="https://www.spacjer.com/blog/2014/02/10/defining-node-dot-js-task-for-heroku-scheduler/">tutorials</a> out there on using the Heroku Scheduling add-on with Node.js, they all seem to suggest the same strange series of steps. I can't understand why they all recommend</p>
<ul>
<li>putting your scheduled task in a file without an extension...</li>
<li>in a directory called 'bin', and...</li>
<li>executing it without specifying <code>node</code> in the command, but instead adding <code>#!/path/to/node</code> to the top of the task file.</li>
</ul>
<p>I originally didn't look at any of these tutorials - I guessed from the examples using other languages in the <a href="https://hboo.ca/posts/2017-02-27-how-to-use-heroku-scheduler-with-node/">Heroku docs</a> that I could just write a normal <code>javascriptfile.js</code> and execute it by running <code>heroku run node javascriptfile.js</code>.</p>
<p>However, Heroku also asserts that you should be able to test your task by running <code>heroku run my task</code> locally, but every time I tried this, it would fail with the following error:</p>
<pre class="language-bash"><code class="language-bash"></code></pre>
<p>Wait, hold on just one cott'n pickin' secon'. I just went to run it so I could dutifully copy the <em>exact</em> error message for y'all, and it ran WITHOUT GLITCHES. wAT?!??</p>
<p>Well. My only proposed explanation is that all the times I ran this in the past, I either</p>
<ol>
<li>hadn't added, committed, and pushed the file to Heroku, or</li>
<li>hadn't waited long enough after adding, committing, and pushing to Heroku for it to be available.</li>
</ol>
<p>Idk if that last one makes any sense. But I swear it has to be something like that, because after reading a tutorial that (said I should be able to do it the way I <a href="https://www.modeo.co/blog/2015/1/8/heroku-scheduler-with-nodejs-tutorial">was doing it</a>, plus) specified adding and committing and pushing the file before trying to <code>heroku run</code> it, I definitely made sure I had done that.</p>
<p>Anyway, where I <em>was</em> going with this was to say that it kept claiming it couldn't find the <code>javascriptfile.js</code> that I was telling it to run. Because my task wouldn't necessarily output anything every time it ran, I simply added an extra line so it would email me every time the file was executed. I also added a similar line to the sibling file that I had copied into the /bin dir and removed the .js from and added the path/to/node to, plus a comment telling me which was which.</p>
<p>My Heroku scheduled tasks now looked like this:</p>
<p><img src="https://hboo.ca/img/heroku-scheduler.png" alt="'node task.js' and 'task'" /></p>
<p>I gratefully soon received an email from my task! It was from the file I had originally included - the one that made structural sense to me. Phew. Maybe I do understand things after all.</p>
<p>Now I wait to see if the other file will also send me an email! I hope the suspense doesn't kill me. If it doesn't, I'll just delete it. If it does, I'll delete it anyway.* Teehee - it's all for <strong>science</strong>!</p>
<p>* I'll delete it anyway because I don't need two files for one task, and I wanna keep the one I came up with all on my own! <img src="https://hboo.ca/img/heart-emoji.png" alt="heart eyes face" /></p>
Oh god Vim is broken
2017-02-24T00:00:00Z
https://hboo.ca/posts/2017-02-24-oh-god-vim-is-broken/
<p>I tried to start writing another post but vim is back to its old habits of appearing to insert weeeeeiiiiiird characters as I type.</p>
<p><img src="https://hboo.ca/img/vim-is-corrupt.png" alt="weird stuff happening here. boxes with 0s and 1s and Bs, and qs and 6s." /></p>
<p>It does this from time to time...I must have messed with some config somewhere. Anyway, PLZ HALP, AM NEED HALP.</p>
<p>I believe it has to do with the character encoding or colours for my shell or something. I am also suspicious that it might have happened when I uninstalled jedi-vim.</p>
<p>It's funny because the other day I was typing and I hardly noticed the weird visual corruption, which made me think of when Rose at RC said having a Linux system hasn't led to an improvement in her ability to solve problems with the OS; instead, her tolerance for living with things being screwed up has increased. I think that is definitely sometimes true. I will go through phases of tolerating-to-the-point-of-not-noticing glaring flaws in my setup, and then desparately trying to fix whatever it is. This has included:</p>
<ul>
<li>when I broke my Windows partition</li>
<li>my computer freezing when plugged into an external display</li>
<li>the mouse being clicked randomly all over the screen whenever the laptop lid was closed</li>
<li>so many things with vim</li>
<li>I don't even know</li>
</ul>
<p>It's an interesting life. I like the challenges that come along with using Linux. Without them, there are 1001 things I would never have learned. Maybe closer to 1,000,001 things.</p>
What is route protection?
2017-02-23T00:00:00Z
https://hboo.ca/posts/2017-02-23-what-is-route-protection/
<p>When I searched this, I found a lot of mentions of Laravel and PHP. Whaat? What is this Laravel? And I certainly donât want to start getting involved with PHP. Surely there is a simpler explanation for this!</p>
<p>Well, now there is! Right here. On your very own screen.</p>
<p>âRoute protectionâ is a term referring to the idea that not all users should be able to access all parts of your app. These parts of your app are (theoretically) accessible at various <em>routes</em> or <em>URLs</em>. For example, perhaps users who are not logged in should be denied access to <a href="http://somewebsite.com/fancystuffyouhadtopayfor">somewebsite.com/fancystuffyouhadtopayfor</a>. Therefore, you may wish to either use a service/plugin, or add some simple logic to your app to "protect" any private or restricted routes.</p>
<p>I was so confuseded when someone said I should use "route protection"; I guess it's just one of those things that are so obvious to the people who know it that they don't see it as worth explaining.</p>
<p>Also, I started writing this post many months ago. I should have just finished it when I started it! Anyway, here it is now. I hope it helps.</p>
Day Whatever @ RC
2017-01-24T00:00:00Z
https://hboo.ca/posts/2017-01-24-day-whatever/
<p><strong>What am I doing?</strong><br />
I'm waiting for git to finish cloning Mozilla's Bedrock repo.<br />
<strong>Why?</strong><br />
So I can set up a dev environment to contribute to Mozilla.<br />
<strong>Why?</strong><br />
So I can get my first bug fix in and give back to FOSS (Free Open Source Software)!!<br />
<strong>Why?</strong><br />
So I can work with Mozilla in the Outreachy project! â€ïž</p>
<p><strong>Thoughts</strong><br />
Following along with their docs on setting up the dev environment is amazing! But of course I have just one suggestion...they say</p>
<blockquote>
<p>If you are on Linux, you will need at least the following packages or their equivalent for your distro:<br />
python-dev libxslt-dev</p>
</blockquote>
<p>Now, in particular because one of them starts with 'python', I tried to <code>pip install</code> both of them. Eventually I realized they needed to be <code>apt-get install</code>ed instead. Whoops.<br />
But maybe people who can't realize that by themselves will struggle even more to actually contribute to the code base...so maybe it's an early test. I passed!</p>
<p>GAH<br />
The tests for some reason don't all pass! So I ran them one by one until I found a culprit - bedrock/newsletter. I don't know what that means or if it'll be helpful, but I feel like I made progress so that's cool.</p>
How to use Sails.js with Pug
2017-01-07T00:00:00Z
https://hboo.ca/posts/2017-01-07-how-to-use-sails-with-pug/
<p>You may know by now that I like to make <a href="https://hboo.ca/posts/2016-08-24-how-to-vue-directive-npm">tutorials for things with dismal search results</a>, and this is no different. The search results when I queried for the title of this post included the following:</p>
<p><img src="https://hboo.ca/img/use-sails-with-pug.png" alt="pugs on sailboats. not the sails or pugs I wanted." /></p>
<p>Yeah. Not exactly what I was looking for. So I started by following <a href="https://www.youtube.com/watch?v=ep6EQ5f82Ts&list=PLf8i4fc0zJBzLhOe6FwHpGhBDgqwInJWZ&index=3">a video tutorial</a> (just kidding, actually I started by blindly trying to merge the basic sails app with my pre-existing code, which was painfully unsuccessful) to the T just to get an idea of how sails works, seeing as Iâm still more than a little confused about routing and http and servers and databases. I shall now extrapolate the process of converting this project to use pug, to a tutorial on starting a sails app with pug.</p>
<p>Normally you would be able to generate a project using a different templating engine than the default EJS, but it seems the name transition from Jade â Pug is not complete. The closest we can get (until <a href="https://www.npmjs.com/package/sails-generate-views-pug">the Pug views generator</a> is publishedâŠ) (<strong>Update: itâs a thing!</strong>) is to run</p>
<pre class="language-bash"><code class="language-bash">sails new puggity-project --template<span class="token operator">=</span>jade</code></pre>
<p>in the terminal to make a new sails project called âpuggity-projectâ. Be sure that you have sails installed globally before trying to run this commandâââyou can do that using the following command (also in the terminal)Â :</p>
<pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> <span class="token function">install</span> sails -g</code></pre>
<p>You may need to preface the command with âsudoâ if this command spits back a bunch of mumblebump about permissions.</p>
<p>Now we need to change all of the Jade config to Pug, including changing filename extensions in /view to .pug, installing pug, and changing the view engine.</p>
<pre class="language-bash"><code class="language-bash"><span class="token builtin class-name">cd</span> puggity-project/views<br /><span class="token keyword">for</span> <span class="token for-or-select variable">file</span> <span class="token keyword">in</span> *.jade<span class="token punctuation">;</span> <span class="token keyword">do</span> <span class="token function">mv</span> <span class="token variable">$file</span> <span class="token variable"><span class="token variable">`</span><span class="token function">basename</span> $file .jade<span class="token variable">`</span></span>.pug<span class="token punctuation">;</span> <span class="token keyword">done</span><br /><span class="token function">npm</span> i --save pug</code></pre>
<p>Open config/views.js and change the line that says <strong>engine: âjadeâ</strong> to say <strong>engine: âpugâ</strong>.<br />
You should now be able to run</p>
<pre class="language-bash"><code class="language-bash">sails lift</code></pre>
<p>or</p>
<pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> start</code></pre>
<p>(whichever you preferââââsails liftâ is their cute start command but for consistency if you work with other npm projects, you might appreciate using ânpm startâ.)<br />
From this point you can basically follow <a href="https://www.npmjs.com/package/sails-generate-views-pug">this tutorial I linked above</a>, being mindful that when the EJS is mentioned, you will need to take the appropriate action but using Pug syntax/files.</p>
<p>Some little notes:</p>
<ul>
<li>In new .pug files, you will need to start with</li>
</ul>
<pre class="language-pug"><code class="language-pug"><span class="token keyword">extends ../layout</span><br /><span class="token keyword">block body</span></code></pre>
<ul>
<li>For ep.3: watch the updated version (which is later in the playlist)</li>
<li>In ep.3: the <code>sails generate user</code> command is going to need to be <code>sails generate api user</code></li>
<li>After running running <code>sails generate api user</code>, you may need to go into config/models.js and set uncomment the âmigrateâ line (I also changed it to <code>migrate: âsafeâ </code>, because I like the sound of âsafeâ!) to avoid command line error msgs</li>
</ul>
<p>In episode 3, you create a form with one input as follows:</p>
<pre class="language-html"><code class="language-html"><input type=âhiddenâ name="_csrf" value=â<%= _csrf %>" ></code></pre>
<p>However, the <% ⊠%> syntax is specific to EJS templates; we need to puglify it! (Not uglifyâŠpug syntax is definitely prettier to my eyes!) Our version will look like this:</p>
<pre class="language-pug"><code class="language-pug"><span class="token tag">input<span class="token attributes"><span class="token punctuation">(</span><span class="token attr-name">type</span><span class="token punctuation">=</span><span class="token attr-value"><span class="token string">"hidden"</span> name<span class="token operator">=</span><span class="token string">"_csrf"</span> value<span class="token operator">=</span> _csrf</span><span class="token punctuation">)</span></span></span></code></pre>
<p>Voila! Câest beautiful.</p>
<p>Then in episode 5, you get into making variables available to your views, which you can read more about in the locals documentation of Sails. They can then be accessed in the Pug-typical way (as seen above for the input âvalueâ attribute), by appending an equals sign, a space, and the variable name to either an attribute or a tag.</p>
<p>There you go! I hope this helps you get started whipping up a Sails.js + Pug app. If you need more inspiration or to see some code, check out my sails + pug project code or the app itself! Good luck and have fun! đ</p>
<p><em>Note</em>: This post was migrated from its <a href="https://medium.com/@heatherbooker/how-to-use-sails-js-with-pug-d3ded437c895#.drv7vifry">original home on Medium</a> on February 23, 2017.</p>
Day 11 (or 8) @ RC
2016-11-16T00:00:00Z
https://hboo.ca/posts/2016-11-16-where-am-i/
<p>This post was originally labelled "Where am I".<br />
I'm not entirely sure whether I should count Monday to Fridays, or weekends too - weekends too I guess, since Fridays themselves aren't even techically normal work days.</p>
<p>Day 11 it is then.<br />
Here's some things I have been doing:</p>
<ul>
<li>socializing</li>
<li>helping people debug</li>
<li>getting help debugging</li>
<li>pairing to solve little puzzles</li>
<li>eating</li>
<li>walking</li>
<li>reading Zulip (internal chat system)</li>
<li>solving Nand to Tetris projects</li>
<li>jumping around spastically from project to project</li>
</ul>
<p>So there's the good and the bad. What did I come here to do? What kinds of things do I want to learn, do, practise, or improve at?</p>
<p>HARD SKILLS</p>
<ul>
<li>low level comprehension from hardware to OSes</li>
<li>using debugging tools for Javascript</li>
<li>knowledge of algorithms, big O complexity, data structures</li>
</ul>
<p>SOFT SKILLS</p>
<ul>
<li>reading other people's code and knowing what's going on</li>
<li>giving and taking programming instructions verbally</li>
<li>being confident in my abilities</li>
</ul>
<p>My big project is to build an interactive-web-app-guide-follow-along that assists other people who want to work through the <em>Nand to Tetris</em> <a href="https://www.nand2tetris.org/">course</a> and/or accompanying book, <em>The elements of Computing Systems</em>. I have been extremely lucky to have a group of people here with whom I can talk about and solve problems, but if I hadn't, I highly doubt that I would have stuck with it. I am also aware of many others who wish they could be/have been part of such a group, and David Branner in particular suggested that a guide would be wonderful. James suggested putting it in interactive web app form, which was perfect timing because I just watched an <a href="https://www.youtube.com/watch?v=8aGhZQkoFbQ">awesome animated explanation of the javascript event loop in browsers</a>.</p>
<p>I am holing myself away in a room in an attempt to focus better. Result: focusing excellently on writing this blog post. Nice try. -_-</p>
Day 3 @ RC
2016-11-09T00:00:00Z
https://hboo.ca/posts/2016-11-09-day-3/
<p>TO DO:</p>
<ul>
<li>ask Michelle about Markov chains</li>
</ul>
Day 2 @ RC
2016-11-08T00:00:00Z
https://hboo.ca/posts/2016-11-08-day-2/
<p><strong>My Computer</strong></p>
<p>Su helped me fix my Windows partition!! Holy smokes! She is a magician!! â€ïž<br />
I should definitely have been able to do it myself - we just reset the whole thing. But it was fun to not have Windows for a while and just live that way. Because whatever.</p>
<p>Also, my poor boring new computer has some new digs - Stanley was sharing some of his long-collected stickers! So I have the git logo, the github octocat, and a fancy octocat from their culturally diverse collection. Wow I should totally not be writing this o.o .</p>
<p><strong>Nand to tetris</strong></p>
<p>I started reading the associated book and it really kind of stinks. It's hard. It's super not fun. I have no idea what they're saying.<br />
Then I was accidentally sitting in a checkin room and Michelle came in so I told her what was up and she told me to find a logic gate sandbox online and mess around. So I read <a href="https://whatis.techtarget.com/definition/logic-gate-AND-OR-XOR-NOT-NAND-NOR-and-XNOR">this</a> and used my brain and played <a href="https://www.neuroproductions.be/logic-lab/">here</a> and it's much more fun and more satisfying.</p>
<p><strong>Veggiematarian</strong></p>
<p>Everyone is so encouraging and helpful. They have all these suggestions of what I can eat that is cheap and veg. I love it. It's amazing.</p>
<p><strong>I helped a person do a thing!</strong></p>
<p>I was totally just a rubber duck. The problem was totally something I do all the time. It was having an incorrect file path. Love it.</p>
<p><strong>Stuff that was interesting that I wasn't actually involved in</strong></p>
<p>Listening to James help Veronica set up her dev environment.</p>
<p><strong>To Do:</strong></p>
<ul>
<li>build a tool that automatically RSVPs me to every event on Zulip, adds it to my google calendar, and then tells me I'm going</li>
<li>build my tesselating youtube video text-in-image processing tool</li>
<li>write hand pricking web app using unhosted</li>
</ul>
RC: Day -2
2016-11-05T00:00:00Z
https://hboo.ca/posts/2016-11-05-day-negative-2/
<p>Today is the day before the day before I will begin a series of days at <a href="https://recurse.com/">the Recurse Center</a>. I have two reasons for writing thisâââOne, they suggest keeping a blog to track your learning etc., but even before that, I read a few blogs from people who went to RC and did just that, like <a href="https://jvns.ca/blog/2013/09/26/hacker-school-day-4-c-unit-testing/">Julia Evans</a>. It was really cool to see what they were doing, and I kindof want a place to organize my thoughts.</p>
<p>I was looking at some job postings and a surprising number of them mentioned âScalaâ. I donât even know what category of language Scala is. Also, a lot of them were data science or machine learning based; or maybe it just seems disproportionately that way because they are âoff-limitsâ to me. I would love to dive into some of that stuff, machine learning and AI in particular, but I donât see 3 months being quite sufficient to really get very far.</p>
<p>To Do:</p>
<ul>
<li>look at Scala</li>
<li>forget about whether learning X will help me get a job</li>
<li>put up No-Frills API so I can start on Nand-to-Tetris on Monday</li>
</ul>
<p><em>Note</em>: This post was migrated from its <a href="https://medium.com/@heatherbooker/rc-day-2-632e910b7c17#.r6xkbrdyw">original home on Medium</a> on February 23, 2017.</p>
How to publish an Vue.js directive to npm
2016-08-24T00:00:00Z
https://hboo.ca/posts/2016-08-24-how-to-vue-directive-npm/
<p>Wow, so Iâm always amazed when something I want to know how to do doesnât stare right back at me in the top 5 Google results. Iâm sure you can guess why I am writing this article today (hint: check the title), but be assured that I have previously been unsuccessful in my mission to publish my Vue.js directive to npm. Please join me for a thrilling recount of my journey to enlightenment.</p>
<p>So the original version of <a href="https://github.com/heatherbooker/vue-sticky-scroll">my directive</a> just had</p>
<pre class="language-js"><code class="language-js">Vue<span class="token punctuation">.</span><span class="token function">directive</span><span class="token punctuation">(</span><span class="token string">'name-of-directive'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span><br /> <span class="token comment">// Definition</span><br /><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Stupidly simple. Perfectamundo. Works great when you just drag the file in, either by cloning/downloading or using a <a href="https://rawgit.com/">CDN</a>.</p>
<p>But it isnât enough to make this work as an npm package. (I know because I tried it.) For that, we will need to sleuth a little moreâââI did this by investigating a bunch of <a href="https://www.npmjs.com/search?q=vue+directive">other peopleâs directives</a> that were already available through npm. I think I must have sleuthed <em>too</em> hard the first time, because it turns out that making a Vue directive work as an npm package is also pretty stupidly simple.</p>
<p>It can be done by essentially the same principle as making anything else available both through npm and a non-node environment (such as a CDN or direct use of the file), which is as follows:</p>
<pre class="language-js"><code class="language-js"><span class="token comment">// Before you create your Vue.directive:</span><br /><span class="token keyword">try</span> <span class="token punctuation">{</span><br /> <span class="token keyword">var</span> Vue <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'vue'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span>e<span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token comment">// It's all good, Vue should already be available globally.</span><br /><span class="token punctuation">}</span><br /><span class="token comment">// Then create your Vue.directive as a variable:</span><br /><span class="token keyword">var</span> myDirective <span class="token operator">=</span> Vue<span class="token punctuation">.</span><span class="token function">directive</span><span class="token punctuation">(</span><span class="token string">''</span><span class="token punctuation">,</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token comment">// Finally, check if you should export it:</span><br /><span class="token keyword">try</span> <span class="token punctuation">{</span><br /> module<span class="token punctuation">.</span>exports <span class="token operator">=</span> myDirective<span class="token punctuation">;</span><br /><span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span>e<span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token comment">// No problem, it should be registered as is.</span><br /><span class="token punctuation">}</span></code></pre>
<p>The try/catch clauses could also be <code>if</code> statements, where you check the environment before doing what needs to be done:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">typeof</span> module <span class="token operator">!==</span> <span class="token string">'undefined'</span> <span class="token operator">&&</span> <span class="token keyword">this</span><span class="token punctuation">.</span>module <span class="token operator">!==</span> module <span class="token operator">&&</span> module<span class="token punctuation">.</span>exports<span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">var</span> Vue <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'vue'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><span class="token comment">// Continue as above, replacing final 'try/catch' with above 'if'</span></code></pre>
<p>But there is some discourse on the best way to do thisâââwhether checking the first and last clauses is sufficient (<a href="https://underscorejs.org/docs/underscore.html#section-11">Underscore</a> does it this way) or the first and second clauses are a preferable pair. Let me know if you have thoughts on the <code>try/catch</code> vs <code>if (module)</code> dilemma.</p>
<p>Of course, everything should be wrapped in an anonymous, self-invoking function to prevent bloating of the global namespace if users are not using node.</p>
<pre class="language-js"><code class="language-js"><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token comment">// Do all the things;</span><br /><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>In any case, either of the above should be sufficient to make your directive available through both platforms. Now all you have to do is npm publish!</p>
<p><em>Note</em>: This post was migrated from its <a href="https://medium.com/@heatherbooker/how-to-publish-an-vue-js-directive-to-npm-e98600fb5d2f#.ngsetlhae">original home on Medium</a> on February 23, 2017.</p>
How to make a reusable âdirectiveâ in Vue.js
2016-08-12T00:00:00Z
https://hboo.ca/posts/2016-08-12-how-to-vue-directive/
<p>I like Vue.js. A lot. (See my <a href="https://hboo.ca/posts/2016-06-15-vue-vs-react">comparison with React.js here</a>.) It is a beautifully simple, straightforward, and superbly functional view-layer framework. Iâve gone over most of the docs multiple times, and I am absolutely enamoured with the clarity they exude. They donât use stupidly obscure words or send you around in circles trying to find what you want. They make you and Vue Just Work.</p>
<p>However, I had a weak spotâââthe âCustom Directivesâ page. I avoided it for the longest time. Not being familiar with Angular (which everyone else seemed to be comparing these âdirectivesâ to those âdirectivesâ), I did not understand what a âdirectiveâ was or why I might want to use it. I couldnât find a page explicitly labelled âNormal Directivesâ so I decided these custom âdirectivesâ were probably super insanely advanced.</p>
<p>Anyway, as it turns out, smack dab on the <a href="https://vuejs.org/guide/overview.html">Vue.js overview</a> page is a succinct introduction to âdirectivesâ:</p>
<blockquote>
<p>Directives are prefixed with v- to indicate that they are special attributes provided by Vue.js, and as you may have guessed, they apply special reactive behavior to the rendered DOM.</p>
</blockquote>
<p>Yup, that is right out of the docs. Apparently it was <em>too</em> succinct for me. If any of you are like me, let me see if I can break down what a âdirectiveâ is even more.</p>
<p>âDirectivesâ in Vue.js are handy little tools or services that <em>do something</em> to a component. Simply by adding âv-your-directive-nameâ as an attribute (like âclassâ or âv-bind:whateverâ or âstyleâ are all attributes) in your markup as follows â</p>
<pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">v-some-directive</span><span class="token punctuation">></span></span>BLAh blaH BLAH or whatever<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span></code></pre>
<p>â you will find that this div now has whatever behaviour the directive specifies.<br />
But what is the difference between:</p>
<ul>
<li>a directive and a component?<br />
See, a component <em>is</em> a thing. A directive <em>does</em> a thing.<br />
Clear as mud? Good. (Weâll get to an example soon.)<br />
What about the difference between:<br />
-a directive and a plugin?<br />
Wait, what <em>is</em> the difference between a directive and a plugin?</li>
</ul>
<p>Well, on this distinction, I admit I really <em>am</em> seeing it clear as mud. It seems that a directive can be, or become, a plugin. Or is it that plugins can be encapsulated in directives? Perhaps if I end up needing to make a plugin, then my comprehension will be strengthened. Please do let me know if you are wiser than I on this topic.</p>
<p>Anyway, now that Iâve bored you to death with the blabbing, letâs dig right in and see a useful example of a custom directive. <a href="https://github.com/heatherbooker/vue-sticky-scroll">Check out the code on Github</a>.</p>
<p>I created a directive (as all great things are created) out of necessity: I wanted a div of a fixed height to always auto-scroll down to the bottom if new content is added. A common problem you would think, no? Various attempts at solutions took hours upon hoursâââusing libraries, requestAnimationFrame, home-hacked fixes, until I was satisfied. Then someone pointed out the excellent browser feature, Mutation Observers. This was an infinitely simpler implementation of the behaviour I desired.</p>
<p>(If what you are really after is how to solve this same problem, I wrote about the exact implementation <a href="https://hboo.ca/posts/2016-08-12-how-to-vue-directive/">here</a>.)</p>
<p>My original directive was not a directive. It was just a function that took the class or id of the div in question as an argument, and used that to attach the behaviour to the element. An Angular.js veteran recommended that I extract this functionality into a directive, so that it would automatically attach to the desired element. What witchcraft is this?! That was my reaction to this push that I needed to finally explore directives.</p>
<p>Oops, that was definitely not digging right in. That was blabbing.</p>
<p>Javascript:</p>
<pre class="language-js"><code class="language-js">Vue<span class="token punctuation">.</span><span class="token function">directive</span><span class="token punctuation">(</span><span class="token string">'sticky-scroll'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span><br /> <span class="token function-variable function">bind</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">var</span> observer <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">MutationObserver</span><span class="token punctuation">(</span>scrollToBottom<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token keyword">var</span> config <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token literal-property property">childList</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">}</span><span class="token punctuation">;</span><br /> observer<span class="token punctuation">.</span><span class="token function">observe</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>el<span class="token punctuation">,</span> config<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token keyword">function</span> <span class="token function">scrollToBottom</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token comment">// whatever it takes to scroll to the bottom</span><br /> <span class="token punctuation">}</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Html: (template in your Vue component)</p>
<pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">v-sticky-scroll</span><span class="token punctuation">></span></span><br /> <span class="token comment"><!-- new elements will be added here, that's why we want to scroll!--></span><br /><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span></code></pre>
<p>Letâs talk about that.</p>
<p>The name of the directive is âsticky-scrollâ, which must be prefaced with âv-â in your template html. The âbindâ method found in the directive is one of three possible: bind, update, and unbind, called respectively when the directive is attached, modified, and detached from an element.</p>
<p>This.el is one of several properties available through the directive-element interface, and is a direct reference to the element. Other properties can specify additional arguments and parameters to modify the directives activity.</p>
<p>You can now clearly see the distinction between the mysterious âdirectiveâ and a component: in the JS file for the directive, there is no html markup. Only behaviour. In contrast, our component has markup, to which the directive is applied.</p>
<p>Finally, I want to talk about making your directive reusable and available to the whole of the Vue.js community. Sharing is caring, as they say, and Vue.js is currently maintained by essentially one person. This incredible feat merits some serious love, and contributing useful features and stuff you create is a great way to spread the love. Some tips for doing this in the most awesome way possible:</p>
<ul>
<li>For maximum simplicity, use a CDN like <a href="https://rawgit.com/">RawGit</a>âââyou can just upload your single directive file to Github and make it available through a CDN</li>
<li>Make sure your code is clean and readableâââusers might have problems or want to modify your source code. // Comments canât hurt.</li>
<li>Throw in a <a href="http://readme.md/">readme.md</a> with a description and usage instructions, and an example preferably</li>
<li>Then, submit a PR with your shiny new directive to <a href="https://github.com/vuejs/awesome-vue">Awesome Vue</a> for the world to see!</li>
</ul>
<p><em>Note</em>: This post was migrated from its <a href="https://medium.com/@heatherbooker/how-to-make-a-reusable-directive-in-vue-js-b28e1dfd76a3#.bt5ya37q2">original home on Medium</a> on February 23, 2017.</p>
How to auto-scroll to the bottom of a div
2016-08-12T00:00:00Z
https://hboo.ca/posts/2016-08-12-how-to-autoscroll/
<p>This article is just going to be a little nublet of an article. Or a nugget. Whatever.<br />
I found it ridiculously difficult to add what I thought was a common, simple feature to a web app: the ability for a div to automatically scroll to the bottom whenever new content is added. I didnât want the page to scroll, and I didnât want the div height to grow, or the content to expand outside the div.</p>
<p>I tried using a library which is supposed to provide this functionality, but I was having no luck. It would sometimes jump around for the first couple of additions, but was terribly inconsistent, and I couldnât understand the source code well enough to tweak and make it work.</p>
<p>Next, I did it the hard way myselfâââby following a summary of how to accomplish it with some sample code using requestAnimationFrame. This was an excellent way to learn more about requestAnimationFrame, which was something I wanted to do anyway. It also eventually worked and solved my problem! Rad.</p>
<p>But get thisâââit turns out thereâs a better way. Introducing the under-appreciated Mutation Observer. Check it out:</p>
<pre class="language-js"><code class="language-js"><span class="token comment">// Get a reference to the div you want to auto-scroll.</span><br /><span class="token keyword">var</span> someElement <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'.className'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token comment">// Create an observer and pass it a callback.</span><br /><span class="token keyword">var</span> observer <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">MutationObserver</span><span class="token punctuation">(</span>scrollToBottom<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token comment">// Tell it to look for new children that will change the height.</span><br /><span class="token keyword">var</span> config <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token literal-property property">childList</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">}</span><span class="token punctuation">;</span><br />observer<span class="token punctuation">.</span><span class="token function">observe</span><span class="token punctuation">(</span>someElement<span class="token punctuation">,</span> config<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>MutationObservers are available in your browser. <em>In your browser!</em> Theyâre not some fancy shtuff. Well, they are fancy shtuff, but you donât have to worry about how they got so fancy, which is what counts in my books.</p>
<p>Now, thatâs all well and good, but how do you do the actual scrolling?!</p>
<p>Two options: jump or smooth scroll.</p>
<p>Jump:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">function</span> <span class="token function">scrollToBottom</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> someElement<span class="token punctuation">.</span>scrollTop <span class="token operator">=</span> someElement<span class="token punctuation">.</span>scrollHeight<span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p>Smooth Scroll:</p>
<pre class="language-js"><code class="language-js"><span class="token comment">// First, define a helper function.</span><br /><span class="token keyword">function</span> <span class="token function">animateScroll</span><span class="token punctuation">(</span><span class="token parameter">duration</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">var</span> start <span class="token operator">=</span> someElement<span class="token punctuation">.</span>scrollTop<span class="token punctuation">;</span><br /> <span class="token keyword">var</span> end <span class="token operator">=</span> someElement<span class="token punctuation">.</span>scrollHeight<span class="token punctuation">;</span><br /> <span class="token keyword">var</span> change <span class="token operator">=</span> end <span class="token operator">-</span> start<span class="token punctuation">;</span><br /> <span class="token keyword">var</span> increment <span class="token operator">=</span> <span class="token number">20</span><span class="token punctuation">;</span><br /> <span class="token keyword">function</span> <span class="token function">easeInOut</span><span class="token punctuation">(</span><span class="token parameter">currentTime<span class="token punctuation">,</span> start<span class="token punctuation">,</span> change<span class="token punctuation">,</span> duration</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token comment">// by Robert Penner</span><br /> currentTime <span class="token operator">/=</span> duration <span class="token operator">/</span> <span class="token number">2</span><span class="token punctuation">;</span><br /> <span class="token keyword">if</span> <span class="token punctuation">(</span>currentTime <span class="token operator"><</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">return</span> change <span class="token operator">/</span> <span class="token number">2</span> <span class="token operator">*</span> currentTime <span class="token operator">*</span> currentTime <span class="token operator">+</span> start<span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /> currentTime <span class="token operator">-=</span> <span class="token number">1</span><span class="token punctuation">;</span><br /> <span class="token keyword">return</span> <span class="token operator">-</span>change <span class="token operator">/</span> <span class="token number">2</span> <span class="token operator">*</span> <span class="token punctuation">(</span>currentTime <span class="token operator">*</span> <span class="token punctuation">(</span>currentTime <span class="token operator">-</span> <span class="token number">2</span><span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token operator">+</span> start<span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /> <span class="token keyword">function</span> <span class="token function">animate</span><span class="token punctuation">(</span><span class="token parameter">elapsedTime</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> elapsedTime <span class="token operator">+=</span> increment<span class="token punctuation">;</span><br /> <span class="token keyword">var</span> position <span class="token operator">=</span> <span class="token function">easeInOut</span><span class="token punctuation">(</span>elapsedTime<span class="token punctuation">,</span> start<span class="token punctuation">,</span> change<span class="token punctuation">,</span> duration<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> someElement<span class="token punctuation">.</span>scrollTop <span class="token operator">=</span> position<span class="token punctuation">;</span><br /> <span class="token keyword">if</span> <span class="token punctuation">(</span>elapsedTime <span class="token operator"><</span> duration<span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token function">setTimeout</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token function">animate</span><span class="token punctuation">(</span>elapsedTime<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><span class="token punctuation">,</span> increment<span class="token punctuation">)</span><br /> <span class="token punctuation">}</span><br /> <span class="token punctuation">}</span><br /> <span class="token function">animate</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><br /><span class="token comment">// Here's our main callback function we passed to the observer</span><br /><span class="token keyword">function</span> <span class="token function">scrollToBottom</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">var</span> duration <span class="token operator">=</span> <span class="token number">300</span> <span class="token comment">// Or however many milliseconds you want to scroll to last</span><br /> <span class="token function">animateScroll</span><span class="token punctuation">(</span>duration<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p>I hope this helps you. If youâre using Vue.js, you can check out <a href="https://github.com/heatherbooker/vue-sticky-scroll">vue-sticky-scroll</a> (alternate name: vue-glue?), a directive I published to simplify the lives of other people who also want what I wanted. I also wrote recently about the <a href="https://hboo.ca/posts/2016-08-12-how-to-vue-directive">making of Vue.js directives</a> in general. Recently being like 20 minutes ago. Woohoo for Vue.js!</p>
<p><em>Note</em>: This post was migrated from its <a href="https://medium.com/@heatherbooker/how-to-auto-scroll-to-the-bottom-of-a-div-415e967e7a24#.etorqdgbe">original home on Medium</a> on February 23, 2017.</p>
How to make an interactive map in React
2016-06-21T00:00:00Z
https://hboo.ca/posts/2016-06-21-interactive-react-map/
<p>I am going to share with you a great and magnificent secret: the stages of creating a clickable svg map in a React project. Are you ready? You might want to take notes, because it is super mind-blowing.</p>
<p>Wait, first hereâs the map, being clicked on (ooh, ahh):</p>
<p><img src="https://hboo.ca/img/map-being-clicked.gif" alt="clickable map being clicked" /></p>
<p>(And if you just want to skip straight to the good stuff, click <a href="https://www.npmjs.com/package/react-world-map">here to get my clickable SVG-based React component world map</a> on npm!)</p>
<p>If you are ready, let us begin:</p>
<p>Stages of creating a clickable SVG map in a React project</p>
<ol>
<li>Hatred</li>
<li>Suffering</li>
<li>Defeat</li>
<li>Suffering</li>
<li>Hatred</li>
<li>Defeat</li>
<li>Hatred</li>
<li>Hated</li>
<li>Utter hatred</li>
<li>SUCCESS!</li>
<li>Just kidding. Have you seen this? Because this. (Edit: that link was broken, <a href="https://s33.postimg.org/niqd2zgwf/code.jpg">try this</a>, or failing that, image search âhow to do codingâ.)</li>
</ol>
<p>Hahaha..haha..haâŠ<em>lying on floor</em></p>
<p>No, but actually. So it was hard. For me. A majority of that, I reckon, is attributable to my lack of experience with various tasks and technologies, such as setting event listeners and using React. However, in the end, I donât think I would actually classify it as too difficult a project for the average front-end developer to take on.</p>
<p>If you are genuinely interested in creating any sort of clickable SVG-based components for your React application, I have compiled the basic steps I ended up taking to complete my map project below. Good luck and have fun!</p>
<p>When I started out, I had webpack <a href="https://www.npmjs.com/package/file-loader">file-loader</a> set up to handle svgs:</p>
<pre class="language-js"><code class="language-js"><span class="token operator">...</span><br /><span class="token keyword">const</span> myImage <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span>â<span class="token punctuation">.</span><span class="token operator">/</span>aFile<span class="token punctuation">.</span>svgâ<span class="token punctuation">)</span><br /><span class="token keyword">class</span> <span class="token class-name">clickableSvg</span> <span class="token keyword">extends</span> <span class="token class-name">React<span class="token punctuation">.</span>Component</span> <span class="token punctuation">{</span><br /> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">super</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /> <span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">return</span> <span class="token punctuation">(</span><br /> <span class="token operator"><</span>div<span class="token operator">></span><br /> <span class="token operator"><</span>img src<span class="token operator">=</span><span class="token punctuation">{</span>myImage<span class="token punctuation">}</span><span class="token operator">></span><br /> <span class="token operator"><</span>\<span class="token operator">/</span>div<span class="token operator">></span><br /> <span class="token punctuation">)</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p>(If youâre not familiar with âclassâ or âconstâ in js, they are new to ES6.)</p>
<p>However, embedding the svg file in an <code><img></code> tag like this means that any links within the svg code are not valid. [Wait, did I just say svg code? Arenât svgs just images? Oh yeah! You can edit svg codeâââitâs a markup language like HTML, made of <code><tags></code>. Cool.] Sources suggested other optionsâââusing an <code><object></code> or <code><iframe></code> tag instead, or directly embedding the svg code in the document. I wasnât keen on the last option, as I felt the svg code for an entire world map was terribly bulky and would make my code messy. I set upon using the iframe tag, in which I could add links around paths/objects, using <code><a xlink:href=â#â></code>.</p>
<p>But I could go on forever about things that didnât work. Letâs summarize some of the key points to making your clickable svg component work with React:</p>
<ul>
<li>the svg code must be directly embedded in your React component</li>
<li>React will not accept any colons (đ or dashes (-) in tag propertiesâââyou can convert to camelCase to circumvent this</li>
<li>links must use the property xlinkHref, not simply href<br />
you can use event listeners to communicate that a component has been clicked</li>
</ul>
<p>(sidenote: Iâm not entirely certain that using event listeners isnât a slightly hacky way to accomplish communication between components, but it worked for my purposes of alerting users of the map as an npm module )</p>
<ul>
<li>to change css when a component is clicked, assign it a variable for a className, and then use an onClick to manipulate the className</li>
</ul>
<p>for me, this looked as follows:</p>
<pre class="language-svg"><code class="language-svg"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>g</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span>âAFâ</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span>{this.mapState.af}</span> <span class="token special-attr"><span class="token attr-name">onClick</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token value javascript language-javascript"><span class="token punctuation">{</span><span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">onMapClick</span><span class="token punctuation">.</span><span class="token function">bind</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">,</span></span></span></span> <span class="token attr-name">âafâ)}</span> <span class="token punctuation">></span></span><br /> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>path</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>path4307<span class="token punctuation">"</span></span> <span class="token attr-name">d</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>M345.902 112.802c-.17.07 ⊠<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span><br /><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>g</span><span class="token punctuation">></span></span></code></pre>
<p>AF represents Africa, which contained two paths. I grouped the paths in Inkscape (where I could easily view which should go together), then in Sublime I assigned a className. Then I added an onClick to call a function which is defined in the class definition, at the same level as the constructor and render functions.</p>
<p>The classNames are originally set either in the constructor using this.mapState = {<see code="" below="">} if you are using ES6 classes, or the componentDidMount function if using React.createClass:</see></p>
<pre class="language-js"><code class="language-js"><span class="token function-variable function">componentDidMount</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span>mapState <span class="token operator">=</span> <span class="token punctuation">{</span><br /> <span class="token literal-property property">na</span><span class="token operator">:</span> <span class="token string">"map-unselected"</span><span class="token punctuation">,</span><br /> <span class="token literal-property property">sa</span><span class="token operator">:</span> <span class="token string">"map-unselected"</span><span class="token punctuation">,</span><br /> <span class="token literal-property property">af</span><span class="token operator">:</span> <span class="token string">"map-unselected"</span><span class="token punctuation">,</span><br /> <span class="token comment">//etc through all continents</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span><span class="token punctuation">,</span></code></pre>
<p>To make my code as clean as possible, after grouping elements into the areas that will need to be individually manipulated (ex continents), I used an svg optimization tool. I thought I would need path IDs so I instructed the tool not to remove them, but it turns out I havenât needed them so they could have been removed. One option you might need to uncheck though, is for removal of unnecessary groupingsâââthe tool may see the groupings we just worked hard to create as unnecessary, and that is definitely not what we want!</p>
<p>Now, getting into the nitty-gritty of it: The map component has the following features in the source code:</p>
<ul>
<li>React state declared in constructor(ES6) or getInitialState(ES5) and used to track âclickedâ state:</li>
</ul>
<pre class="language-js"><code class="language-js"><span class="token function-variable function">getInitialState</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">return</span> <span class="token punctuation">{</span><span class="token literal-property property">clicked</span><span class="token operator">:</span> ânoneâ<span class="token punctuation">}</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><span class="token punctuation">,</span></code></pre>
<ul>
<li>Fire an event when clicked, denoting current clicked state:</li>
</ul>
<pre class="language-js"><code class="language-js"><span class="token function-variable function">componentDidUpdate</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">emitEvent</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><span class="token punctuation">,</span><br /> <span class="token function-variable function">emitEvent</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">const</span> clickedEvent <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">CustomEvent</span><span class="token punctuation">(</span><br /> âWorldMapClickedâ<span class="token punctuation">,</span><br /> <span class="token punctuation">{</span><span class="token literal-property property">detail</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token literal-property property">clickedState</span><span class="token operator">:</span> <span class="token keyword">this</span><span class="token punctuation">.</span>state<span class="token punctuation">.</span>clicked<span class="token punctuation">}</span><span class="token punctuation">}</span><br /> <span class="token punctuation">)</span><span class="token punctuation">;</span><br /> window<span class="token punctuation">.</span><span class="token function">dispatchEvent</span><span class="token punctuation">(</span>clickedEvent<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><span class="token punctuation">,</span></code></pre>
<p>The event is dispatched on componentDidUpdate, which guarantees that it is receiving the new state. Firing an event allows users of the npm module to easily track what is happening (again, I think this might be hacky).</p>
<p>There are two functions which handle the state and classNamesâââthe first determines what to set <code>this.state.clicked</code> to by using some if/else statements and comparing the area clicked to the previous state, and the second manages classNames for css purposes by resetting all to the default, unselected, then if necessary, changing only the selected area to have a className reflecting that.</p>
<p>It is important to note that the states should be suitable class names, such as âmap-selectedâ and âmap-unselectedâ, as they are assigned as className attributes to the groups in the svg! These classNames can then be referenced through CSS to change the appearance.</p>
<p>Tune in next week for some choice words on making a React component available as an npm module and through a CDN.</p>
<p>And thatâs it! Thatâs all there is to using SVG to its full clickable, CSS-able potential. Donât forget to <a href="https://github.com/heatherbooker/clickable-svg-map">check out the project on github</a> if you need any clarification, or would like to use it yourself! Happy map-making!</p>
<p><em>Note</em>: This post was migrated from its <a href="https://medium.com/@heatherbooker/how-to-make-an-interactive-map-in-react-f4e6e074b500#.entvl9iu5">original home on Medium</a> on February 23, 2017.</p>
Vue.js vs React.js
2016-06-15T00:00:00Z
https://hboo.ca/posts/2016-06-15-vue-vs-react/
<p>Ooh, this is going to be a juicy one! Iâm sure many people are fierce supporters of one of these technologies and zealous bashers of the other. Both Vue.js and React.js are both pretty new to the sceneâââletâs get some background information to begin. Iâll go in reverse alphabetical order to avoid offending anyone right out of the gates. đ</p>
<p>First of all, Vue and React are very similar. They are both libraries intended to be used to make composable âviewsâ(Vueâs words) or âuser interfacesâ(Reactâs words), with reactive data binding. Composable, in this case, meaning based on the separation of view concerns into units described as âcomponentsâ. In terms of data, both recommend a uni-directional flow of data.</p>
<p><a href="https://vuejs.org/">Vue.js</a> was created and maintained by Evan You and released publicly in early 2014. It positions itself as a simpler, more straightforward implementation of the component-based data-binding view concept.</p>
<p><a href="https://facebook.github.io/react/">React.js</a> was released a year earlier, after being created by Jordan Walke for use at Facebook. Frankly, until I began researching for this article, I had no idea there was a single person behind itâââFacebook definitely gets the acclaim for React.</p>
<p>Vue is arguably the underdog at the moment. React absolutely took the javascript world by stormâââit is currently the 6th most starred project ever on Github, and you would be hard pressed to be a front-end developer currently and not have heard anything about it. Vue even directly likens itself to React in its â<a href="https://blog.evanyou.me/2015/10/25/vuejs-re-introduction/">(re)introductionâ article</a>:</p>
<blockquote>
<p>When it comes to structuring complex interfaces, Vue takes an approach that is very similar to React: itâs components all the way down.</p>
</blockquote>
<p>The uni-directional data flow is an idea originally referred to by React as âFluxâ. In this idea, data changes flow through a central container of state before they are sent back out to wherever the data may be needed. They each have their own personalized versions of Fluxâââthe most popular for React is Redux*, written by Dan Abramov. Since its inception, Redux has been widely praised by the community as well as the React team at Facebook themselves. Redux is also compatible with Vue, though Vuex is an architecture similarly based on Flux while being more specifically tailored to Vue.</p>
<p>Alright. Now that all that factual stuff is out of the way, lets talk about our feelings. My first foray into React was decidedly painful. I had never used such an architecture before, and many people agree with me on the following point: the documentation is not beginner friendly. In this excellent article <a href="https://blog.andrewray.me/reactjs-for-stupid-people/">ReactJS for Stupid People</a>, Andrew Ray points out Reactâs bewilderingly full and disorganized sidebar with multiple, competing entry points. Reactâs use of JSX, which looks like HTML tags written in the middle of a JS file, makes things hard enough, without additions such asâââa mix of ES6 syntax and âsafeâ JS throughout Reactâs documentation and the hoardes of other tutorials found throughout the interwebs, superfluous yet pervasive use of webpack(which also has notoriously poor documentation), and the whole flux/redux/state/props mess(at least in my brain it was a mess). All in all, I think three things are the root of my lesser valuation of React:</p>
<ol>
<li>A ton of nearly inextricable tools (webpack, babel, jsx, redux/reflux/alt..)</li>
<li>Unnecessary complication, in my opinion, compared to Vue</li>
<li>Confusing documentation</li>
</ol>
<p>These three aforementioned items are surely related. However, I feel that Vue scores significantly higher than React on all three. I barely needed to venture away from the official Vue docs to get started using it; even when I did turn to Google, I frequently ended up back in the official docs to find my answer! To me, this is a major winâââto have a technology clear enough that it can be sufficiently explained in one go, and to sufficiently and clearly do so. I expect that the Vue docs were written by the creator of Vue, which would afford the absolute clarity that accompanies such a position.</p>
<p>I must end by saying that I enjoy using bothâââI appreciate Reactâs current far-reach, as well as Vueâs dedication to simplicity. But I canât help but lean towards team Vue. In any case, long live component based UIs!</p>
<p>*Redux is technically not flux. But it was heavily inspired by it.</p>
<p><em>Note</em>: This post was migrated from its <a href="https://medium.com/@heatherbooker/vue-js-vs-react-js-28caa8f9b033#.ojssrqrl3">original home on Medium</a> on February 23, 2017.</p>
Getting started with React and Webpack
2016-06-09T00:00:00Z
https://hboo.ca/posts/2016-06-09-getting-started-react-webpack/
<p>I <a href="https://hboo.ca/posts/2016-05-28-if-gulp-were-a-person">recently wrote about</a> the wonders of gulp. Ironically, as soon as it was published, I ditched gulp for webpack. Actually thatâs not quite trueâââI first tried to incorporate browserify into gulp. I knew I needed some sort of packaging system in order to use JSX and React, and of these two most popular, browserify and webpack, webpack was touted to be a real mind-bender to set up. Everywhere I looked suggested that people who werenât terribly experienced with other module-requiring systems like CommonJS should probably use browserify. So I got to work setting it up, only to realize that webpack would pay off in the long run.</p>
<p>Scratch browserify. Move on to webpack. The internet was rightâââit was a pain to set up. Letâs dig right in and see if we canât set up our own project right now using React and Webpack. (If you canât be bothered to follow along, feel free to git clone my <a href="https://github.com/heatherbooker/webpack-react-starter">Webpack-React starter</a>âââa complete environment to use React and Webpack, as well as SCSS.)</p>
<p>We will be creating a project âanyProjectâ in a directory âdevâ. Feel free to adapt these to your needs.</p>
<pre class="language-bash"><code class="language-bash"><span class="token function">mkdir</span> dev/anyProject<br /><span class="token builtin class-name">cd</span> dev/anyProject</code></pre>
<p>npm is a dandy package manager we will be using to set up webpack and react. Make sure you have npm installed by typing <code>npm -v</code>âââcheck <a href="https://docs.npmjs.com/getting-started/installing-node">here</a> or <a href="https://blog.npmjs.org/post/85484771375/how-to-install-npm">here</a> for details.</p>
<p>Run <code>npm init -y</code> to get startedâââthis will initialize your project with a package.json file. The -y option tells npm to use default settings; if you forget to use it, just press enter until you have gone through all of the questions. Running npm init -f accomplishes the same, but it also warns you:</p>
<p><img src="https://hboo.ca/img/npm-warn.png" alt="npm being a know-it-all" /></p>
<p>Alarming! Better stick to -y which gets the job done without sassing you. (not the css typeâŠ)</p>
<p>Next, we install webpack:</p>
<pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> i webpack -S</code></pre>
<p>This should have initialized a node_modules folder in your current directory (dev/anyProject, in this example). If not, webpack may have been downloaded to a node_modules folder found higher up in your directory tree. Webpack should now also be listed in the âdependenciesâ section of your package.json. Letâs create a configuration file for webpack now, to tell it how to handle our files and what we want it do.</p>
<pre class="language-bash"><code class="language-bash"><span class="token function">touch</span> webpack.config.js</code></pre>
<p>Open webpack.config.js, and type the following:</p>
<pre class="language-js"><code class="language-js">module<span class="token punctuation">.</span>exports <span class="token operator">=</span> <span class="token punctuation">{</span><br /> <span class="token literal-property property">entry</span><span class="token operator">:</span> â<span class="token punctuation">.</span><span class="token operator">/</span>src<span class="token operator">/</span>index<span class="token punctuation">.</span>jsxâ<span class="token punctuation">,</span><br /> <span class="token literal-property property">output</span><span class="token operator">:</span> <span class="token punctuation">{</span><br /> <span class="token literal-property property">path</span><span class="token operator">:</span> âbuildâ<span class="token punctuation">,</span><br /> <span class="token literal-property property">filename</span><span class="token operator">:</span> âindex<span class="token punctuation">.</span>jsâ<br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p>This sets the first file webpack looks at as âindex.jsxâ located in directory âsrcâ, and writes the output to a file âindex.jsâ located in dir âbuildâ. But how does our JSX become plain ol JS? Webpack uses âloadersâ to essentially translate code; we need to add loaders for whatever functionality we desire. First npm install some loaders: Babel will help the transition from JSX to js:</p>
<pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> i babel-loader babel-preset-es2015 babel-preset-react -S</code></pre>
<p>Then go back to the webpack.config.js, and at the same level as âentryâ and âoutputâ, add a key âmoduleâ which will contain configuration information for our loaders, starting with babel:</p>
<pre class="language-js"><code class="language-js"> <span class="token operator">...</span><br /> <span class="token punctuation">,</span> <span class="token literal-property property">module</span><span class="token operator">:</span> <span class="token punctuation">{</span><br /> <span class="token literal-property property">loaders</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">{</span><br /> <span class="token literal-property property">test</span><span class="token operator">:</span> <span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">\.jsx$</span><span class="token regex-delimiter">/</span></span><span class="token punctuation">,</span><br /> <span class="token literal-property property">exclude</span><span class="token operator">:</span> <span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">node_modules</span><span class="token regex-delimiter">/</span></span><span class="token punctuation">,</span><br /> <span class="token literal-property property">loader</span><span class="token operator">:</span> âbabelâ<span class="token punctuation">,</span><br /> <span class="token literal-property property">query</span><span class="token operator">:</span> <span class="token punctuation">{</span><br /> <span class="token literal-property property">presets</span><span class="token operator">:</span> <span class="token punctuation">[</span>âes2015â<span class="token punctuation">,</span> âreactâ<span class="token punctuation">]</span><br /> <span class="token punctuation">}</span><br /> <span class="token punctuation">}</span><span class="token punctuation">]</span><br /> <span class="token punctuation">}</span></code></pre>
<p>But where are our heads?! (not the git typeâŠ) We donât even have React in our project yet! Better fix that. Run:</p>
<pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> i react react-dom -S</code></pre>
<p>Letâs check that everything weâve done so far is working. We will need directories âsrcâ and âbuildâ, an index.jsx file and an index.html file.</p>
<pre class="language-bash"><code class="language-bash"><span class="token function">mkdir</span> src build<br /><span class="token function">touch</span> src/index.jsx<br /><span class="token function">touch</span> src/index.html</code></pre>
<p>Hopefully you are using an editor like Sublime which will auto-generate a basic HTML doc by typing âhtmlâ and pressing tab. Then throw in a quick </p><div> with an id=âappâ, and a script tag so the index.html looks like this:<p></p>
<pre class="language-html"><code class="language-html"><span class="token doctype"><span class="token punctuation"><!</span><span class="token doctype-tag">DOCTYPE</span> <span class="token name">html</span><span class="token punctuation">></span></span><br /><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>html</span><span class="token punctuation">></span></span><br /><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>head</span><span class="token punctuation">></span></span><br /> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>title</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>title</span><span class="token punctuation">></span></span><br /><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>head</span><span class="token punctuation">></span></span><br /><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>body</span><span class="token punctuation">></span></span><br /> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span>âappâ</span><span class="token punctuation">></span></span><br /> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span><br /><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>script</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>text/javascript<span class="token punctuation">"</span></span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>index.js<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token script"></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>script</span><span class="token punctuation">></span></span><br /><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>body</span><span class="token punctuation">></span></span><br /><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>html</span><span class="token punctuation">></span></span></code></pre>
<p>Next weâll create a quick component in index.jsx using React. Start by requiring in react and react-dom, then create a class and render a component:</p>
<pre class="language-jsx"><code class="language-jsx"><span class="token keyword">var</span> React <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span>âreactâ<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token keyword">var</span> ReactDOM <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span>âreact<span class="token operator">-</span>domâ<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token keyword">var</span> AComponent <span class="token operator">=</span> React<span class="token punctuation">.</span><span class="token function">createClass</span> <span class="token punctuation">(</span><span class="token punctuation">{</span><br /> <span class="token function-variable function">render</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">return</span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span><span class="token punctuation">></span></span><span class="token plain-text">HELLO WORLD!</span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />ReactDOM<span class="token punctuation">.</span><span class="token function">render</span><span class="token punctuation">(</span><br /> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span><span class="token class-name">AComponent</span></span> <span class="token punctuation">/></span></span><span class="token punctuation">,</span><br /> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span>âappâ<span class="token punctuation">)</span><br /><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>(PSâââyou may want to install a plugin for your text editor that you can set to parse JSX files (ex, Babel).)<br />
For now, we will need to manually copy our index.html into the build directory:</p>
<pre class="language-bash"><code class="language-bash"><span class="token function">cp</span> src/index.html build</code></pre>
<p>Now all we have to do is run webpack! We will put a command into our package.json in the âscriptsâ, so that npm can help us run webpack (the âtestâ script should have been auto-generated with the package.json file):</p>
<pre class="language-js"><code class="language-js"><span class="token string-property property">"scripts"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br /> <span class="token string-property property">"test"</span><span class="token operator">:</span> <span class="token string">"echo \"Error: no test specified\" && exit 1"</span><span class="token punctuation">,</span><br /> <span class="token string-property property">"build"</span><span class="token operator">:</span> <span class="token string">"webpack"</span><br /> <span class="token punctuation">}</span><span class="token punctuation">,</span></code></pre>
<p>Now in your terminal/command line just type:</p>
<pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> run build</code></pre>
<p>And open dev/anyProject/build/index.html in your browser and you should see this:</p>
<p><img src="https://hboo.ca/img/hello-world.png" alt="'Hello world' in top left corner of your page" /></p>
<p>Awesome! It works! You have successfully set up a project with webpack and react! But you might be thinking : we copied that index.html file manually, that was stupid. Youâre right! Letâs prepare this project a little more for the real world. We want to handle html files, and we might as well also use webpack for one of its great skillsââârequiring in all sorts of tidbits, such as images. I like using SVGs as they are highly editable, and resize well.</p>
<p>Start by installing html-webpack-plugin and file-loader:</p>
<pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> i html-webpack-plugin file-loader -D</code></pre>
<p>As their names suggest, the former is a plugin while the latter is a loader. To use the plugin, we require it at the top of the webpack.config.js:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">var</span> HtmlWebpackPlugin <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span>âhtml<span class="token operator">-</span>webpack<span class="token operator">-</span>pluginâ<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Then after the loaders, we add a new section called plugins to the module.exports, and reference the HtmlWebpackPlugin var we just created. I like to instruct it to use a template, so that in the template I can have the one </p><div id="âappâ"> for React to inject content into:<p></p>
<pre class="language-js"><code class="language-js"> <span class="token punctuation">}</span><span class="token punctuation">,</span><br /> <span class="token literal-property property">plugins</span><span class="token operator">:</span> <span class="token punctuation">[</span><br /> <span class="token keyword">new</span> <span class="token class-name">HtmlWebpackPlugin</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br /> <span class="token literal-property property">template</span><span class="token operator">:</span> â<span class="token punctuation">.</span><span class="token operator">/</span>src<span class="token operator">/</span>index<span class="token punctuation">.</span>htmlâ<br /> <span class="token punctuation">}</span><span class="token punctuation">)</span><br /> <span class="token punctuation">]</span><br /><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p>Scroll down to see how to set up the file loader (along with a SCSS loader).</p>
<p>Now two last things: I like to be able to use SCSS , so we will set up a loader for that, and we can also set up React HMR for to serve our webpage and update it every time we make a change to a file. This is an excellent time-saver for development!</p>
<pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> i babel-preset-react-hmre sass-loader node-sass css-loader style-loader -D</code></pre>
<p>To set up the file loader for images and the SCSS loader, add the following to the âloadersâ array in the webpack.config.js:</p>
<pre class="language-js"><code class="language-js"><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span><br /> <span class="token literal-property property">test</span><span class="token operator">:</span> <span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">\.scss$</span><span class="token regex-delimiter">/</span></span><span class="token punctuation">,</span><br /> <span class="token literal-property property">loaders</span><span class="token operator">:</span> <span class="token punctuation">[</span>âstyleâ<span class="token punctuation">,</span> âcssâ<span class="token punctuation">,</span> âsassâ<span class="token punctuation">]</span><br /> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span><br /> <span class="token literal-property property">test</span><span class="token operator">:</span> <span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">\.svg$</span><span class="token regex-delimiter">/</span></span><span class="token punctuation">,</span><br /> <span class="token literal-property property">loader</span><span class="token operator">:</span> âfileâ<br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span><span class="token punctuation">]</span></code></pre>
<p>And finally, setting up hot module reloading is very easy. Simply add âreact-hmreâ to the presets array in the babel loader:</p>
<pre class="language-js"><code class="language-js"><span class="token literal-property property">presets</span><span class="token operator">:</span> <span class="token punctuation">[</span>âes2015â<span class="token punctuation">,</span> âreactâ<span class="token punctuation">,</span> âreact<span class="token operator">-</span>hmreâ<span class="token punctuation">]</span></code></pre>
<p>Then in package.json, add a new script which can be run with ânpm startâ:</p>
<pre class="language-js"><code class="language-js"><span class="token string-property property">"start"</span><span class="token operator">:</span> <span class="token string">"webpack-dev-server --progress --inline --hot"</span></code></pre>
<p>Once you run ânpm startâ, you can open localhost:8080 to see your app change as you develop it. Voila, thatâs it! Now you can write SCSS and JSX and use React to create awesome apps. Get to it!</p>
<p><em>Note</em>: This post was migrated from its <a href="https://medium.com/@heatherbooker/vue-js-vs-react-js-28caa8f9b033#.ojssrqrl3">original home on Medium</a> on February 23, 2017.</p>
</div></div>
Prototyping a web app on Linux
2016-05-30T00:00:00Z
https://hboo.ca/posts/2016-05-30-prototyping-web-on-linux/
<p>I take great pride and pleasure in using an operating system sometimes thought of as difficult, risky, and geared towards programmers. Being the extremely novice developer that I am, I like to boost my sense of competence by using this somewhat elite OS so that I can bask in the surprise of others when they find out that I am using neither Windows nor MAC.</p>
<p>However, along with the perks of using an a slightly atypical OS come its inevitable, intrinsically linked downfalls: in this case, namely a lack of support for and access to popular proprietary programs. Luckily, the open-source community is beautiful and prolific, its efforts affording the ability to hack together a solution to nearly any problem you should wish to tackle.</p>
<p>My latest endeavour, prototyping my next project, has been no exception. The objective: create a high-fidelity, really pretty, visually-identical, interactive approximation of what I envision my web app looking like and being able to do. I began by trying out some web apps advertised for prototyping, InVision and Marvel Appâââwhich, of course, are indifferent to my OSâââI was off to a good start. InVision didnât work out, but Marvel App was promising, allowing you create designs with its <a href="https://blog.marvelapp.com/introducing-canvas-design-wireframe-and-animate-directly-in-marvel/">canvas function</a>. However, there was a glaring flaw: once you move on from creating screen1 to screen2, screen3 <em>must</em> be based off screen2âââthereâs no way to use screen1 as a starting point. This becomes extremely frustrating extremely quickly, and I was getting really tempted to cut corners and just omit entire interactions and features.</p>
<p>So, I migrated my project over to some OS-based image editing software. (Note: I am a complete noob at image manipulations.) I had previously used GIMP, but gave InkScape a run this time. Abode Illustrator seems to typically be the tool of choice for operations like mine, but it is of course unavailable for Linux. Having never used Illustrator, I expect that I experienced exactly the same amount of difficulty getting started with InkScape as I would have with Illustrator. As with many things on the most user-friendly Linux distros (ie Ubuntu based), there is a wealth of online knowledge in the form of question forums and tutorials. This meant that I could just google any problem I ran into for instant assistance. I reckon Illustrator similarly has plenty of how-to information available on the interwebz.</p>
<p>By taking advantage of all the help available, I was able to get a handle on using InkScape to mock-up some beautiful screens. I then uploaded each of them back into Marvel App and used Marvel to add interactions between them. And you know what? I donât think prototying in Linux was particularly hardship-prone.</p>
<p>There was one important lesson learned, that I must remind myself of:</p>
<ul>
<li>If itâs not simple, just google it!<br />
Usually I am too stubbornâââI try until Iâm mad and then declare it impossible. âJust google itâ is a much better tactic.</li>
</ul>
<p>All said and done, I feel much more confident about mocking-up and prototyping apps for future projects after this experience and Iâm not at all concerned that my OS is impeding my pace. Another point for Linux!</p>
<p><em>Note</em>: This post was migrated from its <a href="https://medium.com/@heatherbooker/prototyping-a-web-app-on-linux-a2834e9a4c55#.o2b92lp0v">original home on Medium</a> on February 23, 2017.</p>
If GULP were a personâŠ
2016-05-28T00:00:00Z
https://hboo.ca/posts/2016-05-28-if-gulp-were-a-person/
<p>Ze* would be pretty amazing. I donât know zir* very well yet, but ze* sure seems to have a lot of people who like zir. Granted, there are also a fair few who are not afraid to speak out against gulpâââbut thatâs hardly unusual when someone wonderful shows up on the scene.</p>
<p>Gulp was a little hard to follow at first. Ze uses all this language that, like everyone in the field, is a little perplexing until youâre used to it. I suppose you would call that <em>jargon</em>. Zir four main capabilities are expressed as <code>.task</code>, <code>.pipe</code>, <code>.src</code>, and <code>.dest</code>. The latter two are simply used to denote the source and destination of the files you would like gulp to operate on. <code>.task</code> is, of course, a description of the task you would like gulp to execute. Now, <code>.pipe</code> is, to my untrained eyes, the most wonderful and curious constituent of gulp. Ze isnât showy about it, but once you understand it, it is the backbone of all the incredible functionality gulp so humbly offers. You see, the aptly named <code>.pipe</code> function takes a reference to a plugin you would like to see used on your code, and then pipes your code through that plugin from <code>.src</code> to <code>.dest</code>, leaving a new, neatly wrapped, perfectly articulated version of your code in wherever you have designated as the destination. The most beautiful thing about gulp, in my view, is the conceptualization afforded by the use of this code that represents sending code through a pipeline where it undergoes various transformations.</p>
<p>If thereâs one thing I know for sure, itâs that gulp loves to accessorize. In fact, ze wouldnât be that notable at all without all zir little friends. Gulp gets along with pug (formerly jade) for html, sass for css, mocha for testing, and basically anyone or anything else youâd like zir to. Ze can help you uglify your code for running, while leaving your original code untouched so when you come back to edit it/check it out, you arenât bewildered by the wall of text that is uglified code. Ze can also lint your code, simplify the use of frameworks like react.js and express, compile coffeescript, and do a million other handy things that just makes zir a great companion.</p>
<p>Now, donât get me wrongâââthere are probably other gizmos and gadgets that accomplish the same things in various permutations and combinations. But gulp can just do so MUCH! By golly, just in researching this article I discovered that ze can work with git for version control! Unbelievable! I tell ya folks, whatever you want to, you talk to gulp and the two of you will work something out to your satisfaction. With all zir connections, you wonât be disappointed.</p>
<p>*Note on âzeâ, âzirâ & âzirsâ: these are commonly used gender-neutral pronouns, intended to lack any connotation of gender. I do not wish to assign a gender to Gulp, and thus I have selected these non-specific pronouns. For more information, feel free to check out this <a href="https://hboo.ca/posts/2016-05-28-if-gulp-were-a-person/%5Cgenderneutralpronoun.wordpress.com">explanation</a> from the Gender Neutral Pronoun Blog.</p>
<p>**Thanks to Dylan Harness for motivating this post.</p>
<p><em>Note</em>: This post was migrated from its <a href="https://medium.com/@heatherbooker/if-gulp-were-a-person-82a6cd6e3e38#.fhs0i3owm">original home on Medium</a> on February 23, 2017.</p>