diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 0000000..e69de29 diff --git a/404.html b/404.html new file mode 100644 index 0000000..0d94b11 --- /dev/null +++ b/404.html @@ -0,0 +1 @@ +

4šŸ˜±4

40404040404

This page does not exist. If you come from a broken link, you may let me know on GitHub.

ā† Go back
\ No newline at end of file diff --git a/CNAME b/CNAME new file mode 100644 index 0000000..e91b760 --- /dev/null +++ b/CNAME @@ -0,0 +1 @@ +diessi.ca \ No newline at end of file diff --git a/atom.xml b/atom.xml new file mode 100644 index 0000000..d99c867 --- /dev/null +++ b/atom.xml @@ -0,0 +1,3925 @@ + + + DiĆ©ssica Gurskas + My home in the internet where I muse about life and computers. + + + Zola + 2024-09-29T14:00:15+00:00 + /atom.xml + + Learning vim: From VS Code to neovim (Part 1) + 2024-09-29T14:00:15+00:00 + 2024-09-29T14:00:15+00:00 + + + + + Unknown + + + + + + /blog/learning-vim/ + + <p>Iā€™ve been a VS Code user for years, but today, I am giving vim (motions &amp; editor) another try. Why?</p> +<ul> +<li>I love keyboard navigation, and vim motions invite you to use your entire keyboard not only to type, going beyond the Ctrl+Shift+Command+Fn+^+{+/ hell.</li> +<li>neovimā€™s plugin ecosystem is GOLD for keyboard enthusiasts e.g. <a href="https://github.com/stevearc/oil.nvim">stevearc/oil.nvim</a>.</li> +<li>Thereā€™s a gap between my terminal and VS Code. No matter what extensions I throw at it, I canā€™t bridge it. Since I spend a lot of time in the terminal anyway, why not edit in it too?</li> +</ul> +<p class="note">Disclaimer: Not a beginner tutorial. Rather a (hopefully inspiring) diary of my vim journey. But if you're curious, I've dropped some learning resources below.</p> +<h2 id="today-i-learned">Today I learned</h2> +<h3 id="which-vim-editor">which vim editor?</h3> +<p>Many editors support vim motions, including VS Code itself. Technically, I could just <a href="https://www.reddit.com/r/vscode/comments/1enlqx1/my_minimal_vscode_setup_heavily_inspired_by_neovim/">make my VS Code more keyboard-centric</a> without switching editors. But right now, Iā€™m exploring <a href="https://neovim.io/">neovim</a>, and learning vim motions across both VS Code and neovim. neovim is cute: small, fast, portable, extendable, widely supported, and not again owned by Microsoft.</p> +<h3 id="vim-kinda-has-4-modes">vim kinda has 4 modes</h3> +<ul> +<li>insert mode (<code>i</code> key; also other keys, see ā€œthe normal modeā€): where you type and insert text, just like a traditional text editor.</li> +<li>visual mode (<code>v</code> key): where you select/highlight text visually, handy for copying/deleting/moving.</li> +<li>normal mode (<code>esc</code> key): where you navigate around the file, most of the time and most efficiently. Keys become ā€œmotionsā€ and ā€œoperatorsā€ that move the cursor and act on text (deleting, finding, replacing).</li> +<li>command-line mode (<code>:</code> key): execute commands on vim, mostly editor-related, e.g. saving files, exiting vim.</li> +</ul> +<p>Traditional text editors offer ways to do the above in a permanent ā€œinsert modeā€, but vim separates that across modes. Many mistakes happen because youā€™re not in the mode you thought you were, it helped me that the ā€œnormalā€ mode cursor looks different than the other modes.</p> +<h3 id="the-normal-mode">the normal mode</h3> +<p>Thereā€™s nothing normal about the normal mode, so I will say again: in vimā€™s normal mode, keys turn into ā€œmotionsā€ (move you around the file) and ā€œoperatorsā€ (act on text, e.g. deleting, finding, replacing). Think of it as a mode with permanently enabled ā€œCmdā€ or ā€œCtrlā€ keys which you use to move around in a regular text editor (I hope?).</p> +<ol> +<li>navigating up (k), down (j), left (h), right (k). (Try not to <a href="https://en.wikipedia.org/wiki/Touch_typing">press l with your pinky finger</a>)</li> +<li>creating new lines under the cursor (o) and above (O)</li> +<li>jumping to next word (w), end of the word (e), or previous word (b)</li> +<li>jumping around lines of code with gg (line 0), G (end of file), {line number you wanna go to}G, {N}j to go down N lines, {N}k to go up N lines</li> +<li>inserting before cursor (i), inserting after cursor (a), insert in the beginning of line (I) or end of line (A)</li> +<li>jumping to beginning of the line (0), end of line ($), or beginning of word (_)</li> +<li>replacing a char (r) or word (R), deleting current character (x), deleting (d) e.g. a line (dd), next word (dw), previous word (db), basically a lot of the commands Iā€™ve already learned above</li> +<li>searching within a line with f(character), plus next (n) and previous (N) occurrence</li> +<li>undo (u), redo (ctl+r). Pretty damn important, you make mistakes all the time.</li> +</ol> +<p>I practiced these commands in roughly that order, moving on once I felt <em>mostly accurate, though still slow</em>. It might seem like a lot, but itā€™s easier when itā€™s about muscle memory and not memorizing a cheatsheet. Once you start combining motions and operators, things get fun. For example: I already use <code>j</code> to move down, could <code>10j</code> jump down 10 lines? Yes (first I tried <code>j10</code> lol). Deleting 3 words backwards? <code>d3b</code>.</p> +<h3 id="little-vim-config">little vim config</h3> +<p>Feeling a bit lost in my editor, had to change some things. I said earlier I was curious about the ecosystem, but now Iā€™m a little overwhelmed. For now, keeping it minimal:</p> +<pre data-lang="lua" style="background-color:#282a36;color:#f8f8f2;" class="language-lua "><code class="language-lua" data-lang="lua"><span style="color:#6272a4;">-- ~/.config/nvim/init.lua +</span><span style="color:#ff79c6;">local </span><span style="color:#ffffff;">o </span><span style="color:#ff79c6;">= </span><span style="color:#ffffff;">vim</span><span style="color:#ff79c6;">.</span><span>opt +</span><span> +</span><span style="color:#ffffff;">o</span><span style="color:#ff79c6;">.</span><span>number </span><span style="color:#ff79c6;">= </span><span style="color:#bd93f9;">true </span><span style="color:#6272a4;">-- Print the line number in front of each line +</span><span style="color:#ffffff;">o</span><span style="color:#ff79c6;">.</span><span>syntax </span><span style="color:#ff79c6;">= </span><span style="color:#f1fa8c;">&quot;on&quot; </span><span style="color:#6272a4;">-- When this option is set, the syntax with this name is loaded. +</span><span style="color:#ffffff;">o</span><span style="color:#ff79c6;">.</span><span>mouse </span><span style="color:#ff79c6;">= </span><span style="color:#f1fa8c;">&quot;a&quot; </span><span style="color:#6272a4;">-- Enable the use of the mouse. &quot;a&quot; you can use on all modes +</span><span style="color:#ffffff;">o</span><span style="color:#ff79c6;">.</span><span>termguicolors </span><span style="color:#ff79c6;">= </span><span style="color:#bd93f9;">true +</span></code></pre> +<p>(By the way, neovim uses Lua for configuration, if youā€™re wondering where the good old vimrc wentā€¦)</p> +<h2 id="references-for-slow-digestion-only">References for SLOW DIGESTION ONLY</h2> +<ul> +<li><a href="https://github.com/mhinz/vim-galore#first-steps">Everything you need to know about vim (GitHub)</a></li> +<li>CLI vimtutor (see above), or <a href="https://openvim.com/">Web interactive vim tutorial</a></li> +<li><a href="https://quickref.me/vim">QuickRef vim cheatsheet</a> / - <a href="http://www.viemu.com/a_vi_vim_graphical_cheat_sheet_tutorial.html">Graphical vi-vim Cheat Sheet and Tutorial</a></li> +<li><a href="https://www.youtube.com/watch?v=X6AR2RMB5tE&amp;list=PLm323Lc7iSW_wuxqmKx_xxNtJC_hJbQ7R">ā€œvim as your editorā€ (YouTube), by ThePrimeagen</a></li> +</ul> +<h2 id="that-s-all-for-now">Thatā€™s all for now</h2> +<p>Back in my teenage years, I tried to learn vim and quickly gave up. Coding was already confusing enough, and I figured, ā€œwhatā€™s the point of typing faster if I donā€™t even know what to type?ā€. Which was pretty wise, in hindsight. Pretty sure I peaked in wisdom right there.</p> +<p>Jokes aside (it was not a joke), Iā€™m still far from hyper-productive on vim. But I wrote this blog post with it, felt focused and felt plenty of fun, which is productive enough I guess? Whether this is novelty, or the vim advantage, only time will tell. Plenty of people go from VS Code to neovim and then back again. Who knows.</p> +<p>Now, the text column width on this editor has been full screen since I started this post, and Iā€™m on the edge of installing <a href="https://github.com/folke/zen-mode.nvim">zen-mode.nvim</a>. Just gotta figure out what is this lazy nvim vs. packer thing.</p> +<p>:wq</p> + + + + + Misc(ellaneous) + 2024-09-20T11:02:00+00:00 + 2024-09-20T11:02:00+00:00 + + + + + Unknown + + + + + + /misc/ + + <h2 id="open-to-work-dove">Open to work šŸ•Šļø</h2> +<p>Beyond my silly online presence, <strong>Iā€™m a multidisciplinary creative partner in projects</strong> and can likely assist you from idea to launch! With over a decade of experience as a computer programmer, Iā€™ve honed my skills in web development, led engineering teams, managed projects, and even designed UI/UX. Just get in touch :-)</p> +<h2 id="get-in-touch">Get in touch</h2> +<p>Iā€™m happy to hear from most humans on most things. Say hi!</p> +<ul> +<li><a href="https://bsky.app/profile/diessica.bsky.social">Bluesky</a> for silly stuff.</li> +<li><strong><a href="https://useplaintext.email/">Plain text email</a></strong>: <a href="mailto:hey+blog@diessi.ca">hey@diessi.ca</a>.</li> +<li><strong><a href="https://signal.org">Signal</a></strong> for serious stuff. <strong>ā­ Preferred as itā€™s encrypted ā­</strong> +<ul> +<li>Donā€™t have my Signal? Please email me with your name and your reason to contact me.</li> +</ul> +</li> +</ul> +<h2 id="metadata">Metadata</h2> +<div class="flex flex-wrap not-prose"> + <img src="/badges/browser.png" width="80" height="41" alt="Viewable with any browser" /> + <!-- <img src="/badges/js.png" alt="JavaScript-free page" /> --> + <img src="/badges/screen.gif" width="80" height="41" alt="Best viewed in hi-colors 800x600 screens" /> + <img src="/badges/nocookie.png" width="80" height="41" alt="This site is certified 100% cookie-free" /> + <a href="https://diessi.ca/atom.xml"><img src="/badges/rss.gif" width="80" height="41" alt="Valid RSS" /></a> + <img src="/badges/trapped.gif" width="80" height="41" alt="Trapped inside da web" /> + <a href="https://github.com/diessica/diessica.github.io"><img src="/badges/github.gif" width="80" height="41" alt="GitHub" /></a> +</div> +<p>This is my independent home on the internet. On my blog, I try to share knowledge and perspectives on what I find interesting ā€“ sometimes computers. When I write, please assume <a href="https://en.wiktionary.org/wiki/IMHO">IMHO</a>/<a href="https://en.wiktionary.org/wiki/IMNSHO">IMNHSO</a> and openness for dialogue.</p> +<p>You may receive my blog updates by subscribing to <a href="https://diessi.ca/atom.xml">my RSS Feed</a>.</p> +<h3 id="license-attribution">License &amp; Attribution</h3> +<ul> +<li>Pages are statically generated with <a href="https://www.getzola.org/">Zola</a> as engine.</li> +<li>88x31 buttons by <a href="https://cyber.dabamos.de/88x31/">The 88x31 GIF Collection</a>.</li> +<li>All my content licensed under <a href="https://creativecommons.org/licenses/by-sa/4.0/">CC BY-SA 4.0</a>.</li> +</ul> +<h3 id="your-privacy">Your Privacy</h3> +<ul> +<li>No analytics tracking. No cookies.</li> +<li>Third-parties usage: Hosted by <a href="https://github.com/diessica/diessica.github.io">GitHub Pages</a> behind <a href="https://www.cloudflare.com/en-gb/privacypolicy/">Cloudflare</a> as CDN.</li> +</ul> + + + + + We Misunderstand Learning + 2024-09-19T13:13:42+00:00 + 2024-09-19T13:13:42+00:00 + + + + + Unknown + + + + + + /blog/we-misunderstand-learning/ + + <p><em>We misunderstand learning.</em> We think learning happens as we consume information, so we insist on consumption, hoping it will make sense. Reading sparks new ideasā€”yet often we merely seek out validation for the ones we already have. <em>We misunderstand learning.</em> We cling to theory like a lifeline, as though it can stand on its own, while overlooking the experimental space where it transforms: practice. Perhaps we gamify it. (Unlearning our addictions is another matter entirely.) We escape the confusion that must lingerā€“it slips us that lingering isnā€™t forever. <em>We misunderstand learning.</em> Through edutainment, we satisfy the illusion of smooth progress, estimated reading times, chapter after chapter. True learning is too disjointed, unpredictable, and fraught with setbacks. We obsess over minimising gaps between repetitions, but are these gaps learning breaks, or learning itself? I recall the first time I picked up a guitar: my fingers aching to stretch, shredding like crazy against the strings. The morning after, I played the chordā€”not through conscious effort or passion, but because my fingers developed dexterity and calluses overnight. <em>We misunderstand learning.</em> Technique matters, yes, but some processes of embedding patterns are handled by our bodies in their own time. Others always seem to have it easier, so we feel ashamed. I wonā€™t lieā€“some do have it easier. But most often we donā€™t know, we werenā€™t there to see behind the ease, and nobodyā€™s quite vulnerable these days.</p> +<p>We misunderstand learning, but once, we were in intimate touch with it. Back when we hadnā€™t yet been subjected to environments of comparison, deadlines, narrow molds, and had our complexities and neuro-diversities amassed into pure functions. Iā€™m still not immune to this. At times, learning as an adult feels like a endless chase of the instinctive dance of curiosity it once was. Throw at it: Pomodoro timers, habit trackers and productivity hacks. Yet, itā€™s only when I sit down to an unmysterious learning practice and truly welcome confusion, chaos, and seeming non-productivity that I feel like I can dance with curiosity again, and learn.</p> + + + + + Fetch a npm package on GitHub without npm install + 2024-08-25T16:30:00+00:00 + 2024-08-25T16:30:00+00:00 + + + + + Unknown + + + + + + /blog/fetch-npm-package-without-npm-install/ + + <p>The other day, a npm package was released broken to a private GitHub registry and it wouldnā€™t install:</p> +<pre style="background-color:#282a36;color:#f8f8f2;"><code><span>&gt; npm install @company/my-package +</span><span>This error happened while installing the dependencies of @company/my-package@0.0.34 +</span><span> +</span><span>another-package is not in the npm registry, or you have no permission to fetch it. +</span></code></pre> +<p>The error message is clear: the released package <code>@company/my-package</code> Iā€™m trying to install depends on a package <code>another-package</code> expected to exist in the npm registry somewhere. But <code>another-package</code> is not there. I already knew those packages came from a monorepo, so likely <code>another-package</code> was only an internal dependency in the monorepo, left unreleased. I wanted to inspect the package contents before releasing any fix to be sure, but couldnā€™t rely on <code>npm install</code> for that. There used to be an option to download npm packages via GitHub UI, but thatā€™s no longer the case.</p> +<h2 id="finding-the-package-tarball">Finding the package tarball</h2> +<p>One can read the packageā€™s metadata to find a download URL for the packageā€™s latest version. Hereā€™s how:</p> +<ol> +<li> +<p>(For private GitHub registries) Grab a <a href="https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens#creating-a-personal-access-token-classic">classic GitHub token</a> with <code>packages:read</code> permissions (hereafter <code>{GITHUB_TOKEN}</code>).</p> +</li> +<li> +<p>The URL of a npm package published to GitHub is <code>https://npm.pkg.github.com/{PACKAGE_NAME}</code>. Use that to fetch the package metadata, which contains the package tarball URL.</p> +</li> +</ol> +<pre data-lang="sh" style="background-color:#282a36;color:#f8f8f2;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#ff79c6;">&gt;</span><span> curl </span><span style="color:#50fa7b;">-L</span><span style="font-style:italic;color:#ffb86c;"> -H </span><span style="color:#f1fa8c;">&quot;Authorization: Bearer {GITHUB_TOKEN}&quot; &quot;https://npm.pkg.github.com/@company%2Fmy-package&quot; </span><span style="color:#ff79c6;">| </span><span style="color:#50fa7b;">grep</span><span style="font-style:italic;color:#ffb86c;"> -o </span><span style="color:#f1fa8c;">&#39;&quot;tarball&quot;:&quot;[^&quot;]*&quot;&#39; +</span><span style="color:#f1fa8c;">&quot;tarball&quot;</span><span style="color:#50fa7b;">:</span><span style="color:#f1fa8c;">&quot;https://npm.pkg.github.com/download/@company/my-package/0.0.34/3d0304f38791214b09ec92a2262ca1697f&quot; +</span></code></pre> +<ol start="3"> +<li>Download the package using the tarball URL.</li> +</ol> +<pre data-lang="sh" style="background-color:#282a36;color:#f8f8f2;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#ff79c6;">&gt;</span><span> curl </span><span style="color:#50fa7b;">-L</span><span style="font-style:italic;color:#ffb86c;"> -H </span><span style="color:#f1fa8c;">&quot;Authorization: Bearer {GITHUB_TOKEN}&quot; &quot;https://npm.pkg.github.com/download/@company/my-package/0.0.34/3d0304f38791214b09ec92a2262ca1697f&quot; </span><span style="color:#ff79c6;">| </span><span style="color:#50fa7b;">tar</span><span> zx +</span></code></pre> +<p>That will download the package to your current folder, and you may inspect the package contents now. :-)</p> + + + + + The Bitter Reality of Ebooks and the Kindle Model + 2023-08-16T13:55:00+00:00 + 2023-08-16T13:55:00+00:00 + + + + + Unknown + + + + + + /blog/the-bitter-reality-of-ebooks/ + + <p>A few years back, I jumped into the world of ebooks to broaden my reading without stacking so many physical books. I went with the ever-popular Kindle; yet the full weight of ā€œowningā€ ebooks, particularly from Amazon, was not something I understood.</p> +<p>ā€¦Until I decided to break up with Amazon, despite its convenience. You know the drill: Amazon <a href="https://www.theguardian.com/technology/2020/feb/05/amazon-workers-protest-unsafe-grueling-conditions-warehouse">exploits workers</a>, <a href="https://fairtaxmark.net/tax-gap-of-silicon-six-over-100-billion-so-far-this-decade/">aggressively avoids taxes</a>, <a href="https://www.bloomberg.com/graphics/2019-amazon-reach-across-markets/">dominates markets</a>, and I was just itching to explore alternative bookstores. The hiccup? My Kindle was firmly rooted and entangled in Amazonā€™s ecosystem. Without Amazon, I could no longer conveniently <em>or legally</em> read books on my Kindle, and without Kindle, I could not legally read books I once purchased on Amazon.</p> +<p>Hereā€™s what Iā€™ve learned while attempting to part ways.</p> +<h2 id="it-all-begins-with-drm">It all begins with ā€œDRMā€</h2> +<p>Digital Rights Management (ā€œDRMā€) might not be a household term, yet its fingerprints are everywhere. <strong>Ever wondered how we consume content via proprietary software, rather than owning the content?</strong></p> +<p>Think Spotify (you never own the music), Netflix (you never own the film), Adobe Creative Cloud (you never own the software), Steam (you never own the game), and Amazon Kindle (you never own the ebook). You download those proprietary software on your device, not the content itself. While you may have a license to the content, but itā€™s not <em>truly</em> yours.</p> +<p>The use and distribution of the copyrighted content provided by those services (and many others) are restricted by DRM (ā€œ<em>Digital Rights Management</em>ā€) technologies, <a href="https://en.wikipedia.org/wiki/Digital_rights_management#Technologies">implemented in various ways, increasingly restrictive and controversial</a>. While DRM aims to address the legitimate need of copyright protection, it fundamentally reshapes the landscape of intellectual consumption, often at the expense of user privacy and freedom. For example:</p> +<ul> +<li> +<p><strong>Content Sharing</strong>: DRM often limits, or restricts altogether, the ability to share, lend and gift content outside of the same ecosystem.</p> +</li> +<li> +<p><strong>Content Portability</strong>: DRM can authorise content to only a specific set of devices or apps, and restrict the supported file formats (even to a proprietary format). That limits content migration across platforms, technologies and devices that better suit you.</p> +</li> +</ul> +<p class="note">The points above reveal an alarming side-effect: dependency on the ecosystem, or "<b>vendor lock-in</b>", which is detrimental to individual freedom and market competition. When content is tightly bound to the platform, disengaging becomes challenging. And when you're limited to sharing only within an ecosystem, your social circle gets roped in too. Kinda seem like cute digital mutualism until it's a toxic relationship you can't leave.</p> +<ul> +<li> +<p><strong>Content Perpetuity</strong>: DRM cannot guarantee perpetual access to content. If a service or platform discontinues the content or themselves entirely, you may simply lose what you purchased. In fact, <a href="https://www.bbc.com/news/technology-47810367">that has already happened</a>, <a href="https://www.nytimes.com/2009/07/18/technology/companies/18amazon.html">more than once</a> or <a href="https://www.bekkelund.net/2012/10/22/outlawed-by-amazon-drm/">twice</a>.</p> +</li> +<li> +<p><strong>Content Geographical Restrictions</strong>: DRM can prevent access to certain content based on location. With the internet alone, we could technically provide equal access to cultural and educational resources ā€“ DRM kills that.</p> +</li> +<li> +<p><strong>Content Offline Access</strong>: DRM often requires <em>online</em> authentication or periodic online checks. Not very nice in low connectivity areas or during travel.</p> +</li> +<li> +<p><strong>Personal Identification</strong>: DRM requires authentication to consume content. By withholding identifiable information, DRM systems may also monitor behavior and consumption patterns and then profile you. <a href="https://en.wikipedia.org/wiki/Nothing_to_hide_argument">Youā€™ve got nothing to hide</a>? Well, perhaps it at least bothers you to have to login? <a href="https://en.wikipedia.org/wiki/Straw_man">(And if that keeps going on we might soon have login on physical books too?! And there will be no refresh token cookie irl?!?????)</a></p> +</li> +</ul> +<p>All those ā€œside-effectsā€ (given they are actually unintended šŸ˜‰) of copyright protection through DRM conveniences corporations. Corporations may not only protect their profit but also <em>actively profit</em> through DRM, charging high customer cost while delivering zero customer value.</p> +<p>Finally, because DRM implementations vary so much, itā€™s nearly impossible to determine your rights without diving into lengthy terms of use agreements. The restrictions are rather obscured by clever marketing ā€“ youā€™ll soon see.</p> +<h2 id="leaving-amazon-and-failing">Leaving Amazon, and failing</h2> +<p>Do you still remember I was trying to break up with Kindle? I get too hung up sometimes but letā€™s not forget why weā€™re both here, right!!?!</p> +<p>First things first, let me make it clear ā€“ I did not want to give up ebooks. Itā€™d been a pleasure to be able to dive into new literature and keep only the gems in my bedroom bookshelf. And I could also carry a multitude of stories effortlessly during my travels.</p> +<p>Secondly, I had no intention of trashing my Kindle. It was a fully functional piece of hardware, and it worked well.</p> +<p>So here was my grand plan: Iā€™d log out of my Amazon account on the Kindle, and source my ebooks somewhere else. Seems pretty straightforward, right? But the hurdles kicked in right from the very first step.</p> +<p class="note">FuN fACt: <a href="https://www.bbc.com/news/technology-19907546">Kindle sales are not very profitable to Amazon</a>, as they hope to make up for it with e-book and app sales.</p> +<p>As it turns out, signing out of my Amazon account meant every single piece of content Iā€™d ever acquired through Kindle would vanish into thin air. On Kindle, your books are tied to your Amazon account.</p> +<p>That was an unforeseen repercussion. I naĆÆvely expected to hold rights over books Iā€™d purchased regardless of whether they were digitally or physically distributed. So I was disappointed and surprised ā€“ with myself, the state of things; both. And yes, I clearly had not read Kindle terms of use back when I got into the ecosystem (otherwise you wouldnā€™t be reading this! šŸ˜‰).</p> +<h3 id="finally-reading-kindle-terms-of-use">FINALLY reading Kindle Terms of Use</h3> +<p>The latest <strong><a href="https://www.amazon.com/gp/help/customer/display.html?nodeId=201014950">Kindle Store Terms of Use</a></strong> (Last updated: November 30, 2022), determines a set of restrictions you buy into when you decide to buy Kindle and Kindle content, DRM-protected or not. The ā€œUse of Kindle Contentā€ section states a couple of DRM-ish things:</p> +<ol> +<li>ebooks are meant to be consumed only on Kindle, or Kindle apps.</li> +</ol> +<p class="note">Upon your download or access of Kindle Content and payment of any applicable fees (including applicable taxes), the Content Provider grants you a non-exclusive right to view, use, and display such Kindle Content an unlimited number of times (for Subscription Content, only as long as you remain an active member of the underlying membership or subscription program), <b>solely through a Kindle Application or as otherwise permitted as part of the Service, solely on the number of Supported Devices specified in the Kindle Store</b>, and solely for your personal, non-commercial use. [...]</p> +<ol start="2"> +<li>when you click ā€œBuy Nowā€<sup class="footnote-reference"><a href="#1">1</a></sup>, you are actually buying a license i.e. renting.</li> +</ol> +<p class="note">Kindle Content is licensed, not sold, to you by the Content Provider. [...]</p> +<p>Coming from DRM-based services like Spotify or Netflix, where you subscribe for access to a collection of music or film, the Kindle model might be a surprise.</p> +<p>Within the Kindle ecosystem, you are able to buy <em>individual</em> content, which does evoke a stronger sense of direct ownership. Yet, when you do so, youā€™re essentially obtaining a license: every ebook is an one-off payment to a mini-subscription. And that was absolutely not straightforward or intuitive to me.</p> +<ol start="3"> +<li>you may not lend or sell your ebooks.</li> +</ol> +<p class="note">Unless specifically indicated otherwise, you may not sell, rent, lease, distribute, broadcast, sublicense, or otherwise assign any rights to the Kindle Content or any portion of it to any third party [...]</p> +<ol start="4"> +<li>your books might disappear anytime.</li> +</ol> +<p class="note">We may change, suspend, or discontinue the Service, in whole or in part, including adding or removing Subscription Content from a Service, at any time without notice.</p> +<p>(Funny enough, I checked <a href="https://web.archive.org/">Wayback Machine</a> and noticed that one was amended around March 2015, after reports of disappearing ebooks years before. šŸ¤·)</p> +<h3 id="and-embracing-the-sacrifice">ā€¦And embracing the sacrifice</h3> +<p>Delving into the Kindleā€™s terms brought the truth crashing down on me: I never really had a choice to transition away from Amazon while retaining my content. Severing ties with Kindle came at a cost I hadnā€™t anticipated, and I felt very exploited for it.</p> +<p>Some might argue I <em>actually</em> had the ā€œchoiceā€ to enter Kindleā€™s ecosystem. And sure, itā€™s true ā€“ I did it willingly, no one coerced me into becoming a Kindle user. But, hey, thereā€™s a nuanced reality here you canā€™t brush aside: we make our individual choices <em>within systems</em>. Thereā€™s an entire environment lying behind the notion of individual choice.</p> +<p>Systems can be designed to subtly exert control or exploit personal choice in ways that arenā€™t always apparent. You canā€™t look at individual choice alone overseeing the environment in which those decisions are made. In no defensiveness, blaming on individual choice is, I dare to say, exactly how exploitative systems maintain their facade of legitimacy. And I donā€™t think being exploited or not should be a choice to be made.</p> +<p>Yeah, a bitter pill to swallow, but a new plan has to emerge out of my anger: to log out of my Amazon account, <strong>and therefore leave books Iā€™ve purchased behind</strong>, and use Kindle only as an e-reader, not a shop.</p> +<h2 id="leaving-amazon-and-failing-less">Leaving Amazon, and failing less</h2> +<p>After logging out of my Amazon account, Iā€™m left with an anonymised Kindle (I hope). At this point I wonder if I even have the right to keep the hardware Iā€™ve purchased, but so far nobody hasnā€™t taken it away from me. šŸ˜‰ So, how can I rebuild my e-book library?</p> +<h3 id="using-kindle-with-other-bookstores">Using Kindle with other bookstores</h3> +<p>Before buying ebooks elsewhere, one needs to understand what file formats are supported by Kindle. The file formats supported by Kindle are MOBI, PRC, PDF, and primarily the proprietary AZW, and the files may or may not be DRM-protected depending on the publisher. <strong>Only Amazon sells AZW books<sup class="footnote-reference"><a href="#2">2</a></sup></strong>. So my options are:</p> +<ul> +<li>MOBI. But no bookstores sell them these days.</li> +<li>PDF. But formatting sucks for reading books.</li> +<li>PRC. I donā€™t know what that is.</li> +</ul> +<p>So I have no options. \šŸ˜Ž/ Bookstores sell <a href="https://en.wikipedia.org/wiki/EPUB">EPUB</a> books, an open standard well supported by all e-readers in the market <strong>but Kindle</strong>. Fortunately, you can manually convert EPUB books into one of the Kindle-compatible formats above. Unfortunately, if the book is DRM-protected (very likely!), you would need to strip out DRM before conversion <strong>which is downright illegal LMAOOOOOO</strong>!!!!! This drives me CRAZY, but letā€™s move on.</p> +<p>For ebook format conversions, Amazon fortunately offers <a href="https://www.amazon.com/gp/feature.html?ie=UTF8&docId=1000765261">Kindle Previewer</a>, a publishing software, but itā€™s just a little too bloated for my goal. So I went with <a href="https://github.com/kovidgoyal/calibre">Calibre</a>, a free and open source e-book manager that does it all. It works wonders!</p> +<p class="note">If you keep your Amazon account, importing EPUB into is easier with <a href="https://www.amazon.com/gp/sendtokindle/email">Send to Kindle</a>. It's a more convenient option but it often messes up with the book formatting.</p> +<p>Ultimately, using non-Amazon ebooks on a Kindle device can involve various technical and legal considerations, especially when dealing with DRM-protected content. DRM-free book shopping is also limited ā€“ DRM <em>is</em> an industry standard! <strong>So using a Kindle without Amazon is not just very inconvenient, itā€™s barely legal.</strong> šŸ˜‰</p> +<p>The most promising plan seems to be tossing Kindle altogether, and choose an open standard e-reader with less hostile DRM platforms, but thatā€™s for another time.</p> +<h2 id="amazon-caters-for-publishers-not-consumers">Amazon caters for publishers, not consumers</h2> +<p>It all makes sense when you put it all together. When traditional publishing giants contemplated the world of e-readers and online stores, they had to be a bit careful about it. With physical distribution, they already had a model that offered a clear sense of ownership and control. Then, remember the music industryā€™s digital transformation, marked by piracy and revenue decline<sup class="footnote-reference"><a href="#3">3</a></sup>? Obviously publishers would be wary of a similar fate.</p> +<p>But in comes a compelling offer from Amazon: a tight grip on digital ownership of books, and a shortcut into an already profitable book marketplace. All or nothing. A captivating promise of control and access which publishers, late to digital transformation, did not pass up. And so seamlessly, Amazon paved the way towards market dominance. šŸ‘</p> +<p>Today, Amazon also positions itself as a platform for emerging writers and attracts independent publishers. So does Spotify for musicians, and Steam for game developers. For both publishers and consumers, content discovery is whatā€™s great about such platforms, despite their license model.</p> +<p>Alternatives like Bandcamp (music) and GOG.com (games) also promote publishersā€™ content. In contrast, their DRM-free<sup class="footnote-reference"><a href="#4">4</a></sup> model ethically caters to both consumers and publishers: the consumer has direct ownership to content, and publishers get their content secured, even earning more<sup class="footnote-reference"><a href="#5">5</a></sup>. How does that work? Fingerprinting content files (i.e. watermarks), but above all, cultivating consumer trust and transparency, and a sense of community and support for artists.</p> +<h2 id="final-words">Final words</h2> +<p>While writing this, an analogy came to mind.</p> +<p>Picture when you buy a physical book from a store. You know that book will patiently await you right where you left it and not vanish into thin air, whether you frequent the store or it eventually shuts down. That store is unaware of your identity. It doesnā€™t know when you open or close the book, nor does it know which passages youā€™ve highlighted. You can even lend the book to a friend, regardless of whether they shop at the same store or if the store recognizes them. And that both of you can go buy books elsewhere later with no strings attached.</p> +<p>But I know thatā€™s kinda corny. Itā€™s an oversimplification. Digital content IS different, and copying files is far easier technically than producing physical copies. We do have new challenges.</p> +<p>Yet, while the analogy might not outright invalidate DRM as a solution, it can serve as a reminder of the current asymmetry of our digital rights today. A nudge to the way our essential rights are exploited within the current framework of digital copyright protection. And, ultimately, it extends an invitation to reimagine it from the ground up. Perhaps looking at how other platforms like Bandcamp have already done so brilliantly, perhaps radically starting at copyright itself.</p> +<h2 id="keep-reading">Keep reading</h2> +<p>ā€¦on how despite massive technical effort and corporate interest, DRM is a flawed security model.</p> +<ul> +<li><a href="https://wiki.openrightsgroup.org/wiki/Digital_Rights_Management">Open Rights Group: Digital Rights Management</a></li> +<li><a href="https://www.defectivebydesign.org/guide/ebooks">Defective by Design: Guide to DRM-Free Literature</a></li> +<li><a href="https://www.defectivebydesign.org/faq">Defective by Design: DRM FAQ</a></li> +<li><a href="https://en.wikipedia.org/wiki/Comparison_of_e-readers#File_format_support">Comparison of e-readers: File format support</a></li> +<li><a href="https://meshedinsights.com/2017/07/09/drm-is-toxic-to-culture/">DRM is Toxic to Culture</a></li> +</ul> +<div class="footnote-definition" id="1"><sup class="footnote-definition-label">1</sup> +<p>As of 16/08/2023, Amazonā€™s checkout button for Kindle ebooks is labeled ā€œBuy Nowā€.</p> +</div> +<div class="footnote-definition" id="2"><sup class="footnote-definition-label">2</sup> +<p><a href="https://s3-us-west-2.amazonaws.com/customerdocumentation/EM/Kindle_User_Guide_EN-US.pdf">ā€œKindle User Guide 4th Edition</a>, p. 39</p> +</div> +<div class="footnote-definition" id="3"><sup class="footnote-definition-label">3</sup> +<p><a href="https://www.sowi.uni-stuttgart.de/dokumente/forschung/soi/soi_2020_4_Dolata.digital.transformation.music.industry.pdf">Ulrich Dolata, ā€œThe Digital Transformation +of the Music Industry: The Second Decade: From Download to Streamingā€ (2020)</a>, p. 7</p> +</div> +<div class="footnote-definition" id="4"><sup class="footnote-definition-label">4</sup> +<p>See <a href="https://get.bandcamp.help/hc/en-us/articles/360013673153-Are-Bandcamp-s-download-formats-DRM-free-">Are Bandcampā€™s download formats DRM-free?</a> and <a href="https://www.gog.com/news/bgog_2022_update_2b_our_commitment_to_drmfree_gaming">GOG 2022 UPDATE #2: OUR COMMITMENT TO DRM-FREE GAMING</a>.</p> +</div> +<div class="footnote-definition" id="5"><sup class="footnote-definition-label">5</sup> +<p>In comparison to Spotify, whose profit margin for publishers is often questioned. See <a href="https://www.nytimes.com/2021/05/07/arts/music/streaming-music-payments.html">Ben Sinano: Musicians Say Streaming Doesnā€™t Pay. Can the Industry Change?</a>.</p> +</div> + + + + + Long Time No See + 2023-06-30T11:19:00+00:00 + 2023-06-30T11:19:00+00:00 + + + + + Unknown + + + + + + /blog/long-time-no-see/ + + <p>In the past three years, a wild mix of stuff dragged me away from writing. More time šŸŒ³ offline ā›°ļø, which was great. Then a demanding role in a small team, the chaotic grip of a global pandemic, increasing perfectionism, and a blossoming and ultimately collapsing relationship ā€“ which all conspired to shake up my pursuits and thrust me into an introspective whirlwind. And as if that wasnā€™t difficult enough, I lost two yearsā€™ worth of drafts in a backup blunder.</p> +<p>Whenever I attempted to restart, I found myself entangled in a web of what still resonated with me and what no longer did. But hey, listing more excuses would only scratch the surface. I recognize now, after seeing how little it takes for me to be back, that parts of me were simply in disarray. Yet, as I come together again, so does my motivation to reclaim what I enjoy, and make time for it despite the busyness and excuses.</p> +<p>So, last night, I did what I do best: I embarked on an in-one-sitting endeavor! I migrated this blog to <a href="https://www.getzola.org/documentation/getting-started/overview/">Zola</a> (a speedy static generator written in Rust), so this WeBpAg3 remains therefore static and snappy af, joining the <a href="https://512kb.club/">&lt;512 kB club</a>. Letting my creativity flow with <a href="https://tailwindcss.com/">Tailwind</a>, I gave my WeBpAg3 an extravagant-outrageous look, and made sure itā€™s accessible. I rewrote my introduction like a million times. I sifted through my writings, organising and archiving some, and lo and behold!: I stumbled upon those lost drafts hidden away in the depths of my physical backups. <em>Pretty thrilling.</em> As a friend once told me, <strong>good things happen when good things happen</strong>.</p> +<p>Long time no see! It all feels quite nice, if you ask me. šŸ˜‰</p> + + + + + What I've Learned by Simply Journaling + 2020-04-20T00:10:15+00:00 + 2020-04-20T00:10:15+00:00 + + + + + Unknown + + + + + + /blog/journaling/ + + <p>In 2018, circumstances inevitably changed and I began taking up much more in life. I was under stress, regardless of being on the safe side, and the patterns that kept me grounded were no longer holding up.</p> +<p>Back then, seeing the big picture was unattainable with the stress snowballing and skewing my perspective. Dwelling in my head, paving the way to <a href="https://en.wikipedia.org/wiki/Learned_helplessness">learned helplessness</a>, I decided to try out journaling.</p> +<p>More than a year later, I can finally say <em>alles gut</em>. Although circumstances havenā€™t changed much, I certainly handle them better. I keep journaling as of today, and am excited to share my setup and (hopefully) motivating takeaways!</p> +<h2 id="how-i-journal">How I Journal</h2> +<p>I did not go for the traditional diary format. I decided to Bullet Journal, a flexible journal method founded in quick lifelogging by means of a pen, paper, and bullet points.</p> +<p>Pen and paper pull me out of my head and let me continuously evolve my notebook as my needs change, since there is no predefined template. As for bullet points, we all know their efficacy: hasty logging and later reviewing at a glimpse.</p> +<h3 id="method">Method</h3> +<p class="note">Peek into <a href="https://bulletjournal.com/pages/learn">Bullet Journal official page</a> for an overview, as I won't dive into the framework basics.</p> +<p>The Bullet Journal framework is made out of four fundamental ā€œcollectionsā€: Index, Daily Log, Monthly Log, and Future Log, plus custom collections you find valuable. After a while of tinkering around, I came to some insights and tweaks.</p> +<ul> +<li> +<p><strong>Index</strong> turned out useful when I added custom collections, as those usually end up scattered across the journal and thus hard to find.</p> +</li> +<li> +<p><strong>Daily Logs</strong> is where I keep track of notes, events, tasks, thoughts, and ideas. (All mixed together, which portrays a day accurately if you ask me.) I recommend using signifiers and nesting (for a tree-like view) in bullet points to convey meaning with ease, as Bullet Journal suggests.</p> +</li> +<li> +<p><strong>Monthly Log</strong> didnā€™t work for me. I steer towards weekly or quarterly ranges. Also, my online calendar is more practical so I couldnā€™t bother drawing calendars every month.</p> +</li> +<li> +<p><strong>Future Logs</strong> are useful to migrate tasks or events to upcoming months, for when you donā€™t get something done but canā€™t ā€œnevermindā€ it either.</p> +</li> +</ul> +<p>As for custom collections, the Bullet Journal ecosystem is huge! Iā€™ve seen stuff of all kinds out there: finance/sleep/food/water trackers, recipes, trip planning, doodles, and whatnot. Yet, these are the ones I always come back to:</p> +<ul> +<li><strong>Diaries</strong>: longer diary entries or brain dumps without the limitation of bullet points, for when I feel like it.</li> +<li><strong>Habit Trackers</strong>: a simple daily tracker to monitor or develop habits across weeks, e.g. meditation, alcohol intake, call family.</li> +<li><strong>Weekly Logs</strong>: my weekly variation of ā€œMonthly Logā€, with upcoming events and small goals for the week. Usually done on Sunday or Monday.</li> +<li><strong>Quarterly Logs</strong>: my quarterly variation of ā€œMonthly Logā€, with upcoming events and big goals for the quarter.</li> +<li><strong>Year Retrospective</strong>: a straightforward year review regarding what did and did not go well, what to keep or let go from last year etc. +I journal spontaneously throughout the day, but mostly in mornings or evenings. I do it every day, even when I donā€™t feel like it. In the long run, thatā€™s gotten me to fathom my anxieties by having them logged as well as what was up days before. It goes a long way to flip through logs of piled up chores, social isolation, binge drinking, and sleep deprivation, to later find yourself taking down ā€œI am anxious. Canā€™t do shitā€.</li> +</ul> +<p>Be that as it may, I donā€™t keep it all gloomy. With my throughput in mind, I may also soften up my daily logs with receipts from exquisite restaurants I come across, cute post-its from friends, or even silly useless quotes from fortune cookies.</p> +<p>At last, I have to say Iā€™m not really a big planner so you can see thatā€™s not what I optimise my journal for. All I strive for is a little awareness of whatever Iā€™m doing for the time being. I enjoy a spontaneous and organic life, and thatā€™s gotten me far enough to make me happy.</p> +<h3 id="pen-paper">Pen &amp; Paper</h3> +<figure class="text-center"><picture><img src="../../media/2020/bullet-journal.jpg" alt="Notebooks on desk. On the left: Camel brown notebook with bear symbol on cover. On the right: Forest green notebook with deer symbol on cover."></picture> +<figcaption> +My 2019 journal (left) and 2020 journal (right).</figcaption></figure> +<p>In 2019, I used an A5+ (slightly wider than regular A5) dot-grid notebook. Itā€™s bulky to carry around but I donā€™t regret it: the pages are wide enough to encourage writing. The quality of its pleasing yellow paper is outstanding, thick enough to prevent ink from leaking through. I ended 2019 with a few pages empty.</p> +<p>This year, I went for something more portable: an A6 dot-grid notebook. It took me a while to get used to the size constraints, and Iā€™ve been certainly more straightforward with my logs. I am pretty sure I will have no pages left this time. (Wondering what was the advantage of it all as Iā€™m not going anywhere anyway thanks to COVID-19.)</p> +<p>As for pens, I use different colours of a 0.4 mm fineliner.</p> +<h2 id="what-i-ve-learned">What Iā€™ve Learned</h2> +<p class="note">I'd not assume these stem necessarily from the way I set myself up. Audio or video recordings, traditional diary, and other journal formats are worth exploring and might help just as well.</p> +<ul> +<li> +<p><strong>Less overwhelm, more time.</strong> To truly chill out when life gets overwhelming, you gotta plan ahead. Especially in already busy weeks, I use my journal to put down chores I commit to get done, prioritising what I signify as deadline-sensitive. Before, with my tendency to overfocus, Iā€™d take up activities without planning and end up neglecting my responsibilities and needs. Imagine how far this can go!</p> +</li> +<li> +<p><strong>Emotional awareness.</strong> Iā€™ve gained a grasp of the phenomenology of my emotions and the lens through which I see life, markedly my cognitive distortions on stressful days. Attitudes like pessimism inevitably surface as you jot down negative thoughts all the time. Being mindful allowed me to reframe negative views, and turn obstacles into opportunities.</p> +</li> +<li> +<p><strong>Better retainment.</strong> Itā€™s easy to fall into the trap of ā€œI have a bad memoryā€ when one has been busy and mooning for so long. Leading a busy life mindlessly is not what I strive for, and journaling only feeds into that: I hold dear people, moments, promises, and no longer miss so many appointments (planning helped here too!).</p> +</li> +<li> +<p><strong>Constant assessment.</strong> Journaling is a tool to assess the present as well as the past and the future. By peeping into where Iā€™ve been, what did/didnā€™t go well, or who I have been with, for instance, I can ponder more sensibly on my growth and relationships. Early feedback on my own life, sort of, to leverage self-improvement in relationships, health, work, and so on.</p> +</li> +</ul> +<h3 id="pitfalls">Pitfalls</h3> +<ul> +<li> +<p><strong>Perfectionism.</strong> Obsession over constant logging or perfection is right at the door for you to slip into. On social media (Pinterest, YouTube), everyoneā€™s journal seems visually-appealing every day without fail. Even Bullet Journal, a method dead straightforward, can be a rabbit hole. Remind yourself to solve your problem in a way that enhances your daily life, not burdens it. You gain absolutely nothing from buying into slices of life people sell online.</p> +</li> +<li> +<p><strong>Habit-building.</strong> When not a habit, journaling is just another chore. Make it effortless and engaging: establish a routine (if thatā€™s your thing), designate it a place where itā€™s always within reach, or tailor the framework to your needs. If you enjoy drawing once in a while, why not? If you have no patience for 29872 different pen colours, why do it? If you want to write about your day with your partner in bullet points instead of coming up with a best-seller love story, who cares?</p> +</li> +<li> +<p><strong>Procrastination.</strong> Journaling constantly nudges you to look back at your life and how youā€™ve been spending your time and energy. That can be challenging and wonā€™t change. For starters, you might come to the unpleasant realisation that you self-sabotage, or that a certain relationship is fading away. If you are avoidant, you will most likely put off journaling often; not because of the method or routine, but fear of what you may find ā€“ fertile soil for procrastination.</p> +</li> +<li> +<p>For pen &amp; paperā€¦ <strong>No backup</strong>. Some companies have tried, but whatā€™s hand-written wonā€™t sync with a cloud server. You do carry the weight if traveling or taking it to work, and itā€™s probably gone if you spill coffee on it. I, though, think the trade-off is worth it and havenā€™t looked back.</p> +</li> +</ul> +<h2 id="final-takeaway-takeout-box">Final Takeaway šŸ„”</h2> +<p>I am all for simplicity, yet that didnā€™t keep my mind from boggling when I realised such a simple tool turned out to be a game-changer. Starting off was not easy, but the benefits showed up and kept me motivated ā€“ a rewarding feeling I wouldnā€™t expect so hastily while building a new habit. Today, itā€™s just effortless and natural.</p> +<p>Ultimately, I hope this stimulates you to try journaling in whatever way and to deem simple tools as helpful to uncomplicate and improve our lives.</p> +<h2 id="references">References</h2> +<ul> +<li><a href="https://bulletjournal.com/pages/learn">Learn Bullet Journal</a></li> +</ul> + + + + + How to Spy on a React Prop with Jest + 2019-10-31T14:15:42+00:00 + 2019-10-31T14:15:42+00:00 + + + + + Unknown + + + + + + /blog/how-to-spy-on-a-prop-with-jest/ + + <p>When we want to test whether a prop has been called, mocking the prop in the component is usually the preferred way. This is how it goes with <a href="https://jestjs.io/">Jest</a> and <a href="https://airbnb.io/enzyme/">Enzyme</a>:</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">buy </span><span style="color:#ff79c6;">= </span><span style="color:#ffffff;">jest</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">fn</span><span>(); +</span><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">wrapper </span><span style="color:#ff79c6;">= </span><span style="color:#ffffff;">enzyme</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">shallow</span><span>(&lt;button onClick={buy}&gt;</span><span style="color:#ffffff;">Buy</span><span style="color:#ff79c6;">&lt;/</span><span style="color:#ffffff;">button</span><span style="color:#ff79c6;">&gt;</span><span>); +</span><span> +</span><span style="color:#ffffff;">wrapper</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">simulate</span><span>(</span><span style="color:#f1fa8c;">&quot;click&quot;</span><span>); +</span><span> +</span><span style="color:#50fa7b;">expect</span><span>(</span><span style="color:#ffffff;">buy</span><span>)</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">toBeCalled</span><span>(); +</span></code></pre> +<p>You may also want to spy on the prop directly, when the component is tested along with a provider passing down its props.</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">wrapper </span><span style="color:#ff79c6;">= </span><span style="color:#ffffff;">enzyme</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">shallow</span><span>( +</span><span> &lt;ClickProvider&gt; +</span><span> &lt;button&gt;</span><span style="color:#ffffff;">Buy</span><span style="color:#ff79c6;">&lt;/</span><span style="color:#ffffff;">button</span><span style="color:#ff79c6;">&gt; +</span><span> </span><span style="color:#ff79c6;">&lt;/</span><span style="color:#ffffff;">ClickProvider</span><span style="color:#ff79c6;">&gt; +</span><span>); +</span><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">buy </span><span style="color:#ff79c6;">= </span><span style="color:#ffffff;">jest</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">spyOn</span><span>(</span><span style="color:#ffffff;">wrapper</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">instance</span><span>()</span><span style="color:#ff79c6;">.</span><span style="color:#ffffff;">props</span><span>, </span><span style="color:#f1fa8c;">&quot;onClick&quot;</span><span>); +</span><span> +</span><span style="color:#ffffff;">wrapper</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">simulate</span><span>(</span><span style="color:#f1fa8c;">&quot;click&quot;</span><span>); +</span><span> +</span><span style="color:#50fa7b;">expect</span><span>(</span><span style="color:#ffffff;">buy</span><span>)</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">toBeCalled</span><span>(); +</span></code></pre> +<p>I am using Enzyme however you should be able to spy on similarly using other testing librariesĀ ā€“Ā just make sure you are spying on a function in the props coming from the component prototype (as in <code>wrapper.instance()</code>).</p> +<p>Thatā€™s all. Just posting it here cuz I couldnā€™t find it easily anywhere else.</p> + + + + + Setup for Audio Interface with Guitar Rig 5 on macOS Mojave + 2019-08-18T22:19:05+00:00 + 2019-08-18T22:19:05+00:00 + + + + + Unknown + + + + + + /blog/guitar-rig-macos-mojave-setup/ + + <p>Setting up <a href="https://www.native-instruments.com/en/products/komplete/guitar/guitar-rig-5-pro/">Guitar Rig 5</a> on macOS Mojave seems not to be straightforward.</p> +<p>Although I had gotten the signals to be sent from my guitar to the audio interface and from the interface to Guitar Rig, somehow itā€™d still not work. Instead of using my audio interface as the input <strong>and output</strong> device on Guitar Rig, I had to set up an ā€œaggregate deviceā€.</p> +<p>This how you can do it too.</p> +<p>(My specs, just so you know:)</p> +<pre data-lang="sh" style="background-color:#282a36;color:#f8f8f2;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#50fa7b;">macOS</span><span> Mojave Version 10.10.14 +</span><span style="color:#50fa7b;">Guitar</span><span> Rig Pro 5.2.2 +</span><span style="color:#50fa7b;">Audio</span><span> Interface Steinberg UR22mkII +</span></code></pre> +<h2 id="audio-midi-setup">Audio MIDI setup</h2> +<ol> +<li> +<p>Open ā€œAudio MIDI setupā€ in your Mac. (Itā€™s a tiny secret sound manager shipped along with the system, youā€™ll find it.)</p> +</li> +<li> +<p>At the very bottom of the app, there is a small + (ā€œplusā€) button wherein you should select <em>ā€œCreate an aggregate deviceā€</em>.</p> +</li> +<li> +<p>Set up your ā€œaggregate deviceā€ with your 1) audio inteface and 2) speakers/headphones/whatever ā€“Ā which should be all shown up there, given the setup is correct. Remember to give your device a remarkable name ā€“ I suggest <em>FUCK COMPUTERS AND AUDIO</em>.</p> +</li> +</ol> +<figure class="text-center"><picture><img src="../../media/2019/guitar-rig-macos-mojave-setup/audio-midi-setup.png" alt="Audio MIDI Setup app open showing audio device with both devices'"></picture> +<figcaption>My custom device in Audio MIDI Setup on macOS.</figcaption></figure> +<ol start="4"> +<li>Go back to Guitar Rig. In the context menu ā€œFileā€, go to <em>ā€œAudio and MIDI Settingsā€</em>. In the ā€œAudioā€ tab, select your aggregate device as the <strong>device</strong>, instead of only the audio interface as you were doing before; then configure input/output as expected in the ā€œRoutingā€ tab.</li> +</ol> +<p>Should work! If it doesnā€™t, <a href="https://support.native-instruments.com/hc/en-us/articles/210275885-I-Cannot-Get-Any-Sound-Output-from-GUITAR-RIG-5">this guide by Native Instruments on how to troubleshoot audio</a> and others guides on the website might help. Depending on your audio interface, make sure the right driver setup is in place ā€“Ā you can try out <a href="http://www.asio4all.org/">ASIO4ALL</a>.</p> +<img src="../../media/2019/guitar-rig-macos-mojave-setup/guitar-rig.png" alt="Guitar Rig app showing its custom amps"> +<p>If it still doesnā€™t work, I am sorry and prolly have no idea. Have fun.</p> + + + + + OMG Climate: Reflecting Together on the Climate Catastrophe + 2019-05-30T11:39:14+00:00 + 2019-05-30T11:39:14+00:00 + + + + + Unknown + + + + + + /blog/omg-climate/ + + <figure class="text-center"><picture><img src="../../media/2019/omg-climate/global-warming-nasa.gif" alt="NASA's illustration of Planet Earth warming process across the years"></picture> +<figcaption>Credits: NASAā€™s Scientific Visualization Studio/Kathryn Mersmann.</figcaption></figure> +<p>Planet Earth, May 2019. <a href="https://www.weforum.org/agenda/2019/05/the-uk-just-became-the-first-country-in-the-world-to-declare-a-state-of-emergency-on-climate-change">The UK has announced a state of emergency for climate change</a> and <a href="https://globalnews.ca/news/5280082/what-is-a-climate-emergency-canada/">Canada considers the same</a>; we are <a href="https://agupubs.onlinelibrary.wiley.com/doi/10.1029/2018JD029522">more confident about our model to capture rising global temperatures</a>, and <a href="https://www.theguardian.com/environment/gallery/2019/may/24/student-climate-strikes-around-the-world">students all around the world walk out of school protesting the lack of climate action</a>. Yet, not enough of us are genuinely concerned about the role weā€™ve played on this catastrophe.</p> +<p>A Saturday afternoon of May and a few square meters in Berlin were what a couple of people needed to openā€“Ā and voluntarily discuss how we impact the Planet to change and how those changes impact us. Topics ranged from radical solarpunk utopiaĀ to more down-to-earth and short-term ideas within our generationā€™s reach today: musings about climate change awareness, sustainability policies for companies, traveling sustainably, tech tools for political change, and how to get out of our bubbles and active listen to other realities.</p> +<p>In this post, Iā€™ll be sharing my personal notes on that engaging and constructive afternoon. There will be, also, references at the end of this post so you can keep yourself posted.</p> +<h2 id="pitching-and-picking-topics-for-discussion">Pitching and picking topics for discussion</h2> +<p><strong>OMG Climate</strong> is an unconference, meaning that attendees proactively come up with the agenda and topics to be discussed. To kick it off, we got instructed to pitch topics for discussion thatā€™d be prioritised also by ourselves into tracks, attended based off our preferences. Everyone was expected to have at least a certain knowledge, even if rather tacit, about the challenges weā€™re facing right now with the climate emergency.</p> +<p>These were the tracks of the first OMG Climate:</p> +<ul> +<li><strong>Track 1</strong>: ā€œLow-carbon travelā€ / ā€œGreen Mafiaā€ / ā€œHow do you sleep at night? Coping with climate anxietyā€</li> +<li><strong>Track 2</strong>: ā€œTech tools for political actionā€ / ā€œCircular economies: Re-use and techā€ / ā€œCompany sustainability policy templateā€</li> +<li><strong>Track 3</strong>: ā€œSolarpunk, imagination and excitementā€ / ā€œCO2 Offsets as an API and tracking carbonā€ / ā€œClimate change awareness in developing countriesā€</li> +</ul> +<p>We had enough attendees for tracks to make for productive discussions. Listening and talking to one another, while facilitated by a volunteer, did the job on keeping up an constructive flow between finding root causes and ways to take action.</p> +<figure class="text-center"><picture><img src="../../media/2019/omg-climate/discussion.jpg" alt="People sitting in a circle, listening attentively to one"></picture> +<figcaption>During the "Green Mafia" discussion.</figcaption></figure> +<p>Iā€™ve joined ā€œLow-carbon travelā€, ā€œGreen mafiaā€, and ā€œClimate change awareness in developing countriesā€, so these are the ones I have more insights about. Towards the end, we all got together to wrap it up, and I have to say: all tracks were interesting, so donā€™t restrain yourself to this post!</p> +<p class="note">The following notes don't reflect directly what's happened or everything that's been said in the event, it's rather my personal perspective. They are also somewhat vague, but I hope you can benefit from them somehow.</p> +<h2 id="low-carbon-travel">Low-carbon travel</h2> +<p>Air travel, even when occasional, has an <a href="https://en.wikipedia.org/wiki/Environmental_impact_of_aviation#Climate_change">environmental impact</a> difficult to make up for no matter how many bamboo toothbrushes we gift our friends, how often we commute by bike or how vegan is our diet.</p> +<p>With low airplane ticket prices getting more popular than ever and enabling people to travel more, how can we make traveling sustainable when <em>not traveling to begin with</em> is not an option? That was the question we kicked off the ā€œlow-carbon travelā€ discussion with.</p> +<h3 id="meeting-notes">Meeting notes</h3> +<figure class="text-center"><picture><img src="../../media/2019/omg-climate/low-carbon.jpg" alt="Piece of paper sticked to the wall with sketches"></picture> +<figcaption>Collective sketch notes about the low-carbon travel track</figcaption></figure> +<ul> +<li>In our circle, everyone seemed to have access to the privilege that is air flying.</li> +<li>We began exploring traveling by breaking it down into traveling for work vs. pleasure.</li> +<li><strong>Ground travel</strong> might be an option; however, itā€™s rather time-consuming and hence less appealing in a capitalist society where time translates to money. How can we shift the paradigm?</li> +<li>Instead of seeing longer trips as wasted time, we should begin seeing the journey as part of the trip.</li> +<li><strong>Traveling less</strong>: We often optimise our trips to visit as many places as possible; instead, we can optimise for depth and start going to fewer places for a longer time. Think: going to a European country and making the most of it, instead of going to 999 different countries just because they are 1-hour-flight away from each other.</li> +<li>Share practical solutions for people to make trade-offs, <a href="http://ecocostsvalue.com/"><strong>EcoCost</strong></a> rather than overwhelming scientific evidence.</li> +<li>What if companies supported employees whose carbon footprint is the least?</li> +<li>Green travel agencies and flying policies.</li> +<li>Search engines for flights obviously donā€™t suggest alternative ways to get to a place when a plane is definitely not the best option.</li> +<li><a href="https://bvg.de">BVG</a> app, on the other hand, recommends walking instead of taking public transport sometimes.</li> +<li>Transport apps could also order route options by the least environmental impact.</li> +<li>The car industry should be ashamed of its climate record.</li> +<li>The train industry is not modernised and integrated, rather rigid.</li> +<li>Investment on 10 km of autobahn could pay off the renovation for bike lanes all over Berlin.</li> +<li>Globalisation vs. environmental footprint: IT workers immigrating usually go back to their countries often since they have the need and resources. I asked whether there was data available on how that situation in particular couldā€™ve increased our carbon emissions coming from aviation.</li> +<li>Business trips by train are possible only among those who have the privilege of a flexible work schedule, such as freelancers.</li> +<li>Making the most out of idle time: we tend to be more creative in idle times, while in a train; not hunching over a keyboard or in an office environment.</li> +<li>ā€œFast-moving home/officeā€ as an alternative to turn the journey time into productive time.</li> +<li><strong>Frequent flyer levy</strong>: A fairer tax system according to how often people fly. Those that fly more should pay more. (More information: <a href="http://afreeride.org/">A Free Ride</a>)</li> +<li>Airline campaigns often promote the image that everyone should become part of a group of young, urban frequent flyers, visiting another city every few weeks for very low costs.</li> +</ul> +<h3 id="action-points">Action points</h3> +<ul> +<li>everyone to shift mindsets in regard to traveling.</li> +<li>everyone to vote instead of buying a bamboo toothbrush.</li> +<li>everyone to use and promote tools with different options of transport within a route, instead of blindly going to specific train or flight websites.</li> +<li>everyone to keep consuming local goods.</li> +<li>airline companies to stop promoting flying as a status symbol.</li> +<li>travel agencies to work out more sustainable ways to travel and consider it in their branding.</li> +</ul> +<h2 id="green-mafia">Green Mafia</h2> +<p>How corporate interests and ideologues work to undermine science and make countries doubt about the risks of climate change? Think <a href="https://www.theguardian.com/environment/planet-oz/2015/aug/06/how-australians-were-ready-to-act-on-climate-science-25-years-ago-and-what-happened-next">what stopped Australia, 25 years ago, to act on climate change</a>.</p> +<p>We should fight back! We mused about beating off lobby groups representing the coal, car, oil, electricity, and aluminium industries using their same sneaky techniques, as a <strong>Green Mafia</strong>. An intriguing and fun topic!</p> +<p>The brainstorming served as a tool to get a grasp on the way those mafias function, and discuss whether the ethical approach is always the way to go when facing a crisis.</p> +<h3 id="meeting-notes-1">Meeting notes</h3> +<figure class="text-center"><picture><img src="../../media/2019/omg-climate/green-mafia.jpg" alt="Piece of paper sticked to the wall with sketches"></picture> +<figcaption>Collective sketch notes about the Green Mafia track</figcaption></figure> +<ul> +<li>Leverage civil disobedience and tools of intimidation to influence green policies for the climate, fight extreme wealth and weaken existing mafias such as the oil industry.</li> +<li>How far should one go with non-ethical practices, such as blackmailing or public shaming of those who harm the planet?</li> +<li>Whatā€™s ethics after all?</li> +<li>Could we use illegal money to fund our causes?</li> +<li>Could we use legal money to fund our cases? There are ways to get money from the state in licit ways such as from green parties.</li> +<li>What if we made the green cause as profitable for the mafia as oil?</li> +<li>Sell a belief system, or use an existing one such as ā€œharmony with natureā€.</li> +<li>Cyber hacking/hijacking internet algorithms to spread awareness instead of climate change denial and fake news as it happens today.</li> +</ul> +<h2 id="awareness-in-developing-countries">Awareness in developing countries</h2> +<p>The rich, the poor and the Earth.</p> +<p><a href="https://www.theguardian.com/environment/2015/dec/02/worlds-richest-10-produce-half-of-global-carbon-emissions-says-oxfam">Worldā€™s richest 10% produce half of the global carbon emissions, while the poorest half contribute a mere 10%</a>; but climate change affects the poorest people the most. Moreover, developing countries are the most responsible for climate change now, and vulnerable too.<sup class="footnote-reference"><a href="#1">1</a></sup></p> +<p>Coming from a developing country, I was looking forward to this topic! Apart from Brazil, we had people from India too. There was a range of issues that could be tackled within this track, such as the risk of massive displacements of people in developing countries, the need of support to adapt, environment destruction for the sake of economic prosperity, how to approach climate change education etc.</p> +<h3 id="meeting-notes-2">Meeting notes</h3> +<ul> +<li>We are <strong>building awareness</strong>, not ā€œteachingā€ others about climate change.</li> +<li>Climate change is an existential threat to life, but it seems rather remote if you think about poverty, disease and economic stagnation. How do we educate children for the long-term if, for some of them, not showing up at school tomorrow means not eating at all?</li> +<li>How do we let them know about the risk of massive displacements of people who have no resources whatsoever to move?</li> +<li>Just by existing in a developed country in Europe, our carbon footprint is more impactful than any developing country.</li> +<li>Indigenous people are already defenders and protectors of the environment more than we will ever be in our generation.</li> +<li>Economic development is a priority in developing countries, and politicians may ignore environmental impact for the sake of it. (See <a href="https://www.climatechangenews.com/2019/01/22/brazils-natural-resources-open-business-bolsonaro-says/">Brazilā€™s natural resources open for business, says Bolsonaro</a>)</li> +<li>Developing countries idealisation of economic development, influenced by ā€œdeveloped world standardsā€: tall buildings and industries all over the place, where often we donā€™t see the green implications of ā€œsuccessā€.</li> +<li>What about a model of development thats puts together the simple living of developing countries with the green development of developed ones?</li> +<li>How waste affects developing countries; example of <a href="https://www.bangkokpost.com/news/world/1666380/philippines-duterte-says-to-sail-garbage-back-to-canada">Philippines to sail garbage back to Canada</a>.</li> +<li>We could shift the discussion to think about environmental impact in terms of social classes instead of countries. After all, rich lifestyles and ā€œstatusā€ in general damage the environment in untold ways.</li> +<li>The <a href="https://en.wikipedia.org/wiki/Swadeshi_movement">Swadeshi movement</a> brought back self-manufactured clothing in India to boycott foreign goods, a part of a movement to liberate India from British control and industrialisation.</li> +<li>When teaching, consider whatā€™s in peopleā€™s context, reach and language instead of whatā€™s ā€œout thereā€.</li> +<li>We should actively listen more to those communities and whatā€™s happening in those countries. Sometimes, instead of thinking that there is something to be taught, we should rather learn from their realities so we can bring about a meaningful conversation.</li> +<li>This is a problem not to be approached by technology, remotely. Itā€™s rather about Politics and Education.</li> +</ul> +<h3 id="action-points-1">Action points</h3> +<ul> +<li>everyone to assure inclusivity, cooperation and engagement across boundaries, <strong>first and foremost</strong>.</li> +<li>countries to keep cooperating efforts <em>internationally</em> through policies, institutional frameworks for development and investments in infrastructure.</li> +</ul> +<h2 id="conclusion">Conclusion</h2> +<p>Well-led communities that strive for welcoming environments enable the best out of people. OMG Climate has shown that ā€“ its <a href="https://en.wikipedia.org/wiki/Unconference">unconference format</a> got everyone to take responsibility and engage towards constructive and meaningful discussions about climate change.</p> +<figure class="text-center"><picture><img src="../../media/2019/omg-climate/presentation.jpg" alt="Participant presenting using microphone, all sketch notes of the unconference sticked to the wall, on background"></picture> +<figcaption>Final presentations wrapping up the tracks.</figcaption></figure> +<p>Although most of us had a tech background, everyone seemed aware: tech alone will not solve all problems, but we are eager to address them either way.</p> +<h2 id="learn-about-climate-change">Learn about Climate Change</h2> +<ul> +<li>Reddit: <a href="https://www.reddit.com/r/climatechange/">/r/climatechange</a> and <a href="https://www.reddit.com/r/globalwarming/">/r/globalwarming</a></li> +<li><a href="https://www.theguardian.com/environment/climate-change">The Guardian on Climate Change</a></li> +<li><a href="https://ourworldindata.org/co2-by-income-region">Global inequalities in COā‚‚ emissions</a></li> +<li><a href="https://anildash.com/2018/10/03/were-still-not-being-alarmist-enough-about-climate-change/">Weā€™re (still) not being alarmist enough about climate change</a></li> +</ul> +<h2 id="more-on-omg-climate">More on OMG Climate</h2> +<ul> +<li><a href="https://ti.to/omg/climate/">OMG Climate Event page</a></li> +<li><a href="https://medium.com/omg-climate">OMG Climate Medium website</a></li> +<li><a href="https://twitter.com/search?q=%23omgclimate&amp;src=typed_query">#OMGCLIMATE on Twitter</a></li> +<li><a href="https://climateaction.tech/">ClimateAction.tech</a></li> +</ul> +<div class="footnote-definition" id="1"><sup class="footnote-definition-label">1</sup> +<p><a href="https://www.cgdev.org/blog/climate-change-and-development-three-charts">Climate Change and Development in Three Charts</a></p> +</div> + + + + + I've Sensory-Deprived Myself In a Tank + 2018-12-02T08:01:00+00:00 + 2018-12-02T08:01:00+00:00 + + + + + Unknown + + + + + + /blog/isolation-tank/ + + <p>I struggle every day trying not to be one step ahead. Living everywhere else but the present and leaping through time have become part of how my brain is wired, so I often find myself not experiencing much anymore.</p> +<p>A while ago, a friend told me about his sensory-deprivation experience in some kind of pool, the so-called <a href="https://en.wikipedia.org/wiki/Isolation_tank"><em>Isolation Tank</em></a>. No sight, no hearing, no touch, no taste, no smell ā€“ the idea of getting absolutely no input from anywhere struck me as a way to get my perception back on track. I decided to try it out.</p> +<p>On a sunny Saturday of November, I, along with my endless stream of thoughts, floated for 1 hour straight in a soundproof egg-shaped tub shallowly filled up with salt water. This is my report.</p> +<h2 id="getting-in">Getting In</h2> +<p>With my bathing suit on and no expectations of anything, I showered, got into the tub and sealed down its cover. My body floated easily on that water that thermically felt like my own skin, and a relaxing sound was playing in the background up to the moment my surroundings got all pitch-black.</p> +<p>The first 15 minutes were all about withstanding how restlessly my mind wanted to get out of there. Iā€™ve had done meditation before, but 1 hour was <em>something else</em>. I recalled I worked 8 hours a day, 5 days a week, and therefore I should be making the most out of my Saturday instead. Leisure time! In modern life, that usually means stimulation by means of binge-drinking with friends, uplifting music, delicious food, watching heart-breaking moviesā€¦. Quite the opposite of soul-crushingly doing nothing.</p> +<p>The mind just plays a lot of games on you all the time. It tricked me into being <em>physically</em> irritated by the water, its salt, that bogus zero-gravity environment, and that Iā€™d be better off giving up <em>for my own survival</em> Ā ā€“ at least, that was how my body anxiously (over-)reacted to it. But there was actually no physiological danger or whatsoever; truth be told, I was way safer than I had ever been throughout that week. I quit panicking.</p> +<p>I came upon different phases of denial, approval and mind-numbness from that onwards. Saw myself bringing up problems and drifting them away. Tried to work out situations I had no control over. Missed music, so made my own by tapping on the water. Went hyper-focused on how I had performed socially last week to what was going to happen in the next few weeks when I eventually hand over my old apartmentā€™s keys to that spiteful Hausmeister who hates my German.</p> +<p>My thoughts just went on super randomly. After a while, I could draw the exact line where each one ended, and got mindful about my weary physical overreactions to them.</p> +<p>Towards the end, I sank into something else: weightlessness, timelessness, solitude were emerging from that isolation. Things started losing shape. Didnā€™t perceive water. I was either a floating head or a floating body. I had to touch my thighs, boobs, neck just to relieve myself from the uncertainty that being so relaxed made me feel about where I was.</p> +<p>I wanted to come back down to Earth from wherever I was, and, surprisingly, <strong>to be myself</strong> ā€“ the way I was. Then time was up.</p> +<h2 id="getting-out">Getting Out</h2> +<p>I showered again to wash the salt off. The spa provided a relaxation lounge that was essential to ease the transition, sinceĀ I had neither desire nor need (important!) to rush anywhere. Hung out there for 1 hour.</p> +<p>The readjusting was an interesting and unexpected phase to me. Had an apple and felt how crispy in sound and taste it was. Drank a glass of water and sensed it going <em>right down through</em>. Read a book and couldnā€™t make sense of why we humans have ever brought up speed reading techniques in the first place.</p> +<p>Stepping out of the spa, I got savagely welcomed by a gloomy afternoon<sup class="footnote-reference"><a href="#1">1</a></sup> undergoing that life I was used to every day. A lot was happening out there: lights of apartments being turned on and out, cars groaning, people running around, traffic noise, the cozy energy of having my friend by my side, sharper textures of the sidewalksā€™ cobblestones, and the joy of a having a sky whose amount of stars doesnā€™t depend on the many times we screw up as human beings, thankfully.</p> +<p>Berlin-Schƶneberg is quite chill so thatā€™s helped to readjust. I was sensible and my thoughts were vivid and receptive ā€“Ā pretty much the actual poetic mood I strive for, where I settle and listen to whatā€™s being said in order to write it down. A mood that is ā€œhighly disturbed by Philosophyā€, as Goethe brilliantly summed up to Schiller once:</p> +<p><em>ā€œI am still hoping for poetic hours, and philosophy, in my case, disturbs the poetic mood, probably because it drives me into the object, for I am never able to keep myself in a purely speculative mood, but have immediately to try and form a distinct conception, and on this account at once fly out into nature. [ā€¦]</em><sup class="footnote-reference"><a href="#2">2</a></sup></p> +<p>I had finally my mind drifted towards just as much of the world as it was going on.</p> +<h2 id="lessons-learned">Lessons Learned</h2> +<p>My poetic mood didnā€™t last muchĀ ā€“ it wore off the day after.</p> +<p>Iā€™ve realized how much we are externally stimulated and easily adapt to it as if it were natural. On top of that, we are internally stimulated by our worries and whatnot: have I paid my taxes? Am I persuading a career? Does my family still love even though I am thousands of kilometers from them? Have I been eating healthy enough?</p> +<p>It turns out itā€™s clear why we donā€™t feel much anymore. Our brain gets wired to parallelising stimuli, and we have less and less coming from our body to the head than the other way around. Apart from that, our experience of the world is barely passive: <strong>we actively generate it</strong> with our biases, mental models, what and how much we consume. Mind shortcuts are crucial, but might restrain us from genuinely experiencing life, getting us to either ignore ou hyper-focus unconsciously.</p> +<p>I, now, have a better grasp of what Erling Kagge meant in <a href="https://www.goodreads.com/book/show/36243813-silence">Silence: In the Age of Noise</a>, written after he had spent fifty days walking solo in Antarctica: <em>ā€œEverything seemed completely flat and white. [ā€¦] Eventually, in complete isolation, I began to notice that nothing was completely flat after all. The ice and snow formed small and large abstract shapes. The uniform whiteness was transformed into countless shades of white. [ā€¦]ā€</em></p> +<p>Meditation is the absolute protagonist here, but floating got me into a different flow, and faster. The topic of <a href="https://en.wikipedia.org/wiki/Sensory_deprivation">sensory deprivation</a> is definitely worth-exploring. Think like: If you ditch sugar for a while, it tastes sweeter afterwards. ;-)</p> +<p>This is pretty much what floating offers: <strong>sensory starvation and you on your own</strong>. You may waste your time and never get to anything, or make even most out of that 1 hour than me.</p> +<p>Personally, I canā€™t wait to do nothing again.</p> +<hr /> +<div class="footnote-definition" id="1"><sup class="footnote-definition-label">1</sup> +<p>Just another Autumn day in Berlin.</p> +</div> +<div class="footnote-definition" id="2"><sup class="footnote-definition-label">2</sup> +<p>Goethe (and Friedrich Schiller). <a href="https://archive.org/stream/correspondencebe01schi/correspondencebe01schi_djvu.txt">Correspondence Between Schiller and Goethe from 1794 to 1805</a>. Translated by George H. Calvert.</p> +</div> + + + + + How I Lock My Bike in Berlin + 2018-08-30T07:00:00+00:00 + 2018-08-30T07:00:00+00:00 + + + + + Unknown + + + + + + /blog/how-i-lock-my-bike-in-berlin/ + + <p class="summary">1 year with a bike in Berlin, and counting...</p> +<p>I bought a bike 2 months after moving to Berlin, and a really good lock 1 day after.</p> +<p>With no clue about the theft scene in Europe ā€“ Berlin, in special ā€“, I did myself some research on <a href="https://www.reddit.com/r/reddit/">/r/berlin</a>, <a href="https://www.reddit.com/r/bicycling/">/r/bycicling</a> and a few other places around the internet. What I did find out? Well, <a href="https://www.welovecycling.com/wide/2015/11/25/european-bike-stealing-championships-in-numbers/">the numbers on bike theft are quite concerning</a>.</p> +<p>Nevertheless, after witnessing some people getting their bikes stolen, I feel privileged to say that <strong>itā€™s been more than 1 year Iā€™ve got my bike</strong>. If that is because of my good lock or my good luck, Iā€™ll never know.</p> +<p>But I can tell you about the lock.</p> +<h2 id="my-lock-setup">My lock setup</h2> +<p>I generally agree that you should invest as much as you can afford in your lock setup. Iā€™ve put a considerable amount of money on mine because I <em>deeply</em> care ā€“ in other words, I have no psychological resilience when it comes to bicycles so losing mine would definitely get me in tears.</p> +<p class="note">If you care about numbers without any trustable source, I've seen recommended somewhere that you should be investing between 10%-20% of the bike price in a lock. šŸ¤·</p> +<p>Therefore, considering the price of having to go home by feet and with tears in my eyes, I did the best I could and went for the <a href="https://www.kryptonitelock.com/en/products/product-information/current-key/000990.html">Kryptonite Evolution Mini-7 with Double Loop Cable</a> (highly recommend you to check their website for more information).</p> +<p>I make sure my bikeā€™s <strong>frame and both wheels</strong> are locked to a fixed rack ā€“ cemented into the ground, ideally.</p> +<figure class="text-center"><picture><img src="../../media/2018/yellow-bike-lock.jpg" alt="Yellow bike in a parking space locked with a U-lock and a flexible steel cable."></picture> +<figcaption>My tiny yellow bike parked and properly locked at the office's parking space! Locking up the U-lock to the front wheel instead is a good alternative. Also, I often wrap the steel cable through the rack.</figcaption></figure> +<p class="note">I had considered the <a href="https://www.kryptonitelock.com/en/products/product-information/current-key/997986.html">Kryptnonite's New York Fahgettaboutdit</a>, but I found it way too heavy and the safety factor difference didn't pay off for me at that time. I'd recommend it if an extra weight is no problem for you though.</p> +<p>For I still have my bike after 1 year, I am honestly happy with my choice. The lock came with:</p> +<ul> +<li>Three keys with an unique number. For your information, Kryptonite has a system where <a href="https://kryptonite.zendesk.com/hc/en-us/articles/231011287-Finding-My-Key-Number-">every key gets a number</a>, so you can order replacements online in case you mess up.</li> +<li>A handy mount made by Kryptonite: <a href="https://www.kryptonitelock.com/en/products/product-information/current-key/000730.html">Transit FlexFrame U-Bracket</a> (not visible in the photo because itā€™s in the top tube), so I donā€™t have to carry the U-lock in my backpack or whatever.</li> +<li>Manuals that I didnā€™t read and got recycled.</li> +<li>1 year coverage according to the <a href="https://www.kryptonitelock.com/en/customer-service/register-for-anti-theft.html">Kryptonteā€™s Anti-theft Program</a>, because the security rating is high enough.</li> +</ul> +<p>Iā€™ve read a couple complaints about the lock not fitting both the wheel and frame to most city racks, however Iā€™ve managed to do it in most racks around Berlin. Itā€™s definitely not the most flexible and spacious lock, but thieves would love some extra space to do their work too, so I think itā€™s just the size it should be after all.</p> +<p>In the worst-case scenario, there is always the <a href="https://www.sheldonbrown.com/lock-strategy.html">Sheldon Method lock strategy</a> ā€“ or <a href="http://www.802bikeguy.com/2011/07/the-modified-sheldon-brown-bike-locking-strategy/">its modified version</a> ā€“ anyway!</p> +<h2 id="what-bike-locks-are-about">What bike locks are about</h2> +<p>When looking for a lock, instead of (only) asking yourself whatā€™s the best lock ever, ask <em>ā€œHow much trouble am I putting a thief into with my lock strategy?ā€</em>.</p> +<p>It hasnā€™t been enough stressed that locks do NOT prevent determined thieves with their lock pics, cable cutters, bolt cutters and angle grinders to steal you bike. Period.</p> +<p>Locks do, though, make it harder for thieves to <em>pick</em> your bike, by increasing the ā€œriskā€ factor in the risk/reward calculation done before they attempt to steal.</p> +<p><strong>Itā€™s all about making it harder</strong>. And how do you do that? By having a <em>diverse</em> lock setup, and, just as important: by being extremely careful on where and how to park.</p> +<p>Donā€™t think just U-lock: saddle locks, wheel locks might be worth-checking too! One awesome lock is just one at the end of the day, and the more tools the thief needs to carry out, the better.</p> +<h2 id="looking-further">Looking further</h2> +<p>Some articles Iā€™ve read last year and that might be interesting if you own a bike and want to learn more on how to keep it safe.</p> +<ul> +<li><a href="https://thewirecutter.com/reviews/best-bike-lock/">Best Bike Lock</a>: Review of several bike locks and learnings on how to pick a good one.</li> +<li><a href="http://thebestbikelock.com/how-to-lock-your-bike/">How to Lock your Bike</a>: Great tips on where to park your bike and what to lock it to.</li> +</ul> +<p>There are a lot of cool videos out on YouTube too, e.g. <a href="https://www.youtube.com/watch?v=IXNASUSivqg">ā€œHow to Lock your Bikeā€ from GCN</a>.</p> +<p>Have a nice ride! šŸš²</p> + + + + + Working Better with Git for a Clear History + 2018-08-04T07:00:00+00:00 + 2018-08-04T07:00:00+00:00 + + + + + Unknown + + + + + + /blog/working-better-with-git-for-a-clear-history/ + + <p>Your teammate worked on a few improvements in all forms of the companyā€™s website. At some point you, also a programmer, are asked for a code review.</p> +<p>This is the feature branchā€™s <strong>commit history</strong> you get in the Pull Request:</p> +<pre data-lang="sh" style="background-color:#282a36;color:#f8f8f2;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#50fa7b;">[290xx26]</span><span> Resolve merge conflicts +</span><span style="color:#50fa7b;">[9efxxf2]</span><span> Refactor event listener for form fields +</span><span style="color:#50fa7b;">[5d9xx5a]</span><span> Update snapshots +</span><span style="color:#50fa7b;">[948xxfa]</span><span> Update dispatch event +</span><span style="color:#50fa7b;">[f5xxea1]</span><span> WIP +</span><span style="color:#50fa7b;">[f8xxaae]</span><span> Revert change +</span><span style="color:#50fa7b;">[49xxf55e]</span><span> Revert changes +</span><span style="color:#50fa7b;">[02xxdf1]</span><span> Update snapshots +</span><span style="color:#50fa7b;">[21xx329]</span><span> Pass down prop +</span><span style="color:#50fa7b;">[28xxa865]</span><span> Fix onChange event and add minimal design in form +</span><span style="color:#50fa7b;">[cfxx37c]</span><span> U[date snapshots +</span><span style="color:#50fa7b;">[cfxx36c]</span><span> Update form to handle onChange event for autofill +</span><span style="color:#50fa7b;">[242xx25]</span><span> Fix another bug with onChange +</span><span style="color:#50fa7b;">[f7xx738]</span><span> Update form component +</span><span style="color:#50fa7b;">[09xx868]</span><span> Update snapshots +</span></code></pre> +<p>It seems like a lot, when actually those improvements are simply 1) fixing a bug with event handling and 2) introducing a minimal style to them. It just that it takes time to visualise that.</p> +<p>Indeed, committing often to a branch is a good practice<sup class="footnote-reference"><a href="#1">1</a></sup> and commits are supposed to be low-level rather than huge. However, a commit is applicable when you have a meaningful, self-contained batch of work to log to the history ā€“Ā and updating Jest snapshots is not it.</p> +<p>How about the following history?</p> +<pre data-lang="sh" style="background-color:#282a36;color:#f8f8f2;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#50fa7b;">[9efxxf2]</span><span> Refactor event listener for form fields +</span><span style="color:#50fa7b;">[cfxx37c]</span><span> Add minimal design in form +</span><span style="color:#50fa7b;">[cfxx36c]</span><span> Update form to handle onChange event for autofill +</span></code></pre> +<p>That history communicates in a clear way <strong>what</strong> in the codebase has been changed in order to get the improvements done. If you want to know <strong>how</strong> itā€™s changed, itā€™s just a matter of checking out a particular commit.</p> +<h2 id="why-a-clear-history-matters">Why a clear history matters</h2> +<p>Apart from facilitating code reviews, since reviewers could grasp the context of the changes right at the first glimpse, <strong>a clear Git history is healthy for the project</strong>.</p> +<p>When commits started to reflect oneā€™s workflow rather than the work done itself, the history turns into a mess of both meaningful and meaningless logs, hard to navigate through and undo changes (since commits are ā€œcheckpointsā€ of work). Itā€™s highly likely that, as time goes by, developers will stop caring about the source code history as the powerful resource it is.</p> +<p>*<em>The final Git history should reflect <em>your work</em> not the way you worked.</em></p> +<p>You begin to lose the benefit of source code management with a messy history, which was supposed to reflect how the codebase evolved over time.</p> +<h2 id="a-better-relationship-with-git">A better relationship with Git</h2> +<p>There are very common comprehensible reasons ā€“ yet not excuses at all! ā€“ for developers to unnecessarily commit. I can think of:</p> +<ol> +<li>ā€œI had to update snapshots/fix unit test/code formatting/a typo in something I introduced.ā€</li> +<li>ā€œI had to merge master.ā€</li> +<li>ā€œI wanted to save my work.ā€</li> +<li>ā€œI donā€™t necessarily follow a clear flow ā€“ I am productive when I work in iterative way and usually do a lot of things at once.ā€</li> +</ol> +<p>They can all be worked out by developing a better relationship with Git itself. That might take a while at first, but when itā€™s part of your daily workflow, you barely think about it at all. <em>(I promise!)</em></p> +<h3 id="first-let-s-talk-git-rebasing">First, letā€™s talk Git rebasing</h3> +<p><a href="https://git-scm.com/docs/git-rebase">Git rebase</a> is a very powerful tool to reorganise your commits. It does a lot, so I wonā€™t get deep into it.</p> +<p>The command <code>git rebase</code> has an important tool you should get comfortable with: <strong>interactive rebase</strong>. Letā€™s say we want to reorganise the latest 3 commits:</p> +<pre data-lang="bash" style="background-color:#282a36;color:#f8f8f2;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#50fa7b;">git</span><span> rebase</span><span style="font-style:italic;color:#ffb86c;"> --interactive</span><span> HEAD</span><span style="color:#bd93f9;">~</span><span>3 +</span></code></pre> +<p class="note"><code>HEAD</code> points to the current branch in your Git repository. You can use @ as an alias as well: <code>@~3</code>, or the commit hash.</p> +<p>Interactive rebase will provide you a text interface with the list of the commits (in this case, within the range <code>HEAD~3..HEAD</code>) that are about to be rebased and actions you can apply to them:</p> +<pre data-lang="bash" style="background-color:#282a36;color:#f8f8f2;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#50fa7b;">pick </span><span style="color:#ff79c6;">[</span><span>242xx25</span><span style="color:#ff79c6;">]</span><span> Fix another bug with onChange +</span><span style="color:#50fa7b;">pick </span><span style="color:#ff79c6;">[</span><span>f7xx738</span><span style="color:#ff79c6;">]</span><span> Update form component +</span><span style="color:#50fa7b;">pick </span><span style="color:#ff79c6;">[</span><span>09xx868</span><span style="color:#ff79c6;">]</span><span> Update snapshots +</span><span> +</span><span style="color:#6272a4;"># Rebase 242xx25..09xx868 onto 242xx25 +</span><span style="color:#6272a4;"># +</span><span style="color:#6272a4;"># Commands: +</span><span style="color:#6272a4;"># p, pick = use commit +</span><span style="color:#6272a4;"># r, reword = use commit, but edit the commit message +</span><span style="color:#6272a4;"># e, edit = use commit, but stop for amending +</span><span style="color:#6272a4;"># s, squash = use commit, but meld into previous commit +</span><span style="color:#6272a4;"># f, fixup = like &quot;squash&quot;, but discard this commit&#39;s log message +</span><span style="color:#6272a4;"># x, exec = run command (the rest of the line) using shell +</span><span style="color:#6272a4;"># +</span><span style="color:#6272a4;"># These lines can be re-ordered; they are executed from top to bottom. +</span><span style="color:#6272a4;"># +</span><span style="color:#6272a4;"># If you remove a line here THAT COMMIT WILL BE LOST. +</span><span style="color:#6272a4;"># +</span><span style="color:#6272a4;"># However, if you remove everything, the rebase will be aborted. +</span><span style="color:#6272a4;"># +</span><span style="color:#6272a4;"># Note that empty commits are commented out +</span></code></pre> +<p class="note"><code>pick</code> just means that commit is included. It's the default.</p> +<p>Editing that file (either by applying actions to commits or reordering them) and closing it will reapply those commits to the branch. Weā€™ll explore some scenarios where that is useful.</p> +<h3 id="rebase-instead-of-merge">Rebase instead of merge</h3> +<p>The branch that you branched from has been updated (letā€™s call it <code>master</code>), so you need to fetch latest changes and merge that into yours with <code>git pull</code>. Instead of merging and introducing an ugly new commit for that, you can rebase and pretend that nothing ever happened in the first place.</p> +<pre data-lang="bash" style="background-color:#282a36;color:#f8f8f2;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#50fa7b;">git</span><span> pull origin master</span><span style="font-style:italic;color:#ffb86c;"> --rebase +</span></code></pre> +<p class="note">"Why isn't that the default then?", you might ask. I'd guess they didn't want to make a feature that rewrites history part of the default behaviour.</p> +<h3 id="squash-commits-when-you-can">Squash commits when you can</h3> +<p>You need to fix a typo, update a test, or include anything else that should have actually been part of a commit previously introduced. You can create a new commit and later squash it to the initial one with rebase.</p> +<pre data-lang="bash" style="background-color:#282a36;color:#f8f8f2;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#50fa7b;">git</span><span> commit</span><span style="font-style:italic;color:#ffb86c;"> -m </span><span style="color:#f1fa8c;">&quot;Update contact form tests&quot; +</span><span style="color:#50fa7b;">git</span><span> rebase</span><span style="font-style:italic;color:#ffb86c;"> -i</span><span> HEAD</span><span style="color:#bd93f9;">~</span><span>2 </span><span style="color:#6272a4;"># act on top of latest 2 commits +</span></code></pre> +<p>Interactive rebase will show up, and you can mark that ā€œUpdate contact form testsā€ as the commit to be squashed into a previous one by changing pick to <code>s</code> (squash).</p> +<p>The squashed commit has to come exactly before the commit you want to squash into, so you might have to some reordering.</p> +<h4 id="fix-up-and-save-time">Fix up and save time</h4> +<p>Using the <code>--fixup</code> flag along with the commit hash of the previous commit will <strong>mark a commit as a fix of an existing one</strong>. Then, when you rebase with <code>--autosquash</code>, they willā€¦ well, automatically get squashed.</p> +<p>Letā€™s say we have fixed a typo in the commit <code>i2r923</code>:</p> +<pre data-lang="bash" style="background-color:#282a36;color:#f8f8f2;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#50fa7b;">git</span><span> commit</span><span style="font-style:italic;color:#ffb86c;"> --fixup</span><span> i2r923 +</span><span style="color:#50fa7b;">git</span><span> rebase</span><span style="font-style:italic;color:#ffb86c;"> --autosquash</span><span> 9ef00f2 </span><span style="color:#6272a4;"># one commit before above +</span></code></pre> +<p class="note">You can configure Git to use the <code>--autosquash</code> flag by default when rebasing. I do that so you can check <a href="https://github.com/diessica/dotfiles/blob/master/git/config">my dotfiles</a> if you're curious.</p> +<p>Quite often, youā€™ll know how far youā€™re traveling from the current commit (HEAD). Instead of specifying hashes, you can just use <code>HEAD</code> as a reference to previous commits:</p> +<pre data-lang="bash" style="background-color:#282a36;color:#f8f8f2;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#50fa7b;">git</span><span> commit</span><span style="font-style:italic;color:#ffb86c;"> --fixup</span><span> HEAD </span><span style="color:#6272a4;"># fix 1 commit before HEAD +</span><span style="color:#50fa7b;">git</span><span> rebase</span><span style="font-style:italic;color:#ffb86c;"> --autosquash -i</span><span> HEAD</span><span style="color:#bd93f9;">~</span><span>1 </span><span style="color:#6272a4;"># squash latest 2 commits +</span></code></pre> +<h3 id="stash-to-save-your-work-in-progress">Stash to save your work in progress</h3> +<p>You want to check or change other branchā€™s files, but donā€™t want to commit unfinished work either. You can <strong>stash your work in progress</strong> (ā€œWIPā€):</p> +<pre data-lang="bash" style="background-color:#282a36;color:#f8f8f2;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#50fa7b;">git</span><span> stash +</span></code></pre> +<p>That stores everything from your working directory into stash. Itā€™s so useful in my day-to-day work that I honestly often cry using it.</p> +<p>On how to get your work back, name your WIPs, or stash specific files, refer to the <a href="https://git-scm.com/book/en/v1/Git-Tools-Stashing">docs on Git staging</a>. No way I am better at explaining than the documentation itself!</p> +<h3 id="commit-selected-chunks-of-your-work">Commit selected chunks of your work</h3> +<p>Remember the ā€œI work in a very messy way, iterating between featuresā€ excuse? This helps. (It helped me yesterday when I refactored and introduced something new to it ā€“ should not be done altogether!Ā ā€“Ā  at the same time without noticing.)</p> +<p>Besides only adding a specific file to your commit with <code>git add</code>, you may want to add only a <strong>chunk of the fileā€™s code</strong> to a commit. That can be achieved with the <code>--patch</code> flag:</p> +<pre data-lang="bash" style="background-color:#282a36;color:#f8f8f2;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#50fa7b;">git</span><span> add</span><span style="font-style:italic;color:#ffb86c;"> --patch +</span></code></pre> +<p>Thatā€™s another interface youā€™ll have to get comfortable with. You can also try out its <code>--interactive</code> option.</p> +<h4 id="using-vs-code">Using VS Code?</h4> +<p>VS Code has a powerful built-in Git editor that allows you to add chunks of code to a commit. To stage specific lines to commit later, open VS Codeā€™s Git editor, select the lines of code you feel should go into a commit, and ā€œStage selected changesā€ by right-clicking on it.</p> +<figure class="text-center"><picture><img src="../../media/2018/vs-code-stage-selected-changes.png" alt="Showing how to use 'Stage Selected Changes' in VS Code"></picture> +<figcaption>Changed the whole thing but want to commit only a chunk of it? VS Code has got you covered.</figcaption></figure> +<p>The <a href="https://code.visualstudio.com/docs/getstarted/userinterface#_command-palette">Command Palette</a> also has a ā€œGit: Stage selected changesā€ option.</p> +<h3 id="rename-commit-messages-for-meaning">Rename commit messages for meaning</h3> +<p>You had a look at the final history and found out your commit messages need some love. To change your latest commit (HEAD), you can just do <code>git commit --amend</code>; for other commits, youā€™ll have to rebase.</p> +<p>Letā€™s say you want to fix the latest 5 commits:</p> +<pre data-lang="bash" style="background-color:#282a36;color:#f8f8f2;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#50fa7b;">git</span><span> rebase</span><span style="font-style:italic;color:#ffb86c;"> -i</span><span> @</span><span style="color:#bd93f9;">~</span><span>5 +</span></code></pre> +<p>That will open up the <strong>interactive rebase</strong> youā€™re already familiar with. Find the commit you want, change pick to <code>e</code> (edit), and save and close the file; after Git rewinds to that commit, edit its message with <code>git commit --amend</code>, and run <code>git rebase --continue</code> when youā€™re done.</p> +<h2 id="got-a-clear-history-push-it">Got a clear history? Push it!</h2> +<blockquote> +<p>Commit Often, Perfect Later, Publish Once.<sup class="footnote-reference"><a href="#1">1</a></sup></p> +</blockquote> +<p>Make sure that your branch has got a clear, readable and meaningful historyā€¦</p> +<pre data-lang="bash" style="background-color:#282a36;color:#f8f8f2;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#50fa7b;">git</span><span> log</span><span style="font-style:italic;color:#ffb86c;"> --oneline +</span></code></pre> +<p>Then push it into the remote repository!</p> +<pre data-lang="bash" style="background-color:#282a36;color:#f8f8f2;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#50fa7b;">git</span><span> push origin head +</span></code></pre> +<p class="note"> If you have already pushed (Y THO???!), you can (carefully) use the force option (<code>-f</code>) to rewrite the remote history.</p> +<h2 id="extra-fixing-the-first-history">Extra: Fixing the first history</h2> +<p>Remember the first history? We can fix it. Itā€™s definitely harder to change it after itā€™s done, but totally doable with <code>rebase -i</code>. A possible solution would be:</p> +<pre data-lang="sh" style="background-color:#282a36;color:#f8f8f2;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#50fa7b;">squash </span><span style="color:#ff79c6;">[</span><span>290xx26</span><span style="color:#ff79c6;">]</span><span> Resolve merge conflicts +</span><span style="color:#50fa7b;">pick </span><span style="color:#ff79c6;">[</span><span>9efxxf2</span><span style="color:#ff79c6;">]</span><span> Refactor event listener for form fields +</span><span style="color:#50fa7b;">squash </span><span style="color:#ff79c6;">[</span><span>5d9xx5a</span><span style="color:#ff79c6;">]</span><span> Update snapshots +</span><span style="color:#50fa7b;">squash </span><span style="color:#ff79c6;">[</span><span>948xxfa</span><span style="color:#ff79c6;">]</span><span> Update dispatch event +</span><span style="color:#50fa7b;">delete </span><span style="color:#ff79c6;">[</span><span>f5xxea1</span><span style="color:#ff79c6;">]</span><span> WIP +</span><span style="color:#50fa7b;">delete </span><span style="color:#ff79c6;">[</span><span>f8xxaae</span><span style="color:#ff79c6;">]</span><span> Revert change +</span><span style="color:#50fa7b;">delete </span><span style="color:#ff79c6;">[</span><span>49xxf55e</span><span style="color:#ff79c6;">]</span><span> Revert changes +</span><span style="color:#50fa7b;">squash </span><span style="color:#ff79c6;">[</span><span>02xxdf1</span><span style="color:#ff79c6;">]</span><span> Update snapshots +</span><span style="color:#50fa7b;">squash </span><span style="color:#ff79c6;">[</span><span>21xx329</span><span style="color:#ff79c6;">]</span><span> Pass down prop +</span><span style="color:#50fa7b;">pick </span><span style="color:#ff79c6;">[</span><span>28xxa865</span><span style="color:#ff79c6;">]</span><span> Fix onChange event and add minimal design in form +</span><span style="color:#50fa7b;">squash </span><span style="color:#ff79c6;">[</span><span>cfxx37c</span><span style="color:#ff79c6;">]</span><span> U[date snapshots +</span><span style="color:#50fa7b;">pick </span><span style="color:#ff79c6;">[</span><span>cfxx36c</span><span style="color:#ff79c6;">]</span><span> Update form to handle onChange event for autofill +</span><span style="color:#50fa7b;">fixup </span><span style="color:#ff79c6;">[</span><span>242xx25</span><span style="color:#ff79c6;">]</span><span> Fix another bug with onChange +</span><span style="color:#50fa7b;">squash </span><span style="color:#ff79c6;">[</span><span>f7xx738</span><span style="color:#ff79c6;">]</span><span> Update form component +</span><span style="color:#50fa7b;">squash </span><span style="color:#ff79c6;">[</span><span>09xx868</span><span style="color:#ff79c6;">]</span><span> Update snapshots +</span></code></pre> +<p><strong>Be mindful about your decisions and make sure you are not losing work along the way</strong>. I deleted commits unused commits (WIP then reverted), squashed ā€œfixā€ and ā€œupdate testsā€ commits, and then picked only those that are meaningful batches of work.</p> +<p>I could have also split <code>Fix onChange event and add minimal design in form</code> into two separate commitsā€¦ But thatā€™s for a future post.</p> +<h2 id="final-considerations">Final considerations</h2> +<p>Nowadays, I can say for sure that Git helps me to work better. Those techniques youā€™ve learned are all part of my daily workflow.</p> +<p>There is always something I donā€™t know about Git though, so I keep exploring. I recommend you do to do the same, and you can start right from your command line:</p> +<pre data-lang="bash" style="background-color:#282a36;color:#f8f8f2;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#50fa7b;">git</span><span> help</span><span style="font-style:italic;color:#ffb86c;"> -w</span><span> reset +</span></code></pre> +<p>Finally, if somehow you donā€™t feel comfortable with moving around your work from the command line, Iā€™d recommend Git GUI clients<sup class="footnote-reference"><a href="#2">2</a></sup> ā€“ they are powerful and simplify visualising branches and its commits, especially when it gets tough<sup class="footnote-reference"><a href="#3">3</a></sup>.</p> +<p>I hope you have better, more sane, work days after that!</p> +<div class="footnote-definition" id="1"><sup class="footnote-definition-label">1</sup> +<p><a href="http://sethrobertson.github.io/GitBestPractices/">Commit Often, Perfect Later, Publish Once: Git Best Practices</a> by Seth Robertson.</p> +</div> +<div class="footnote-definition" id="2"><sup class="footnote-definition-label">2</sup> +<p>Some clients I can think of: <a href="https://desktop.github.com/">GitHubā€™s Git client</a> (free), <a href="https://www.gitkraken.com/">Git Kraken</a> (free), <a href="https://www.git-tower.com/">Git Tower</a> (paid).</p> +</div> +<div class="footnote-definition" id="3"><sup class="footnote-definition-label">3</sup> +<p>It will get tough, because source code management is not easy. Anyhow, itā€™s always tougher when you care about things anyway. Easiest thing is not to care about anything at all.</p> +</div> + + + + + Computer and Human Languages + 2018-06-20T18:06:00+00:00 + 2018-06-20T18:06:00+00:00 + + + + + Unknown + + + + + + /blog/computer-and-human-languages/ + + <p class="note">Basic knowledge of computer languages (mainly JavaScript) is assumed.</p> +<p>Some time ago, a friend of mine asked how skilled Iā€™d say I was with JavaScript. I told him I was <em>fluent</em>.</p> +<p>ā€“Ā <em>Fluent? What does it mean to be fluent?</em></p> +<p>ā€“Ā <em>Well, think Portuguese.</em> ā€“Ā We both speak Portuguese ā€” <em>I donā€™t know every word, but I do know the language enough to express anything I need somehow.</em></p> +<p>It turned out that ā€œfluentā€ was just the perfect word.</p> +<hr /> +<p>Fluency is a powerful and straightforward concept to express your ability with a language. When it comes to <strong>human languages</strong>, itā€™s the ability to fully communicate your intentions to a human; for <strong>computer languages</strong>, the ability to fully communicate your intentions to a computer.</p> +<p>That line of thought is shared in one of the most important and revolutionary introductory books to Computer Science. In <em>Structure and Interpretation of Computer Programs</em>, right before introducing Lisp (the programming language used throughout the book) a similar analogy is made:</p> +<blockquote> +<p>Just as our everyday thoughts are usually expressed in our natural language (such as English, French, or Japanese), and descriptions of quantitative phenomena are expressed with mathematical notations, our procedural thoughts will be expressed in Lisp. <sup class="footnote-reference"><a href="#1">1</a></sup></p> +</blockquote> +<p>For both kinds of languages, the levels are the same: one <em>cannot</em> communicate; <em>can poorly</em> do it (beginner); <em>can</em> do it (native/fluent), or <em>can brilliantly</em> do it (think book authors, public speakers, and Software Engineers in a senior level).</p> +<h2 id="why-do-they-match-so-well">Why do they match so well?</h2> +<p>They match because the linguistics of computer and natural languages wonderfully intersect. Both consist of <strong>syntax</strong>, <strong>semantics</strong> and <strong>pragmatics</strong> functions, found in the core of theoretical linguistics.</p> +<p>In their ecosystem, we can also find <strong>syntax trees</strong> and different <strong>style guides</strong>.</p> +<h3 id="syntax">Syntax</h3> +<p><strong>Syntax</strong> is the set of rules that govern how language elements are combined to form a valid expression.</p> +<p>In English, the basic rule is that elements like nouns, verbs and punctuation marks must follow the <a href="https://en.m.wikipedia.org/wiki/Subject%E2%80%93verb%E2%80%93object">subject-verb-object order</a> to produce a valid sentence. In JavaScript, a programming language, to produce a valid conditional statement, elements such as <code>if</code>, parenthesis, braces, comparison operators (<code>===</code>, <code>&lt;=</code> ) must be combined in a certain order too.</p> +<p>In the same way that ā€œDo they car a put?ā€ (??) is not valid English, the following code is not valid JavaScript:</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="color:#ff79c6;">if </span><span>{</span><span style="color:#bd93f9;">1 </span><span style="color:#ff79c6;">=== </span><span style="color:#bd93f9;">2</span><span>} ( +</span><span> </span><span style="color:#ffffff;">return </span><span style="color:#bd93f9;">true +</span><span>) +</span><span style="color:#6272a4;">// =&gt; SyntaxError: missing ( before condition +</span><span> +</span><span style="color:#ffffff;">add x y </span><span style="color:#ff79c6;">= </span><span style="color:#ffffff;">x </span><span style="color:#ff79c6;">+ </span><span style="color:#ffffff;">y </span><span style="color:#6272a4;">// u can&#39;t use elm&#39;s lambda syntax on js, no +</span></code></pre> +<p class="note">And just like a pedant friend would do when you write shitty English, the computer will throw a syntax error when running your program. Forgot closing a brace? Wrote an <code>if</code> statement condition using curly braces instead of parenthesis? Well, <code>SyntaxError</code>!</p> +<p>This, however, is valid JavaScript:</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="color:#ff79c6;">if </span><span>(</span><span style="color:#bd93f9;">1 </span><span style="color:#ff79c6;">=== </span><span style="color:#bd93f9;">2</span><span>) { +</span><span> </span><span style="color:#ff79c6;">return </span><span style="color:#bd93f9;">true +</span><span>} </span><span style="color:#6272a4;">// &quot;if (1 === 2) return true&quot; is also fine! +</span><span> +</span><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#50fa7b;">add </span><span style="color:#ff79c6;">= </span><span>(</span><span style="font-style:italic;color:#ffb86c;">x</span><span>, </span><span style="font-style:italic;color:#ffb86c;">y</span><span>) </span><span style="font-style:italic;color:#8be9fd;">=&gt; </span><span style="color:#ffffff;">x </span><span style="color:#ff79c6;">+ </span><span style="color:#ffffff;">y +</span></code></pre> +<p>In HTML there are syntax rules too. Adding a <code>div</code> inside <code>ul</code>, for instance, is invalid. An unordered list in HTML (<code>ul</code>) only allows list items as children, such as <code>li</code> ā€“Ā and <code>div</code> is not one.</p> +<p>Languages have different degrees of syntax strictness, which is what usually makes some harder to grasp than others. Think the <strong>German language</strong> ā€“ German imposes very strict rules for articles: they may vary in number, gender, and function. English, on the other hand, has a definite (the) and an indefinite article (a/an)Ā ā€“ and thatā€™s it.</p> +<p>The same applies to computer languages: some happen to be extremely strict when it comes to syntax, while others are designed for greater syntactic flexibility, letting you achieve the same result in different ways. Think <strong>semicolons</strong>: they are optional when ending statements in JavaScript, but mandatory in C.</p> +<h3 id="semantics">Semantics</h3> +<p><strong>Semantics</strong> is what the language expression evaluates to. In human languages, expressions evaluate to thoughts, questions, answers; while computers evaluate expressions to CPU instructions that comprise a programā€™s flow.</p> +<p>Consider the following English statement:</p> +<blockquote> +<p>The ant ran over the car.</p> +</blockquote> +<p>I donā€™t know what ants you are familiar with, but even though the sentence contains the necessary elements in correct order and grammar, that doesnā€™t make sense. The statement is <strong>syntactically correct</strong> but <strong>semantically wrong</strong> ā€“Ā we canā€™t conceive a meaning from it.</p> +<p>(<em>ā€œThe car ran over the antā€</em>, however, would be definitely more acceptable to our ears.)</p> +<p>We can relate semantics to computer languages in several ways (like ā€œsolving the wrong problemā€, basically), but the ā€œsemanticā€ word bubbles up more often when we think about HTML. Consider the following markup:</p> +<pre data-lang="html" style="background-color:#282a36;color:#f8f8f2;" class="language-html "><code class="language-html" data-lang="html"><span>&lt;</span><span style="color:#ff79c6;">span</span><span>&gt;What is a fruit?&lt;/</span><span style="color:#ff79c6;">span</span><span>&gt; +</span><span>&lt;</span><span style="color:#ff79c6;">div</span><span>&gt; +</span><span> A fruit is something that humans eat. Some examples of fruits are: +</span><span> watermelon, pineapple and apples. +</span><span>&lt;/</span><span style="color:#ff79c6;">div</span><span>&gt; +</span></code></pre> +<p>The elements <code>span</code> and <code>div</code> do exist in the language and are validly marked in this case (I didnā€™t do <code>&gt;div&lt;</code>, right?), so the browser will understand and show it accordingly to the user. The syntax is correct; yet, <code>span</code> and <code>divs</code> are non-semantic elements, so computers wonā€™t get any meaning from it. Again, <strong>syntactically correct</strong> but <strong>semantically wrong</strong>.</p> +<p>That text, though, is clearly a title and a paragraph. With a bit of HTML knowledge, we can communicate this in a meaningful way to computers! The language provides elements to achieve that.</p> +<p>The following code improves the previous markup for better semantics.</p> +<pre data-lang="html" style="background-color:#282a36;color:#f8f8f2;" class="language-html "><code class="language-html" data-lang="html"><span>&lt;</span><span style="color:#ff79c6;">h1</span><span>&gt;What is a fruit?&lt;/</span><span style="color:#ff79c6;">h1</span><span>&gt; +</span><span>&lt;</span><span style="color:#ff79c6;">p</span><span>&gt; +</span><span> A fruit is something that humans eat. Some examples of fruits are: +</span><span> watermelon, pineapple and apples. +</span><span>&lt;/</span><span style="color:#ff79c6;">p</span><span>&gt; +</span></code></pre> +<p>The element <code>h1</code> is being used to communicate the main title, and <code>p</code> communicates the paragraph. Both syntax and semantics make sense now!</p> +<h3 id="pragmatics">Pragmatics</h3> +<p><strong>Pragmatics</strong> is what the language expression evaluates to within its interactional context ā€“Ā which might totally affect semantics and syntax.</p> +<p>In a natural language, the context is essentially built around the cultural aspects of the speaker, place, time, manner, and several others unpredictable aspects that humans introduce when communicating.</p> +<p>For computer languages, we can see pragmatics as the methodology or implementation used when approaching a problem: composition vs. inheritance, functional vs. imperative, picking a Design Pattern etc.</p> +<p>Consider the following examples:</p> +<ul> +<li>A child saying that the food is horrible to a beginner that started cooking just recently.</li> +<li>A new joiner in the company filters items in an JavaScript array using <code>forEach</code>, but the team expected <code>filter</code> to be used ā€“Ā a more functional approach.</li> +<li>A programmer implements Fibonacci with recursion instead of iteration.</li> +<li>Your friend uses a very erudite language to add a cake recipe on the internet.</li> +</ul> +<p>What do they all have in common? By themselves, they are neither right or wrong ā€“ <em>unless</em> you consider the context in which they were approached in.</p> +<p>Having either syntax or semantic skills wonā€™t help you understand whatā€™s wrong, since pragmatics is more about whatā€™s <strong>appropriate</strong> within a context. Some approaches are more elegant, antiquated, or dialect-basedĀ than others, and we can only tell how valid they are considering what we are trying to achieve.</p> +<h3 id="syntax-trees">Syntax trees</h3> +<p>Both kinds of languages can be represented using syntax trees, a concept that reuses the mathematical concept of <a href="https://en.m.wikipedia.org/wiki/Partially_ordered_set">partially ordered sets</a>.</p> +<p>Human languages are analysed through the Concrete Syntax Tree (ā€œCSTā€), a context-free analysis that tells us about the function of each language token (word, punctuation etc) used.</p> +<p>This is the Concrete Syntax Tree for the previous sentence, <em>ā€œThe water drank a glass of Mary.ā€</em>:</p> +<figure class="text-center"><picture><img src="../../media/2018/mary-glass-syntax-tree.png" alt="Concrete Syntax Tree of the sentence 'The water drank a glass of Mary.'"></picture> +<figcaption>Concrete Syntax Tree for a sentence in a human language, where "S" stands for "sentence", "N" for "noun", "V" for "verb", and P for "phrase". See <a href="https://en.m.wikipedia.org/wiki/Parse_tree">Wikipedia on Parse Trees</a> for more information.</figcaption></figure> +<p>Computer languages are also represented using syntax trees! When the code (high-level) gets translated into instructions for the computer (low-level), a program called <em>compiler</em> make uses of them. The Concrete Syntax Trees for a program contains a lot of detailed information, from whitespaces to language expressions, so you can imagine a CST for a real-world JavaScript program as something really lengthy.</p> +<p class="note">What compilers do might be tough to understand at first, but think of this program inside us that converts languages to meaning ā€“ our <b>internal <i>compiler</i></b>. Kids improve their compilers while communicating with their families, so every day they get to understand their mother language even more. If you understand English yet struggle with German, we can say your <i>German compiler is pretty bad and has to be improved</i>.</p> +<p>The compiler simplifies the CST down to the expressions that truly represent the program after syntax analysis. Thatā€™s where the <strong>Abstract Syntax Tree</strong> (AST) comes in: the syntax tree that actually lies at the heart of semantic definitions!</p> +<p>Letā€™s consider the following JavaScript program:</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="font-style:italic;color:#8be9fd;">let </span><span style="color:#ffffff;">x </span><span style="color:#ff79c6;">= </span><span style="color:#bd93f9;">0 +</span><span> +</span><span style="color:#ff79c6;">if </span><span>(</span><span style="color:#ffffff;">x</span><span>) { +</span><span> </span><span style="color:#ffffff;">x</span><span style="color:#ff79c6;">++ +</span><span>} +</span></code></pre> +<p>This is the Abstract Syntax Tree for it:</p> +<figure class="text-center"><picture><img width="400" src="../../media/2018/abstract-syntax-tree.png" alt="Concrete Syntax Tree of the sentence 'The water drank a glass of Mary.'"></picture> +<figcaption>Abstract Syntax Tree for a JavaScript program.</figcaption></figure> +<p>Itā€™s really about the essentials when considering language grammar. If a whitespace means nothing in a language, that wonā€™t show up in the AST.</p> +<p>Compare that against <a href="https://raw.githubusercontent.com/cst/cst/master/docs/cst-example.png">a Concrete Syntax Tree for another program of similar size</a>, which is way more detailed, and therefore more useful in a language-specification level.</p> +<h3 id="style-guides">Style guides</h3> +<p>When the same expression can be written in several ways because the language is not strict enough about it, style guides aim to answer the question of <strong>which style to go for</strong>. Curiously, style guides of writing are just as useful for programmers as they are for journalists!</p> +<p>Letā€™s say Iā€™m telling someone my favourite fruits. I could do it in different ways:</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="color:#ffffff;">My favourite fruits are watermelon</span><span>, </span><span style="color:#ffffff;">bananas and strawberries</span><span style="color:#ff79c6;">. +</span><span> +</span><span style="color:#6272a4;">// or using the Oxford comma +</span><span style="color:#ffffff;">My favourite fruits are watermelon</span><span>, </span><span style="color:#ffffff;">bananas</span><span>, </span><span style="color:#ffffff;">and strawberries</span><span style="color:#ff79c6;">. +</span></code></pre> +<p class="note">The Oxford comma comes from the <a href="https://www.ox.ac.uk/sites/files/oxford/media_wysiwyg/University%20of%20Oxford%20Style%20Guide.pdf">Oxford Style Guide</a>.</p> +<p>In JavaScript, you can write a <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Working_with_Objects">JavaScript object</a> in different ways too:</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">hero </span><span style="color:#ff79c6;">= </span><span>{ +</span><span> firstName: </span><span style="color:#f1fa8c;">&quot;Ada&quot;</span><span>, +</span><span> lastName: </span><span style="color:#f1fa8c;">&quot;Lovelace&quot;</span><span>, +</span><span> birthYear: </span><span style="color:#bd93f9;">1815</span><span>, +</span><span> superPower: </span><span style="color:#f1fa8c;">&quot;computers&quot;</span><span>, +</span><span>} +</span><span> +</span><span style="color:#6272a4;">// or comma-first style +</span><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">hero </span><span style="color:#ff79c6;">= </span><span>{ +</span><span> firstName: </span><span style="color:#f1fa8c;">&quot;Ada&quot;</span><span>, +</span><span> lastName: </span><span style="color:#f1fa8c;">&quot;Lovelace&quot;</span><span>, +</span><span> birthYear: </span><span style="color:#bd93f9;">1815</span><span>, +</span><span> superPower: </span><span style="color:#f1fa8c;">&quot;computers&quot;</span><span>, +</span><span>} +</span></code></pre> +<p>Either way, <strong>thereā€™s no definite rule</strong>. They mean the same, only changing their style of writing.</p> +<p>Some examples of style guides are <a href="https://github.com/airbnb/javascript">Airbnbā€™s Style guide</a>, for writing JavaScript; and <a href="http://www.chicagomanualofstyle.org/home.html">Chicago style guide</a>, for general writing.</p> +<h2 id="where-they-don-t-match">Where they donā€™t match</h2> +<blockquote> +<p>The programmer, like the poet, works only slightly removed from pure thought-stuff. He builds his castles in the air, from air, creating by exertion of the imagination. [ā€¦] Yet the program construct, unlike the poetā€™s words, is real in the sense that it moves and works, producing visible outputs separately from the construct itself. It prints results, draws pictures, produces sounds, moves arms. <sup class="footnote-reference"><a href="#2">2</a></sup></p> +</blockquote> +<p>Even with all the similarities, programming languages are still artificial, while human languages are natural. Computers are rigorous, wonā€™t allow you to be ambiguous, and only get what you mean if you put it the right way.</p> +<p>You wonā€™t have filler words in a computer language, because computers donā€™t benefit from your thought process. Humans do benefit, though, and Iā€™d even say that those communication imperfections is what connects us to others.</p> +<p>Apart from that, <strong>a programming language is an interface between you and a computer, while a natural language is an interface between you and another human being.</strong> You are communicating to a computer, but as a human ā€“ and you probably wonā€™t be the only one doing it.</p> +<p>Writing in a way thatā€™s meaningful for both is therefore part of the writing process ā€“ and probably the most demanding one.</p> +<h2 id="final-thoughts">Final thoughts</h2> +<p>Just like experienced programmers look at documentation and easily apply language features to create pieces of software, fluent English speakers would look at the dictionary and easily come up with phrases.</p> +<p>Because both computer and natural languages share linguistic structures, speaking about programming skills in terms of fluency works just as well.</p> +<p>After all, fluency is all about how easily our intentions are expressed with a language.</p> +<hr /> +<p class="note">As a next reading, I'd highly recommend <a href="https://medium.freecodecamp.org/exploring-the-linguistics-behind-regular-expressions-596fab41146">Exploring the Linguistics Behind Regular Expressions</a> if you are interested in the linguistics of computer languages.</p> +<hr /> +<p><a href="https://www.reddit.com/r/compsci/comments/8t413x/computer_and_human_languages_the_linguistics_of/">Follow the discussion thread on Reddit</a></p> +<div class="footnote-definition" id="1"><sup class="footnote-definition-label">1</sup> +<p>ā€œProgramming in Lispā€ in <em>ā€œStructure and Interpretation of Computer Programsā€</em>, 1979.</p> +</div> +<div class="footnote-definition" id="2"><sup class="footnote-definition-label">2</sup> +<p>Fred Brooks. <em>ā€œThe Mythical Man-Month: Essays on Software Engineeringā€</em>, 1975, page 7.</p> +</div> + + + + + React and Form Management: Is Redux Form Worth It? + 2018-05-21T18:14:00+00:00 + 2018-05-21T18:14:00+00:00 + + + + + Unknown + + + + + + /blog/react-and-form-management-is-redux-form-worth-it/ + + <p class="note">This is an improvement over my answer to a question in a Brazilian forum: "<a href="https://github.com/frontendbr/forum/issues/929">is using Redux for forms worth it?</a>", in Portuguese. It assumes previous knowledge with React and Redux, and also mentions <a href="https://redux-form.com/">Redux Form</a>, a library for managing forms in React.</p> +<p>It depends.</p> +<p>I know ā€œit dependsā€ is far from an interesting answer, yet thatā€™s the perfect-generic answer to any <em>ā€œis using X worth it?ā€</em> question. It really depends, yes, but more often you donā€™t need that.</p> +<p>Last year I picked Redux Form to build a multi-step form wizard, each step containing different forms, with its own fields and validations (some of them asynchronous!). In the end, all forms would be merged into one JavaScript object to be sent at some point.</p> +<p>So, Iā€™d like to share my experiences and hopefully help you to figure it out what your problem is, and help you to decide by telling you how Iā€™ve solved mine.</p> +<h2 id="where-redux-form-thrives">Where Redux Form thrives</h2> +<p><a href="https://redux-form.com/">Redux Form</a> is useful for larger and more complex forms where <strong>ease of development</strong>, <strong>high control</strong> (especially), <strong>consistency</strong>, and <strong>persistence</strong> (especially) are required. There are advantages from:</p> +<ol> +<li>the state form being in the Redux store, and</li> +<li>Redux Formā€™s abstraction itself.</li> +</ol> +<p>Which are two different things. You might need both, just one, or none at all.</p> +<h3 id="ease-of-development">Ease of development</h3> +<p>Considering you are using <a href="https://redux-form.com/7.3.0/docs/api/field.md/">Redux Formā€™s Field</a> and wrap your form in its <a href="https://redux-form.com/7.3.0/docs/api/reduxform.md/">higher-order component</a> ā€“Ā youā€™re done. Your form will work out of the box.</p> +<p class="note">Yes, you could also get to build forms in a productive way with only React, but I think it's still worth-mentioning that Redux Form makes it really painless.</p> +<h3 id="high-control">High control</h3> +<p>You can manipulate forms from anywhere in the application: you trigger Redux actions provided by Redux Form and thatā€™s all. No need to create your own Redux reducers and actions.</p> +<p>Redux Form is also flexible on what can be an input. <strong>Anything works as a field</strong>: custom 3rd-party inputs, a regular HTML input, a fancy select component without any standard form element at allā€¦ Just pass the right props to it.</p> +<p>You can set up validation at the form and field level, supporting either synchronous or asynchronous validation. The errors triggered are also in the store ā€“Ā which makes it sweet to give useful feedbacks for users from anywhere, and also to debug! šŸ‘Œ</p> +<h3 id="consistency">Consistency</h3> +<p>All forms have the same data structure so youā€™d have the exact same information for every form and its fields, such as field values, field/form validity and further information (is the field touched? Pristine? Dirty?) in the Redux store.</p> +<p>Of course you can build forms consistently just by using React itself, but using Redux Form definitely enforces it.</p> +<h3 id="persistence">Persistence</h3> +<p>Since the state is already in the Redux store, Redux Form is easily pluggable with tools from the ecosystem.</p> +<p>Letā€™s say you want to save drafts from userā€™s inputs so people can finish and submit the form later. Redux Form + <a href="https://github.com/rt2zz/redux-persist">redux-persist</a> make it pretty easy: the rehydrate process in the Redux store autofills the UI like magic!</p> +<h2 id="where-redux-form-might-die">Where Redux Form might die</h2> +<p class="note">In the thread, someone mentioned the article <a href="https://matwrites.com/redux-form-is-dead/">Redux Form is dead.</a> <b>TL;DR</b>: It's not fucking dead, as any library, framework and whatsoever that has an "X is dead" post for it.</p> +<p>Letā€™s not forget that the JavaScript community is flooded with ā€œX is deadā€ articles for everything in the ecosystem. That post, in particular, mentions valid points to consider such as ephemerality of the state (quoting Dan Abramov), performance issues within Redux Form, and the project maintenance/activity. I will go through them a bit.</p> +<h3 id="form-data-in-the-redux-store">Form data in the Redux store</h3> +<p><a href="https://twitter.com/dan_abramov">Dan Abramov</a>, creator of Redux, <a href="https://github.com/reduxjs/redux/issues/1287#issuecomment-175351978">said</a>: <em>ā€œUse React for ephemeral state that doesnā€™t matter to the app globally and doesnā€™t mutate in complex ways. For example, a toggle in some UI element, a form input state. [ā€¦]ā€.</em></p> +<p>Which is completely accurate. Where your state should live in your app depends entirely on its <strong>ephemerality</strong> ā€“Ā how trivial it is for the application as a whole when it comes to reading, updating it and so on.</p> +<p>In the post, that quote is used to support the claim that Redux Form fucks up when stores all form data in the Redux store by default ā€“ a <strong>pretty bold design decision</strong> for sure.</p> +<p>However, Dan did not write that in stone ā€“ he never does and heā€™s clear about it. That should serve as an encouragement for developers to think better about where your applicationā€™s states should go into. So, yes, you should think twice ā€“ and that doesnā€™t kill Redux Form.</p> +<p>The state of a form wizard, whose input data persists until the end of the steps (in a session or local level, for instance), whose inputs may trigger UI changes, whose inputs gets touched and changed by external components, itā€™s definitely <strong>not as ephemeral as the state of a newsletter sign up or a contact form</strong>. In the former, the form state is important for the whole application. Just notice thatā€™s a very specific case.</p> +<h3 id="performance-issues">Performance issues</h3> +<p>Redux Form has reached a well-optimised (see <a href="https://github.com/erikras/redux-form/issues/529">redux-form #529</a> and <a href="https://github.com/erikras/redux-form/issues/1405">redux-form #1405</a>) state.</p> +<p>When it comes to performance, though, you should never rest easy anyway. If you measure and find that your forms are slow, you should find bottlenecks and optimise from that.</p> +<h3 id="project-activity">Project activity</h3> +<p>Regarding the project activity, it is something to consider when deciding, and should always be. Is it active? Are there people maintaining it? Can YOU help to maintain it?</p> +<p>Yes, Erik (the author) has recently started working on another solution called <a href="https://github.com/final-form/final-form">Final Form</a>, which moves the form state out of the Redux store. However, Redux Form is mature, still well maintained (<a href="https://github.com/erikras/redux-form">check GitHub</a>, and he even said it himself <a href="https://www.reddit.com/r/reactjs/comments/7fukt7/introducing_react_final_form_high_performance/dqf8lw1/?utm_content=permalink&amp;utm_medium=front&amp;utm_source=reddit&amp;utm_name=reactjs">on Reddit</a>), and its documentation is great.</p> +<h2 id="final-words">Final words</h2> +<p>Only if the state of your form is non-trivial enough to live in the Redux store, Iā€™d give it a chance for Redux Form, <strong>especially</strong> if you are considering making your own solution. Redux Form has suffered and evolved a lot and nowadays it has a very stable and mature API you can count on, Iā€™d say.</p> +<p>Other React form management solutions you should definitely be looking at are <a href="https://github.com/jaredpalmer/formik">Formik</a> and <a href="https://github.com/final-form/react-final-form">react-final-form</a>, by Redux Formā€™s author. They donā€™t rely on Redux for state management and are most likely what you need now ā€“Ā or not.</p> +<p>The price is the abstraction, of course, it always is. šŸ™„ However, their everyday API is indeed minimal though, just be prepared to go through the documentation when you need to achieve specific stuff. In return, donā€™t forget youā€™ll get a consistent and solid structure to build forms upon.</p> +<p>Have fun building forms! šŸŽ‰</p> + + + + + T. T. T. + 2018-04-01T23:36:00+00:00 + 2018-04-01T23:36:00+00:00 + + + + + Unknown + + + + + + /blog/ttt/ + + <i> +Put up in a place<br /> +where it's easy to see<br /> +the cryptic admonishment<br /> +&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;T. T. T.<br /> +<p>When you feel how depressingly<br /> +slowly you climb,<br /> +itā€™s well to remember that<br /> +Ā Ā Ā Ā Ā Ā Things Take Time. +</i></p> +<p>Piet Hein</p> + + + + + Writing Mode in VS Code + 2018-02-28T02:30:00+00:00 + 2018-02-28T02:30:00+00:00 + + + + + Unknown + + + + + + /blog/writing-mode-in-vs-code/ + + <p>Iā€™m a big fan of writing. Iā€™m also a big fan of using my <strong>code editor</strong> and <strong>Markdown</strong> for that!</p> +<figure class="text-center"><img src="../../media/2018/vs-code-writing-mode.png" alt="Screenshot of the VS Code in the zen mode without any clutter"> +<figcaption>My "writing mode" in VS Code, with the dark theme enabled.</figcaption></figure> +<p>Code editors are usually packed with a bunch of useful features, such as multi-selection, syntax highlighting, a file tree easy to operate, and sometimes even <a href="https://code.visualstudio.com/docs/languages/markdown">Markdown support</a>Ā ā€“ which I need for writing my articles, notes, to-do lists, and absolutely everything I can write using Markdown. I love having a consistent workflow and thatā€™s crucial to me, so why not?</p> +<p>After configuring my editor of choice, VS Code, to get rid of the coding mode clutter (and also after <a href="https://github.com/Microsoft/vscode/pull/40757">an important update on its zen mode</a> ā¤ļø), Iā€™ve finally achieved a totally distraction-free writing experience!</p> +<h2 id="setting-up-the-writing-mode">Setting up the ā€œWriting Modeā€</h2> +<h3 id="1-user-settings">1. User Settings</h3> +<p>There are some important details to achieve total focus on writing. No line numbers, word wrap enabled, comfortable line height, no rulers, are some of them.</p> +<p>Since I only write in Markdown, I only set up those settings (and other tweaks) specifically for that language.</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="color:#6272a4;">// github.com/diessica/dotfiles/blob/master/vscode/settings.json +</span><span>{ +</span><span> </span><span style="color:#ff79c6;">.... +</span><span> +</span><span> </span><span style="color:#f1fa8c;">&quot;[markdown]&quot;</span><span>: { +</span><span> </span><span style="color:#6272a4;">// force centering in zen mode +</span><span> </span><span style="color:#f1fa8c;">&quot;zenMode.centerLayout&quot;</span><span>: </span><span style="color:#bd93f9;">true</span><span>, +</span><span> </span><span style="color:#6272a4;">// use the beautiful duospace font when available +</span><span> </span><span style="color:#f1fa8c;">&quot;editor.fontFamily&quot;</span><span>: </span><span style="color:#f1fa8c;">&quot;iA Writer Duospace, monospace&quot;</span><span>, +</span><span> </span><span style="color:#6272a4;">// enable word wrap, since horizontal scroll while writing isn&#39;t human +</span><span> </span><span style="color:#f1fa8c;">&quot;editor.wordWrap&quot;</span><span>: </span><span style="color:#bd93f9;">true</span><span>, +</span><span> </span><span style="color:#6272a4;">// i don&#39;t need line numbers, i&#39;m not coding +</span><span> </span><span style="color:#f1fa8c;">&quot;editor.lineNumbers&quot;</span><span>: </span><span style="color:#f1fa8c;">&quot;off&quot;</span><span>, +</span><span> </span><span style="color:#6272a4;">// light by default, but can be easily toggled to dark +</span><span> </span><span style="color:#f1fa8c;">&quot;workbench.colorTheme&quot;</span><span>: </span><span style="color:#f1fa8c;">&quot;Default Light+&quot;</span><span>, +</span><span> </span><span style="color:#6272a4;">// i don&#39;t need rules, i&#39;m not coding +</span><span> </span><span style="color:#f1fa8c;">&quot;editor.rulers&quot;</span><span>: [], +</span><span> </span><span style="color:#6272a4;">// larger text, to improve focus on writing +</span><span> </span><span style="color:#f1fa8c;">&quot;editor.fontSize&quot;</span><span>: </span><span style="color:#bd93f9;">14</span><span>, +</span><span> </span><span style="color:#6272a4;">// more comfortable line height +</span><span> </span><span style="color:#f1fa8c;">&quot;editor.lineHeight&quot;</span><span>: </span><span style="color:#bd93f9;">25</span><span>, +</span><span> </span><span style="color:#6272a4;">// disable editor suggestions based on previous words +</span><span> </span><span style="color:#f1fa8c;">&quot;editor.quickSuggestions&quot;</span><span>: </span><span style="color:#bd93f9;">false</span><span>, +</span><span> }, +</span><span> +</span><span> </span><span style="color:#ff79c6;">... +</span><span>} +</span></code></pre> +<p class="note">You can learn more about this file by checking the docs on <a href="https://code.visualstudio.com/docs/getstarted/settings">"User and Workspace Settings"</a>.</p> +<p>Now, <strong>toggle zen mode</strong> in VS Code (see <a href="https://code.visualstudio.com/docs/getstarted/keybindings">Keybindings</a>, or <code>View &gt; Toggle Zen Mode</code>) and check if that fits you!</p> +<h3 id="2-theme">2. Theme</h3> +<p>Honestly, I think the default themes provided by VS Code do a great job. I use Dark+ as the dark theme; for light themes, either Quiet Light or Solarized Light.</p> +<p class="note">If you don't like them, feel free to pick anything else, since most themes provide sufficient Markdown support anyway. Just don't procrastinate ā€“ a good theme won't make you a better writer.</p> +<h3 id="3-font">3. Font</h3> +<p>My font of choice for writing is the <a href="https://github.com/iaolo/iA-Fonts/tree/master/iA%20Writer%20Duospace">Duospace</a>, designed by the people behind the text editor <a href="https://ia.net/writer/">iaWriter</a>. Itā€™s a free and beautiful font shaped for the perfect writing experience.</p> +<h3 id="4-extensions">4. Extensions</h3> +<ul> +<li><a href="https://marketplace.visualstudio.com/items?itemName=streetsidesoftware.code-spell-checker">Spell Checker</a> catches your spelling errors.</li> +<li><a href="https://marketplace.visualstudio.com/items?itemName=ms-vscode.wordcount">Word Count</a> helps you to not to be too wordy.</li> +<li><a href="https://marketplace.visualstudio.com/items?itemName=yzhang.markdown-all-in-one">Markdown All in One</a> gives you some extra power to play with Markdown files.</li> +<li><a href="https://marketplace.visualstudio.com/items?itemName=mushan.vscode-paste-image">Paste Image</a> lets you directly paste images from clipboard to files.</li> +</ul> +<h2 id="extra-tips">Extra tips</h2> +<ul> +<li><a href="https://code.visualstudio.com/docs/languages/markdown#_markdown-preview">VS Codeā€™s Markdown Preview</a> is your friend ā€“Ā use it when youā€™re done with writing!</li> +<li>Configure the spell checker for your language, there are dictionary extensions for that available in the <a href="https://marketplace.visualstudio.com/">marketplace</a>. I also have <a href="https://marketplace.visualstudio.com/items?itemName=streetsidesoftware.code-spell-checker-portuguese-brazilian">the Brazilian Portuguese package</a> installed, for instance.</li> +<li>Like extensions? Keep exploring! The extension <a href="https://marketplace.visualstudio.com/items?itemName=shinnn.alex">alex</a>, for instance, catches insensitive, inconsiderate writing in texts.</li> +<li>Learn the Markdown keybindings provided by the All in One extension for a better workflow.</li> +</ul> +<p>Happy writing! šŸŒŸ</p> + + + + + My Hacking Adventure in Lithuania + 2018-02-15T00:00:00+00:00 + 2018-02-15T00:00:00+00:00 + + + + + Unknown + + + + + + /blog/my-hacking-adventure-in-lithuania/ + + <div class="summary"> +<p>Exploring the country where my surname came from and hacking collaboratively at Science Hack Day Vilnius!</p> +</div> +<p>I love to hack stuff, and, this year, Iā€™ve been pushing myself to do more of that along with people.</p> +<p>Thatā€™s how I found a hackathon called Science Hack Day, a weekend event with the goal of ā€œmaking weird, silly or serious things with scienceā€<sup class="footnote-reference"><a href="#1">1</a></sup> in collaboration with others. Although I missed the Berlin edition for just a few days after it happened in November, another event was about to come ā€“Ā this time, in <strong>Lithuania</strong>, where my surname ā€œGurskasā€ came from.</p> +<p>There it was the perfect replacement: the <a href="http://vilnius.sciencehackday.org/">Science Hack Day Vilnius 2018</a> would be my great excuse to explore the country where my grandfather was born.</p> +<p>Right on the last minute, I got a bedroom in a cheap hotel booked, and my flight and event tickets ready. All set for the hacking adventure!</p> +<h2 id="welcome-to-vilnius">Welcome to Vilnius</h2> +<p>Approximately 2 hours from Berlin by plane, there I was: Vilnius, the capital of Lithuania. A modest city, so small you can pretty much explore everything by feet.</p> +<p>Temperatures were more negative than in Berlin. Winter, and the city wasnā€™t the most colourful either, so the atmosphere was somewhat dark ā€“ even though the snow was painting all buildings, houses, and streets in a shining white.</p> +<p>The cold was totally dismissible as soon as I met the Lithuanians, warm and welcoming people who seemed to lead a simple life.</p> +<h2 id="science-hack-day-vilnius-2018">Science Hack Day Vilnius 2018</h2> +<figure class="text-center"><picture><img src="../../media/2018/sdhv18-trophies.jpg" alt="Trophies for different prize categories"></picture> +<figcaption>Trophies for different prize categories. (Photo: <a href="http://makerraitis.com">Raitis Gocentas</a>)</figcaption></figure> +<p>A Science Hack Day is a 2-day event run by volunteers. Since itā€™s a hackathon, itā€™s pretty hectic and leaves you exhausted at the end. However, also since itā€™s a hackathon, itā€™s remarkably rewarding at the end.</p> +<p>These were my days!</p> +<h3 id="first-day">First Day</h3> +<p>Early on Saturday, I walked to <a href="https://technarium.lt/">Technarium</a>, where the event would happen. Itā€™s a laid-back and community-operated hackerspace in Vilnius, where technology enthusiasts work or co-work on their projects and share knowledge. My perfect habitat, sort of.</p> +<figure class="text-center"><picture><img src="../../media/2018/sdhv18-technarium.jpg" alt="Technarium space"></picture> +<figcaption>Technarium. (Photo: <a href="http://makerraitis.com">Raitis Gocentas</a>)</figcaption></figure> +<p>I found a seat in the middle of a diverse crowd of enthusiasts: kids, teenagers, and adults (in which you could also find scientists and professors). I had forgotten to adjust my clock to the local timezone when I arrived in Lithuania ā€“ 1 hour ahead of Berlin ā€“, so I was kinda late and the talks on open science had already started.</p> +<p>With honestly no idea on how all thatā€™d end up (a feeling Iā€™m used to, since I always do unexpected stuff to myself anyway), I was watching the talks and telling myself that the worst that could happen was that Iā€™d have no idea and no team, and would end up just exploring what others were building. It didnā€™t sound any bad at all! Being around creative people is always appreciated anyway.</p> +<figure class="text-center"><picture><img src="../../media/2018/sdhv18-badge.jpg" width="800" alt="Electronic hackable badge and stickers from Science Hack Day Vilnius 2018"></picture> +<figcaption>Electronic hackable badge and some stickers I got for joining the event! The badge features a WiFi-enabled micro-controller and MicroPython, for some hardware hacking fun. <a href="https://github.com/Technariumas/shd18badge">Check the badge's GitHub repository</a>.</figcaption></figure> +<p>After the talks, it was time for people to pitch about their potential projects. Most ideas involved Biology, Programming, Physics, Chemistry ā€“Ā anything related to (science) hacking! One of the ideas, from a team of 3 guys, was to build an audio visualiser.</p> +<p><em>ā€œWe need a Python engineer who understands some audio engineeringā€</em>, they said, in Lithuanian (thanks person who was real-time translating everything!). Luckily, in a beautiful coincidence, I love music, Python, and also have been playing with spectrum analysis for audio visualisation in the last year ā€“ so I decided to take a shot and ask them to join the team.</p> +<p>They said they had no idea how to get the input from a microphone, and that they knew more about the hardware part, Arduino, and manipulating those machines in the hackerspace to come up with a cool design for our project. Iā€™m just bad at things that require manual work that isnā€™t with the keyboard, so my manual help would be typing Python for 2 days on my laptop. They accepted it. So far, we had:</p> +<ul> +<li>the idea;</li> +<li>an Arduino Nano;</li> +<li>a power supply;</li> +<li>long LED strip lights;</li> +<li>an acrylic sheet.</li> +</ul> +<p>Since Arduino Nano isnā€™t powerful enough for that computation, itā€™d be only used for data acquisition, and the spectrometer would live in our Python program in my laptop, computing the Fourier transform of the audio signals.</p> +<p>By the end of the day, we managed to get input from the microphone, analyse its signals in the frequency domain with Python, and start mapping that data to be sent to our Arduino over a serial interface. Some libraries we played with were: <a href="https://people.csail.mit.edu/hubert/pyaudio/">pyaudio</a>, <a href="http://www.numpy.org/">numpy</a>, <a href="https://github.com/pyserial/pyserial">pyserial</a>, <a href="https://matplotlib.org/">matplotlib</a>.</p> +<h3 id="second-day">Second Day</h3> +<p>Now with the clock correctly set (thanks to my friend that asked what timezone I was in, otherwise I wouldnā€™t ever know), I was on my way to Technarium again, walking over and under snow in that early Sunday morning.</p> +<p>A day in the Science Hack Day Vilnius was a day with Lithuanian hearty lunch, black coffee, and hard work around kind people. (By the way, if you ever end up there, try the <a href="https://en.m.wikipedia.org/wiki/Kibinai">kibinai</a> ā€“ I ate one filled with spinach and will never forget how it smelled and tasted.)</p> +<p>Most people there were Lithuanians and I didnā€™t know anything about their language besides ā€œlabas vakarasā€<sup class="footnote-reference"><a href="#2">2</a></sup> (ā€œgood eveningā€), so I felt like an outsider sometimes. My teammates and other Lithuanians in the event ā€“Ā including kids ā€“, though, were friendly and spoke English flawlessly, and fortunately even translated some stuff into English for me.</p> +<p class="note"><b>Curious fact:</b> A teenager at the event told me that my surname was "wrong" ā€“Ā in Lithuania, single women get a different surname suffix, so my name should be Gurskaite ("skaite" suffix, instead of ā€“kas). In Brazil, of course, they didnā€™t know that and only cloned my grandfatherā€™s surname ā€“ with the "kas" suffix, since he was a man: Gurskas.</p> +<p>More talks in the morning on open hardware and software. They introduced everyone to GitHub, and many people, even students, were already familiar with it. The importance given to open source was impressive! That made me really happy.</p> +<p>Time flew on the second day! We had got the data we needed, and the next step was to decide on what would be more fun: to map amplitudes from the maximum frequency to RGB values for all LEDs, or map each LED to a frequency and change its colour depending on the amplitude? We picked up the latter, and got our LEDs to blink.</p> +<hr /> +<p>One of my teammates was learning Programming. He told me he didnā€™t know what programming languages to really <em>sit down and learn</em>, as seen that there were a lot of them out there. True, and a nice question! I gave him a biased answer, of course: ā€œgo for Python or JavaScriptā€. My reasons? Way more fun. Besides beginner-friendly, those languages have the most interesting, welcoming and lively ecosystems I know these days.</p> +<hr /> +<p>We were running out of time. While 2 of my teammates were building the LED tower, the other and I were testing the code and trying to improve our algorithm, everything at the same time. Eventually, we got our LEDs to blink the way we wanted them to, and the clock pointed 18:00 sharp. <strong>Time for presenting</strong>!</p> +<figure class="text-center"><picture><img src="../../media/2018/sdhv18-lasers.jpg" alt="Laser project presentation"></picture> +<figcaption>Project showing how lasers work. It emitted sounds too! (Photo: <a href="http://makerraitis.com">Raitis Gocentas</a>)</figcaption></figure> +<p>Teams came up with a lot of cool things! Projects related to lasers, contactless payment systems security tests, <a href="https://www.instagram.com/p/BfEKAXYH-iH">shopping-cart-rocket launch</a> (#SpaceXLithuania!), plant-watering automation, posters with LEDs crafted by kids celebrating the 100th year of the Lithuanian as an independent countryā€¦ And ours, of course.</p> +<figure class="text-center"><picture><img src="../../media/2018/sdhv18-spectrogram.jpg" alt="Presenting the LED tower to the public"></picture> +<figcaption>Two of my teammates (one's missing!) and me. I was weirdly concentrated uttering different notes to show how LEDs reacted to frequencies. (Photo: <a href="http://makerraitis.com">Raitis Gocentas</a>)</figcaption></figure> +<p>There were different category prizes, and we won as the <strong>Best Data Hack</strong>!</p> +<p>I got the honor to take home not just this LED-powered trophy below, but also a memorable experience I had the pleasure to share with people I didnā€™t know in a country I didnā€™t know.</p> +<figure class="text-center"><picture><img src="../../media/2018/sdhv18-prize.jpg" width="800" alt="A trophy for Best Data Hack 2018 and a Raspberry Pi"></picture> +<figcaption>A trophy for the Best Data Hack 2018 and a Raspberry Pi. Our prizes for having fun!</figcaption></figure> +<p>The Hack Day ended with a science show by <a href="http://n-2.lt/en/performances/">N2</a>!Ā Lots of fun with liquid nitrogen and eating cookies at temperatures close to the absolute zero. My teammates, Physics students, knew a lot of the science behind that stuff so I got some extra explanations! (I have to say, though, that one of my greatest learnings of that day was to not to chew those cookies slowly ā€“ they stick to your tongue in a TORTURING way.)</p> +<figure class="text-center"><picture><img src="../../media/2018/sdhv18-n2-fire.jpg" alt="N2 science show group playing with fire"></picture> +<figcaption>Playing with fire. Literally. (Photo: <a href="http://makerraitis.com">Raitis Gocentas</a>)</figcaption></figure> +<p>Itā€™s always truly amazing to experience closely how creative and curious humans are! The event was awesome, well-organised, and, last but not least, <em>fun</em>. Organisers provided us all the materials (food included!), borrowing me even the single USB-C adapter they had!</p> +<p>Clearly, the only intent behind Science Hack Days is for people to <strong>share and learn</strong> openly. And that has been achieved just right.</p> +<h2 id="final-words">Final words</h2> +<p>Open knowledge is one of the most valuable things in this world. I have no doubt.</p> +<p>Iā€™m happy to have picked such an eccentric travel destination for my weekend, and really grateful for everything I saw and everyone Iā€™ve met on the way.</p> +<figure class="text-center"><picture><img src="../../media/2018/gurskas-snow.jpg" alt="Gurskas written in snow"></picture> +<figcaption>I don't feel my fingertips anymore since I did that. Writing in the snow: definitely NOT encouraged!</figcaption></figure> +<p>Lithuania was freezing, yes, but people were warm.</p> +<div class="footnote-definition" id="1"><sup class="footnote-definition-label">1</sup> +<p>From the <a href="/blog/my-hacking-adventure-in-lithuania/%20https://en.m.wikipedia.org/wiki/Science_Hack_Day">Science Hack Dayā€™s Wikipedia page</a>.</p> +</div> +<div class="footnote-definition" id="2"><sup class="footnote-definition-label">2</sup> +<p>Special thanks to my father, who taught me that, otherwise I wouldnā€™t know anything really.</p> +</div> + + + + + Creativity + 2018-02-05T21:25:00+00:00 + 2018-02-05T21:25:00+00:00 + + + + + Unknown + + + + + + /blog/creativity/ + + <p>In a life where, by default, thereā€™s no meaning at all, I value creating above all. If Iā€™m creating, thatā€™s a meaningful day.</p> +<p>Lately, Iā€™ve been pondering on the phenomenon of creativity and why creative people are so inspiring to be around. They just broaden my perception of the universe profoundly. What really happens?</p> +<h2 id="the-phenomenon">The Phenomenon</h2> +<p>In an interview in the late 1990s<sup class="footnote-reference"><a href="#1">1</a></sup>, Steve Jobs said something that years later would be seen as one of the most simple but accurate definitions of creativity:</p> +<blockquote> +<p>Creativity is just connecting things.</p> +</blockquote> +<p>And he followed with something I couldnā€™t help but relate: <em>ā€œWhen you ask creative people how they did something, they feel a little guilty because they didnā€™t really do it, they just saw something. It seemed obvious to them after a while. [ā€¦]ā€</em>.</p> +<p>In the wake of being called creative, I was used to responding with the most unfair answer ever: ā€œBut everything I did was mixing stuff from here and there!?!ā€œ. It turns out, however, that ā€œmixing stuffā€ actually describes precisely the process creative people go through.</p> +<p>And when Steve Jobs said that, he was mixing stuff as well! He most likely got inspired by James Webb Youngā€™s conception of idea, presented in his book <a href="https://www.goodreads.com/book/show/534755.A_Technique_for_Producing_Ideas">A Technique for Producing Ideas</a>, from the 1940s.</p> +<blockquote> +<p>An idea is nothing more nor less than a new combination of old elements [and] the capacity to bring old elements into new combinations depends largely on the ability to see relationships.</p> +</blockquote> +<p class="note">For James to suggest that, well, guess what? He was inspired by <a href="https://en.wikipedia.org/wiki/Vilfredo_Pareto">Pareto</a>'s idea of the "speculator", a personality type characterized by a constant preoccupation with the possibilities of new combinations of old elements. (Which sort of proves his own point on "ideas as a combination of old elements".)</p> +<p>Creatives are just so overloaded with elements to mix that those overflow and flow out of their heads, and they canā€™t help but inspire everyone around.</p> +<p>They reframe experiences and mix their elements to be synthesised into something valuable and unique. From songs, painting, programming to scientific theories ā€“ all of them comes from <strong>mixtures</strong>. When the mixture feels good, either as a homogeneous or heterogeneous result, itā€™s then a <em>creation</em>.</p> +<h2 id="the-creation-the-weird">The Creation, The Weird</h2> +<figure class="text-center"><picture><img class="mx-auto" src="../../media/2018/creativity.png" width="500" alt="Creativity comics"></picture> +<figcaption><a href="http://dorrismccomics.com/post/64681231561">Creativity</a>, by Alex Norris.</figcaption></figure> +<p>When the creation distances itself too much from its origin elements (which are things people are already aware of, most likely), itā€™s perceived as <strong>weird</strong>, rather than authentic. But thatā€™s when we truly innovate! To come up with the weird, though, we have to limit ourselves to certain existing elements ā€“ an outstanding habit people like Alan Turing had.</p> +<p class="note">Alan Turing was an inspiring computer scientist. Among other cool stuff, he proposed humans to consider the question <a href="http://phil415.pbworks.com/f/TuringComputing.pdf">"Can computers think?"</a>, and also designed <a href="https://en.m.wikipedia.org/wiki/Bombe">cryptanalytical machines</a>, crucial to cracking German encoded communication during the World War II. Cool stuff!</p> +<p>As described by James Wilkinson, who worked closely with him, Turing avoided looking at previous work on a topic just so he could invent something truly original, truly <strong>weird</strong>.</p> +<p><em>ā€Turing had a strong predilection for working things out from first principles, usually in the first instance without consulting any previous work on the subject, and no doubt it was this habit which gave his work that characteristically original flavor.ā€œ</em> <sup class="footnote-reference"><a href="#2">2</a></sup></p> +<p>Finally, the ones who release their creations end up turning into painters, mathematicians, writers, architects, sculptors, programmers, musicians. Itā€™s a process that happens in absolutely every realm of thinking and work.</p> +<p>And you know what?</p> +<h2 id="it-s-been-shown-by-nature">ā€¦Itā€™s Been Shown by Nature</h2> +<p>When Young and Steve Jobs pointed out that the creative process wasnā€™t magic, they, again, didnā€™t do anything ā€œnewā€ either. That definition has been shown by Nature for a long time, and, as early as 450 B.C, the philosopher <a href="https://en.wikipedia.org/wiki/Anaxagoras">Anaxagoras</a> described it:</p> +<blockquote> +<p>Wrongly do the Greeks suppose that something<sup class="footnote-reference"><a href="#3">3</a></sup> begins or ceases to be; for nothing comes into being or is destroyed; but all is an aggregation or secretion of pre-existing things; so that all becoming might more correctly be called becoming mixed, and all corruption, becoming separate.</p> +</blockquote> +<p class="note">That might remember you of the Law of Conservation of Mass, later defined by the chemist Antoine Lavoisier.</p> +<p>Just like in the creative process, Nature has always found a way out of its problems by coming up with solutions from pre-existing elements. Even the Planet Earth has transformed from a violent, molten rock to a supporter of life by using what the Universe had already provided!</p> +<p>Its process of creation was the same as the humanā€™s creative process for the discovery of fire, the invention of the wheel, shitty <em>and</em> useful startup ideas, the Pink Floydā€™s Echoes song, and all quotes in this post: mixing, connecting, combining ā€œstuffā€. From the Planet Earth to what youā€™re reading right now, the laws that ruled their creations were, in essence, the same.</p> +<div class="footnote-definition" id="1"><sup class="footnote-definition-label">1</sup> +<p>Steve Jobs. <a href="https://www.wired.com/1996/02/jobs-2/">ā€œSteve Jobs: The Next Insanely Great Thingā€</a>. WIRED. January 1996.</p> +</div> +<div class="footnote-definition" id="2"><sup class="footnote-definition-label">2</sup> +<p>James H. Wilkinson, <a href="http://www.jdl.ac.cn/turing/pdf/p137-wilkinson.pdf">ā€œSome Comments from a Numerical Analystā€</a>, 1970. <a href="https://en.wikipedia.org/wiki/Turing_Award">Turing Award</a> lecture, <em>Journal of the ACM</em>. February 1971.</p> +</div> +<div class="footnote-definition" id="3"><sup class="footnote-definition-label">3</sup> +<p>Iā€™ve deliberately changed ā€œaughtā€, an archaic English word, to ā€œsomethingā€ for the sake of readability.</p> +</div> + + + + + Dental Health and Habits + 2017-12-21T08:58:09+00:00 + 2017-12-21T08:58:09+00:00 + + + + + Unknown + + + + + + /blog/dental-health-and-habits/ + + <p>Brushing teeth is a good habit. An easy-to-build one, Iā€™d say, thanks to the immediate reward given by the refreshing sensation. After brushing, you <em>feel</em> clean right away.</p> +<p>On the other hand, flossing teeth isnā€™t a habit as easy to build. After flossing, what comes to mind is how dirty your teeth still were even though you just brushed, not how cleaner they became. Thereā€™s no such thing as a fresh sensation in your mouth.</p> +<p>When you finish brushing your teeth, theyā€™re still dirty ā€“Ā no doubt. However, itā€™s still gratifying, since youā€™re fooled by the menthol ability to trigger the cooling sensation.Ā <em>(Hence the human inclination to brushing rather than flossing!?)</em></p> +<p>In terms of dental health, though, flossing teeth is more effective on cleaning than brushing<sup class="footnote-reference"><a href="#1">1</a></sup>, <strong>even if it doesnā€™t feel like it.</strong> Thereā€™s no immediate reward in flossing, but definitely a long-term one.</p> +<p>What am I trying to say? Apart from dental health advice, that sort of reminds me that we shouldnā€™t rely on feeling instantaneously compensated as a fuel to build habits. After all, some things just need the long-term to pay off; for we to benefit from them.</p> +<div class="footnote-definition" id="1"><sup class="footnote-definition-label">1</sup> +<p>Iā€™ve read that at some point in my life but donā€™t remember where. You can find some resources out there, such as ā€œ<a href="https://askthedentist.com/flossing-or-brushing-more-important/">Whatā€™s More Important: Flossing or Brushing?</a>ā€. Anyway, I think weā€™re safe assuming that flossing is, at least, <em>as important</em> as brushing.</p> +</div> + + + + + Expressive JavaScript Conditionals (for Humans) + 2017-10-30T00:00:00+00:00 + 2017-10-30T00:00:00+00:00 + + + + + Unknown + + + + + + /blog/expressive-javascript-conditionals/ + + <p>Conditionals! As programmers, we write at least one every day. Easy to write, horrible to read, and sometimes it seems as though thereā€™s no way to work around that.</p> +<p>Today, Iā€™m happy to share some patterns Iā€™ve learned over time and have spread heavily in code reviews. Letā€™s rethink conditionals to make the most out of a languageā€™s power of expression ā€“Ā in the case of this article, JavaScript.</p> +<h2 id="patterns-for-conditionals">Patterns for Conditionals</h2> +<p>First, to put you in the mood, a quote from Literate Programming<sup class="footnote-reference"><a href="#1">1</a></sup>, by Donald Knuth.</p> +<blockquote> +<p>The practitioner of literate programming can be regarded as an essayist, whose main concern is with exposition and excellence of style. Such an author, with thesaurus in hand, chooses the names of variables carefully and explains what each variable means. He or she strives for a program that is comprehensible because its concepts have been introduced in an order that is best for human understanding, using a mixture of formal and informal methods that reinforce each other.</p> +</blockquote> +<p>That sums up the approach for this post: purely aimed at <strong>how to write code for people to read</strong>. Performance doesnā€™t matter now, since 1) thatā€™s not the goal and 2) I donā€™t believe in premature optimisation.</p> +<p>Iā€™ll briefly talk about each pattern, but whatā€™s more important here is to read the code carefully and get something out of it (as if it were poetry or something!).</p> +<h3 id="1-variables-that-hold-conditions">1. Variables that hold conditions</h3> +<p>When your condition is made up of an expression (or many of them), you can store it within meaningful-named variables.</p> +<p>Letā€™s say, to illustrate, that our program holds some data about a fruit and we have to check whether that fruit is a banana. We could do this:</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">fruit </span><span style="color:#ff79c6;">= </span><span>{ +</span><span> colors: [</span><span style="color:#f1fa8c;">&quot;yellow&quot;</span><span>, </span><span style="color:#f1fa8c;">&quot;green&quot;</span><span>], +</span><span> sweet: </span><span style="color:#bd93f9;">true</span><span>, +</span><span>} +</span><span> +</span><span style="color:#ff79c6;">if </span><span>(</span><span style="color:#ffffff;">fruit</span><span style="color:#ff79c6;">.</span><span style="color:#ffffff;">sweet </span><span style="color:#ff79c6;">=== </span><span style="color:#bd93f9;">true </span><span style="color:#ff79c6;">&amp;&amp; </span><span style="color:#ffffff;">fruit</span><span style="color:#ff79c6;">.</span><span style="color:#ffffff;">colors</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">some</span><span>((</span><span style="font-style:italic;color:#ffb86c;">color</span><span>) </span><span style="font-style:italic;color:#8be9fd;">=&gt; </span><span style="color:#ffffff;">color </span><span style="color:#ff79c6;">=== </span><span style="color:#f1fa8c;">&quot;yellow&quot;</span><span>)) { +</span><span> </span><span style="color:#50fa7b;">alert</span><span>(</span><span style="color:#f1fa8c;">&quot;do your stuff šŸŒ&quot;</span><span>) +</span><span> </span><span style="color:#ff79c6;">return </span><span style="color:#f1fa8c;">&quot;is banana&quot; +</span><span>} +</span></code></pre> +<p>Or we could store our conditions in variables!</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">fruit </span><span style="color:#ff79c6;">= </span><span>{ +</span><span> colors: [</span><span style="color:#f1fa8c;">&quot;yellow&quot;</span><span>, </span><span style="color:#f1fa8c;">&quot;green&quot;</span><span>], +</span><span> sweet: </span><span style="color:#bd93f9;">true</span><span>, +</span><span>} +</span><span> +</span><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">isSweet </span><span style="color:#ff79c6;">= </span><span style="color:#ffffff;">fruit</span><span style="color:#ff79c6;">.</span><span style="color:#ffffff;">sweet </span><span style="color:#ff79c6;">=== </span><span style="color:#bd93f9;">true </span><span style="color:#6272a4;">// or just `fruit.sweet` +</span><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">isYellow </span><span style="color:#ff79c6;">= </span><span style="color:#ffffff;">fruit</span><span style="color:#ff79c6;">.</span><span style="color:#ffffff;">colors</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">some</span><span>((</span><span style="font-style:italic;color:#ffb86c;">color</span><span>) </span><span style="font-style:italic;color:#8be9fd;">=&gt; </span><span style="color:#ffffff;">color </span><span style="color:#ff79c6;">=== </span><span style="color:#f1fa8c;">&quot;yellow&quot;</span><span>) +</span><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">isBanana </span><span style="color:#ff79c6;">= </span><span style="color:#ffffff;">isYellow </span><span style="color:#ff79c6;">&amp;&amp; </span><span style="color:#ffffff;">isSweet +</span><span> +</span><span style="color:#ff79c6;">if </span><span>(</span><span style="color:#ffffff;">isBanana</span><span>) { +</span><span> </span><span style="color:#50fa7b;">alert</span><span>(</span><span style="color:#f1fa8c;">&quot;do your stuff šŸŒ&quot;</span><span>) +</span><span> </span><span style="color:#ff79c6;">return </span><span style="color:#f1fa8c;">&quot;is banana&quot; +</span><span>} +</span></code></pre> +<p class="note">Not all conditions need to be in a variable. <code>fruit.sweet</code>, for instance, is quite expressive by its own.</p> +<p>This way, if we or our workmates need to know what makes a fruit a banana in our program, itā€™s just a matter of checking out the variable itself. The logic for how conditions evaluate will be there, behind a meaningful name.</p> +<p>Itā€™s even more useful for composing and reusing conditions.</p> +<h4 id="filtering-arrays">Filtering arrays</h4> +<p class="note">In the previous example, all variables were conditions based on the <code>fruit</code> object, for didactic purposes. Commonly, though, those variables actually store (pure) functions that take any fruit and test against it. I'm changing that to fit this example.</p> +<p>Letā€™s say weā€™ve got an array of fruits and we need to filter all the bananas out of it.</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">fruits </span><span style="color:#ff79c6;">= </span><span>[ +</span><span> { +</span><span> colors: [</span><span style="color:#f1fa8c;">&quot;yellow&quot;</span><span>, </span><span style="color:#f1fa8c;">&quot;green&quot;</span><span>], +</span><span> sweet: </span><span style="color:#bd93f9;">true</span><span>, +</span><span> }, +</span><span> { +</span><span> colors: [</span><span style="color:#f1fa8c;">&quot;red&quot;</span><span>], +</span><span> sweet: </span><span style="color:#bd93f9;">false</span><span>, </span><span style="color:#6272a4;">// don&#39;t know what kind of fruit this&#39;d be +</span><span> }, +</span><span>] +</span><span> +</span><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#50fa7b;">isSweet </span><span style="color:#ff79c6;">= </span><span>(</span><span style="font-style:italic;color:#ffb86c;">fruit</span><span>) </span><span style="font-style:italic;color:#8be9fd;">=&gt; </span><span style="color:#ffffff;">fruit</span><span style="color:#ff79c6;">.</span><span style="color:#ffffff;">sweet </span><span style="color:#ff79c6;">=== </span><span style="color:#bd93f9;">true +</span><span> +</span><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#50fa7b;">isYellow </span><span style="color:#ff79c6;">= </span><span>(</span><span style="font-style:italic;color:#ffb86c;">fruit</span><span>) </span><span style="font-style:italic;color:#8be9fd;">=&gt; </span><span style="color:#ffffff;">fruit</span><span style="color:#ff79c6;">.</span><span style="color:#ffffff;">colors</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">some</span><span>((</span><span style="font-style:italic;color:#ffb86c;">color</span><span>) </span><span style="font-style:italic;color:#8be9fd;">=&gt; </span><span style="color:#ffffff;">color </span><span style="color:#ff79c6;">=== </span><span style="color:#f1fa8c;">&quot;yellow&quot;</span><span>) +</span><span> +</span><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#50fa7b;">isBanana </span><span style="color:#ff79c6;">= </span><span>(</span><span style="font-style:italic;color:#ffb86c;">fruit</span><span>) </span><span style="font-style:italic;color:#8be9fd;">=&gt; </span><span style="color:#50fa7b;">isSweet</span><span>(</span><span style="color:#ffffff;">fruit</span><span>) </span><span style="color:#ff79c6;">&amp;&amp; </span><span style="color:#50fa7b;">isYellow</span><span>(</span><span style="color:#ffffff;">fruit</span><span>) +</span><span> +</span><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">bananas </span><span style="color:#ff79c6;">= </span><span style="color:#ffffff;">fruits</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">filter</span><span>(</span><span style="color:#ffffff;">isBanana</span><span>) +</span></code></pre> +<p>So expressive! I love the way that I can read that last line and even a kid (a non-programmer one!) can understand. <em>(Yes, Iā€™ve tried that.)</em></p> +<p>The currying technique would help introduce expressiveness without the verbosity for <code>isBanana</code>. An optional appendix at the end of the article elaborates more on that, if youā€™re curious.</p> +<p>Thatā€™s it. Hold on to that one though ā€“ itā€™s the foundation for whatā€™s next.</p> +<h3 id="2-define-value-conditionally">2. Define value conditionally</h3> +<p>Still considering the variables from the example above, this could also be done:</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">myFruit </span><span style="color:#ff79c6;">= </span><span style="color:#ffffff;">isYellow </span><span style="color:#ff79c6;">&amp;&amp; </span><span style="color:#ffffff;">isSweet </span><span style="color:#ff79c6;">&amp;&amp; </span><span style="color:#f1fa8c;">&quot;banana&quot; +</span><span style="color:#ff79c6;">return </span><span style="color:#ffffff;">myFruit +</span></code></pre> +<p>The value for the <code>myFruit</code> variable will only be assigned to ā€œbananaā€ if those conditions are true. Pretty useful for when values are defined conditionally!</p> +<p>That saves you from <code>if (isYellow &amp;&amp; isSweet) [...]</code>, and itā€™s quite expressive, Iā€™d say. An expressive expression. šŸ‘Œ</p> +<h3 id="3-define-value-conditionally-with-fallback">3. Define value conditionally with fallback</h3> +<figure class="text-center"><picture><img width="250" src="https://imgs.xkcd.com/comics/conditionals_2x.png" alt="Conditionals, a comic from xkcd"></picture> +<figcaption><a href="http://xkcd.com/1652">xkcd: Conditionals</a></figcaption></figure> +<p>What if we want something else in case itā€™s not a banana? Instead of an <code>if (isBanana) [...]</code> with <code>else</code>, go for the <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator">ternary operator</a>.</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">isBanana </span><span style="color:#ff79c6;">= </span><span style="color:#ffffff;">isYellow </span><span style="color:#ff79c6;">&amp;&amp; </span><span style="color:#ffffff;">isSweet +</span><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">myFruit </span><span style="color:#ff79c6;">= </span><span style="color:#ffffff;">isBanana </span><span style="color:#ff79c6;">? </span><span style="color:#f1fa8c;">&quot;is banana&quot; </span><span style="color:#ff79c6;">: </span><span style="color:#f1fa8c;">&quot;is other stuff&quot; +</span><span style="color:#ff79c6;">return </span><span style="color:#ffffff;">myFruit +</span></code></pre> +<p>Some additional but important advice Iā€™d give regarding ternary expressions:</p> +<ul> +<li>Make them as compound as possible.</li> +<li>Do NOT nest them. Donā€™t pretend the nesting is readable ā€“Ā itā€™s not even human to do that.</li> +<li>Donā€™t avoid writing <code>if</code> statements because you want to look smart.</li> +</ul> +<h3 id="4-check-for-all-conditions">4. Check for all conditions</h3> +<p>Weā€™ve (finally) found out that checking for <code>isYellow</code> and <code>isSweet</code> isnā€™t enough to make sure the fruit is a banana. After all, yellow pepper is both sweet and yellow and itā€™s still not a banana, right?</p> +<p>Right. We then add more checks to the <code>isBanana</code> variable, and this time theyā€™re ugly ones: they check whether the fruit is either from Brazil or Ecuador, both top banana producing countries.</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">fruit </span><span style="color:#ff79c6;">= </span><span>{ +</span><span> colors: [</span><span style="color:#f1fa8c;">&quot;yellow&quot;</span><span>, </span><span style="color:#f1fa8c;">&quot;green&quot;</span><span>], +</span><span> sweet: </span><span style="color:#bd93f9;">true</span><span>, +</span><span> countries: [ +</span><span> { +</span><span> name: </span><span style="color:#f1fa8c;">&quot;Brazil&quot;</span><span>, +</span><span> topProducer: </span><span style="color:#bd93f9;">true</span><span>, </span><span style="color:#6272a4;">// i&#39;m brazilian and therefore biased +</span><span> }, +</span><span> { +</span><span> name: </span><span style="color:#f1fa8c;">&quot;Ecuador&quot;</span><span>, +</span><span> topProducer: </span><span style="color:#bd93f9;">false</span><span>, +</span><span> }, +</span><span> ], +</span><span>} +</span><span> +</span><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">isSweet </span><span style="color:#ff79c6;">= </span><span style="color:#ffffff;">fruit</span><span style="color:#ff79c6;">.</span><span style="color:#ffffff;">sweet </span><span style="color:#ff79c6;">=== </span><span style="color:#bd93f9;">true </span><span style="color:#6272a4;">// or just `fruit.sweet` +</span><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">isYellow </span><span style="color:#ff79c6;">= </span><span style="color:#ffffff;">fruit</span><span style="color:#ff79c6;">.</span><span style="color:#ffffff;">colors</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">some</span><span>((</span><span style="font-style:italic;color:#ffb86c;">color</span><span>) </span><span style="font-style:italic;color:#8be9fd;">=&gt; </span><span style="color:#ffffff;">color </span><span style="color:#ff79c6;">=== </span><span style="color:#f1fa8c;">&quot;yellow&quot;</span><span>) +</span><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">isBrazilian </span><span style="color:#ff79c6;">= </span><span style="color:#ffffff;">fruit</span><span style="color:#ff79c6;">.</span><span style="color:#ffffff;">countries</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">find</span><span>((</span><span style="font-style:italic;color:#ffb86c;">i</span><span>) </span><span style="font-style:italic;color:#8be9fd;">=&gt; </span><span style="color:#ffffff;">i</span><span style="color:#ff79c6;">.</span><span>name </span><span style="color:#ff79c6;">=== </span><span style="color:#f1fa8c;">&quot;Brazil&quot;</span><span>) +</span><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">isEcuadorian </span><span style="color:#ff79c6;">= </span><span style="color:#ffffff;">fruit</span><span style="color:#ff79c6;">.</span><span style="color:#ffffff;">countries</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">find</span><span>((</span><span style="font-style:italic;color:#ffb86c;">i</span><span>) </span><span style="font-style:italic;color:#8be9fd;">=&gt; </span><span style="color:#ffffff;">i</span><span style="color:#ff79c6;">.</span><span>name </span><span style="color:#ff79c6;">=== </span><span style="color:#f1fa8c;">&quot;Ecuador&quot;</span><span>) +</span><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">isBanana </span><span style="color:#ff79c6;">= </span><span style="color:#ffffff;">isYellow </span><span style="color:#ff79c6;">&amp;&amp; </span><span style="color:#ffffff;">isSweet </span><span style="color:#ff79c6;">&amp;&amp; </span><span style="color:#ffffff;">isBrazilian </span><span style="color:#ff79c6;">&amp;&amp; </span><span style="color:#ffffff;">isEcuadorian +</span><span> +</span><span style="color:#ff79c6;">if </span><span>(</span><span style="color:#ffffff;">isBanana</span><span>) { +</span><span> </span><span style="color:#50fa7b;">alert</span><span>(</span><span style="color:#f1fa8c;">&quot;do your stuff!11 šŸŒ&quot;</span><span>) +</span><span> </span><span style="font-style:italic;color:#66d9ef;">console</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">log</span><span>(</span><span style="color:#f1fa8c;">&quot;now this is really a banana&quot;</span><span>) +</span><span>} +</span></code></pre> +<p>Did you see how big <code>isBanana</code> is getting? Weā€™d have to start breaking lines in those <code>&amp;&amp;</code> to improve readability, which, personally, I donā€™t like doing.</p> +<p>If refactoring the booleans into new variables isnā€™t an option anymore, what about <em>storing the conditions in an array and testing every item for truthiness</em>?</p> +<p>Use the power of <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/every">arrayā€™s <code>every</code></a>:</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">isBanana </span><span style="color:#ff79c6;">= </span><span>[</span><span style="color:#ffffff;">isYellow</span><span>, </span><span style="color:#ffffff;">isSweet</span><span>, </span><span style="color:#ffffff;">isEcuadorian</span><span>, </span><span style="color:#ffffff;">isBrazilian</span><span>]</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">every</span><span>(</span><span style="font-style:italic;color:#66d9ef;">Boolean</span><span>) </span><span style="color:#6272a4;">// or `x =&gt; x === true` +</span></code></pre> +<p class="note">Repetitive friendly reminder: don't store every condition in a variable. Remember you can always add the condition itself to the array.</p> +<p>You can even turn that into a snippet:</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#50fa7b;">all </span><span style="color:#ff79c6;">= </span><span>(</span><span style="font-style:italic;color:#ffb86c;">arr</span><span>) </span><span style="font-style:italic;color:#8be9fd;">=&gt; </span><span style="color:#ffffff;">arr</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">every</span><span>(</span><span style="font-style:italic;color:#66d9ef;">Boolean</span><span>) +</span><span> +</span><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">isBanana </span><span style="color:#ff79c6;">= </span><span style="color:#50fa7b;">all</span><span>([</span><span style="color:#ffffff;">isYellow</span><span>, </span><span style="color:#ffffff;">isSweet</span><span>, </span><span style="color:#ffffff;">isEcuadorian</span><span>, </span><span style="color:#ffffff;">isBrazilian</span><span>]) +</span></code></pre> +<p>I donā€™t know how useful that looks for you, but, in everyday work, I really appreciate doing it.</p> +<h3 id="5-check-for-any-condition">5. Check for any condition</h3> +<p>What if weā€™ve got crazy and weā€™re fine considering something a banana when itā€™s either yellow, Brazilian or sweet?</p> +<p>Use the power of <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some">arrayā€™s <code>some</code></a>:</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">isBanana </span><span style="color:#ff79c6;">= </span><span>[</span><span style="color:#ffffff;">isYellow</span><span>, </span><span style="color:#ffffff;">isSweet</span><span>, </span><span style="color:#ffffff;">isBrazilian</span><span>]</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">some</span><span>(</span><span style="font-style:italic;color:#66d9ef;">Boolean</span><span>) </span><span style="color:#6272a4;">// or `x =&gt; x === true` +</span></code></pre> +<p class="note">Yeah, yeah, I know, you can just use the <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_Operators#Logical_OR_()">OR operator</a>.</p> +<p>If any of them evaluates to true, profit! ā€“Ā itā€™s a banana. šŸŒ</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#50fa7b;">any </span><span style="color:#ff79c6;">= </span><span>(</span><span style="font-style:italic;color:#ffb86c;">arr</span><span>) </span><span style="font-style:italic;color:#8be9fd;">=&gt; </span><span style="color:#ffffff;">arr</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">some</span><span>(</span><span style="font-style:italic;color:#66d9ef;">Boolean</span><span>) +</span><span> +</span><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">isBanana </span><span style="color:#ff79c6;">= </span><span style="color:#50fa7b;">any</span><span>([</span><span style="color:#ffffff;">isYellow</span><span>, </span><span style="color:#ffffff;">isSweet</span><span>, </span><span style="color:#ffffff;">isBrazilian</span><span>]) +</span></code></pre> +<p>In other words, being a Brazilian means youā€™re a banana! It doesnā€™t sound any bad to me honestly.</p> +<p>Pretty similar to <a href="http://ramdajs.com/docs/#either">Ramdaā€™s <code>either</code></a>. šŸ˜Ž</p> +<h3 id="6-early-return">6. Early return</h3> +<p>We want something special for when the banana is Brazilian! <code>else</code> conditions would do the trick, wouldnā€™t they?</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">fruit </span><span style="color:#ff79c6;">= </span><span>{ +</span><span> colors: [</span><span style="color:#f1fa8c;">&quot;yellow&quot;</span><span>, </span><span style="color:#f1fa8c;">&quot;green&quot;</span><span>], +</span><span> sweet: </span><span style="color:#bd93f9;">true</span><span>, +</span><span> countries: [ +</span><span> { +</span><span> name: </span><span style="color:#f1fa8c;">&quot;Brazil&quot;</span><span>, +</span><span> topProducer: </span><span style="color:#bd93f9;">true</span><span>, </span><span style="color:#6272a4;">// i&#39;m brazilian and therefore biased +</span><span> }, +</span><span> { +</span><span> name: </span><span style="color:#f1fa8c;">&quot;Ecuador&quot;</span><span>, +</span><span> topProducer: </span><span style="color:#bd93f9;">false</span><span>, +</span><span> }, +</span><span> ], +</span><span>} +</span><span> +</span><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">isSweet </span><span style="color:#ff79c6;">= </span><span style="color:#ffffff;">fruit</span><span style="color:#ff79c6;">.</span><span style="color:#ffffff;">sweet </span><span style="color:#ff79c6;">=== </span><span style="color:#bd93f9;">true </span><span style="color:#6272a4;">// or just `fruit.sweet` +</span><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">isYellow </span><span style="color:#ff79c6;">= </span><span style="color:#ffffff;">fruit</span><span style="color:#ff79c6;">.</span><span style="color:#ffffff;">colors</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">some</span><span>((</span><span style="font-style:italic;color:#ffb86c;">color</span><span>) </span><span style="font-style:italic;color:#8be9fd;">=&gt; </span><span style="color:#ffffff;">color </span><span style="color:#ff79c6;">=== </span><span style="color:#f1fa8c;">&quot;yellow&quot;</span><span>) +</span><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">isBrazilian </span><span style="color:#ff79c6;">= </span><span style="color:#ffffff;">fruit</span><span style="color:#ff79c6;">.</span><span style="color:#ffffff;">countries</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">find</span><span>((</span><span style="font-style:italic;color:#ffb86c;">i</span><span>) </span><span style="font-style:italic;color:#8be9fd;">=&gt; </span><span style="color:#ffffff;">i</span><span style="color:#ff79c6;">.</span><span>name </span><span style="color:#ff79c6;">=== </span><span style="color:#f1fa8c;">&quot;Brazil&quot;</span><span>) +</span><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">isEcuadorian </span><span style="color:#ff79c6;">= </span><span style="color:#ffffff;">fruit</span><span style="color:#ff79c6;">.</span><span style="color:#ffffff;">countries</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">find</span><span>((</span><span style="font-style:italic;color:#ffb86c;">i</span><span>) </span><span style="font-style:italic;color:#8be9fd;">=&gt; </span><span style="color:#ffffff;">i</span><span style="color:#ff79c6;">.</span><span>name </span><span style="color:#ff79c6;">=== </span><span style="color:#f1fa8c;">&quot;Ecuador&quot;</span><span>) +</span><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">isBanana </span><span style="color:#ff79c6;">= </span><span style="color:#ffffff;">isYellow </span><span style="color:#ff79c6;">&amp;&amp; </span><span style="color:#ffffff;">isSweet +</span><span> +</span><span style="color:#ff79c6;">if </span><span>(</span><span style="color:#ffffff;">isBanana </span><span style="color:#ff79c6;">&amp;&amp; </span><span style="color:#ffffff;">isBrazilian</span><span>) { +</span><span> </span><span style="color:#6272a4;">// first true case! +</span><span> </span><span style="color:#50fa7b;">alert</span><span>(</span><span style="color:#f1fa8c;">&quot;i am a brazilian banana i love football šŸŒ&quot;</span><span>) +</span><span>} </span><span style="color:#ff79c6;">else if </span><span>(</span><span style="color:#ffffff;">isBanana </span><span style="color:#ff79c6;">&amp;&amp; </span><span style="color:#ffffff;">isEcuadorian</span><span>) { +</span><span> </span><span style="color:#50fa7b;">alert</span><span>(</span><span style="color:#f1fa8c;">&quot;i am an ecuadorian banana do not mess with me šŸŒ&quot;</span><span>) +</span><span>} </span><span style="color:#ff79c6;">else </span><span>{ +</span><span> </span><span style="color:#50fa7b;">alert</span><span>(</span><span style="color:#f1fa8c;">&quot;a normal banana from somewhere else&quot;</span><span>) +</span><span>} +</span></code></pre> +<p>Alternatively, THOOOUGH, we can early return (nothing at all, i.e. <code>undefined</code>), which will make <strong>our code stops its flow at that point</strong>.</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="color:#ff79c6;">if </span><span>(</span><span style="color:#ffffff;">isBanana </span><span style="color:#ff79c6;">&amp;&amp; </span><span style="color:#ffffff;">isBrazilian</span><span>) { +</span><span> </span><span style="color:#50fa7b;">alert</span><span>(</span><span style="color:#f1fa8c;">&quot;i am a brazilian banana i love football šŸŒ&quot;</span><span>) +</span><span> </span><span style="color:#ff79c6;">return </span><span style="color:#6272a4;">// sTAAAAHP!!!1 +</span><span>} +</span><span> +</span><span style="color:#ff79c6;">if </span><span>(</span><span style="color:#ffffff;">isBanana </span><span style="color:#ff79c6;">&amp;&amp; </span><span style="color:#ffffff;">isEcuadorian</span><span>) { +</span><span> </span><span style="color:#50fa7b;">alert</span><span>(</span><span style="color:#f1fa8c;">&quot;i am an ecuadorian banana do not mess with me šŸŒ&quot;</span><span>) +</span><span> </span><span style="color:#ff79c6;">return </span><span style="color:#6272a4;">// DON&#39;T GO ANY FURTHER, JAVASCRIPT!11 +</span><span>} +</span><span> +</span><span style="color:#6272a4;">// or do, whatever +</span><span style="color:#50fa7b;">alert</span><span>(</span><span style="color:#f1fa8c;">&quot;a normal banana from somewhere else&quot;</span><span>) +</span></code></pre> +<p class="note">Those checks could also be refactored into a variable named <code>isBrazilianBanana</code>. I found it too much for this example though, so this is just a friendly reminder that your conditions can always be composable.</p> +<p>Keep in mind that early returns might make the flow of your program confusing. Different from when youā€™re using <code>else</code> conditions, itā€™s not explicit that the conditionals are from the same logical group anymore.</p> +<h3 id="7-check-for-the-same-variable">7. Check for the same variable</h3> +<p>Letā€™s get the colour of the fruits! Each fruit has one.</p> +<p>Hmmmā€¦ Different cases that require different handling, but all handled cases depend on the same thing. What do we do? We conditionally check for its value and handle the case depending on that.</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#50fa7b;">getFruitColor </span><span style="color:#ff79c6;">= </span><span>(</span><span style="font-style:italic;color:#ffb86c;">fruit</span><span>) </span><span style="font-style:italic;color:#8be9fd;">=&gt; </span><span>{ +</span><span> </span><span style="color:#ff79c6;">if </span><span>(</span><span style="color:#ffffff;">fruit </span><span style="color:#ff79c6;">=== </span><span style="color:#f1fa8c;">&quot;banana&quot;</span><span>) { +</span><span> </span><span style="color:#ff79c6;">return </span><span style="color:#f1fa8c;">&quot;is yellow&quot; +</span><span> } </span><span style="color:#ff79c6;">else if </span><span>(</span><span style="color:#ffffff;">fruit </span><span style="color:#ff79c6;">=== </span><span style="color:#f1fa8c;">&quot;apple&quot;</span><span>) { +</span><span> </span><span style="color:#ff79c6;">return </span><span style="color:#f1fa8c;">&quot;is red&quot; +</span><span> } </span><span style="color:#ff79c6;">else if </span><span>(</span><span style="color:#ffffff;">fruit </span><span style="color:#ff79c6;">=== </span><span style="color:#f1fa8c;">&quot;orange&quot;</span><span>) { +</span><span> </span><span style="color:#ff79c6;">return </span><span style="color:#f1fa8c;">&quot;is orange&quot; +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#50fa7b;">getFruitColor</span><span>(</span><span style="color:#f1fa8c;">&quot;banana&quot;</span><span>) </span><span style="color:#6272a4;">// =&gt; is yellow +</span></code></pre> +<p class="note">This code would benefit from early returns, and, of course, the <code>switch</code> statement.</p> +<p>Or we donā€™t. Because, alternatively, we can create a getter function (<code>getFruitColor</code>) that:</p> +<ol> +<li>inputs a key (<code>fruit</code>), and</li> +<li>outputs the value that was assigned to that key in a specific map (<code>fruitColors</code>).</li> +</ol> +<p>Like this:</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">fruitColors </span><span style="color:#ff79c6;">= </span><span>{ +</span><span> banana: </span><span style="color:#f1fa8c;">&#39;is yellow&#39; +</span><span> </span><span style="color:#ffffff;">apple</span><span>: </span><span style="color:#f1fa8c;">&#39;is red&#39;</span><span>, +</span><span> orange: </span><span style="color:#f1fa8c;">&#39;is orange&#39;</span><span>, +</span><span>} +</span><span> +</span><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#50fa7b;">getFruitColor </span><span style="color:#ff79c6;">= </span><span style="font-style:italic;color:#ffb86c;">fruit </span><span style="font-style:italic;color:#8be9fd;">=&gt; </span><span style="color:#ffffff;">fruitColors</span><span>[</span><span style="color:#ffffff;">fruit</span><span>] +</span><span> +</span><span style="color:#50fa7b;">getFruitColor</span><span>(</span><span style="color:#f1fa8c;">&#39;banana&#39;</span><span>) </span><span style="color:#6272a4;">// fruitColors[&#39;banana&#39;] =&gt; is yellow +</span></code></pre> +<p>Simplifying, since that map isnā€™t useful outside of the getter itself anyway:</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#50fa7b;">getFruitColor </span><span style="color:#ff79c6;">= </span><span style="font-style:italic;color:#ffb86c;">fruit </span><span style="font-style:italic;color:#8be9fd;">=&gt; </span><span>({ +</span><span> banana: </span><span style="color:#f1fa8c;">&#39;is yellow&#39; +</span><span> </span><span style="color:#ffffff;">apple</span><span>: </span><span style="color:#f1fa8c;">&#39;is red&#39;</span><span>, +</span><span> orange: </span><span style="color:#f1fa8c;">&#39;is orange&#39;</span><span>, +</span><span>}[</span><span style="color:#ffffff;">fruit</span><span>] +</span><span> +</span><span style="color:#50fa7b;">getFruitColor</span><span>(</span><span style="color:#f1fa8c;">&#39;banana&#39;</span><span>) </span><span style="color:#6272a4;">// =&gt; is yellow +</span></code></pre> +<p>This is a very common technique I first saw on a <a href="https://javascriptweblog.wordpress.com/2010/03/08/caseagainstswitch/">blog post from Angus Croll</a> in 2010. I love the simplicity of it.</p> +<p>Nowadays thereā€™s even more freedom with this technique, considering features such as <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer#Computed_property_names">computed property names for objects</a>. But donā€™t get too creative with that! Go for whatā€™s more readable and expressive for you <strong>AND</strong> the people you work with.</p> +<h3 id="appendix-currying-because-verbosity-isn-t-expressiveness">Appendix: Currying, because verbosity isnā€™t expressiveness</h3> +<p class="note">This is an additional reading and requires familiarity with curried functions. For further reading on the currying technique, I recommend the <a href="https://drboolean.gitbooks.io/mostly-adequate-guide/content/ch4.html#cant-live-if-livin-is-without-you">"Currying" chapter</a> of the book Mostly Adequate Guide to Functional Programming, or <a href="https://www.sitepoint.com/currying-in-functional-javascript/">A Beginnerā€™s Guide to Currying</a>, as a more beginner-friendly introduction.</p> +<p>Letā€™s reconsider:</p> +<ol> +<li>the problem from the 1st, where we had an array of fruits and had to create a function that checks whether the fruit passed to it was a banana, and</li> +<li>the <code>all</code> util from the 4th pattern.</li> +</ol> +<h4 id="check-for-all-conditions-revisited">Check for all conditions, revisited</h4> +<p>Imagine if we had a lot of conditions for <code>isBanana</code>. We could use <code>&amp;&amp;</code> or even <code>all</code>.</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#50fa7b;">isBanana </span><span style="color:#ff79c6;">= </span><span>(</span><span style="font-style:italic;color:#ffb86c;">fruit</span><span>) </span><span style="font-style:italic;color:#8be9fd;">=&gt; +</span><span> </span><span style="color:#50fa7b;">isBanana</span><span>(</span><span style="color:#ffffff;">fruit</span><span>) </span><span style="color:#ff79c6;">&amp;&amp; +</span><span> </span><span style="color:#50fa7b;">isSweet</span><span>(</span><span style="color:#ffffff;">fruit</span><span>) </span><span style="color:#ff79c6;">&amp;&amp; +</span><span> </span><span style="color:#50fa7b;">isEcuadorian</span><span>(</span><span style="color:#ffffff;">fruit</span><span>) </span><span style="color:#ff79c6;">&amp;&amp; +</span><span> </span><span style="color:#50fa7b;">isBrazilian</span><span>(</span><span style="color:#ffffff;">fruit</span><span>) +</span><span style="color:#6272a4;">// or +</span><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#50fa7b;">isBanana </span><span style="color:#ff79c6;">= </span><span>(</span><span style="font-style:italic;color:#ffb86c;">fruit</span><span>) </span><span style="font-style:italic;color:#8be9fd;">=&gt; +</span><span> </span><span style="color:#50fa7b;">all</span><span>([ +</span><span> </span><span style="color:#50fa7b;">isYellow</span><span>(</span><span style="color:#ffffff;">fruit</span><span>), +</span><span> </span><span style="color:#50fa7b;">isSweet</span><span>(</span><span style="color:#ffffff;">fruit</span><span>), +</span><span> </span><span style="color:#50fa7b;">isEcuadorian</span><span>(</span><span style="color:#ffffff;">fruit</span><span>), +</span><span> </span><span style="color:#50fa7b;">isBrazilian</span><span>(</span><span style="color:#ffffff;">fruit</span><span>), +</span><span> ]) +</span></code></pre> +<p>Itā€™s meaningful, easy to read, but introduces too much verbosity. The currying technique could help us introduce more meaning without being verbose. With some changes in the <code>all</code> util, that could be boiled down to:</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">isBanana </span><span style="color:#ff79c6;">= </span><span style="color:#50fa7b;">all</span><span>([</span><span style="color:#ffffff;">isSweet</span><span>, </span><span style="color:#ffffff;">isYellow</span><span>, </span><span style="color:#ffffff;">isEcuadorian</span><span>, </span><span style="color:#ffffff;">isBrazilian</span><span>]) +</span><span style="color:#6272a4;">// no explicit fruit here, and still works! +</span><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">bananas </span><span style="color:#ff79c6;">= </span><span style="color:#ffffff;">fruits</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">filter</span><span>(</span><span style="color:#ffffff;">isBanana</span><span>) +</span></code></pre> +<p>Notice weā€™re not explicitly passing fruit anymore. How do we do that? By making <code>all</code> a curried function. There are some ways to achieve that, hereā€™s one:</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#50fa7b;">all </span><span style="color:#ff79c6;">= </span><span>(</span><span style="font-style:italic;color:#ffb86c;">conditions</span><span>) </span><span style="font-style:italic;color:#8be9fd;">=&gt; </span><span>(</span><span style="font-style:italic;color:#ffb86c;">currentItem</span><span>) </span><span style="font-style:italic;color:#8be9fd;">=&gt; +</span><span> </span><span style="color:#ffffff;">conditions</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">map</span><span>((</span><span style="font-style:italic;color:#ffb86c;">condition</span><span>) </span><span style="font-style:italic;color:#8be9fd;">=&gt; </span><span style="color:#50fa7b;">condition</span><span>(</span><span style="color:#ffffff;">currentItem</span><span>))</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">every</span><span>(</span><span style="font-style:italic;color:#66d9ef;">Boolean</span><span>) +</span></code></pre> +<p>It takes the array of conditions and returns a function that takes the current item and calls each condition with that (as <em>argument</em>!). At the end, we check whether they all evaluated to true. Itā€™s not magic, itā€™s CURRYING!!!11<sup class="footnote-reference"><a href="#2">2</a></sup></p> +<p>Thatā€™s, of course, a simplistic implementation, which has costed me an array (from <code>map</code>). Whatā€™s important to get is how we play with <strong>function arguments under the hood</strong> to achieve currying.</p> +<p>You can curry your functions using <a href="http://ramdajs.com/docs/#all">Ramdaā€™s <code>curry</code></a> (or Lodashā€™s, whatever); or, if youā€™re interested on that as an util, <a href="http://ramdajs.com/docs/#all">Ramdaā€™s <code>all</code></a> and <a href="https://github.com/ramda/ramda/blob/master/source/all.js">its source</a> are really worth-checking!</p> +<h2 id="final-considerations">Final considerations</h2> +<p>By striving for conditionals as expressions other than statements, you write code in a <strong>functional</strong> approach. Code with a clearer sense of what itā€™s being checked without having to unearth to its foundations. Code thatā€™s easier and faster for people to reason about.</p> +<p><strong>But if your code is fine with an <code>if</code> rather than an object lookup or a ternary operator, just stick to it.</strong></p> +<p>Itā€™d break the whole purpose of this post if those patterns were used for looking smart. However, if refactoring your conditionals with them would lead to a more expressive codebase, go for it! Play with the patterns, <strong>compound them</strong>. Use your creativity to communicate well.</p> +<p>Itā€™s a language, after all.</p> +<div class="footnote-definition" id="1"><sup class="footnote-definition-label">1</sup> +<p>A programming paradigm first introduced by Donald Knuth, with the goal of providing an alternative, human, perspective on the programmerā€™s motivation. <a href="http://www.literateprogramming.com/knuthweb.pdf">Read the article</a>.</p> +</div> +<div class="footnote-definition" id="2"><sup class="footnote-definition-label">2</sup> +<p><strong>It may seem more magic than currying sometimes.</strong> JavaScript isnā€™t a purely functional language, so such techniques arenā€™t as popular as they are in Haskell community, for instance. Simplicity conflicts with easiness here.</p> +</div> + + + + + UI Components that Abstract Mistakes + 2017-10-14T18:06:00+00:00 + 2017-10-14T18:06:00+00:00 + + + + + Unknown + + + + + + /blog/ui-components-that-abstract-mistakes/ + + <p>2017, October 14th.</p> +<p>A cloudy day <sup class="footnote-reference"><a href="#1">1</a></sup> of Autumn in Berlin, probably something else in the place you live, <em>and</em> youā€™ve read the same date twice <em>and</em> this introduction actually doesnā€™t matter. But let me tell you about something that matters.</p> +<p>Everything is made up of <code>&lt;div&gt;</code>s and <code>&lt;span&gt;</code>s again, utterly hidden behind abstractions proudly called components. No one seems to remember <em>(or do they?)</em> the difference between <code>p</code> and <code>span</code>, let alone the point of using <code>section</code> rather than <code>div</code>.</p> +<p>Bad decisions ā€“ to not just to say bad and even invalid HTML markupĀ ā€“ are buried in components developers find awesome to compose user interfaces with. The web, and people, pay the price.</p> +<hr /> +<h2 id="creating-components">Creating components</h2> +<p class="note">From now on, to explain my point, I'll be assuming some familiarity with <a href="https://reactjs.org/" title="React">React</a> (a JavaScript library), although this applies to any kind of component abstraction.</p> +<p>Letā€™s say you just started a brand new React web app. You need to create a button at some point, and, because itā€™s reused in other parts of the app, has custom styles and also a fancy icon, you decide to introduce a component with all that abstracted out. Nice! You could do it like this:</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#50fa7b;">Button </span><span style="color:#ff79c6;">= </span><span>({ </span><span style="font-style:italic;color:#ffb86c;">onClick</span><span>, </span><span style="font-style:italic;color:#ffb86c;">children </span><span>}) </span><span style="font-style:italic;color:#8be9fd;">=&gt; </span><span>( +</span><span> </span><span style="color:#ff79c6;">&lt;</span><span style="color:#ffffff;">span class</span><span style="color:#ff79c6;">=</span><span style="color:#f1fa8c;">&quot;my-horrible-button&quot; </span><span style="color:#ffffff;">onClick</span><span style="color:#ff79c6;">=</span><span>{</span><span style="color:#ffffff;">onClick</span><span>}</span><span style="color:#ff79c6;">&gt; +</span><span> </span><span style="color:#ff79c6;">&lt;</span><span style="color:#ffffff;">i class</span><span style="color:#ff79c6;">=</span><span style="color:#f1fa8c;">&quot;my-terrible-font-awesome-icon&quot;</span><span style="color:#ff79c6;">&gt;</span><span>&lt;/i&gt; +</span><span> {</span><span style="font-style:italic;color:#ffb86c;">children</span><span>} +</span><span> </span><span style="color:#ff79c6;">&lt;/</span><span style="color:#ffffff;">span</span><span style="color:#ff79c6;">&gt; +</span><span>) +</span></code></pre> +<p>The user interface is then composed as the following:</p> +<pre data-lang="tsx" style="background-color:#282a36;color:#f8f8f2;" class="language-tsx "><code class="language-tsx" data-lang="tsx"><span>&lt;</span><span style="color:#ff79c6;">h1</span><span>&gt;Brazilian Bananas (1 kg)&lt;/</span><span style="color:#ff79c6;">h1</span><span>&gt; +</span><span>&lt;</span><span style="color:#ff79c6;">p</span><span>&gt;Sweet and healthy bananas!&lt;/</span><span style="color:#ff79c6;">p</span><span>&gt; +</span><span>&lt;</span><span style="color:#ff79c6;">p</span><span>&gt;Absolutely the best.&lt;/</span><span style="color:#ff79c6;">p</span><span>&gt; +</span><span>&lt;</span><span style="font-style:italic;color:#66d9ef;">Button </span><span style="color:#50fa7b;">onClick</span><span style="color:#ff79c6;">={</span><span>() </span><span style="font-style:italic;color:#8be9fd;">=&gt; </span><span style="color:#50fa7b;">alert</span><span>(</span><span style="color:#f1fa8c;">&#39;šŸŒ&#39;</span><span>)</span><span style="color:#ff79c6;">}</span><span>&gt;Buy $0.99&lt;/</span><span style="color:#ff79c6;">button</span><span>&gt; +</span></code></pre> +<p>It looks good! You were born for this, werenā€™t you?</p> +<p>Quite easy to miss whatā€™s wrong when components are just used like that. A button, isnā€™t it? The engineering team can easily grasp what that means and what that does, after all.</p> +<p>It could also be a <code>&lt;FormLabel /&gt;</code> or <code>&lt;Paragraph /&gt;</code> as <code>span</code> elements, or <code>div</code>s all over that place. Although they all work, mistakes are abstracted in components.</p> +<p class="note">I specifically talk about markup as the mistake throughout this article, however it could be anything really. Components look inoffensive when you're using them.</p> +<h2 id="the-web-isn-t-your-abstraction">The web isnā€™t your abstraction</h2> +<p>Now that HTML is all abstracted through JavaScript libraries and frameworks (which is not wrong), I wonder whether developers only went for semantic elements for the sake of making markup more readable for themselves. With React, your <code>&lt;Header&gt;</code> now may be a <code>div</code>. Out of the abstraction, though, youā€™d think twice before going for a <code>div</code> to make a headerĀ ā€“ youā€™d rather use HTML5ā€™s <code>header</code>.</p> +<p><strong>Because of the abstraction, output markup isnā€™t something we talk that much about anymore.</strong></p> +<p>Did we really get the benefits of HTML5 and why new elements were introduced? Why <code>button</code>? <sup class="footnote-reference"><a href="#2">2</a></sup> Whatā€™s <code>header</code> useful for? Why should one use <code>section</code> at all?</p> +<p class="note">By the way, do you know how many occurrences of <code>header</code>, <code>article</code>, <code>section</code> I've found on Netflix's landing page? Zero. It's all div soup.</p> +<p>Matter of fact is that browser engines and people ā€“ nothing less thanĀ the ones who you really write code for ā€“ wonā€™t ever know about your abstractions. A screen reader wonā€™t know your ā€œbuttonā€ is actually a button<sup class="footnote-reference"><a href="#3">3</a></sup>. (They will definitely get to know the <code>span</code> though, and that wonā€™t help.)</p> +<figure class="text-center"><picture><img src="https://imgs.xkcd.com/comics/tags.png" alt="xkcd, comic #1444"></picture> +<figcaption><a href="http://xkcd.com/1144">xkcd: Tags</a></figcaption></figure> +<p>Also, itā€™s never been easier to write invalid markup without even realizing it! After React, it seems acceptable to place a <code>button</code> inside an anchor link, and even giant elephants inside <code>span</code>. Has anyone ever thought why they are considered invalid markup in the first place?</p> +<h2 id="don-t-make-it-hard">Donā€™t make it hard</h2> +<p>Browsers and assistive technologies are smarter than ever<sup class="footnote-reference"><a href="#4">4</a></sup>, indeed, yet they still count on developers to write code they can understand and people can benefit from. By doing so, you make it easy for:</p> +<ol> +<li><strong>people</strong>, who will be able to navigate around the website, skipping over navigation sections or quickly jumping from one article to another<sup class="footnote-reference"><a href="#5">5</a></sup>.</li> +<li><strong>yourself</strong>, so you donā€™t have to reimplement default browser behaviours.</li> +</ol> +<p>Therefore, please: donā€™t waste features that technologies try to give users, and developers, out of the box.</p> +<p>Remember who you write code for.</p> +<div class="footnote-definition" id="1"><sup class="footnote-definition-label">1</sup> +<p>If I had managed to publish this yesterday, the day would be sunny. Iā€™ve missed the opportunity to make the article seems a little happier.</p> +</div> +<div class="footnote-definition" id="2"><sup class="footnote-definition-label">2</sup> +<p>The button element was first introduced in HTML4. (<a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button">Source</a>)</p> +</div> +<div class="footnote-definition" id="3"><sup class="footnote-definition-label">3</sup> +<p>Whatā€™s wrong with using a non-semantic element as a button? Well, if the button is accessible, nothing really. But doing so demands <a href="https://www.marcozehe.de/2013/04/24/easy-aria-tip-6-making-clickables-accessible/">extra work</a> that nobody is up for, besides that fact that <a href="https://www.nczonline.net/blog/2013/01/29/you-cant-create-a-button/">you canā€™t actually create a button</a>.</p> +</div> +<div class="footnote-definition" id="4"><sup class="footnote-definition-label">4</sup> +<p>Technologies may even process <code>&lt;span class="tel"&gt;123-456-7890&lt;/span&gt;</code> as a telephone, and allow for automatic dialling of it. See <a href="https://en.wikipedia.org/wiki/Microformat">microformat</a> for more information.</p> +</div> +<div class="footnote-definition" id="5"><sup class="footnote-definition-label">5</sup> +<p>Why not, right? After all, <code>article</code>s are for independent pieces of content, e.g., an user-submitted comment or a forum post. (<a href="https://www.w3.org/TR/html5/sections.html#the-article-element">Source</a>)</p> +</div> + + + + + Tchau + 2017-05-13T16:12:00+00:00 + 2017-05-13T16:12:00+00:00 + + + + + Unknown + + + + + + /blog/tchau/ + + <p class="summary">de ViamĆ£o, Brasil para Berlim, Alemanha. šŸ‡©šŸ‡Ŗ</p> +<blockquote class="epigraph -default-color"> +<p>ā€“Ā <em>Tu tem que ver o que Ć© pra ti, sabe? Se tu ficar aĆ­, tu provavelmente vai ficar nessa mesma por bastante tempo. Ɖ isso que tu quer?</em></p> +<p>ā€“ <em>NĆ£o, meu sonho sempre foi morar fora, do paĆ­s.</em></p> +<p>ā€“ <strong>O meu tambĆ©m Ć©. Esse Ć© o meu foco, pra sempre. Eu nunca tirei isso da mente.</strong></p> +</blockquote> +<p>A memĆ³ria parece distante agora, mas nĆ£o faz muito tempo que eu tive essa conversa. 30 de MarƧo de 2016. JĆ” faz um pouco mais de um ano. FalĆ”vamos de indecisƵes, insatisfaƧƵes e mudanƧas, quando sonhos vieram Ć  tona.</p> +<p><strong>Sonhos.</strong> Pessoalmente, penso neles como desejos fixos que habitam a nossa consciĆŖncia junto a outros desejos, mais efĆŖmeros, e que, assim que vocĆŖ os deixa de lado (nem que seja um pouco), inconvenientemente voltam a te atormentar; lembrar que eles ainda estĆ£o lĆ” e nĆ£o sĆ£o como os outros desejos.</p> +<hr /> +<blockquote> +<p>Esse Ć© o meu foco, pra sempre. Eu nunca tirei isso da mente.</p> +</blockquote> +<p>Palavras minhas. Confesso, me assustam. Ou melhor, me assustavam. O que me assusta mais agora Ć© o fato de eu ter lido isto em menos de um ano depois:</p> +<blockquote> +<p>Iā€™m personally very happy to say that after everything weā€™ve heard and seen, we think youā€™re a great match for us and would love for you to join our team here in Berlin.</p> +</blockquote> +<p><em>([ā€¦] Pessoalmente, estou muito feliz de dizer que, depois de tudo que nĆ³s ouvimos e vimos, achamos que vocĆŖ tem tudo a ver com a gente e gostarĆ­amos que se juntasse ao nosso time aqui em Berlim!)</em></p> +<p>O que seria para sempre o meu foco, o desejo que eu descorri por 30 linhas no meu LG R510 em uma carta de maio de 2012, aquilo que eu nunca havia tirado da mente, naquele momento surgia como uma oportunidade. Eu topei.</p> +<p>Foram vĆ”rios passos antes disso, e eu lembro de estar ansiosa antes de cada um deles. Encontrei pessoas maravilhosas durante o caminho, com um coraĆ§Ć£o tĆ£o grande como o meu. Tanto na vida quanto nessa entrevista em particular.</p> +<p>Nas entrevistas, o processo simplesmente fluiu. Penso e gosto de pensar que Ć© o que acontece quando os aspectos tĆ©cnicos sĆ£o vistos como meros meios necessĆ”rios para aquilo que realmente importa: criar.</p> +<p>Desde aquele momento atĆ© hoje, o dia do meu voo, o tempo pareceu nunca passar em alguns momentos, e, em outros, passar rĆ”pido demais. Mesmo com a percepĆ§Ć£o confusa do tempo, tenho certeza de que poder enviar a mensagem abaixo Ć© algo que eu nĆ£o imaginava para tĆ£o cedo.</p> +<p class="note"> +<p><em>Just got the call! [ā€¦] Thatā€™s an important moment of my life for sure. Iā€™m just, you know, happy. Thank you for this.</em></p> +</p> +<p><em>The call</em>. A ligaĆ§Ć£o se referia a do Consulado Geral da Alemanha de Porto Alegre que recebi no dia 8 de maio, dizendo o que esperei 2 semanas (ou toda a minha vida?) para ouvir. <strong>O meu visto estava aprovado.</strong> Ali estava, sem dĆŗvidas, um momento importante da minha vida.</p> +<p>Do resto do telefonema, confesso, nĆ£o lembro muito. Minha maior memĆ³ria desses instantes foi a de andar com o coraĆ§Ć£o cheio atĆ© o centro de Porto Alegre como se fosse a Ćŗltima vez. E foi, pelo menos por um bom tempo.</p> +<hr /> +<p>Um sonho pode, afinal, terminar de 2 maneiras: sendo abandonado ou realizado.</p> +<p>Meu caso Ć© o segundo, e, sinceramente, nĆ£o estĆ” fĆ”cil acreditar. Se vocĆŖ me disser que a partir de hoje eu jĆ” nĆ£o moro mais onde cresci, que meu voo hoje Ć© sĆ³ de ida, essa informaĆ§Ć£o serĆ” processada de forma que ela nĆ£o faƧa sentido na minha realidade. Eu nĆ£o vou acreditar.</p> +<p>Por outro lado, nesse momento da minha vida em que a gratidĆ£o transcende o mĆ©rito, acredito em vĆ”rias outras coisas. A principal Ć© que sou o resultado do fenĆ“meno que acontece quando a oportunidade encontra o anseio: alguĆ©m, no passado, acreditou em mim; alguĆ©m, no presente, acredita em mim. E eu nĆ£o as deixei decepcionar.</p> +<hr /> +<p>Hoje estou voando para Berlim, a capital da Alemanha, para fazer o que amo na <a href="http://hellofresh.com">HelloFresh</a>, que me ajudou em todo o processo. Sou grata por isso, por tudo.</p> +<p>Quanto Ć  realidade, nĆ£o Ć© que eu nĆ£o tenha medo. Eu tenho. Eu tive medo em todas as vezes que ousei. Desde o primeiro emprego que fui atrĆ”s no Brasil (no tĆ©dio do meu Ensino MĆ©dio), dos projetos alĆ©m do meu conhecimento, atĆ© o meu primeiro emprego fora do Brasilā€¦ eu tive medo em todos eles.</p> +<p>Eu sĆ³ jamais deixaria o sonho terminar do outro jeito, entĆ£o eu topei tudo mesmo assim.</p> + + + + + Choose Life šŸ‡©šŸ‡Ŗ + 2017-05-12T19:15:00+00:00 + 2017-05-12T19:15:00+00:00 + + + + + Unknown + + + + + + /blog/choose-life-in-berlin/ + + <p>Choose life. Choose a job. Choose a career. Choose relocation. Choose giving life a <em>fresh</em><sup class="footnote-reference"><a href="#1">1</a></sup> beginning. Choose an one-way flight ticket. Choose fitting your entire life in a 23 kg suitcase. Choose getting rid of all your crap. Choose a higher Human Development Index. Choose being thousands of kilometers far away. Choose devastating your loved ones. Choose different bureaucracies you still donā€™t understand. Choose calling another place home. Choose not fitting in <em>(you never did anyway!)</em>. Choose saying goodbye to places, food and friends, then choose new places, food, and friends. Choose memories. Choose developing new tastes. Choose being forced to develop social skills. Choose ignorance. Choose mundane and boring activities as exciting adventures. Choose not speaking your mother language. Choose limited self-expression. Choose missing the food from your country, and especially your mumā€™s. Choose letting part of your heart be elsewhere. Choose adapting 24/7. Choose wondering what the fuck you are doing. And choose getting the answer as soon as you go outside. Choose not understanding jokes from natives. Choose recognising you can do anything, anywhere. Choose not knowing if you should. Choose the bittersweet feeling of moving abroad. Choose to be afraid. Choose your future. Choose life.</p> +<p>But why wouldnā€™t I want to do a thing like that?</p> +<p>I chose to choose life. And the reasons? There are no reasons. Who needs reasons when youā€™ve got Berlin?<sup class="footnote-reference"><a href="#2">2</a></sup></p> +<div class="footnote-definition" id="1"><sup class="footnote-definition-label">1</sup> +<p>See <a href="https://hellofresh.com">HelloFresh</a>, which helped me relocating to Berlin.</p> +</div> +<div class="footnote-definition" id="2"><sup class="footnote-definition-label">2</sup> +<p>The entire essay is inspired by Mark Rentonā€™s ā€œChoose Lifeā€ speech from <a href="http://www.imdb.com/title/tt0117951">Trainspotting</a>, a movie that makes me think a lot about life choices.</p> +</div> + + + + + A Minimal Workspace on macOS + 2017-05-04T19:45:57+00:00 + 2017-05-04T19:45:57+00:00 + + + + + Unknown + + + + + + /blog/a-minimal-workspace-on-macos/ + + <p>Ask me for a screenshot of my desktop and all you get is a wallpaper ā€“ if Iā€™m using any. Everything else is hidden, unless actually requested by me.</p> +<p>Thatā€™s the way I work on macOS. The minimal way.</p> +<figure class="text-center"><video class="aligncenter" style="padding: 0; width: 100%;" autoplay="autoplay" loop="loop"><source type="video/mp4" src="../../media/2017/macos_desktop.mp4"></video> +<figcaption>My macOS desktop. This + Spotlight = life. šŸ˜Ž</figcaption></figure> +<p>In my workspace, there are no desktop items, app icons, time clock, battery percentage, transition delays, distracting animations, dashboards or context menus.</p> +<p>Too much information makes it easy for me to get stimulated and then distracted. So I like it minimal.</p> +<h2 id="recipe-for-the-minimal-ok-hand">Recipe for the minimal šŸ‘Œ</h2> +<p><strong>Get rid of everything you can</strong>. Hide. Disable. Assume everything is useless, not useful. <em>(I actually use this approach for life.)</em></p> +<p>Youā€™ll get frustrated sometimes, because there are simple things you want so bad to get rid of but then found out itā€™s impossible unless you hack things. SRLSY GOTTA LOVE APPLE šŸ˜šŸ˜šŸ˜</p> +<p>Well, letā€™s begin! Follow the steps below and type the commands in a <strong>terminal</strong>. If youā€™re not familiar with a terminal, Iā€™m pretty sure itā€™s possible to find those settings in ā€œSystem Preferencesā€ as well.</p> +<p><em>(ā€¦But I highly recommend you to open a terminal and start typing around because SRSLY USING A TERMINAL IS LIKE KNOWLEDGE AND POWER 4 UR ENTIRE LIFE!!!!!!!!)</em></p> +<h3 id="hide-your-desktop">Hide your desktop</h3> +<p>Itā€™s easier to live without than to live with it. Disable it and it wonā€™t be something you have to clean up anymore!</p> +<pre data-lang="bash" style="background-color:#282a36;color:#f8f8f2;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#50fa7b;">defaults</span><span> write com.apple.finder CreateDesktop</span><span style="font-style:italic;color:#ffb86c;"> -bool</span><span> false +</span></code></pre> +<h3 id="hide-your-dock">Hide your dock</h3> +<p>Itā€™ll be only shown when you hover it.</p> +<pre data-lang="bash" style="background-color:#282a36;color:#f8f8f2;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#50fa7b;">defaults</span><span> write com.apple.dock autohide</span><span style="font-style:italic;color:#ffb86c;"> -bool</span><span> true +</span></code></pre> +<p>Other cool things you can do too to keep your dock clean are:</p> +<pre data-lang="bash" style="background-color:#282a36;color:#f8f8f2;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#6272a4;"># Minimize windows into their application&#39;s icon +</span><span style="color:#50fa7b;">defaults</span><span> write com.apple.dock minimize-to-application</span><span style="font-style:italic;color:#ffb86c;"> -bool</span><span> true +</span><span> +</span><span style="color:#6272a4;"># Wipe all (default) app icons from the Dock +</span><span style="color:#50fa7b;">defaults</span><span> write com.apple.dock persistent-apps</span><span style="font-style:italic;color:#ffb86c;"> -array +</span></code></pre> +<p>Because I initialise apps from Spotlight, I really donā€™t mind not having any app in my dock. Sometimes I ask myself why do I have a dock at all. šŸ¤”</p> +<p>Andā€¦ Launchpad. WHY?????? šŸ˜­</p> +<h3 id="hide-your-menu-bar">Hide your menu bar</h3> +<p>Itā€™ll be only shown when you hover it.</p> +<pre data-lang="bash" style="background-color:#282a36;color:#f8f8f2;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#50fa7b;">defaults</span><span> write NSGlobalDomain _HIHideMenuBar</span><span style="font-style:italic;color:#ffb86c;"> -bool</span><span> true +</span></code></pre> +<p class="note">I really like this one, but if you feel it's too radical for you, try hiding only menu bar icons with <a href="(http://matthewpalmer.net/vanilla/">Vanilla</a> (recommended) or <a href="https://www.macbartender.com">Bartender</a>.</p> +<h3 id="disable-dashboard">Disable dashboard</h3> +<p>Why does it even exist? šŸ˜’</p> +<pre data-lang="bash" style="background-color:#282a36;color:#f8f8f2;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#6272a4;"># Disable Dashboard +</span><span style="color:#50fa7b;">defaults</span><span> write com.apple.dashboard mcx-disabled</span><span style="font-style:italic;color:#ffb86c;"> -bool</span><span> true +</span><span> +</span><span style="color:#6272a4;"># Don&#39;t show Dashboard as a Space +</span><span style="color:#50fa7b;">defaults</span><span> write com.apple.dock dashboard-in-overlay</span><span style="font-style:italic;color:#ffb86c;"> -bool</span><span> true +</span></code></pre> +<h3 id="disable-and-or-speed-up-animations">Disable and/or speed up animations</h3> +<p>Saving some time because I donā€™t think those really add anything to my user experience on macOS.</p> +<pre data-lang="bash" style="background-color:#282a36;color:#f8f8f2;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#6272a4;"># Disable window animations and Get Info animations +</span><span style="color:#50fa7b;">defaults</span><span> write com.apple.finder DisableAllAnimations</span><span style="font-style:italic;color:#ffb86c;"> -bool</span><span> true +</span><span> +</span><span style="color:#6272a4;"># Remove the auto-hiding Dock delay +</span><span style="color:#50fa7b;">defaults</span><span> write com.apple.dock autohide-delay</span><span style="font-style:italic;color:#ffb86c;"> -float</span><span> 0 +</span><span> +</span><span style="color:#6272a4;"># Remove the animation when hiding/showing the Dock +</span><span style="color:#50fa7b;">defaults</span><span> write com.apple.dock autohide-time-modifier</span><span style="font-style:italic;color:#ffb86c;"> -float</span><span> 0 +</span><span> +</span><span style="color:#6272a4;"># Don&#39;t animate opening applications from the Dock +</span><span style="color:#50fa7b;">defaults</span><span> write com.apple.dock launchanim</span><span style="font-style:italic;color:#ffb86c;"> -bool</span><span> false +</span><span> +</span><span style="color:#6272a4;"># Speed up Mission Control animations +</span><span style="color:#50fa7b;">defaults</span><span> write com.apple.dock expose-animation-duration</span><span style="font-style:italic;color:#ffb86c;"> -float</span><span> 0.1 +</span></code></pre> +<p>Finally, restart system stuff:</p> +<pre data-lang="bash" style="background-color:#282a36;color:#f8f8f2;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#50fa7b;">killall</span><span> Finder</span><span style="color:#ff79c6;">; </span><span style="color:#50fa7b;">killall</span><span> Dock</span><span style="color:#ff79c6;">; </span><span style="color:#50fa7b;">killall</span><span> SystemUIServer +</span></code></pre> +<p>And thatā€™s it! šŸŽ‰ Life-changing commands for sure. Now just donā€™t forget cleaning your actual desk too.</p> +<p>For more on the way I work, <a href="http://github.com/diessica/dotfiles">my dotfiles</a> are worth-checking!</p> +<p class="note">Sorry for using too many emojis. Just shipped this feature here on my blog and I can't help myself! šŸ˜¬</p> + + + + + I Travelled to Photographs + 2017-04-19T10:13:00+00:00 + 2017-04-19T10:13:00+00:00 + + + + + Unknown + + + + + + /blog/archive/i-travelled-to-photographs/ + + <p>February was ending.</p> +<p>Usually, such thing would mean regular summer days. However, it wasnā€™t summer or even a regular day ā€“ this was something else.</p> +<p>February 25th was winter. In that cold afternoon, I ended up into a place Iā€™ll never forget: photographs from my phoneā€™s gallery.</p> +<hr /> +<p>My steps were slow.</p> +<p>Red bricks erected the walls of houses built on top of an equally red-bricked avenue.</p> +<p>The windows of the houses were made of a wood strategically white-colored to match the brickā€™s white grouts. With such detail, it was pretty easy to forgive the toughness those bricks carried.</p> +<p>Houses ended themselves in grey roofing shingles. The roofs were all hipped. <em>Houses with hip roofs, gotta love them!</em>, I thought to myself. (Imagine the ā€œVā€ letter upside down on top of a square ā€“ thatā€™s a house with a hip roof.)</p> +<p>Showing a winter that was already leaving, dark trees with dry twigs were in contrast against a white sky ā€“ the whitest Iā€™d ever seen in my life. <em>Damn!</em> The whole picture looked like a painting, while the white sky worked as the canvas board on which all that was drawn.</p> +<p>I remember walking and trying to get everything I could, until a freezing wind blew abruptly into my face. It was February, though. From where I come, February meant summer, not freezing winds. Why was February that cold?</p> +<p>In an attempt to clear things up, I told myself what I believed that was true: <em>Youā€™re just looking at photographs from your phoneā€™s gallery. Thereā€™s no need to get this excited!</em> Ok. So I was home and looking at the ā€œWallpapersā€ album I had on my phone.</p> +<p>A moment later, I found myself facing a large and wonderful canal, in which someone was solitary paddling a boat to somewhere. <em>What a view.</em></p> +<p>Then, self-awareness hit me again: <em>Wait. Isnā€™t my smartphone in my pocket?</em> How could I be possibly looking at photographs on it?</p> +<p>I immediately started touching my entire body in a desperate hunt for my phone. And there it was. In my fucking coat. It wasnā€™t really possible for me to see photographs on my phone ā€“ that shit was in my pocket all the time.</p> +<p>Besides, why would I be wearing a coat on summer? And, if I was already wearing a coat, how could I be still cold? How inappropriate were my clothes for that weather? Only a person who sensed that winter solely with the eyes would underestimate its coldness like that!</p> +<p>The boat was really leaving through the canal. The view wasnā€™t photographs. What was all that, then?</p> +<p>I got my phone from my pocket, turned off airplane mode, and opened the Maps app. <em>Come on, where am I?</em></p> +<p>ā€œNoorder Amstelkanaalā€, I read. <em>Wow.</em></p> +<p>All of a sudden, February 25th was a cold winter in Amsterdam. My very first one.</p> +<figure class="text-center"><picture><source media="(min-width: 63.125rem)" srcset="../../media/2017/noorder-amstelkanaal.jpg"><source media="(min-width: 45rem)" srcset="../../media/2017/noorder-amstelkanaal.jpg 2x, ../../media/2017/noorder-amstelkanaal_medium.jpg 1x" ><source media="(max-width: 45rem)" srcset="../../media/2017/noorder-amstelkanaal.jpg 2x, ../../media/2017/noorder-amstelkanaal_medium.jpg 1x"><img srcset="../../media/2017/noorder-amstelkanaal.jpg 2x, ../../media/2017/noorder-amstelkanaal_small.jpg 1x" alt="Noorder Amstelkanaal"></picture> +<figcaption>Someone solitary paddling a boat to somewhere in Noorder Amstelkanaal, an Amsterdam's canal.</figcaption></figure> +<p>I guess I travelled to photographs.</p> + + + + + Catalysis + 2017-04-13T11:27:00+00:00 + 2017-04-13T11:27:00+00:00 + + + + + Unknown + + + + + + /blog/catalysis/ + + <p>As a High School student, I remember always finding Chemistry something between the boring and intriguing. Still, it isnā€™t hard to find myself wondering about the science concepts Iā€™ve learned at that time.</p> +<p>Lately, Iā€™ve been particularly thinking about <em>catalysis</em>.</p> +<hr /> +<p>In Chemistry, catalysis is the acceleration of a reaction due to the participation of a substanceĀ ā€“ the ā€œcatalystā€.</p> +<p>The way a catalyst induces a reaction to happen faster is intriguing. Curiously, it neither gives the reaction more energy nor change its environmental conditions. Catalysts have an even better strategy: they <strong>lower the amount of energy required</strong> for the reaction to take place.</p> +<figure class="text-center"><picture><img src="../../media/2017/catalysis-diagram.png" srcset="../../media/2017/catalysis-diagram_2x.png 2x" alt="Diagrama representando conhecimento como ele realmente Ć©"></picture> +<figcaption>Uncatalyzed reaction (solid) vs. catalyzed reaction (dashed). The highest point is the energy required for the reaction to happen. </figcaption></figure> +<p>In a catalysed reaction, then, the same product is obtained for less energy. Bringing this concept to our lives is quite thought-provoking.</p> +<p>Sometimes it isnā€™t possible for us to achieve something because it demands <em>more</em> time or energy than what we currently have. To deal with this, we then try looking for them in our livesĀ ā€“ which mostly means depriving yourself of things.</p> +<p>However, matter of fact is that optimising isnā€™t always about getting rid of things in your life. If we think of catalysis, we can manage it differently.</p> +<p>What if the problem werenā€™t the lack of energy or time, but that weā€™re in need of <em>too much</em> of them in order to get things done? <strong>Having a catalyst would totally figure it out</strong>. Without something that pushes us forward, weā€™ll always require more energy for the product we want to get.</p> +<p>At this point, you may think your catalyst is your motivation. Motivation is out of our control though ā€“ which makes it a goal, not a source. Itā€™s also too ephemeral, and a catalyst mustnā€™t ever be consumed by an unique reaction, just like in Chemistry. We canā€™t count on being motivated!</p> +<p>So it goes more like what <em>habitual and practical</em> things in life would give you productivity for less. Is it everyday meditation? A partner by your side? Self-confidence? Inspiring weekends without thinking of work at all? Eating healthy? Going out for a walk every day?</p> +<p>You have to mind what pushes your forward. Catalysts themselves cannot make a reaction happen that wouldnā€™t happen on its own, but they sure make it occur under less extreme conditions. Itā€™s an improvement when youā€™re already motivated.</p> +<p>So, whatā€™s your catalyst?</p> + + + + + Don't Blame it on React or Redux + 2017-03-18T13:49:00+00:00 + 2017-03-18T13:49:00+00:00 + + + + + Unknown + + + + + + /blog/dont-blame-it-on-react-or-redux/ + + <p>What most people donā€™t know when they first get into Redux is that, just like React, Redux itself is meant to be <strong>simple</strong>. And as seen that simplicity is a goal, both React and Redux <em>wonā€™t</em> and <em>donā€™t want</em> to tell you how to solve everything.</p> +<p>They wonā€™t tell you how to deal with side effects, or what HTTP request library you should use. Thatā€™s completely delegated to the JavaScript ecosystem.</p> +<p><strong>React and Redux alone donā€™t do much for really complex web applications.</strong></p> +<p>React indirectly delegates state management problems to solutions like Flux. On the other hand, Redux, for instance, delegates dealing with async stuff or even the <em>too-much-boilerplate</em> problem that people complain.</p> +<p>But <strong>what motivates React and Redux to be that way?</strong> Some reasons I can think of are:</p> +<ul> +<li>Both libraries are highly focused on their principles, not the built-in stuff. The efficiency of them is on the <em>why</em> and <em>how</em>, not the <em>what</em>.</li> +<li>They aim to be a great fit for both simple <em>and</em> large applications, so the ā€œplug-in-playā€ approach is followed. (A framework wouldnā€™t ever do everything a programmer needs anywayā€¦)</li> +<li>Diversity of solutions. Because React and Redux are more like ā€œplug-in-playā€, the ā€œpluginsā€ (tools, libraries, middlewares) will evolve by themselves. For instance: <a href="https://github.com/mzabriskie/axios">axios</a>, a HTTP request library, will evolve in parallel to Redux itselfĀ ā€“ which certainly make things move forward faster!</li> +</ul> +<hr /> +<p>If your applicationā€™s state is messy, donā€™t blame it on React. If you find yourself writing too much boilerplate, donā€™t blame it on Redux. <strong>React and Redux donā€™t really do much</strong>, but this is by design.</p> +<p>React is awesome not just because it makes it possible to turn a large and complex application into simple components.</p> +<p>Redux is awesome not just because it makes it effortless to deal with and share state throughout an application.</p> +<p>Theyā€™re also awesome because of <strong>their great and diverse ecosystem</strong>. So, when you buy into React or Redux, itā€™s better for you to buy into their ecosystem too.</p> + + + + + var that = this? Nah. + 2017-03-15T09:00:00+00:00 + 2017-03-15T09:00:00+00:00 + + + + + Unknown + + + + + + /blog/var-that-this-nah/ + + <p>Tried JavaScript for some minutes? You probably already wrote the following.</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="font-style:italic;color:#8be9fd;">var </span><span style="color:#ffffff;">that </span><span style="color:#ff79c6;">= </span><span style="color:#bd93f9;">this</span><span>; +</span></code></pre> +<p>(Or one of its variants, such as <code>var self = this</code>.)</p> +<p>Thatā€™s a pretty common pattern when you found yourself in a situation where:</p> +<ol> +<li>you have a function nested inside of an objectā€™s method, and</li> +<li>you want to access the objectā€™s properties, but</li> +<li>JavaScriptā€™s <code>this</code> is bound in an unexpected way.</li> +</ol> +<hr /> +<p>Workarounding unexpected callback scope is one of the main situations where developers write <code>var self = this</code>.</p> +<p>Letā€™s assume a piece of code with a callback function.</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="font-style:italic;color:#8be9fd;">function </span><span style="color:#50fa7b;">Requester</span><span>(</span><span style="font-style:italic;color:#ffb86c;">data</span><span>, </span><span style="font-style:italic;color:#ffb86c;">req</span><span>) { +</span><span> </span><span style="color:#bd93f9;">this</span><span style="color:#ff79c6;">.</span><span>data </span><span style="color:#ff79c6;">= </span><span style="color:#ffffff;">data</span><span>; +</span><span> +</span><span> </span><span style="color:#ffffff;">req</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">done</span><span>(</span><span style="font-style:italic;color:#8be9fd;">function </span><span>() { +</span><span> </span><span style="font-style:italic;color:#66d9ef;">console</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">log</span><span>(</span><span style="color:#bd93f9;">this</span><span style="color:#ff79c6;">.</span><span>data); </span><span style="color:#6272a4;">// undefined +</span><span> }); +</span><span>} +</span></code></pre> +<p>Youā€™d expect <code>this.data</code> to be the <code>data</code> argument. Yet, JavaScript tells you that it is actually <code>undefined</code>.</p> +<p>So, because Stack Overflow says so, you do the following:</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="font-style:italic;color:#8be9fd;">function </span><span style="color:#50fa7b;">Requester</span><span>(</span><span style="font-style:italic;color:#ffb86c;">data</span><span>, </span><span style="font-style:italic;color:#ffb86c;">req</span><span>) { +</span><span> </span><span style="color:#bd93f9;">this</span><span style="color:#ff79c6;">.</span><span>data </span><span style="color:#ff79c6;">= </span><span style="color:#ffffff;">data</span><span>; +</span><span> </span><span style="font-style:italic;color:#8be9fd;">var </span><span style="color:#ffffff;">self </span><span style="color:#ff79c6;">= </span><span style="color:#bd93f9;">this</span><span>; </span><span style="color:#6272a4;">// NOOOOOoOooo +</span><span> +</span><span> </span><span style="color:#ffffff;">req</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">done</span><span>(</span><span style="font-style:italic;color:#8be9fd;">function </span><span>() { +</span><span> </span><span style="font-style:italic;color:#66d9ef;">console</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">log</span><span>(</span><span style="color:#ffffff;">self</span><span style="color:#ff79c6;">.</span><span>data); +</span><span> }); +</span><span>} +</span></code></pre> +<p>And never stops doing it in your life.</p> +<p>Still do it? Iā€™m flattered to tell you that <strong>you donā€™t need that extra variable anymore</strong>.</p> +<h2 id="arrow-functions">Arrow functions</h2> +<p>Go with <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions">arrow functions</a> instead. Besides having a shorter syntax, arrow functions bind to the parent scope by default.</p> +<p>The scope that was firstly intuitive to you will work as expected now.</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="font-style:italic;color:#8be9fd;">function </span><span style="color:#50fa7b;">Requester</span><span>(</span><span style="font-style:italic;color:#ffb86c;">data</span><span>, </span><span style="font-style:italic;color:#ffb86c;">req</span><span>) { +</span><span> </span><span style="color:#bd93f9;">this</span><span style="color:#ff79c6;">.</span><span>data </span><span style="color:#ff79c6;">= </span><span style="color:#ffffff;">data</span><span>; +</span><span> +</span><span> </span><span style="color:#ffffff;">req</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">done</span><span>(() </span><span style="font-style:italic;color:#8be9fd;">=&gt; </span><span>{ +</span><span> </span><span style="font-style:italic;color:#66d9ef;">console</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">log</span><span>(</span><span style="color:#bd93f9;">this</span><span style="color:#ff79c6;">.</span><span>data); </span><span style="color:#6272a4;">// intuitive as hell! +</span><span> }); +</span><span>} +</span></code></pre> +<p class="note">You can count on them most of the time, but they also have unexpected behaviour in more advanced cases. After all, you're dealing with the `this` keyword. So don't just go around refactoring all anonymous functions into arrow ones and expecting everything to work.</p> +<h2 id="you-may-also-bind">You may also <code>.bind()</code>!</h2> +<p>If for some reason (such as <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions#Browser_compatibility">no support for IE</a>) you canā€™t use them, check JavaScriptā€™s <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind"><code>bind</code></a>. Itā€™s not as awesome as arrow functions, but does the job.</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="font-style:italic;color:#8be9fd;">function </span><span style="color:#50fa7b;">Requester</span><span>(</span><span style="font-style:italic;color:#ffb86c;">data</span><span>, </span><span style="font-style:italic;color:#ffb86c;">req</span><span>) { +</span><span> </span><span style="color:#bd93f9;">this</span><span style="color:#ff79c6;">.</span><span>data </span><span style="color:#ff79c6;">= </span><span style="color:#ffffff;">data</span><span>; +</span><span> +</span><span> </span><span style="color:#ffffff;">req</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">done</span><span>( +</span><span> </span><span style="font-style:italic;color:#8be9fd;">function </span><span>() { +</span><span> </span><span style="font-style:italic;color:#66d9ef;">console</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">log</span><span>(</span><span style="color:#bd93f9;">this</span><span style="color:#ff79c6;">.</span><span>data); +</span><span> }</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">bind</span><span>(</span><span style="color:#bd93f9;">this</span><span>) +</span><span> ); +</span><span>} +</span></code></pre> + + + + + Shared Variables Between JavaScript and CSS + 2017-01-15T15:00:00+00:00 + 2017-01-15T15:00:00+00:00 + + + + + Unknown + + + + + + /blog/shared-variables-between-javascript-and-css/ + + <p>Because it assures consistency throughout the project and avoids <a href="https://en.m.wikipedia.org/wiki/Magic_number_(programming)">magic numbers</a>, sharing variables between JavaScript and CSS code may help you to keep your project codebase tidy and easier to reason about.</p> +<p class="note"> +<p>For this article, when talking about CSS, the word ā€œvariableā€ may mean <a href="https://www.w3.org/TR/css-variables/">custom property</a> or <a href="https://www.w3.org/TR/2016/WD-mediaqueries-4-20160126/#custom-mq">custom media query</a>.</p> +</p> +<h2 id="getting-started">Getting Started</h2> +<p>First, create a <strong>object</strong> containing your variables and export it.</p> +<p>My JS file containing the object will be called <code>variables.js</code>.</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="color:#ff79c6;">export default </span><span>{ +</span><span> mainColor: </span><span style="color:#f1fa8c;">&quot;#000&quot;</span><span>, +</span><span> secondaryColor: </span><span style="color:#f1fa8c;">&quot;#fff000&quot;</span><span>, +</span><span> fullHeight: </span><span style="color:#f1fa8c;">&quot;100vh&quot;</span><span>, +</span><span>}; +</span></code></pre> +<p>No magic is needed to use those variables in your JS filesĀ ā€“ just <code>import</code> them when you need it. But in order to communicate those variables to your CSS files and use them with <code>var()</code>, some magic is needed.</p> +<p>For this, I will be using <a href="http://cssnext.io/">cssnext</a>, a PostCSS plugin, and injecting that object into our stylesheets as <strong>custom properties</strong>.</p> +<p>Webpack example:</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="color:#ff79c6;">import </span><span style="color:#ffffff;">cssNext </span><span style="color:#ff79c6;">from </span><span style="color:#f1fa8c;">&quot;postcss-cssnext&quot;</span><span>; +</span><span style="color:#ff79c6;">import </span><span style="color:#ffffff;">myVars </span><span style="color:#ff79c6;">from </span><span style="color:#f1fa8c;">&quot;./variables&quot;</span><span>; +</span><span> +</span><span style="font-style:italic;color:#66d9ef;">module</span><span style="color:#ff79c6;">.</span><span style="font-style:italic;color:#66d9ef;">exports </span><span style="color:#ff79c6;">= </span><span>{ +</span><span> </span><span style="color:#6272a4;">// Entry, loaders, plugins... +</span><span> +</span><span> </span><span style="color:#50fa7b;">postcss</span><span>: () </span><span style="font-style:italic;color:#8be9fd;">=&gt; </span><span>[ +</span><span> </span><span style="color:#50fa7b;">cssNext</span><span>({ +</span><span> features: { +</span><span> customProperties: { variables: </span><span style="color:#ffffff;">myVars </span><span>}, +</span><span> }, +</span><span> }), +</span><span> ], +</span><span>}; +</span></code></pre> +<p class="note"> +<p>Since Iā€™m just using <a href="https://github.com/MoOx/postcss-cssnext">postcss-cssnext</a> API, itā€™s also possible to do it with the build tool of your choice. Check <a href="http://cssnext.io/usage/#features">docs on passing options to cssnext features</a>.</p> +</p> +<h2 id="getting-real-world-with-breakpoints">Getting Real-world with Breakpoints</h2> +<p>Sharing breakpoints between JavaScript and your stylesheets is a great real-world example.</p> +<p>Itā€™s time for <code>variables.js</code> to grow then!</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="color:#ff79c6;">export </span><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">properties </span><span style="color:#ff79c6;">= </span><span>{ +</span><span> mainColor: </span><span style="color:#f1fa8c;">&quot;#000&quot;</span><span>, +</span><span> secondaryColor: </span><span style="color:#f1fa8c;">&quot;#fff000&quot;</span><span>, +</span><span> fullHeight: </span><span style="color:#f1fa8c;">&quot;100vh&quot;</span><span>, +</span><span>}; +</span><span> +</span><span style="color:#ff79c6;">export </span><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">mediaQueries </span><span style="color:#ff79c6;">= </span><span>{ +</span><span> secondaryColor: </span><span style="color:#f1fa8c;">&quot;#fff000&quot;</span><span>, +</span><span> desktop: </span><span style="color:#f1fa8c;">&quot;(min-width: 1024px)&quot;</span><span>, +</span><span> tablet: </span><span style="color:#f1fa8c;">&quot;(min-width: 768px)&quot;</span><span>, +</span><span> mobile: </span><span style="color:#f1fa8c;">&quot;(min-width: 320px)&quot;</span><span>, +</span><span>}; +</span></code></pre> +<p>Because itā€™s not possible to create a media query containing a custom property, we need to inject <code>mediaQueries</code> as <strong>custom media queries</strong>.</p> +<p>Letā€™s update the previous Webpack example in order to let cssnext to know about both custom media queries and properties.</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="color:#ff79c6;">import </span><span style="color:#ffffff;">cssNext </span><span style="color:#ff79c6;">from </span><span style="color:#f1fa8c;">&quot;postcss-cssnext&quot;</span><span>; +</span><span style="color:#ff79c6;">import </span><span>{ </span><span style="color:#ffffff;">properties</span><span>, </span><span style="color:#ffffff;">mediaQueries </span><span>} </span><span style="color:#ff79c6;">from </span><span style="color:#f1fa8c;">&quot;./variables&quot;</span><span>; +</span><span> +</span><span style="font-style:italic;color:#66d9ef;">module</span><span style="color:#ff79c6;">.</span><span style="font-style:italic;color:#66d9ef;">exports </span><span style="color:#ff79c6;">= </span><span>{ +</span><span> </span><span style="color:#6272a4;">// Entry, loaders, plugins... +</span><span> +</span><span> </span><span style="color:#50fa7b;">postcss</span><span>: () </span><span style="font-style:italic;color:#8be9fd;">=&gt; </span><span>[ +</span><span> </span><span style="color:#50fa7b;">cssNext</span><span>({ +</span><span> features: { +</span><span> customProperties: { variables: </span><span style="color:#ffffff;">properties </span><span>}, +</span><span> customMedia: { extensions: </span><span style="color:#ffffff;">mediaQueries </span><span>}, +</span><span> }, +</span><span> }), +</span><span> ], +</span><span>}; +</span></code></pre> +<p>Done! Some usage examples for CSS, JS and even React are provided below.</p> +<h3 id="usage">Usage</h3> +<h4 id="css-example">CSS Example</h4> +<p>Using custom properties and custom media queries according to settings from <code>variables.js</code> file.</p> +<pre data-lang="css" style="background-color:#282a36;color:#f8f8f2;" class="language-css "><code class="language-css" data-lang="css"><span style="color:#50fa7b;">.banner </span><span>{ +</span><span> </span><span style="font-style:italic;color:#66d9ef;">background</span><span>: </span><span style="color:#6be5fd;">red</span><span>; +</span><span> </span><span style="font-style:italic;color:#66d9ef;">height</span><span>: </span><span style="color:#8be9fd;">var</span><span>(</span><span style="font-style:italic;color:#66d9ef;">--fullHeight</span><span>); </span><span style="color:#6272a4;">/* Custom property */ +</span><span> +</span><span> @media (</span><span style="font-style:italic;color:#66d9ef;">--desktop</span><span>) { +</span><span> </span><span style="color:#6272a4;">/* Custom media query */ +</span><span> </span><span style="font-style:italic;color:#66d9ef;">width</span><span>: </span><span style="color:#bd93f9;">50</span><span style="color:#ff79c6;">%</span><span>; +</span><span> } +</span><span>} +</span></code></pre> +<h4 id="javascript-example">JavaScript example</h4> +<p class="note"> +<p>Example below uses <a href="http://wicky.nillia.ms/enquire.js/">enquire.js</a> library.</p> +</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="color:#ff79c6;">import </span><span style="color:#ffffff;">enquire </span><span style="color:#ff79c6;">from </span><span style="color:#f1fa8c;">&quot;enquire.js&quot;</span><span>; +</span><span style="color:#ff79c6;">import </span><span>{ </span><span style="color:#ffffff;">customMedia </span><span>} </span><span style="color:#ff79c6;">from </span><span style="color:#f1fa8c;">&quot;./variables&quot;</span><span>; +</span><span> +</span><span style="color:#ffffff;">enquire +</span><span> </span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">register</span><span>(</span><span style="color:#ffffff;">customMedia</span><span style="color:#ff79c6;">.</span><span style="color:#ffffff;">tablet</span><span>, () </span><span style="font-style:italic;color:#8be9fd;">=&gt; </span><span>{ +</span><span> </span><span style="font-style:italic;color:#66d9ef;">console</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">log</span><span>(</span><span style="color:#f1fa8c;">&quot;Matched tablet resolution&quot;</span><span>); +</span><span> }) +</span><span> </span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">register</span><span>(</span><span style="color:#ffffff;">customMedia</span><span style="color:#ff79c6;">.</span><span style="color:#ffffff;">mobile</span><span>, () </span><span style="font-style:italic;color:#8be9fd;">=&gt; </span><span>{ +</span><span> </span><span style="font-style:italic;color:#66d9ef;">console</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">log</span><span>(</span><span style="color:#f1fa8c;">&quot;Matched mobile resolution&quot;</span><span>); +</span><span> }); +</span></code></pre> +<h4 id="react-example">React example</h4> +<p>Rendering a component only on desktop resolutions.</p> +<p class="note"> +<p>Example below uses <a href="https://github.com/contra/react-responsive">react-responsive</a> library.</p> +</p> +<pre data-lang="tsx" style="background-color:#282a36;color:#f8f8f2;" class="language-tsx "><code class="language-tsx" data-lang="tsx"><span style="color:#ff79c6;">import </span><span style="color:#ffffff;">MediaQuery </span><span style="color:#ff79c6;">from </span><span style="color:#f1fa8c;">&quot;react-responsive&quot;</span><span>; +</span><span style="color:#ff79c6;">import </span><span>{ </span><span style="color:#ffffff;">customMedia </span><span>} </span><span style="color:#ff79c6;">from </span><span style="color:#f1fa8c;">&quot;./variables&quot;</span><span>; +</span><span> +</span><span style="font-style:italic;color:#8be9fd;">function </span><span style="color:#50fa7b;">DesktopOnlyComponent</span><span>() { +</span><span> </span><span style="color:#6272a4;">/* (min-width: 1024px), according to variables.js */ +</span><span> +</span><span> </span><span style="color:#ff79c6;">return </span><span>( +</span><span> &lt;</span><span style="font-style:italic;color:#66d9ef;">MediaQuery </span><span style="color:#50fa7b;">query</span><span style="color:#ff79c6;">={</span><span style="color:#ffffff;">customMedia</span><span style="color:#ff79c6;">.</span><span style="color:#ffffff;">desktop</span><span style="color:#ff79c6;">}</span><span>&gt; +</span><span> &lt;</span><span style="color:#ff79c6;">p</span><span>&gt;My desktop-only component!&lt;/</span><span style="color:#ff79c6;">p</span><span>&gt; +</span><span> &lt;/</span><span style="font-style:italic;color:#66d9ef;">MediaQuery</span><span>&gt; +</span><span> ); +</span><span>} +</span></code></pre> +<h2 id="final-words">Final Words</h2> +<p>A non-consistent front-end codebase is just messy.</p> +<p>I really use this technique on everyday work, and itā€™s a cheap way to significantly improve the quality of the front-end codebase.</p> +<p>So, donā€™t underestimate it! Besides breakpoints, there are infinite possibilities for this, such as project colors, layout dimensions and other shared stuff that can easily get out of hand while working on a large project.</p> + + + + + How to Exclude CSS, Images, Anything from Unit Tests + 2016-11-19T09:54:29+00:00 + 2016-11-19T09:54:29+00:00 + + + + + Unknown + + + + + + /blog/how-to-exclude-css-images-anything-from-unit-tests/ + + <div class="summary"> +<p>Your app needs all those <code>require</code>, but your unit tests may not.</p> +</div> +<p>When developing web applications, we deal with assets that our JavaScript tests donā€™t have to be aware of.</p> +<p>If using Webpack, which enables different imports in your JavaScript files, youā€™ve configured <a href="https://webpack.github.io/docs/loaders.html">loaders</a> that your test runner probably know nothing about. Therefore, that SVG image in your React component and the <code>import</code>ed CSS will both be parsed like JavaScript in your tests. A lot of confusing errors will be thrown, of course.</p> +<p>So letā€™s learn to exclude anything your unit tests, from styles (CSS, Sass), images (PNG, SVG), to other specific imports (like <a href="https://diessi.ca/blog/svg-images-as-react-components-with-webpack/">SVG images as React components</a>).</p> +<h2 id="hook-your-require-calls">Hook your <code>require()</code> calls</h2> +<p>By intercepting <code>require()</code> calls, you can make your testing framework ignore <strong>what you want</strong> to be ignored <strong>the way you want</strong> it to be ignored.</p> +<p>Itā€™s also useful in isomorphic setups.</p> +<h3 id="return-an-empty-module">Return an empty module</h3> +<p>It all comes to returning an empty module for unwanted imports. It looks like this:</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="font-style:italic;color:#66d9ef;">module</span><span style="color:#ff79c6;">.</span><span style="font-style:italic;color:#66d9ef;">exports </span><span style="color:#ff79c6;">= </span><span style="color:#f1fa8c;">&quot;&quot;</span><span>; +</span></code></pre> +<h3 id="jest">Jest</h3> +<p>For Jest, configure <a href="https://facebook.github.io/jest/docs/configuration.html#modulenamemapper-object-string-string">moduleNameMapper</a> to return the empty module for specific extensions. Example:</p> +<pre data-lang="json" style="background-color:#282a36;color:#f8f8f2;" class="language-json "><code class="language-json" data-lang="json"><span style="color:#eeeeee;">&quot;</span><span style="color:#f1fa8c;">jest</span><span style="color:#eeeeee;">&quot;</span><span>: { +</span><span> </span><span style="color:#eeeeee;">&quot;</span><span style="color:#f1fa8c;">moduleNameMapper</span><span style="color:#eeeeee;">&quot;</span><span>: { +</span><span> </span><span style="color:#eeeeee;">&quot;</span><span style="color:#ff79c6;">\\</span><span style="color:#f1fa8c;">.(css|jpg|png)$</span><span style="color:#eeeeee;">&quot;</span><span>: </span><span style="color:#eeeeee;">&quot;</span><span style="color:#f1fa8c;">&lt;rootDir&gt;/empty-module.js</span><span style="color:#eeeeee;">&quot; +</span><span> } +</span><span>} +</span></code></pre> +<h3 id="other-testing-frameworks">Other testing frameworks</h3> +<p><a href="https://www.npmjs.com/package/require-hacker">require-hacker</a> is an option for hooking <code>require()</code> calls.</p> +<p class="note"> +<p>You can also use built-in compilers (like moduleNameMapper in Jest or <a href="https://mochajs.org/#compilers">Mocha compilers</a>), or even only import <a href="https://github.com/bkonkle/ignore-styles">ignore-styles</a> into your testing framework (which is preconfigured).</p> +</p> +<p>Iā€™ll stick to require-hacker and custom configuration because thereā€™s more flexibility.</p> +<p>Get it from npm:</p> +<pre data-lang="sh" style="background-color:#282a36;color:#f8f8f2;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#50fa7b;">npm</span><span> install require-hacker</span><span style="font-style:italic;color:#ffb86c;"> --save-dev +</span></code></pre> +<h4 id="configure">Configure</h4> +<p>Create a JavaScript file and set custom handlers for specific extensions using require-hackerā€™s <a href="https://github.com/halt-hammerzeit/require-hacker#hookfile_extension-resolve">hook()</a> method.</p> +<p>Assuming you want to ignore CSS and PNG files, always return an empty module for them:</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="color:#ff79c6;">import </span><span style="color:#ffffff;">requireHacker </span><span style="color:#ff79c6;">from </span><span style="color:#f1fa8c;">&quot;require-hacker&quot;</span><span>; +</span><span style="color:#ffffff;">requireHacker</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">hook</span><span>(</span><span style="color:#f1fa8c;">&quot;png&quot;</span><span>, () </span><span style="font-style:italic;color:#8be9fd;">=&gt; </span><span style="color:#f1fa8c;">&#39;module.exports = &quot;&quot;&#39;</span><span>); +</span><span style="color:#ffffff;">requireHacker</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">hook</span><span>(</span><span style="color:#f1fa8c;">&quot;css&quot;</span><span>, () </span><span style="font-style:italic;color:#8be9fd;">=&gt; </span><span style="color:#f1fa8c;">&#39;module.exports = &quot;&quot;&#39;</span><span>); +</span></code></pre> +<p class="note"> +<p>Because youā€™re smart, youā€™ll store all extensions in a variable and <code>forEach</code> them, so thereā€™s no need to repeat yourself. <a href="https://gist.github.com/diessica/e6a6ea601d2b19cdcc6881197b6b5c8d">Example</a>.</p> +</p> +<h4 id="import-into-your-test-runner">Import into your test runner</h4> +<p>Let your favourite testing framework know about the <code>require</code> hacking! Some examples, assuming a <code>ignore-utils.js</code> file:</p> +<h5 id="mocha">Mocha</h5> +<p>Add to your <a href="https://mochajs.org/#mochaopts">mocha.opts</a>, or use the <code>--require</code> flag:</p> +<pre data-lang="sh" style="background-color:#282a36;color:#f8f8f2;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#50fa7b;">mocha</span><span style="font-style:italic;color:#ffb86c;"> --require</span><span> ./ignore-utils +</span></code></pre> +<h5 id="ava">ava</h5> +<p>Add to your <code>package.json</code>:</p> +<pre data-lang="json" style="background-color:#282a36;color:#f8f8f2;" class="language-json "><code class="language-json" data-lang="json"><span style="color:#eeeeee;">&quot;</span><span style="color:#f1fa8c;">ava</span><span style="color:#eeeeee;">&quot;</span><span>: { +</span><span> </span><span style="color:#eeeeee;">&quot;</span><span style="color:#f1fa8c;">require</span><span style="color:#eeeeee;">&quot;</span><span>: [ +</span><span> </span><span style="color:#eeeeee;">&quot;</span><span style="color:#f1fa8c;">./ignore-utils</span><span style="color:#eeeeee;">&quot; +</span><span> ] +</span><span>} +</span></code></pre> +<p>Now some files will be treated like shit in your JavaScript testsĀ ā€“ which is AWESOME!</p> +<h2 id="bonus-react-null-component">Bonus: React null component</h2> +<p>You donā€™t need to load that boring SVG icon of a house to test that critical feature in a React component, right?</p> +<p><em>Right.</em> In case youā€™re using <a href="https://github.com/sairion/svg-inline-loader">svg-inline-loader</a>, which transform your SVG files into React components, you cannot just return an empty module because your test case would be actually expecting a React component. Things will break. Annoying errors will be shown.</p> +<p>So, instead of returning an empty module for SVG files, return an empty React component. Letā€™s set a custom handler for that!</p> +<h3 id="configure-1">Configure</h3> +<p class="note"> +<p>This example uses require-hacker. For Jest, export a React null component and set it in <code>moduleNameMapper</code>.</p> +</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="color:#ff79c6;">import </span><span style="color:#ffffff;">requireHacker </span><span style="color:#ff79c6;">from </span><span style="color:#f1fa8c;">&quot;require-hacker&quot;</span><span>; +</span><span> +</span><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">reactNullComponent </span><span style="color:#ff79c6;">= </span><span style="color:#f1fa8c;">` +</span><span style="color:#f1fa8c;"> require(&#39;react&#39;).createClass({ +</span><span style="color:#f1fa8c;"> render() { +</span><span style="color:#f1fa8c;"> return null; +</span><span style="color:#f1fa8c;"> } +</span><span style="color:#f1fa8c;"> }) +</span><span style="color:#f1fa8c;">`</span><span>; +</span><span style="color:#ffffff;">requireHacker</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">hook</span><span>(</span><span style="color:#f1fa8c;">&quot;svg&quot;</span><span>, () </span><span style="font-style:italic;color:#8be9fd;">=&gt; </span><span style="color:#f1fa8c;">`module.exports = ${</span><span style="color:#ffffff;">reactNullComponent</span><span style="color:#f1fa8c;">}`</span><span>); +</span></code></pre> +<h2 id="conclusion">Conclusion</h2> +<p>Iā€™ve spent a lot of time figuring out how to make everything work, because:</p> +<ol> +<li>At the beginning, it was quite confusing to get what was clearly going on.</li> +<li>Thereā€™s a ton of options out there (Webpack null loaders; <a href="https://github.com/bkonkle/ignore-styles">ignore-styles</a>, which also provide custom handlers; <a href="https://github.com/morlay/babel-plugin-transform-require-ignore">babel-plugin-transform-require-ignore</a>ā€¦).</li> +<li>I didnā€™t want to handle all the ignored extensions the same say.</li> +</ol> +<p>Yeahā€¦ Sometimes our JavaScript unit tests just know too much.</p> + + + + + A Bit on Random Numbers in JavaScript + 2016-11-15T16:50:00+00:00 + 2016-11-15T16:50:00+00:00 + + + + + Unknown + + + + + + /blog/a-bit-on-random-numbers-in-javascript/ + + <p><code>Math.random()</code> is a JavaScript function that outputs a random number in the range <code>[0, 1)</code> (from 0 up to 1, but doesnā€™t include 1). Itā€™s the main source of randomness in JavaScript.</p> +<p>Although the output looks random, itā€™s actually not.</p> +<h2 id="behind-the-scenes">Behind the Scenes</h2> +<p><code>Math.random()</code> uses a <strong>pseudo-random number generator</strong> (PRNG). Those algorithms work completely determined by a initial value called ā€œseedā€.</p> +<blockquote> +<p>Given a seed, the sequence of random numbers is deterministic.</p> +</blockquote> +<p>Every PRNG requires a seed, which <em>generally</em> is the current system time in milliseconds. Yeah, simple as that.</p> +<p>Speaking of JavaScript language, the PRNG algorithm to deal with the seed is left up to implementors<sup class="footnote-reference"><a href="#1">1</a></sup>. The algorithm powering V8ā€™s <code>Math.random()</code> was very poor quality until last year (2015), and implementations between engines were pretty inconsistent.</p> +<p>But the scenario has changed. Currently, JavaScript Engines such as SpiderMonkey, V8, Webkit and Chakra all implements <a href="https://en.wikipedia.org/wiki/Xorshift">Xorshift128+</a> algorithm<sup class="footnote-reference"><a href="#2">2</a></sup>, faster than the previous one.</p> +<h2 id="secure-randomness">Secure Randomness</h2> +<p>Although randomness was improved in most JavaScript engines, it isnā€™t trustworthy as seen that standard PRNGs are highly predictable after a certain period. Thatā€™s where Web Crypto API shines!</p> +<p><a href="https://www.w3.org/TR/WebCryptoAPI/">Web Cryptography API</a> introduces <code>window.crypto.getRandomValues</code>, a cryptographically secure pseudo-random number generator (CSPNG), whose output is impossible or highly improbable to distinguish from a truly random one.</p> +<h3 id="example">Example</h3> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="color:#6272a4;">// Array containing two 32-bit integers +</span><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">arr </span><span style="color:#ff79c6;">= new </span><span>Int32Array(</span><span style="color:#bd93f9;">2</span><span>); +</span><span> +</span><span style="color:#6272a4;">// Override array integers with random values +</span><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">random </span><span style="color:#ff79c6;">= </span><span style="color:#ffffff;">crypto</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">getRandomValues</span><span>(</span><span style="color:#ffffff;">arr</span><span>); +</span><span> +</span><span style="color:#ff79c6;">for </span><span>(</span><span style="font-style:italic;color:#8be9fd;">let </span><span style="color:#ffffff;">i </span><span style="color:#ff79c6;">= </span><span style="color:#bd93f9;">0</span><span>; </span><span style="color:#ffffff;">i </span><span style="color:#ff79c6;">&lt; </span><span style="color:#ffffff;">random</span><span style="color:#ff79c6;">.</span><span>length; </span><span style="color:#ffffff;">i</span><span style="color:#ff79c6;">++</span><span>) { +</span><span> </span><span style="font-style:italic;color:#66d9ef;">console</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">log</span><span>(</span><span style="color:#ffffff;">random</span><span>[</span><span style="color:#ffffff;">i</span><span>]); +</span><span>} +</span></code></pre> +<p class="note">Of course it comes at a performance cost, so make sure you really need secure random numbers in your program.</a> +<h2 id="conclusion">Conclusion</h2> +<p>If you need apparent randomnessā€“less and speed, youā€™d probably better off using <code>Math.random()</code>. If you need high-quality randomness, such as in cryptography applications, hashing or statistics, go for a CSPNG such as <code>window.crypto.getRandomValues</code> instead.</p> +<div class="footnote-definition" id="1"><sup class="footnote-definition-label">1</sup> +<p>See <a href="https://tc39.github.io/ecma262/#sec-math.random">ES2015 spec on <code>Math.random()</code></a>.</p> +</div> +<div class="footnote-definition" id="2"><sup class="footnote-definition-label">2</sup> +<p>Sources: <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=322529">SpiderMonkey</a>, <a href="http://v8project.blogspot.com.br/2015/12/theres-mathrandom-and-then-theres.html">V8</a>, <a href="https://bugs.webkit.org/show_bug.cgi?id=151641">Webkit</a>, <a href="https://github.com/Microsoft/ChakraCore/pull/145">Chakra</a>.</p> +</div> + + + + + Horizontal and Vertical Align Anything with CSS + 2016-11-06T19:10:01+00:00 + 2016-11-06T19:10:01+00:00 + + + + + Unknown + + + + + + /blog/horizontal-and-vertical-align-anything-with-css/ + + <p>Using <code>translate()</code> is one of the easiest ways^[Flexbox also provides a great solution. See <a href="https://philipwalton.github.io/solved-by-flexbox/demos/vertical-centering/">Solved by Flexbox: Vertical Centering</a>] to instantly horizontal and vertical align any element with CSS without knowing its dimensions.</p> +<h2 id="vertical-align">Vertical Align</h2> +<p>You probably know the ā€œ<a href="http://zerosixthree.se/vertical-align-anything-with-just-3-lines-of-css/">vertical align with just 3 lines of CSS</a>ā€ trick, which uses <code>translateY()</code>.</p> +<pre data-lang="css" style="background-color:#282a36;color:#f8f8f2;" class="language-css "><code class="language-css" data-lang="css"><span style="color:#50fa7b;">.my-element </span><span>{ +</span><span> </span><span style="font-style:italic;color:#66d9ef;">position</span><span>: </span><span style="color:#6be5fd;">absolute</span><span>; +</span><span> </span><span style="font-style:italic;color:#66d9ef;">top</span><span>: </span><span style="color:#bd93f9;">50</span><span style="color:#ff79c6;">%</span><span>; +</span><span> </span><span style="font-style:italic;color:#66d9ef;">transform</span><span>: </span><span style="color:#8be9fd;">translateY</span><span>(</span><span style="color:#bd93f9;">-50</span><span style="color:#ff79c6;">%</span><span>); +</span><span>} +</span></code></pre> +<h2 id="horizontal-align">Horizontal Align</h2> +<p>But did you know itā€™s also possible to use <code>translate()</code> to horizontal align elements?</p> +<pre data-lang="css" style="background-color:#282a36;color:#f8f8f2;" class="language-css "><code class="language-css" data-lang="css"><span style="color:#50fa7b;">.my-element </span><span>{ +</span><span> </span><span style="font-style:italic;color:#66d9ef;">position</span><span>: </span><span style="color:#6be5fd;">absolute</span><span>; +</span><span> </span><span style="font-style:italic;color:#66d9ef;">left</span><span>: </span><span style="color:#bd93f9;">50</span><span style="color:#ff79c6;">%</span><span>; +</span><span> </span><span style="font-style:italic;color:#66d9ef;">transform</span><span>: </span><span style="color:#8be9fd;">translateX</span><span>(</span><span style="color:#bd93f9;">-50</span><span style="color:#ff79c6;">%</span><span>); +</span><span>} +</span></code></pre> +<h2 id="vertical-and-horizontal-align">Vertical and Horizontal Align</h2> +<p>ā€‹ Mixing both, we can horizontal and vertical align anything!</p> +<pre data-lang="css" style="background-color:#282a36;color:#f8f8f2;" class="language-css "><code class="language-css" data-lang="css"><span style="color:#50fa7b;">.my-element </span><span>{ +</span><span> </span><span style="font-style:italic;color:#66d9ef;">position</span><span>: </span><span style="color:#6be5fd;">absolute</span><span>; +</span><span> </span><span style="font-style:italic;color:#66d9ef;">left</span><span>: </span><span style="color:#bd93f9;">50</span><span style="color:#ff79c6;">%</span><span>; +</span><span> </span><span style="font-style:italic;color:#66d9ef;">top</span><span>: </span><span style="color:#bd93f9;">50</span><span style="color:#ff79c6;">%</span><span>; +</span><span> </span><span style="font-style:italic;color:#66d9ef;">transform</span><span>: </span><span style="color:#8be9fd;">translateX</span><span>(</span><span style="color:#bd93f9;">-50</span><span style="color:#ff79c6;">%</span><span>) </span><span style="color:#8be9fd;">translateY</span><span>(</span><span style="color:#bd93f9;">-50</span><span style="color:#ff79c6;">%</span><span>); +</span><span>} +</span></code></pre> +<p class="note"> +<p>See <a href="http://output.jsbin.com/dusesi">JSBin</a>.</p> +</p> + + + + + A Better ES2015+ and JSX Workflow in VS Code + 2016-10-30T00:00:00+00:00 + 2016-10-30T00:00:00+00:00 + + + + + Unknown + + + + + + /blog/a-better-es2015-and-jsx-workflow-in-vs-code/ + + <p>Lately Iā€™ve been trying <a href="https://code.visualstudio.com">VS Code</a>, a code editor based on <a href="http://electron.atom.io/">Electron</a>. Since then, it really surprised me and itā€™s been a nice coding experience.</p> +<h2 id="but">Butā€¦</h2> +<p>By default, JS syntax highlighting and ES2015+ and JSX support donā€™t work as expected.</p> +<p>Iā€™ve tried to workaround it by using:</p> +<ol> +<li><a href="https://marketplace.visualstudio.com/items?itemName=ms-vscode.js-atom-grammar">Atom grammar</a>. JSX support was pretty bad.</li> +<li>A <a href="https://marketplace.visualstudio.com/items?itemName=ms-vscode.typescript-javascript-grammar">development branch of VS Code colorization</a>, which is delivered as an extension. Finally got JSX to work properly, but syntax highlighting was still missing something.</li> +</ol> +<p>So, no success.</p> +<h2 id="improving-your-vs-code-workflow">Improving your VS Code workflow</h2> +<p>After much trial and error, I came up with a better JS workflow in VS Code.</p> +<h3 id="1-fix-js-syntax-highlighting">1. Fix JS syntax highlighting</h3> +<p>Install the <a href="https://marketplace.visualstudio.com/items?itemName=joshpeng.sublime-babel-vscode">Sublime Babel extension</a> and make sure youā€™re using one of the suggested color themes. (I like <a href="https://marketplace.visualstudio.com/items?itemName=joshpeng.theme-charcoal-oceanicnext">Charcoal Oceanic Next</a>!)</p> +<h3 id="2-use-javascript-react-in-js-files">2. Use ā€œJavaScript Reactā€ in .js files</h3> +<p>VS Code only uses ā€œJavaScript Reactā€ syntax in <code>.jsx</code> files. Add the following to your User (or Workspace) Settings:</p> +<pre data-lang="json" style="background-color:#282a36;color:#f8f8f2;" class="language-json "><code class="language-json" data-lang="json"><span style="color:#eeeeee;">&quot;</span><span style="color:#f1fa8c;">files.associations</span><span style="color:#eeeeee;">&quot;</span><span>: { +</span><span> </span><span style="color:#eeeeee;">&quot;</span><span style="color:#f1fa8c;">*.js</span><span style="color:#eeeeee;">&quot;</span><span>: </span><span style="color:#eeeeee;">&quot;</span><span style="color:#f1fa8c;">javascriptreact</span><span style="color:#eeeeee;">&quot; +</span><span>} +</span></code></pre> +<h3 id="3-enable-emmet-for-jsx">3. Enable Emmet for JSX</h3> +<p>(Thatā€™s a plus!)</p> +<p>VS Code uses Emmet by default, but doesnā€™t enable it for <code>.jsx</code> files. Add the following to your User Settings:</p> +<pre data-lang="json" style="background-color:#282a36;color:#f8f8f2;" class="language-json "><code class="language-json" data-lang="json"><span style="color:#eeeeee;">&quot;</span><span style="color:#f1fa8c;">emmet.syntaxProfiles</span><span style="color:#eeeeee;">&quot;</span><span>: { +</span><span> </span><span style="color:#eeeeee;">&quot;</span><span style="color:#f1fa8c;">javascript</span><span style="color:#eeeeee;">&quot;</span><span>: </span><span style="color:#eeeeee;">&quot;</span><span style="color:#f1fa8c;">jsx</span><span style="color:#eeeeee;">&quot; +</span><span>} +</span></code></pre> +<h2 id="let-s-improve-vs-code">Letā€™s improve VS Code!</h2> +<p>There has been <a href="https://code.visualstudio.com/updates#_preview-typescript-javascript-grammar">improvements for JS grammar</a> already, but itā€™s still not perfect.</p> +<p>Fortunately, VS Code is an <strong><a href="https://github.com/Microsoft/vscode">open source project</a></strong> and can be improved by developers like us! Letā€™s not leave it like this. Give useful feedback and help!</p> +<p>Happy coding!</p> + + + + + I'm Tired of Beautiful-Looking User Interfaces + 2016-10-23T12:50:35+00:00 + 2016-10-23T12:50:35+00:00 + + + + + Unknown + + + + + + /blog/i-m-tired-of-beautiful-looking-interfaces/ + + <div class="summary"> +<p>What if the user interface is more beautiful-looking than <strong>usable</strong>, <strong>understandable</strong>, and <strong>intuitive</strong>?</p> +</div> +<p>The visual aspects of an user interface play an essential role in organising information. Once youā€™ve got the resources, however, that turns out to be the easiest part of an Interface Design process.</p> +<p>Sure we like things that look nice, but looking nice doesnā€™t compensate a bad product design. <strong>Visual communication should not compensate flaws.</strong></p> +<p>If you spend most of the time looking for visual inspiration rather than conducting research, doing usability tests, and studying metrics such as business goals and conversion rates, you will probably come up with a interface that only looks beautiful.</p> +<p>And Iā€™m tired of beautiful-looking interfaces.</p> + + + + + Encadeamento de MĆ©todos em JavaScript + 2016-08-06T16:11:32+00:00 + 2016-08-06T16:11:32+00:00 + + + + + Unknown + + + + + + /blog/encadeamento-de-metodos-em-javascript/ + + <p>Popular em diversas bibliotecas JavaScript, o encadeamento de mĆ©todos (<em>ā€œmethod chainingā€</em>) Ć© uma tĆ©cnica usada para invocar diversos mĆ©todos em um mesmo objeto.</p> +<p>Com o objetivo de <strong>melhorar a legibilidade do cĆ³digo</strong>, a tĆ©cnica Ć© vastamente utilizada na API da jQuery, o que certamente influenciou na popularidade da biblioteca.</p> +<p>Se vocĆŖ jĆ” utilizou jQuery, o estilo do cĆ³digo abaixo pode ser familiar:</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="color:#50fa7b;">$</span><span>(</span><span style="color:#f1fa8c;">&quot;#my-element&quot;</span><span>) +</span><span> </span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">css</span><span>(</span><span style="color:#f1fa8c;">&quot;background&quot;</span><span>, </span><span style="color:#f1fa8c;">&quot;purple&quot;</span><span>) +</span><span> </span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">height</span><span>(</span><span style="color:#bd93f9;">100</span><span>) +</span><span> </span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">animate</span><span>({ height: </span><span style="color:#bd93f9;">250 </span><span>}) +</span><span> </span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">find</span><span>(</span><span style="color:#f1fa8c;">&quot;input&quot;</span><span>) +</span><span> </span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">fadeIn</span><span>(</span><span style="color:#bd93f9;">200</span><span>) +</span><span> </span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">val</span><span>(</span><span style="color:#f1fa8c;">&quot;&quot;</span><span>) +</span><span> </span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">end</span><span>(); +</span></code></pre> +<p class="note"> +<p>No exemplo acima, uma Ćŗnica declaraĆ§Ć£o faz vĆ”rias coisas. No entanto, uma boa prĆ”tica com <em>method chaining</em> Ć© <strong>fazer somente uma aĆ§Ć£o por declaraĆ§Ć£o</strong>. ;-)</p> +</p> +<p>Perceba que vĆ”rios mĆ©todos sĆ£o invocados no objeto <code>$('#my-element')</code>, sem a necessidade de repetĆ­-lo. JĆ” sem <em>Method Chaining</em>, Ć© necessĆ”rio fazer a referĆŖncia diversas vezes:</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">myElement </span><span style="color:#ff79c6;">= </span><span style="color:#50fa7b;">$</span><span>(</span><span style="color:#f1fa8c;">&quot;#my-element&quot;</span><span>); +</span><span style="color:#ffffff;">myElement</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">css</span><span>(</span><span style="color:#f1fa8c;">&quot;background&quot;</span><span>, </span><span style="color:#f1fa8c;">&quot;purple&quot;</span><span>); +</span><span style="color:#ffffff;">myElement</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">height</span><span>(</span><span style="color:#bd93f9;">100</span><span>); +</span><span style="color:#ffffff;">myElement</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">fadeIn</span><span>(</span><span style="color:#bd93f9;">200</span><span>); +</span></code></pre> +<h2 id="exemplo">Exemplo</h2> +<p>Vamos criar um contador <code>Counter</code>:</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="font-style:italic;color:#ff79c6;">class </span><span>Counter { +</span><span> </span><span style="font-style:italic;color:#8be9fd;">constructor</span><span>() { +</span><span> </span><span style="color:#bd93f9;">this</span><span style="color:#ff79c6;">.</span><span>value </span><span style="color:#ff79c6;">= </span><span style="color:#bd93f9;">0</span><span>; +</span><span> } +</span><span> +</span><span> </span><span style="color:#50fa7b;">increase</span><span>() { +</span><span> </span><span style="color:#bd93f9;">this</span><span style="color:#ff79c6;">.</span><span>value </span><span style="color:#ff79c6;">+= </span><span style="color:#bd93f9;">1</span><span>; +</span><span> } +</span><span> +</span><span> </span><span style="color:#50fa7b;">decrease</span><span>() { +</span><span> </span><span style="color:#bd93f9;">this</span><span style="color:#ff79c6;">.</span><span>value </span><span style="color:#ff79c6;">-= </span><span style="color:#bd93f9;">1</span><span>; +</span><span> } +</span><span> +</span><span> </span><span style="color:#50fa7b;">log</span><span>() { +</span><span> </span><span style="font-style:italic;color:#66d9ef;">console</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">log</span><span>(</span><span style="color:#bd93f9;">this</span><span style="color:#ff79c6;">.</span><span>value); +</span><span> } +</span><span>} +</span></code></pre> +<p>Agora, vamos instanciar um contador e usar seus mĆ©todos:</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">counter </span><span style="color:#ff79c6;">= new </span><span>Counter(); +</span><span style="color:#ffffff;">counter</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">increase</span><span>(); +</span><span style="color:#ffffff;">counter</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">log</span><span>(); </span><span style="color:#6272a4;">// =&gt; 1 +</span><span style="color:#ffffff;">counter</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">decrease</span><span>(); +</span><span style="color:#ffffff;">counter</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">log</span><span>(); </span><span style="color:#6272a4;">// =&gt; 0 +</span></code></pre> +<p>Perceba que Ć© necessĆ”rio fazer vĆ”rias declaraƧƵes para interagir com a instĆ¢ncia, o que prejudica a legibilidade do cĆ³digo.</p> +<p>E se tentarmos usar <em>Method Chaining</em>ā€¦</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="color:#ff79c6;">new </span><span>Counter()</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">increase</span><span>()</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">log</span><span>(); +</span><span style="color:#6272a4;">// &gt; TypeError: Cannot read property &#39;log&#39; of undefined +</span></code></pre> +<p>Perceba que <code>log()</code> estĆ” sendo executado em <code>new Counter().increase()</code>, que, por sua vez, estĆ” retornando <code>undefined</code>. Portanto, ainda nĆ£o Ć© possĆ­vel interagir com <code>Counter</code> dessa forma.</p> +<h2 id="como-encadear-metodos">Como Encadear MĆ©todos</h2> +<p>Para evitar a repetiĆ§Ć£o do objeto, Ć© necessĆ”rio que seus mĆ©todos retornem o prĆ³prio objeto.</p> +<p>Veja este exemplo com Promises:</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="color:#50fa7b;">getJSON</span><span>(</span><span style="color:#f1fa8c;">&quot;users.json&quot;</span><span>) +</span><span> </span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">then</span><span>(</span><span style="color:#6be5fd;">JSON</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">parse</span><span>) +</span><span> </span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">then</span><span>((</span><span style="font-style:italic;color:#ffb86c;">response</span><span>) </span><span style="font-style:italic;color:#8be9fd;">=&gt; </span><span style="font-style:italic;color:#66d9ef;">console</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">log</span><span>(</span><span style="color:#f1fa8c;">&quot;Olha o JSON!&quot;</span><span>, </span><span style="color:#ffffff;">response</span><span>)) +</span><span> </span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">catch</span><span>((</span><span style="font-style:italic;color:#ffb86c;">error</span><span>) </span><span style="font-style:italic;color:#8be9fd;">=&gt; </span><span style="font-style:italic;color:#66d9ef;">console</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">log</span><span>(</span><span style="color:#f1fa8c;">&quot;Falhou!&quot;</span><span>, </span><span style="color:#ffffff;">error</span><span>)); +</span></code></pre> +<p>Isso sĆ³ Ć© possĆ­vel pois os mĆ©todos <code>then()</code> and <code>catch()</code> sempre retornam outras promises. Assim, podemos dizer que as Promises sĆ£o <strong>fluent APIs</strong>, tal como a jQuery.</p> +<h3 id="quem-lembra-do-this">Quem Lembra do <code>this</code>?</h3> +<p>Para os mĆ©todos serem encadeados, serĆ” necessĆ”rio retornar o contexto (<code>this</code>) em cada mĆ©todo.</p> +<blockquote> +<p>Em JavaScript, <code>this</code> sempre se refere ao contexto de execuĆ§Ć£o de funĆ§Ć£o.</p> +</blockquote> +<p>No caso de um mĆ©todo, que Ć© uma funĆ§Ć£o de um objeto, refere-se ao prĆ³prio objeto.</p> +<h4 id="exemplo-com-method-chaining-pattern">Exemplo com <em>Method Chaining Pattern</em></h4> +<p>Para implementar o encadeamento de mĆ©todos na classe <code>Counter</code>, apenas retornamos seu contexto a cada mĆ©todo:</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="font-style:italic;color:#ff79c6;">class </span><span>Counter { +</span><span> </span><span style="font-style:italic;color:#8be9fd;">constructor</span><span>() { +</span><span> </span><span style="color:#bd93f9;">this</span><span style="color:#ff79c6;">.</span><span>value </span><span style="color:#ff79c6;">= </span><span style="color:#bd93f9;">0</span><span>; +</span><span> } +</span><span> </span><span style="color:#50fa7b;">increase</span><span>() { +</span><span> </span><span style="color:#bd93f9;">this</span><span style="color:#ff79c6;">.</span><span>value </span><span style="color:#ff79c6;">+= </span><span style="color:#bd93f9;">1</span><span>; +</span><span> </span><span style="color:#ff79c6;">return </span><span style="color:#bd93f9;">this</span><span>; </span><span style="color:#6272a4;">// Aqui! +</span><span> } +</span><span> </span><span style="color:#50fa7b;">decrease</span><span>() { +</span><span> </span><span style="color:#bd93f9;">this</span><span style="color:#ff79c6;">.</span><span>value </span><span style="color:#ff79c6;">-= </span><span style="color:#bd93f9;">1</span><span>; +</span><span> </span><span style="color:#ff79c6;">return </span><span style="color:#bd93f9;">this</span><span>; </span><span style="color:#6272a4;">// Aqui! +</span><span> } +</span><span> </span><span style="color:#50fa7b;">log</span><span>() { +</span><span> </span><span style="font-style:italic;color:#66d9ef;">console</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">log</span><span>(</span><span style="color:#bd93f9;">this</span><span style="color:#ff79c6;">.</span><span>value); +</span><span> </span><span style="color:#ff79c6;">return </span><span style="color:#bd93f9;">this</span><span>; </span><span style="color:#6272a4;">// E aqui! +</span><span> } +</span><span>} +</span></code></pre> +<p>Agora, ao executar <code>new Counter().increase()</code>, o retorno jĆ” nĆ£o serĆ” mais <code>undefined</code>.</p> +<p>ā€¦E, portanto, Ć© possĆ­vel fazer <em>method chaining</em>!</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="color:#ff79c6;">new </span><span>Counter() +</span><span> </span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">increase</span><span>() +</span><span> </span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">log</span><span>() </span><span style="color:#6272a4;">// =&gt; 1 +</span><span> </span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">decrease</span><span>() +</span><span> </span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">log</span><span>(); </span><span style="color:#6272a4;">// =&gt; 0 +</span></code></pre> +<h2 id="conclusao">ConclusĆ£o</h2> +<p>No universo de APIs orientadas a objetos, o encadeamento de mĆ©todos Ć© uma tĆ©cnica incrĆ­vel se o seu objetivo Ć© tornar o cĆ³digo mais expressivo e fluente.</p> +<p>No geral, <em>fluent APIs</em> sĆ£o sim interessantes de se entender e implementar, e vocĆŖ pode ter certeza disso analisando o primeiro exemplo com jQuery do inĆ­cio deste artigo. Ɖ fantĆ”stico! Mas Ć© importante entender que <strong>o encadeamento de mĆ©todos nem sempre tornarĆ” as coisas mais fĆ”ceis</strong> (debugar, por exemplo, se torna mais difĆ­cil), e, portanto, a maneira aparentemente ā€œmĆ”gicaā€ com que elas funcionam nĆ£o deve ser sempre levada em consideraĆ§Ć£o.</p> + + + + + SVG Images as React Components with Webpack + 2016-08-02T22:00:00+00:00 + 2016-08-02T22:00:00+00:00 + + + + + Unknown + + + + + + /blog/svg-images-as-react-components-with-webpack/ + + <p>If youā€™ve ever tried to load inline SVG (using <a href="https://github.com/sairion/svg-inline-loader">svg-inline-loader</a>) into React, you know it seriously hurts peopleā€™s eyes.</p> +<pre data-lang="tsx" style="background-color:#282a36;color:#f8f8f2;" class="language-tsx "><code class="language-tsx" data-lang="tsx"><span style="color:#ff79c6;">import </span><span style="color:#ffffff;">React </span><span style="color:#ff79c6;">from </span><span style="color:#f1fa8c;">&quot;react&quot;</span><span>; +</span><span style="color:#ff79c6;">import </span><span style="color:#ffffff;">IconRemove </span><span style="color:#ff79c6;">from </span><span style="color:#f1fa8c;">&quot;./icons/remove.svg&quot;</span><span>; +</span><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#50fa7b;">RemoveButton </span><span style="color:#ff79c6;">= </span><span>() </span><span style="font-style:italic;color:#8be9fd;">=&gt; </span><span>( +</span><span> &lt;</span><span style="color:#ff79c6;">button</span><span>&gt; +</span><span> &lt;</span><span style="color:#ff79c6;">div </span><span style="color:#50fa7b;">dangerouslySetInnerHTML</span><span style="color:#ff79c6;">={</span><span>{ __html: </span><span style="color:#ffffff;">IconRemove </span><span>}</span><span style="color:#ff79c6;">} </span><span>/&gt; +</span><span> &lt;</span><span style="color:#ff79c6;">span</span><span>&gt;Remove&lt;/</span><span style="color:#ff79c6;">span</span><span>&gt; +</span><span> &lt;/</span><span style="color:#ff79c6;">button</span><span>&gt; +</span><span>); +</span></code></pre> +<p>So what if it looked like this instead?</p> +<pre data-lang="tsx" style="background-color:#282a36;color:#f8f8f2;" class="language-tsx "><code class="language-tsx" data-lang="tsx"><span style="color:#ff79c6;">import </span><span style="color:#ffffff;">React </span><span style="color:#ff79c6;">from </span><span style="color:#f1fa8c;">&quot;react&quot;</span><span>; +</span><span style="color:#ff79c6;">import </span><span style="color:#ffffff;">IconRemove </span><span style="color:#ff79c6;">from </span><span style="color:#f1fa8c;">&quot;./icons/remove.svg&quot;</span><span>; +</span><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#50fa7b;">RemoveButton </span><span style="color:#ff79c6;">= </span><span>() </span><span style="font-style:italic;color:#8be9fd;">=&gt; </span><span>( +</span><span> &lt;</span><span style="color:#ff79c6;">button</span><span>&gt; +</span><span> &lt;</span><span style="font-style:italic;color:#66d9ef;">IconRemove </span><span>/&gt; +</span><span> &lt;</span><span style="color:#ff79c6;">span</span><span>&gt;Remove&lt;/</span><span style="color:#ff79c6;">span</span><span>&gt; +</span><span> &lt;/</span><span style="color:#ff79c6;">button</span><span>&gt; +</span><span>); +</span></code></pre> +<p>Much better, donā€™t you think?</p> +<p>Thatā€™s what <a href="https://github.com/jhamlet/svg-react-loader">svg-react-loader</a> does. It <strong>process your SVG file and returns a React component</strong>, which is compiled with Babel (more on this below).</p> +<h2 id="using-the-loader">Using the Loader</h2> +<pre data-lang="sh" style="background-color:#282a36;color:#f8f8f2;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#50fa7b;">npm</span><span> install svg-react-loader</span><span style="font-style:italic;color:#ffb86c;"> --save-dev +</span></code></pre> +<p class="note"> +<p>Refer to <a href="https://webpack.github.io/docs/using-loaders.html#usage">Webpack docs</a> for more information on loaders usage. Also, make sure you have installed <a href="https://github.com/jhamlet/svg-react-loader#dependencies">svg-react-loaderā€™s dependencies</a>.</p> +</p> +<h3 id="1-in-module-request">1. In Module Request</h3> +<p>The simplest method, although the configuration convention is preferred. Using svg-react-loader and <a href="https://github.com/babel/babel-loader">babel-loader</a>, import your icon just like:</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="color:#ff79c6;">import </span><span style="color:#ffffff;">IconRemove </span><span style="color:#ff79c6;">from </span><span style="color:#f1fa8c;">&quot;babel!svg-react!./icons/remove.svg&quot;</span><span>; +</span></code></pre> +<h3 id="2-in-webpack-config-file-recommended">2. In Webpack Config File (Recommended)</h3> +<p>Add in your Webpack configuration fileā€™s <code>loaders</code> array.</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span>{ +</span><span> test: </span><span style="color:#f1fa8c;">/</span><span style="color:#ff79c6;">\.</span><span style="color:#f1fa8c;">svg</span><span style="color:#ff79c6;">$</span><span style="color:#f1fa8c;">/</span><span>, +</span><span> loader: </span><span style="color:#f1fa8c;">&#39;babel!svg-react&#39; +</span><span>} +</span></code></pre> +<p>Import your icon just like:</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="color:#ff79c6;">import </span><span style="color:#ffffff;">IconRemove </span><span style="color:#ff79c6;">from </span><span style="color:#f1fa8c;">&quot;./icons/remove.svg&quot;</span><span>; +</span></code></pre> +<h2 id="usage-examples">Usage Examples</h2> +<p>Loader in module request method (1):</p> +<pre data-lang="tsx" style="background-color:#282a36;color:#f8f8f2;" class="language-tsx "><code class="language-tsx" data-lang="tsx"><span style="color:#ff79c6;">import </span><span style="color:#ffffff;">React </span><span style="color:#ff79c6;">from </span><span style="color:#f1fa8c;">&quot;react&quot;</span><span>; +</span><span style="color:#ff79c6;">import </span><span style="color:#ffffff;">IconRemove </span><span style="color:#ff79c6;">from </span><span style="color:#f1fa8c;">&quot;babel!svg-react!./icons/remove.svg&quot;</span><span>; +</span><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#50fa7b;">RemoveButton </span><span style="color:#ff79c6;">= </span><span>() </span><span style="font-style:italic;color:#8be9fd;">=&gt; </span><span>( +</span><span> &lt;</span><span style="color:#ff79c6;">button</span><span>&gt; +</span><span> &lt;</span><span style="font-style:italic;color:#66d9ef;">IconRemove </span><span>/&gt; +</span><span> &lt;</span><span style="color:#ff79c6;">span</span><span>&gt;Remove&lt;/</span><span style="color:#ff79c6;">span</span><span>&gt; +</span><span> &lt;/</span><span style="color:#ff79c6;">button</span><span>&gt; +</span><span>); +</span></code></pre> +<p>Loader in Webpack config file method (2):</p> +<pre data-lang="tsx" style="background-color:#282a36;color:#f8f8f2;" class="language-tsx "><code class="language-tsx" data-lang="tsx"><span style="color:#ff79c6;">import </span><span style="color:#ffffff;">React </span><span style="color:#ff79c6;">from </span><span style="color:#f1fa8c;">&quot;react&quot;</span><span>; +</span><span style="color:#ff79c6;">import </span><span style="color:#ffffff;">IconRemove </span><span style="color:#ff79c6;">from </span><span style="color:#f1fa8c;">&quot;./icons/remove.svg&quot;</span><span>; +</span><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#50fa7b;">RemoveButton </span><span style="color:#ff79c6;">= </span><span>() </span><span style="font-style:italic;color:#8be9fd;">=&gt; </span><span>( +</span><span> &lt;</span><span style="color:#ff79c6;">button</span><span>&gt; +</span><span> &lt;</span><span style="font-style:italic;color:#66d9ef;">IconRemove </span><span>/&gt; +</span><span> &lt;</span><span style="color:#ff79c6;">span</span><span>&gt;Remove&lt;/</span><span style="color:#ff79c6;">span</span><span>&gt; +</span><span> &lt;/</span><span style="color:#ff79c6;">button</span><span>&gt; +</span><span>); +</span></code></pre> +<h2 id="a-note-on-svg-loaders">A Note on SVG Loaders</h2> +<p>Sometimes, we donā€™t want all of our SVG files to be loaded as React components. If you use a SVG in a <code>img</code> element, for example, it may lead to conflicts. Fortunately, you can avoid them by being more specific in <code>test</code> regular expression:</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span>{ +</span><span> test: </span><span style="color:#f1fa8c;">/</span><span style="color:#ff79c6;">\.</span><span style="color:#f1fa8c;">inline</span><span style="color:#bd93f9;">.</span><span style="color:#f1fa8c;">svg</span><span style="color:#ff79c6;">$</span><span style="color:#f1fa8c;">/</span><span>, +</span><span> loader: </span><span style="color:#f1fa8c;">&#39;babel!svg-react&#39; +</span><span>}, +</span><span>{ +</span><span> test: </span><span style="color:#f1fa8c;">/</span><span style="color:#ff79c6;">\.</span><span style="color:#f1fa8c;">jpe</span><span style="color:#ff79c6;">?</span><span style="color:#f1fa8c;">g</span><span style="color:#ff79c6;">$|\.</span><span style="color:#f1fa8c;">gif</span><span style="color:#ff79c6;">$|\.</span><span style="color:#f1fa8c;">png</span><span style="color:#ff79c6;">$|^</span><span style="color:#f1fa8c;">(?!</span><span style="color:#bd93f9;">.</span><span style="color:#ff79c6;">*\.</span><span style="color:#f1fa8c;">inline</span><span style="color:#ff79c6;">\.</span><span style="color:#f1fa8c;">svg</span><span style="color:#ff79c6;">$</span><span style="color:#f1fa8c;">)</span><span style="color:#bd93f9;">.</span><span style="color:#ff79c6;">*\.</span><span style="color:#f1fa8c;">svg</span><span style="color:#ff79c6;">$</span><span style="color:#f1fa8c;">/</span><span>, +</span><span> loader: </span><span style="color:#f1fa8c;">&#39;url&#39; +</span><span>} +</span></code></pre> +<p>Now, only SVG files ending with <code>.inline.svg</code> will be loaded as React components. Youā€™re good to go!</p> + + + + + A Cascata das VariĆ”veis do CSS + 2016-05-30T22:00:00+00:00 + 2016-05-30T22:00:00+00:00 + + + + + Unknown + + + + + + /blog/a-cascata-das-variaveis-do-css/ + + <p style="text-align: center"><a href="http://caniuse.com/#feat=css-variables">Suporte</a> | <a href="https://www.w3.org/TR/css-variables/">EspecificaĆ§Ć£o</a></p> +<p>Muito embora todos os seres humanos do Planeta Terra tenham odiado sua sintaxe, as variĆ”veis finalmente chegaram ao CSSĀ ā€“Ā e elas sĆ£o mais poderosas do que vocĆŖ imagina!</p> +<h2 id="motivacao">MotivaĆ§Ć£o</h2> +<p>O desenvolvimento de grandes aplicaƧƵes web implica inevitavelmente em grandes folhas de estilo, que devem ser organizadas de forma que facilite a manutenĆ§Ć£o. Muitos valores definidos para propriedades sĆ£o repetidos, quando poderiam ser reutilizados e padronizados, de forma compartilhada, pela folha de estilo.</p> +<p>Nesse contexto, surgem as variĆ”veis no CSS, tambĆ©m chamadas de <em>Custom Properties</em>Ā ā€“Ā pois, tecnicamente, Ć© isso que elas sĆ£o.</p> +<h2 id="definicao">DefiniĆ§Ć£o</h2> +<p>As <em>Custom Properties</em> sĆ£o propriedades CSS customizadas (ou seja, vocĆŖ configura o seu valor) iniciadas com <code>--</code>, de nome <em>case-sensitive</em>, e que sĆ£o utilizadas no documento atravĆ©s da funĆ§Ć£o <code>var()</code>. Por serem propriedades, Ć© importante compreender que seu comportamento Ć© idĆŖntico ao de uma propriedade qualquer do CSS (guarde essa informaĆ§Ć£o!).</p> +<h3 id="exemplo">Exemplo</h3> +<pre data-lang="css" style="background-color:#282a36;color:#f8f8f2;" class="language-css "><code class="language-css" data-lang="css"><span>:root { +</span><span> </span><span style="font-style:italic;color:#66d9ef;">--colorPrimary</span><span>: </span><span style="color:#6be5fd;">purple</span><span>; +</span><span>} +</span><span> +</span><span style="color:#ff79c6;">a </span><span>{ +</span><span> </span><span style="font-style:italic;color:#66d9ef;">color</span><span>: </span><span style="color:#8be9fd;">var</span><span>(</span><span style="font-style:italic;color:#66d9ef;">--colorPrimary</span><span>); +</span><span>} +</span></code></pre> +<p>(Eu nĆ£o conheƧo ninguĆ©m que gosta da ideia esplĆŖndida do <code>--</code>. Mas elas nĆ£o vĆ£o deixar de iniciar com <code>--</code> se vocĆŖ reclamar. Inclusive, <a href="http://www.xanthir.com/blog/b4KT0">isso jĆ” foi discutido o suficiente</a>.)</p> +<h2 id="a-funcao-var">A funĆ§Ć£o <code>var()</code></h2> +<p>Quem viabiliza o uso de <em>Custom Properties</em>? Ela:</p> +<pre data-lang="css" style="background-color:#282a36;color:#f8f8f2;" class="language-css "><code class="language-css" data-lang="css"><span style="color:#ff79c6;">var</span><span>( &lt;</span><span style="color:#ff79c6;">custom-property-name</span><span>&gt; [, &lt;</span><span style="color:#50fa7b;">declaration-value</span><span>&gt; ]? ) +</span></code></pre> +<p>O primeiro parĆ¢metro Ć© o nome da propriedade, e o segundo, opcional, Ć© o valor a ser usado como <em>fallback</em> caso o primeiro argumento seja invĆ”lido (por exemplo: uma variĆ”vel com <code>20px</code> sendo usada como valor de um <code>background</code>, ou variĆ”vel inexistente).</p> +<h2 id="escopo">Escopo</h2> +<p>Cascata, especificidade, heranƧaā€¦ Esses conceitos sĆ£o muito importantes para entender o poder das variĆ”veis do CSS ā€“ e do CSS no geral, eu diria.</p> +<p>Aqui, uma das informaƧƵes mais importantes deste artigo: As <em>Custom Properties</em> seguem <strong>regras de cascata</strong> tal como qualquer outra propriedade do CSS.</p> +<p>Por isso, quando quisermos que a variĆ”vel esteja disponĆ­vel ā€œglobalmenteā€ (para todos os seletores), a declaramos no seletor <code>:root</code>, que Ć© o prĆ³prio documento HTML. Isso acontece pois <strong>o efeito cascata do CSS permite que todos seus descendentes herdem a propriedade.</strong> Legal, nĆ©?</p> +<p>A propriedade customizada, tal como qualquer outra propriedade, pode ser sobreescrita atravĆ©s de seletores. Seu valor serĆ” definido de acordo com a <strong>especifidade</strong> deles.</p> +<p class="note"> +<p>A implementaĆ§Ć£o de <em>Custom Properties</em> do CSSNext nĆ£o segue regras de cascata. Apenas variĆ”veis declaradas no <code>:root</code> sĆ£o vĆ”lidas. :-(</p> +</p> +<h3 id="exemplo-1">Exemplo</h3> +<pre data-lang="css" style="background-color:#282a36;color:#f8f8f2;" class="language-css "><code class="language-css" data-lang="css"><span>:root { +</span><span> </span><span style="font-style:italic;color:#66d9ef;">--bgColor</span><span>: </span><span style="color:#6be5fd;">indianred</span><span>; +</span><span>} +</span><span> +</span><span style="color:#ff79c6;">div </span><span>{ +</span><span> </span><span style="font-style:italic;color:#66d9ef;">--bgColor</span><span>: </span><span style="color:#6be5fd;">darkseagreen</span><span>; +</span><span>} +</span><span> +</span><span style="color:#50fa7b;">#wow </span><span>{ +</span><span> </span><span style="font-style:italic;color:#66d9ef;">--bgColor</span><span>: </span><span style="color:#6be5fd;">darkcyan</span><span>; +</span><span>} +</span><span> +</span><span style="color:#ff79c6;">* </span><span>{ +</span><span> </span><span style="font-style:italic;color:#66d9ef;">background-color</span><span>: </span><span style="color:#8be9fd;">var</span><span>(</span><span style="font-style:italic;color:#66d9ef;">--bgColor</span><span>); +</span><span>} +</span></code></pre> +<p>Nesse caso:</p> +<ul> +<li>Todos os elementos sĆ£o vermelhos.</li> +<li>Exceto elementos <code>div</code> e seus filhos, que seriam verdes.</li> +<li>Exceto o elemento com id <code>wow</code> e seus filhos, que seriam ciano.</li> +</ul> +<p>As Ćŗltimas versƵes do Firefox e Chrome jĆ” implementaram as variĆ”veis nativas do CSS. Se estiver utilizando algum desses navegadores, o exemplo abaixo ilustrarĆ” o funcionamento do CSS acima.</p> +<p><a class="jsbin-embed" href="http://jsbin.com/meboki/edit?html,output">JS Bin on jsbin.com</a><script src="http://static.jsbin.com/js/embed.min.js?3.35.12"></script></p> +<h2 id="manipulando-variaveis-css-com-javascript">Manipulando variĆ”veis CSS com JavaScript</h2> +<p>Outra informaĆ§Ć£o valiosa sobre as variĆ”veis do CSS Ć© a possibilidade de acessĆ”-las e alterĆ”-las via JavaScript, usando a interface <a href="https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleDeclaration"><code>CSSStyleDeclaration</code></a> para interagir com propriedades.</p> +<h3 id="exemplo-2">Exemplo</h3> +<p>Considerando:</p> +<pre data-lang="css" style="background-color:#282a36;color:#f8f8f2;" class="language-css "><code class="language-css" data-lang="css"><span>:root { +</span><span> </span><span style="font-style:italic;color:#66d9ef;">--my-color</span><span>: </span><span style="color:#6be5fd;">darkcyan</span><span>; +</span><span> </span><span style="font-style:italic;color:#66d9ef;">background-color</span><span>: </span><span style="color:#8be9fd;">var</span><span>(</span><span style="font-style:italic;color:#66d9ef;">--my-color</span><span>); +</span><span>} +</span></code></pre> +<p>VocĆŖ pode obter o valor da propriedade <code>--my-color</code>, atravĆ©s do <code>window.getComputedStyle()</code> e <code>getPropertyValue()</code>.</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">myColor </span><span style="color:#ff79c6;">= </span><span style="color:#50fa7b;">getComputedStyle</span><span>(document</span><span style="color:#ff79c6;">.</span><span>body)</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">getPropertyValue</span><span>(</span><span style="color:#f1fa8c;">&quot;--my-color&quot;</span><span>); +</span><span style="font-style:italic;color:#66d9ef;">console</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">log</span><span>(</span><span style="color:#ffffff;">myColor</span><span>); </span><span style="color:#6272a4;">// =&gt; darkcyan +</span></code></pre> +<p>VocĆŖ pode alterar o valor da variĆ”vel, atravĆ©s do <code>setProperty()</code> do <a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/style">objeto <code>style</code></a>:</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span>document</span><span style="color:#ff79c6;">.</span><span>body</span><span style="color:#ff79c6;">.</span><span>style</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">setProperty</span><span>(</span><span style="color:#f1fa8c;">&quot;--my-color&quot;</span><span>, </span><span style="color:#f1fa8c;">&quot;tomato&quot;</span><span>); +</span></code></pre> +<p class="note"> +<p>ConheƧa o <code>CSSStyleDeclaration</code> abrindo o DevTools e digitando <code>getComputedStyle(document.body)</code> no console.</p> +</p> +<h2 id="curiosidades">Curiosidades</h2> +<ul> +<li>VocĆŖ nĆ£o pode armazenar nomes de propriedades do CSS como <em>Custom Properties</em>.</li> +</ul> +<pre data-lang="css" style="background-color:#282a36;color:#f8f8f2;" class="language-css "><code class="language-css" data-lang="css"><span style="color:#ff79c6;">div </span><span>{ +</span><span> </span><span style="font-style:italic;color:#66d9ef;">--myProperty</span><span>: overflow; +</span><span> var(</span><span style="font-style:italic;color:#66d9ef;">--myProperty</span><span>): </span><span style="color:#6be5fd;">hidden</span><span>; </span><span style="color:#6272a4;">/* Erro de sintaxe */ +</span><span>} +</span></code></pre> +<p>ā€¦Em compensaĆ§Ć£o, vocĆŖ pode armazenar qualquer outra coisa (e usĆ”-las com JavaScript!):</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="color:#ff79c6;">--</span><span>foo: </span><span style="color:#ff79c6;">if </span><span>(</span><span style="color:#ffffff;">x </span><span style="color:#ff79c6;">&gt; </span><span style="color:#bd93f9;">5</span><span>) </span><span style="color:#bd93f9;">this</span><span style="color:#ff79c6;">.</span><span>width </span><span style="color:#ff79c6;">= </span><span style="color:#bd93f9;">10</span><span>; +</span></code></pre> +<ul> +<li>VocĆŖ nĆ£o pode formar valores com variĆ”veis.</li> +</ul> +<pre data-lang="css" style="background-color:#282a36;color:#f8f8f2;" class="language-css "><code class="language-css" data-lang="css"><span style="color:#ff79c6;">div </span><span>{ +</span><span> </span><span style="font-style:italic;color:#66d9ef;">--myContainerWidth</span><span>: </span><span style="color:#bd93f9;">300</span><span>; +</span><span> </span><span style="font-style:italic;color:#66d9ef;">width</span><span>: </span><span style="color:#8be9fd;">var</span><span>(</span><span style="font-style:italic;color:#66d9ef;">--myContainerWidth</span><span>) px; </span><span style="color:#6272a4;">/* Valor invĆ”lido */ +</span><span> </span><span style="color:#6272a4;">/* =&gt; 300 px, em vez de 300px */ +</span><span>} +</span></code></pre> +<p>ā€¦Ao menos que vocĆŖ use <code>calc()</code>:</p> +<pre data-lang="css" style="background-color:#282a36;color:#f8f8f2;" class="language-css "><code class="language-css" data-lang="css"><span style="color:#ff79c6;">div </span><span>{ +</span><span> </span><span style="font-style:italic;color:#66d9ef;">--myContainerWidth</span><span>: </span><span style="color:#bd93f9;">300</span><span>; +</span><span> </span><span style="font-style:italic;color:#66d9ef;">width</span><span>: </span><span style="color:#8be9fd;">calc</span><span>(</span><span style="color:#8be9fd;">var</span><span>(</span><span style="font-style:italic;color:#66d9ef;">--myContainerWidth</span><span>) </span><span style="color:#ff79c6;">* </span><span style="color:#bd93f9;">1</span><span style="color:#ff79c6;">px</span><span>); </span><span style="color:#6272a4;">/* =&gt; width: 300px; */ +</span><span>} +</span></code></pre> +<h2 id="consideracoes-finais">ConsideraƧƵes Finais</h2> +<p>As <em>Custom Properties</em> abriram novas possibilidades para o uso de variĆ”veis em folhas de estilo. Depois de diversas especificaƧƵes e sintaxes (<a href="https://www.w3.org/TR/2013/WD-css-variables-1-20130620/#var-">nem sempre foi <code>--</code></a>, acredite!), elas estĆ£o finalmente em fase de implementaĆ§Ć£o nos navegadores.</p> +<p>Tem interesse em se aprofundar em outras novas funcionalidades do CSS? Acompanhe a sĆ©rie <a href="/blog/o-css-do-futuro/">O CSS do Futuro</a>!</p> + + + + + O CSS do Futuro + 2016-05-29T23:21:51+00:00 + 2016-05-29T23:21:51+00:00 + + + + + Unknown + + + + + + /blog/o-css-do-futuro/ + + <div class="summary"> +<p>JĆ” existem <a href="https://drafts.csswg.org/">especificaƧƵes</a> garantindo funcionalidades incrĆ­veis para o CSS: variĆ”veis; uma nova sintaxe para <em>media queries</em>; <em>nesting</em>; novos seletores, valores e propriedades. E vocĆŖ pode usĆ”-las, <strong>hoje</strong>.</p> +</div> +<p>Neste artigo, introduzo uma sĆ©rie de artigos relacionados Ć s principais funcionalidades do CSS do futuro, alĆ©m da ferramenta <a href="http://cssnext.io/">CSSNext</a>, que permite que vocĆŖ as utilize sem esperar o suporte do navegador.</p> +<p>(A fins didĆ”ticos, Ć© possĆ­vel assemelhar o CSSNext ao <a href="https://babeljs.io/">Babel</a>, que, por sua vez, tambĆ©m permite desenvolver com o JavaScript do futuro ao transpilar o cĆ³digo JavaScript da prĆ³xima geraĆ§Ć£o para um cĆ³digo suportado pelos navegadores atuais.)</p> +<p>Ao final desse artigo, vocĆŖ saberĆ” como desenvolver, hoje, com o CSS do futuro.</p> +<hr /> +<h2 id="introducao-ao-postcss">IntroduĆ§Ć£o ao PostCSS</h2> +<p>O CSSNext estĆ” relacionado com PostCSS. Mas o que Ć© o PostCSS, afinal?</p> +<p>O <a href="https://github.com/postcss/postcss">PostCSS</a> Ć© apenas uma ferramenta que permite (prĆ© ou pĆ³s) processar o CSS atravĆ©s de plugins em JavaScript. Um desses plugins Ć© o CSSNextĀ ā€“ assim como, por exemplo, o <a href="https://github.com/postcss/autoprefixer">Autoprefixer</a>, que trabalha na etapa de pĆ³s-processamento do CSS, adicionando <em>vendor prefixes</em>.</p> +<p>A transformaĆ§Ć£o de estilos Ć© viabilizada de forma integralmente <strong>agnĆ³stica</strong>: nada Ć© dito sobre como e com o que serĆ” feito. Com o PostCSS, vocĆŖ Ć© responsĆ”vel pelo workflow de processamento do estilo. Ɖ possĆ­vel utilizar <a href="https://github.com/jonathantneal/precss">funcionalidades prĆ©-processadas</a> e/ou <a href="https://github.com/postcss/sugarss">sintaxe do Sass</a>, <a href="https://github.com/ben-eb/cssnano">minificar</a> e adicionar <em>vendor prefixes</em> ā€“Ā tudo de forma ā€œplugĆ”velā€!</p> +<p>Como o PostCSS nunca Ć© utilizado sozinho, o prĆ³ximo passo Ć© plugar o CSSNext a ele.</p> +<h2 id="como-usar-o-cssnext">Como usar o CSSNext</h2> +<p>Se vocĆŖ quiser apenas testar as funcionalidades dos novos mĆ³dulos do CSS, vocĆŖ pode <a href="http://cssnext.io/playground">brincar com o CSSNext no navegador</a>.</p> +<h3 id="no-workflow">No workflow</h3> +<p>Em um ambiente de desenvolvimento, Ć© necessĆ”rio usĆ”-lo com o PostCSS. A <a href="http://cssnext.io/setup/#usage">documentaĆ§Ć£o do CSSNext</a> guia vocĆŖ para configurĆ”-lo em seu workflow, seja com Webpack, Browserify, Gulp, Grunt, [ā€¦], ou interface de linha de comando.</p> +<p>Em todos os casos, a configuraĆ§Ć£o se resume a passar um <em>array</em> com os processadores desejados para o PostCSS. Nesse caso, o processador a ser plugado Ć© apenas o <a href="https://www.npmjs.com/package/postcss-cssnext">postcss-cssnext</a>:</p> +<pre data-lang="sh" style="background-color:#282a36;color:#f8f8f2;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#50fa7b;">$</span><span> npm install postcss-cssnext</span><span style="font-style:italic;color:#ffb86c;"> --save-dev +</span></code></pre> +<h2 id="principais-funcionalidades">Principais Funcionalidades</h2> +<p>Aprofunde-se nas principais funcionalidades do CSS do Futuro atravĆ©s dos artigos abaixo. Abra o <a href="http://cssnext.io/playground/">playground do CSSNext</a> e bons estudos!</p> +<ul> +<li><a href="/blog/a-cascata-das-variaveis-do-css/">A Cascata das VariĆ”veis do CSS</a></li> +<li>Uma Nova Sintaxe Para Media Queries</li> +<li>Seletores CSS em Um Novo NĆ­vel</li> +<li>Manipulando Cores Com CSS</li> +</ul> + + + + + Mass Deleting Files from Slack + 2016-04-17T00:10:15+00:00 + 2016-04-17T00:10:15+00:00 + + + + + Unknown + + + + + + /blog/mass-deleting-files-from-slack/ + + <p>Slack comes with limited file storage, so you eventually run out of space. Deleting files isnā€™t easy though: there is no way to <strong>bulk delete</strong> them using the web interface.</p> +<p><strong>Slack forces you to delete one by one.</strong></p> +<p>And although Slack can force humans, it canā€™t force JavaScript. So JavaScript to the rescue!</p> +<h2 id="how-to-delete-multiple-files-from-slack">How to delete multiple files from Slack</h2> +<p>In order to free up space, youā€™ll need;</p> +<ul> +<li><a href="https://nodejs.org/">Node.js</a> version 5 or later;</li> +<li>A Slack token, which you can get from <a href="https://api.slack.com/docs/oauth-test-tokens">Slack API docs</a>;</li> +<li>A terminal.</li> +</ul> +<h3 id="installing">Installing</h3> +<p>Open your terminal and install <code>slack-delete-files</code> package globally using Node Package Manager:</p> +<pre data-lang="sh" style="background-color:#282a36;color:#f8f8f2;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#50fa7b;">$</span><span> npm install</span><span style="font-style:italic;color:#ffb86c;"> -g</span><span> slack-delete-files +</span></code></pre> +<h3 id="running">Running</h3> +<pre data-lang="sh" style="background-color:#282a36;color:#f8f8f2;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#50fa7b;">$</span><span> slack-delete-files +</span></code></pre> +<p class="note"> +<p>Youā€™ll be asked for your Slack token and whether you want to delete <em>all files</em> or only <em>files older than 30 days</em>.</p> +</p> +<h3 id="done">Done!</h3> +<p>Your space is probably back!</p> +<p>After deleting, you can uninstall the package:</p> +<pre data-lang="sh" style="background-color:#282a36;color:#f8f8f2;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#50fa7b;">$</span><span> npm uninstall</span><span style="font-style:italic;color:#ffb86c;"> -g</span><span> slack-delete-files +</span></code></pre> +<p><a href="https://github.com/diessica/slack-delete-files">Contribute on GitHub</a>.</p> + + + + + A FantĆ”stica Diversidade do Front-end + 2016-04-09T15:10:00+00:00 + 2016-04-09T15:10:00+00:00 + + + + + Unknown + + + + + + /blog/a-fantastica-diversidade-do-front-end/ + + <p class="summary">Os diferentes perfis de desenvolvedores front-end Ć© um tĆ³pico que frequente em fĆ³runs de discussĆ£o. Quais perfis o mercado espera? Como posso me definir enquanto desenvolvedor(a) front-end?</p> +<p>Vi, recentemente, uma <a href="https://www.facebook.com/careers/jobs/a0I1200000IALJQ/">vaga no Facebook para Front-end Engineer com foco em Acessibilidade</a>. Pensei ā€œFoco em acessibilidade? Que especĆ­fico!ā€, e, segundos depois, todas as discussƵes que jĆ” tive sobre os perfis de desenvolvedores front-end me vieram Ć  mente.</p> +<p>Falar sobre esse assunto Ć© falar sobre <strong>como interpretar vagas de emprego sem entrar em desespero</strong>.</p> +<h2 id="mesmo-papel-diversas-habilidades">Mesmo Papel, Diversas Habilidades</h2> +<p>Estuda Motion Design a fim de desenvolver nĆ£o sĆ³ sites, mas experiĆŖncias fantĆ”sticas? Estuda UX Design e prĆ”ticas de Acessibilidade a fim de desenvolver produtos que engajam o mĆ”ximo de pessoas possĆ­vel? Estuda padrƵes de arquitetura de software a fim de desenvolver aplicaƧƵes web complexas e escalĆ”veis no client-side?</p> +<p>VocĆŖ pode estudar e gostar todos; estudar mais um mais do que o outro; trabalhar com um, mas tender a outro; e pode atĆ© mesmo nĆ£o focar em nenhum dos que eu citei acima. Em qualquer uma das possibilidades, vocĆŖ provavelmente <strong>nĆ£o deixarĆ” de ser um profissional da Ć”rea de front-end</strong> ā€“Ā mas terĆ”, com certeza, um mercado especĆ­fico e uma carreira que se basearĆ£o nas suas escolhas profissionais.</p> +<p><strong>Existe uma diversidade incrĆ­vel de habilidades na Ć”rea de desenvolvimento front-end.</strong></p> +<p><strong>Somos o intermediĆ”rio entre o back-end e o design</strong>, mas nosso papel Ć© transformar o web design em uma experiĆŖncia real. Essa (grande) responsabilidade faz com que desenvolvamos diversas habilidades, e algumas sĆ£o inegavelmente desenvolvidas em maior ou menor nĆ­vel. Nesse desnĆ­vel, encontramos de <em>Motion Designers</em> a <em>JavaScript Developers</em>, cada um com seu espaƧo em times e projetos especĆ­ficos.</p> +<p>E nĆ£o hĆ” nada de errado nisso. O surgimento dessas especializaƧƵes ā€“ que podem (e devem) ser escolhidas por vocĆŖĀ ā€“ Ć© apenas um resultado da complexidade atual do desenvolvimento front-end.</p> +<h2 id="confie-nas-suas-habilidades">Confie nas Suas Habilidades</h2> +<p>(ou ā€œVocĆŖ NĆ£o Precisa Ser o Candidato Perfeito Para Todas as Vagas de Front-end Existentesā€.)</p> +<p>Por que eu disse que <em>falar sobre esse assunto Ć© falar sobre como interpretar vagas de emprego sem entrar em desespero</em>?</p> +<p>Pense: VocĆŖ Ć© experiente, estuda com frequĆŖncia, mas, ocasionalmente, procura vagas de emprego e se vĆŖ insuficiente. Ok, convenhamos, a possibilidade existe: vocĆŖ nĆ£o estar atingindo os requisitos mĆ­nimos das vagas pode sim ser um sinal de que algo estĆ” errado. Mas provavelmente nĆ£o Ć© o caso.</p> +<p><strong>Talvez vocĆŖ esteja procurando vagas para um perfil que nĆ£o Ć© o seu.</strong> NĆ£o precisamos aceitar ter expertises variadas como Ć© exigido; afinal, muitas vagas na Ć”rea de TI viram piada justamente por esse motivo. Desde que vocĆŖ entenda a multidisciplinaridade como mais valiosa que qualquer disciplina, apenas abrace o que prefere e se aprofunde, torne-se uma referĆŖncia nisso.</p> +<p>No fim, suas preferĆŖncias moldarĆ£o vocĆŖ como profissional. Elas farĆ£o com que vocĆŖ seja incluĆ­do(a) ou excluĆ­do(a) de vĆ”rias oportunidades, o que, por consequĆŖncia, moldarĆ” sua carreira.</p> +<p>Estude o que gosta, reconheƧa suas preferĆŖncias, confie nas suas habilidades, e, entĆ£o, procure vagas sem entrar em desespero.</p> +<h2 id="perfis-de-desenvolvedores-front-end">Perfis de Desenvolvedores Front-end</h2> +<p>No <a href="https://github.com/frontendbr/forum/issues/32">fĆ³rum do Front-end Brasil</a>, foi proposta a divisĆ£o de separar profissionais de front-end que desenvolvem a camada de apresentaĆ§Ć£o dos que arquitetam aplicaƧƵes que interagem com back-end. Concordo com a divisĆ£o. Tenho uma visĆ£o bem definida, com base nas exigĆŖncias atuais do mercado internacional.</p> +<h3 id="dois-perfis-uma-proposta">Dois Perfis: Uma Proposta</h3> +<h4 id="front-end-developer">Front-end Developer</h4> +<p>A ponte entre o design e o front-end. (ā€œUI Developerā€ Ć© um nome alternativo.)</p> +<h5 id="habilidades">Habilidades</h5> +<ul> +<li>ProficiĆŖncia em HTML semĆ¢ntico, CSS e JavaScript a nĆ­vel de desenvolvimento da camada de apresentaĆ§Ć£o da aplicaĆ§Ć£o.</li> +<li>PrincĆ­pios e boas prĆ”ticas de User Experience Design.</li> +<li>PrincĆ­pios e boas prĆ”ticas de Acessibilidade.</li> +<li>ProficiĆŖncia em metodologias de organizaĆ§Ć£o do CSS como OOCSS, SMACSS e BEM.</li> +<li>NoƧƵes de User Interface Design.</li> +<li>NoƧƵes de Motion Design.</li> +<li>NoƧƵes de back-end, geralmente a nĆ­vel de integraĆ§Ć£o com CMS.</li> +</ul> +<h5 id="responsabilidades">Responsabilidades</h5> +<ul> +<li>Planejamento e desenvolvimento da camada de apresentaĆ§Ć£o da aplicaĆ§Ć£o.</li> +<li>ImplementaĆ§Ć£o do <em>live styleguide</em>, junto ao designer.</li> +<li>Metodologia e estrutura a ser usada no CSS.</li> +<li>ParticipaĆ§Ć£o no processo de Design (pois <a href="http://bradfrost.com/blog/post/development-is-design/"><em>Development is Design</em></a>).</li> +</ul> +<h4 id="front-end-engineer">Front-end Engineer</h4> +<p>A ponte entre o front-end e o back-end. (Dependendo do projeto, ā€œJavaScript Developerā€ pode ser mais apropriado.)</p> +<h5 id="habilidades-1">Habilidades</h5> +<ul> +<li>ProficiĆŖncia em HTML e CSS, mas sua especializaĆ§Ć£o Ć© JavaScript.</li> +<li>ProficiĆŖncia em Design Patterns e padrƵes de arquitetura de software.</li> +<li>Conhecimento de modelo cliente-servidor, HTTP, REST.</li> +<li>PrincĆ­pios e boas prĆ”ticas de Performance.</li> +<li>PrincĆ­pios e boas prĆ”ticas de SeguranƧa.</li> +<li>NoƧƵes de estratĆ©gias de desenvolvimento, como IntegraĆ§Ć£o ContĆ­nua (CI).</li> +</ul> +<h5 id="responsabilidades-1">Responsabilidades</h5> +<ul> +<li>Planejamento e desenvolvimento da aplicaĆ§Ć£o JavaScript.</li> +<li>AutomatizaĆ§Ć£o das tarefas.</li> +<li><em>Tooling</em> da aplicaĆ§Ć£o.</li> +<li>ImplementaĆ§Ć£o de uma metodologia de testes.</li> +</ul> +<p class="note"> +<p>NĆ£o concordo com o nome ā€œFront-end Designerā€, <a href="http://bradfrost.com/blog/post/frontend-design/">sugerido pelo Brad Frost</a>. Ainda que desenvolvedores front-end participem do processo de design, tornar funcional a camada de apresentaĆ§Ć£o Ć© uma etapa do desenvolvimento de software ā€“Ā nĆ£o do design. O fato do desenvolvimento front-end ser erroneamente considerado mais programaĆ§Ć£o do que design, quando deveria ser os dois, Ć© um argumento que nĆ£o justifica o nome.</p> +</p> +<h3 id="qual-deles">ā€¦Qual Deles?</h3> +<p>Normalmente temos um pouco dos dois, mas sempre um mais do que o outro. Nesse caso, uma boa maneira de explicitar o seu papel sem desmerecer o outro Ć© falar sobre suas habilidades, em vez de se apegar a um rĆ³tulo.</p> +<p><strong>Dificilmente um rĆ³tulo resumirĆ” todo o seu conhecimento.</strong></p> +<p>Eu nĆ£o me apego a isso, por exemplo. Mesmo exercendo a funĆ§Ć£o de Front-end Engineer atualmente, continuo me denominando ā€œFront-end Developerā€.</p> +<h2 id="a-vaga-ideal-para-suas-habilidades">A Vaga Ideal Para Suas Habilidades</h2> +<p>Ɖ utĆ³pico esperar que todos desenvolvedores front-end sejam bons UX Designers, Motion Designers, JavaScript Developersā€¦ Isso nĆ£o existe. As empresas procuram diferentes perfis de desenvolvedores front-end. <strong>E elas nem sempre sabem disso.</strong></p> +<p>As empresas nĆ£o simplesmente procuram um Front-end Developer ou um Front-end Engineer. Existem vagas bastante hĆ­bridas, como Front-end Engineers <em>com foco</em> em UX ou Acessibilidade, ou atĆ© mesmo Front-end Developers <em>com noƧƵes</em> de arquiteturas como MVC. Plenamente possĆ­vel e vĆ”lido!</p> +<p>Cabe a vocĆŖ identificar se Ć© ideal Ć  vaga de emprego que quer se candidatar e se suas habilidades sĆ£o compatĆ­veis com a expectativa da empresa. ƀ empresa, cabe a identificaĆ§Ć£o do seu perfil, a fim de alocar vocĆŖ em um projeto e time que explorem suas habilidades.</p> +<p>Ɖ o cenĆ”rio perfeito, pelo menos.</p> +<h2 id="lembre-se-da-nossa-essencia">Lembre-se da Nossa EssĆŖncia</h2> +<p>Independente de como vocĆŖ se posiciona e rotula, dos projetos que trabalha e do caminho que quer seguir, o front-end nĆ£o deixarĆ” de orbitar ao redor da trinca <strong>HTML, CSS</strong> e <strong>JavaScript</strong>.</p> +<p>Enquanto vocĆŖ possuir interesse nessas trĆŖs linguagens, os seus outros interesses apenas moldarĆ£o o seu caminho profissional.</p> +<p>E, temos sorte: na Ć”rea de front-end, a diversidade de caminhos Ć© fantĆ”stica.</p> + + + + + 5 Bibliotecas Essenciais para Desenvolver React Apps + 2016-03-21T23:00:00+00:00 + 2016-03-21T23:00:00+00:00 + + + + + Unknown + + + + + + /blog/5-bibliotecas-essenciais-para-desenvolver-react-apps/ + + <p>O conjunto de ferramentas, boilerplates e bibliotecas disponĆ­veis formam um ecossistema incrĆ­vel em torno do React.</p> +<p>No meio de tudo, existem ferramentas que sĆ£o comuns ā€“ e essenciais ā€“Ā a diversas aplicaƧƵes, independente de suas arquiteturas. Cito cinco delas.</p> +<h2 id="1-classnames">1. <a href="https://www.npmjs.com/package/classnames">classnames</a></h2> +<p>Muitas vezes, no React, um estado representarĆ” um comportamento visual do componente (ā€œselecionadoā€, ā€œpressionadoā€, ā€œfocadoā€), normalmente associado a uma classe CSS.</p> +<p>Um botĆ£o e seus estados <em>disabled</em> e <em>hovered</em>, por exemplo, ficariam assim:</p> +<pre data-lang="tsx" style="background-color:#282a36;color:#f8f8f2;" class="language-tsx "><code class="language-tsx" data-lang="tsx"><span>&lt;</span><span style="color:#ff79c6;">button +</span><span> </span><span style="color:#50fa7b;">type</span><span style="color:#ff79c6;">=</span><span style="color:#f1fa8c;">&quot;submit&quot; +</span><span> </span><span style="color:#50fa7b;">onMouseOver</span><span style="color:#ff79c6;">={...} +</span><span> </span><span style="color:#50fa7b;">className</span><span style="color:#ff79c6;">={</span><span style="color:#50fa7b;">classNames</span><span>(</span><span style="color:#f1fa8c;">&#39;button&#39;</span><span>, </span><span style="color:#bd93f9;">this</span><span style="color:#ff79c6;">.</span><span style="color:#ffffff;">props</span><span style="color:#ff79c6;">.</span><span>className, { +</span><span> </span><span style="color:#f1fa8c;">&#39;button--disabled&#39;</span><span>: </span><span style="color:#bd93f9;">this</span><span style="color:#ff79c6;">.</span><span style="color:#ffffff;">state</span><span style="color:#ff79c6;">.</span><span style="color:#ffffff;">isDisabled</span><span>, +</span><span> </span><span style="color:#f1fa8c;">&#39;button--hovered&#39;</span><span>: </span><span style="color:#bd93f9;">this</span><span style="color:#ff79c6;">.</span><span style="color:#ffffff;">state</span><span style="color:#ff79c6;">.</span><span style="color:#ffffff;">isHovered +</span><span> })</span><span style="color:#ff79c6;">} +</span><span>/&gt; +</span></code></pre> +<p>Perceba que o Classnames facilita a manipulaĆ§Ć£o condicional de classes com React, removendo vĆ”rios blocos de <code>if</code>/<code>else</code> do seu cĆ³digo.</p> +<h2 id="2-react-router">2. <a href="https://www.npmjs.com/package/react-router">react-router</a></h2> +<p>Se vocĆŖ estĆ” desenvolvendo uma <em>Single-page Application</em>, vocĆŖ precisarĆ” sincronizar a interface do usuĆ”rio com a URL.</p> +<p>O React Router Ć© a melhor soluĆ§Ć£o de rotas para aplicaƧƵes desenvolvidas com React, e isso se deve bastante a sua API declarativa e pensada para componentes.</p> +<p>Considere a seguinte configuraĆ§Ć£o de rotas:</p> +<pre data-lang="tsx" style="background-color:#282a36;color:#f8f8f2;" class="language-tsx "><code class="language-tsx" data-lang="tsx"><span style="color:#ff79c6;">import </span><span style="color:#ffffff;">React </span><span style="color:#ff79c6;">from </span><span style="color:#f1fa8c;">&quot;react&quot;</span><span>; +</span><span style="color:#ff79c6;">import </span><span>{ </span><span style="color:#ffffff;">render </span><span>} </span><span style="color:#ff79c6;">from </span><span style="color:#f1fa8c;">&quot;react-dom&quot;</span><span>; +</span><span style="color:#ff79c6;">import </span><span>{ </span><span style="color:#ffffff;">Router</span><span>, </span><span style="color:#ffffff;">Route</span><span>, </span><span style="color:#ffffff;">browserHistory </span><span>} </span><span style="color:#ff79c6;">from </span><span style="color:#f1fa8c;">&quot;react-router&quot;</span><span>; +</span><span> +</span><span style="color:#ff79c6;">import </span><span style="color:#ffffff;">App </span><span style="color:#ff79c6;">from </span><span style="color:#f1fa8c;">&quot;components/App&quot;</span><span>; +</span><span style="color:#ff79c6;">import </span><span style="color:#ffffff;">Homepage </span><span style="color:#ff79c6;">from </span><span style="color:#f1fa8c;">&quot;screens/Homepage&quot;</span><span>; +</span><span style="color:#ff79c6;">import </span><span style="color:#ffffff;">About </span><span style="color:#ff79c6;">from </span><span style="color:#f1fa8c;">&quot;screens/About&quot;</span><span>; +</span><span style="color:#ff79c6;">import </span><span style="color:#ffffff;">Contact </span><span style="color:#ff79c6;">from </span><span style="color:#f1fa8c;">&quot;screens/Contact&quot;</span><span>; +</span><span> +</span><span style="color:#50fa7b;">render</span><span>( +</span><span> &lt;</span><span style="font-style:italic;color:#66d9ef;">Router </span><span style="color:#50fa7b;">history</span><span style="color:#ff79c6;">={</span><span style="color:#ffffff;">browserHistory</span><span style="color:#ff79c6;">}</span><span>&gt; +</span><span> &lt;</span><span style="font-style:italic;color:#66d9ef;">Route </span><span style="color:#50fa7b;">path</span><span style="color:#ff79c6;">=</span><span style="color:#f1fa8c;">&quot;/&quot; </span><span style="color:#50fa7b;">component</span><span style="color:#ff79c6;">={</span><span style="color:#ffffff;">App</span><span style="color:#ff79c6;">}</span><span>&gt; +</span><span> &lt;</span><span style="font-style:italic;color:#66d9ef;">IndexRoute </span><span style="color:#50fa7b;">component</span><span style="color:#ff79c6;">={</span><span style="color:#ffffff;">Homepage</span><span style="color:#ff79c6;">} </span><span>/&gt; +</span><span> &lt;</span><span style="font-style:italic;color:#66d9ef;">Route </span><span style="color:#50fa7b;">path</span><span style="color:#ff79c6;">=</span><span style="color:#f1fa8c;">&quot;about&quot; </span><span style="color:#50fa7b;">component</span><span style="color:#ff79c6;">={</span><span style="color:#ffffff;">About</span><span style="color:#ff79c6;">} </span><span>/&gt; +</span><span> &lt;</span><span style="font-style:italic;color:#66d9ef;">Route </span><span style="color:#50fa7b;">path</span><span style="color:#ff79c6;">=</span><span style="color:#f1fa8c;">&quot;contact&quot; </span><span style="color:#50fa7b;">component</span><span style="color:#ff79c6;">={</span><span style="color:#ffffff;">Contact</span><span style="color:#ff79c6;">} </span><span>/&gt; +</span><span> &lt;/</span><span style="font-style:italic;color:#66d9ef;">Route</span><span>&gt; +</span><span> &lt;/</span><span style="font-style:italic;color:#66d9ef;">Router</span><span>&gt;, +</span><span> document</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">getElementById</span><span>(</span><span style="color:#f1fa8c;">&quot;react-root&quot;</span><span>) +</span><span>); +</span></code></pre> +<p>Perceba que hĆ” uma instĆ¢ncia inicial da rota e outras rotas aninhadas, formando uma hierarquia. Essa hierarquia Ć© a essĆŖncia do React Router.</p> +<p>Considere que temos um App (<code>App.js</code>):</p> +<pre data-lang="tsx" style="background-color:#282a36;color:#f8f8f2;" class="language-tsx "><code class="language-tsx" data-lang="tsx"><span style="color:#ff79c6;">import </span><span style="color:#ffffff;">React</span><span>, { </span><span style="color:#ffffff;">Component </span><span>} </span><span style="color:#ff79c6;">from </span><span style="color:#f1fa8c;">&#39;react&#39; +</span><span style="color:#ff79c6;">import </span><span>{ </span><span style="color:#ffffff;">IndexLink</span><span>, </span><span style="color:#ffffff;">Link </span><span>} </span><span style="color:#ff79c6;">from </span><span style="color:#f1fa8c;">&#39;react-router&#39; +</span><span> +</span><span style="font-style:italic;color:#ff79c6;">class </span><span>App </span><span style="color:#ff79c6;">extends </span><span style="text-decoration:underline;font-style:italic;color:#8be9fd;">Component </span><span>{ +</span><span> </span><span style="color:#50fa7b;">render</span><span>() { +</span><span> </span><span style="color:#ff79c6;">return </span><span>( +</span><span> &lt;</span><span style="color:#ff79c6;">div</span><span>&gt; +</span><span> &lt;</span><span style="color:#ff79c6;">nav</span><span>&gt; +</span><span> &lt;</span><span style="font-style:italic;color:#66d9ef;">IndexLink </span><span style="color:#50fa7b;">to</span><span style="color:#ff79c6;">=</span><span style="color:#f1fa8c;">&quot;/&quot;</span><span>&gt;Homepage&lt;/</span><span style="color:#ff79c6;">li</span><span>&gt; +</span><span> &lt;</span><span style="font-style:italic;color:#66d9ef;">Link </span><span style="color:#50fa7b;">to</span><span style="color:#ff79c6;">=</span><span style="color:#f1fa8c;">&quot;/about&quot;</span><span>&gt;About&lt;/</span><span style="font-style:italic;color:#66d9ef;">Link</span><span>&gt; +</span><span> &lt;</span><span style="font-style:italic;color:#66d9ef;">Link </span><span style="color:#50fa7b;">to</span><span style="color:#ff79c6;">=</span><span style="color:#f1fa8c;">&quot;/contact&quot;</span><span>&gt;Contact&lt;/</span><span style="font-style:italic;color:#66d9ef;">Link</span><span>&gt; +</span><span> &lt;/</span><span style="color:#ff79c6;">nav</span><span>&gt; +</span><span> +</span><span> &lt;</span><span style="color:#ff79c6;">div</span><span>&gt; +</span><span> </span><span style="color:#ff79c6;">{</span><span style="color:#bd93f9;">this</span><span style="color:#ff79c6;">.</span><span style="color:#ffffff;">props</span><span style="color:#ff79c6;">.</span><span style="color:#ffffff;">children</span><span style="color:#ff79c6;">} +</span><span> &lt;/</span><span style="color:#ff79c6;">div</span><span>&gt; +</span><span> &lt;/</span><span style="color:#ff79c6;">div</span><span>&gt; +</span><span> ) +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#ff79c6;">export default </span><span style="color:#ffffff;">App +</span></code></pre> +<p class="note"> +<p><strong>Dica</strong>: O componente acima nĆ£o tem um estado prĆ³prio, portanto, ele Ć© um <em>Pure Component</em> (ou <em>Dumb Component</em>). Componentes sob estas condiƧƵes podem ā€“ e devem ā€“Ā ser transformados em <em>Stateless Functional Components</em>. ^[Sugiro a leitura de <a href="https://medium.com/@joshblack/stateless-components-in-react-0-14-f9798f8b992d">Functional Stateless Components in React 0.14</a>]</p> +</p> +<p>Uma explicaĆ§Ć£o rĆ”pida: Todas as subrotas da rota do componente <code>App</code> (os <code>&lt;Route&gt;</code> dentro de <code>&lt;Route&gt;</code>) terĆ£o seus componentes transferidos como props para o componente <code>App</code> (e por isso o <code>this.props.children</code>) ao entrar na rota atravĆ©s do <code>&lt;Link&gt;</code>.</p> +<p>A <a href="https://github.com/reactjs/react-router/tree/1.0.x/docs">documentaĆ§Ć£o do React Router</a> dispensa quaisquer outras explicaƧƵes!</p> +<h2 id="3-react-helmet">3. <a href="https://www.npmjs.com/package/react-helmet">react-helmet</a></h2> +<p>Dificilmente vocĆŖ usarĆ” o React Router sem o Helmet. O Helmet te dĆ”, no prĆ³prio componente, o controle do <code>head</code> do documento.</p> +<p>Um caso de uso simples Ć© alterar o tĆ­tulo do documento, Ćŗtil quando a aplicaĆ§Ć£o entra em uma nova rota:</p> +<pre data-lang="tsx" style="background-color:#282a36;color:#f8f8f2;" class="language-tsx "><code class="language-tsx" data-lang="tsx"><span>&lt;</span><span style="font-style:italic;color:#66d9ef;">Helmet </span><span style="color:#50fa7b;">title</span><span style="color:#ff79c6;">=</span><span style="color:#f1fa8c;">&quot;Carrinho de Compras&quot; </span><span>/&gt; +</span></code></pre> +<h2 id="4-jsx-control-statements">4. <a href="https://www.npmjs.com/package/jsx-control-statements">jsx-control-statements</a></h2> +<p>JSX facilita a escrita da marcaĆ§Ć£o do componente e torna seu cĆ³digo mais fĆ”cil de ler e entender. Mas e quando a renderizaĆ§Ć£o do componente Ć© condicional? E quando renderizamos componentes dinamicamente?</p> +<p>Seu cĆ³digo termina provavelmente assim:</p> +<pre data-lang="tsx" style="background-color:#282a36;color:#f8f8f2;" class="language-tsx "><code class="language-tsx" data-lang="tsx"><span>&lt;</span><span style="color:#ff79c6;">div</span><span>&gt; +</span><span> </span><span style="color:#ff79c6;">{</span><span style="color:#ffffff;">todos</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">map</span><span>(</span><span style="font-style:italic;color:#8be9fd;">function </span><span>(</span><span style="font-style:italic;color:#ffb86c;">todo</span><span>, </span><span style="font-style:italic;color:#ffb86c;">index</span><span>) { +</span><span> </span><span style="color:#ff79c6;">return </span><span>&lt;</span><span style="font-style:italic;color:#66d9ef;">TodoItem </span><span style="color:#50fa7b;">data</span><span style="color:#ff79c6;">={</span><span style="color:#ffffff;">todo</span><span style="color:#ff79c6;">} </span><span style="color:#50fa7b;">key</span><span style="color:#ff79c6;">={</span><span style="color:#ffffff;">index</span><span style="color:#ff79c6;">} </span><span>/&gt;; +</span><span> })</span><span style="color:#ff79c6;">} +</span><span>&lt;/</span><span style="color:#ff79c6;">div</span><span>&gt; +</span></code></pre> +<p>E assim:</p> +<pre data-lang="tsx" style="background-color:#282a36;color:#f8f8f2;" class="language-tsx "><code class="language-tsx" data-lang="tsx"><span>&lt;</span><span style="color:#ff79c6;">div</span><span>&gt;</span><span style="color:#ff79c6;">{</span><span style="color:#ffffff;">condition </span><span style="color:#ff79c6;">&amp;&amp; </span><span>&lt;</span><span style="color:#ff79c6;">span</span><span>&gt;&lt;/</span><span style="color:#ff79c6;">span</span><span>&gt;</span><span style="color:#ff79c6;">}</span><span>&lt;/</span><span style="color:#ff79c6;">div</span><span>&gt; +</span></code></pre> +<p>Ou de uma das vĆ”rias outras formas: condicionais inline, operaƧƵes ternĆ”rias, funƧƵes para renderizar componentes condicionalmenteā€¦ PrĆ”ticas que, em grande escala, podem prejudicar a legibilidade do cĆ³digo. E Ć© na <strong>legibilidade</strong> que o jsx-control-statements vence.</p> +<p>O primeiro exemplo, por exemplo, ficaria assim:</p> +<pre data-lang="tsx" style="background-color:#282a36;color:#f8f8f2;" class="language-tsx "><code class="language-tsx" data-lang="tsx"><span>&lt;</span><span style="color:#ff79c6;">div</span><span>&gt; +</span><span> &lt;</span><span style="font-style:italic;color:#66d9ef;">For </span><span style="color:#50fa7b;">each</span><span style="color:#ff79c6;">=</span><span style="color:#f1fa8c;">&quot;todo&quot; </span><span style="color:#50fa7b;">index</span><span style="color:#ff79c6;">=</span><span style="color:#f1fa8c;">&quot;index&quot; </span><span style="color:#50fa7b;">of</span><span style="color:#ff79c6;">={</span><span style="color:#ffffff;">todos</span><span style="color:#ff79c6;">}</span><span>&gt; +</span><span> &lt;</span><span style="font-style:italic;color:#66d9ef;">TodoItem </span><span style="color:#50fa7b;">data</span><span style="color:#ff79c6;">={</span><span style="color:#ffffff;">todo</span><span style="color:#ff79c6;">} </span><span style="color:#50fa7b;">key</span><span style="color:#ff79c6;">={</span><span style="color:#ffffff;">index</span><span style="color:#ff79c6;">} </span><span>/&gt; +</span><span> &lt;/</span><span style="font-style:italic;color:#66d9ef;">For</span><span>&gt; +</span><span>&lt;/</span><span style="color:#ff79c6;">div</span><span>&gt; +</span></code></pre> +<h2 id="5-axios-ou-fetch-api">5. <a href="https://www.npmjs.com/package/axios">axios</a> ou Fetch API</h2> +<p>NĆ£o Ć© uma dependĆŖncia apenas de aplicaƧƵes React, mas vocĆŖ provavelmente vai precisar de um cliente HTTP. (<strong>Um cliente HTTP de gente adulta</strong>, que nĆ£o Ć© o <code>$.ajax</code>.) Existem duas Ć³timas opƧƵes: <a href="https://www.npmjs.com/package/axios">axios</a> e o fetch (ā€œ<a href="https://fetch.spec.whatwg.org/">WHATWG Fetch API</a>ā€).</p> +<h3 id="axios">axios</h3> +<p>Uma biblioteca maravilhosa.</p> +<p>A API do axios Ć© completa: tĆŖm interceptadores de requisiĆ§Ć£o, mĆŗltiplas requisiƧƵes em paraleloā€¦ E suas requisiƧƵes retornam lindas promises.</p> +<p>Fazendo uma requisiĆ§Ć£o <code>POST</code>:</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="color:#ff79c6;">import </span><span style="color:#ffffff;">axios </span><span style="color:#ff79c6;">from </span><span style="color:#f1fa8c;">&quot;axios&quot;</span><span>; +</span><span> +</span><span style="color:#ffffff;">axios +</span><span> </span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">post</span><span>( +</span><span> </span><span style="color:#f1fa8c;">&quot;/api/pets&quot;</span><span>, +</span><span> { name: </span><span style="color:#f1fa8c;">&quot;Bard&quot;</span><span>, cat: </span><span style="color:#bd93f9;">false </span><span>}, +</span><span> { headers: { </span><span style="color:#f1fa8c;">&quot;X-Custom-Header&quot;</span><span>: </span><span style="color:#f1fa8c;">&quot;foobar&quot; </span><span>} } +</span><span> ) +</span><span> </span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">then</span><span>(() </span><span style="font-style:italic;color:#8be9fd;">=&gt; </span><span style="font-style:italic;color:#66d9ef;">console</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">log</span><span>(</span><span style="color:#f1fa8c;">&quot;Pet salvo com sucesso!&quot;</span><span>)) +</span><span> </span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">catch</span><span>((</span><span style="font-style:italic;color:#ffb86c;">response</span><span>) </span><span style="font-style:italic;color:#8be9fd;">=&gt; </span><span style="font-style:italic;color:#66d9ef;">console</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">log</span><span>(</span><span style="color:#ffffff;">response</span><span>)); +</span></code></pre> +<h3 id="fetch-api">Fetch API</h3> +<p>O fetch, por outro lado, jĆ” Ć© um <em><a href="https://fetch.spec.whatwg.org/">living standard</a></em>, e, nesse momento, tem suporte bĆ”sico nos navegadores Firefox, Chrome e Opera. Ɖ recomendado, no entanto, o uso de um <a href="https://www.npmjs.com/package/isomorphic-fetch">polyfill</a>, por ser uma tecnologia ainda experimental.</p> +<p>A mesma requisiĆ§Ć£o <code>POST</code> ficaria assim:</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="color:#50fa7b;">fetch</span><span>(</span><span style="color:#f1fa8c;">&quot;/api/pets&quot;</span><span>, { +</span><span> method: </span><span style="color:#f1fa8c;">&quot;post&quot;</span><span>, +</span><span> headers: { </span><span style="color:#f1fa8c;">&quot;X-Custom-Header&quot;</span><span>: </span><span style="color:#f1fa8c;">&quot;foobar&quot; </span><span>}, +</span><span> body: { name: </span><span style="color:#f1fa8c;">&quot;Bard&quot;</span><span>, cat: </span><span style="color:#bd93f9;">false </span><span>}, +</span><span>}) +</span><span> </span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">then</span><span>(() </span><span style="font-style:italic;color:#8be9fd;">=&gt; </span><span style="font-style:italic;color:#66d9ef;">console</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">log</span><span>(</span><span style="color:#f1fa8c;">&quot;Pet salvo com sucesso!&quot;</span><span>)) +</span><span> </span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">catch</span><span>((</span><span style="font-style:italic;color:#ffb86c;">response</span><span>) </span><span style="font-style:italic;color:#8be9fd;">=&gt; </span><span style="font-style:italic;color:#66d9ef;">console</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">log</span><span>(</span><span style="color:#ffffff;">response</span><span>)); +</span></code></pre> +<p class="note"> +<p>VocĆŖ pode saber mais sobre o Fetch API no <a href="https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API">Mozilla Developer Network</a>.</p> +</p> +<h2 id="consideracoes">ConsideraƧƵes</h2> +<p>Embora eu tenha citado apenas cinco, existem diversas bibliotecas e componentes que descomplicam o processo de desenvolvimento de uma aplicaĆ§Ć£o com React. Sem dĆŗvidas, Ć© um dos ecossistemas mais relevantes que front-end jĆ” teve.</p> +<p>Destaco que nĆ£o cobri um tĆ³pico que, quando se trata de React, Ć© bastante pertinente: formulĆ”rios. <strong>Lidar com formulĆ”rios no React Ć© complicado.</strong> Nesse primeiro momento, resolvi deixar o tema de lado para nĆ£o fugir da proposta do artigo.</p> + + + + + O Til no JavaScript + 2015-10-31T00:00:00+00:00 + 2015-10-31T00:00:00+00:00 + + + + + Unknown + + + + + + /blog/o-til-no-javascript/ + + <p class="summary"> +<p>Incompreendido, o operador til (<code>~</code>) Ć© um mistĆ©rio que ninguĆ©m discute. Primeiro, pois Ć© um operador bitwise, e, segundo, pois seus casos de uso sĆ£o bastante misteriososā€¦</p> +</p> +<h2 id="voce-consegue-dizer">VocĆŖ consegue dizerā€¦</h2> +<p>em <strong>valor</strong> e <strong>tipo de dado</strong>, o que serĆ” impresso no console nas situaƧƵes abaixo?</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="font-style:italic;color:#66d9ef;">console</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">log</span><span>(</span><span style="color:#ff79c6;">~~</span><span style="color:#f1fa8c;">&quot;1&quot;</span><span>); +</span><span style="font-style:italic;color:#66d9ef;">console</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">log</span><span>(</span><span style="color:#ff79c6;">~</span><span style="color:#bd93f9;">8.2</span><span>); +</span><span style="font-style:italic;color:#66d9ef;">console</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">log</span><span>(</span><span style="color:#ff79c6;">~</span><span style="color:#bd93f9;">false</span><span>); +</span><span style="font-style:italic;color:#66d9ef;">console</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">log</span><span>(</span><span style="color:#ff79c6;">~~</span><span style="color:#f1fa8c;">&quot;5.9&quot;</span><span>); +</span><span style="font-style:italic;color:#66d9ef;">console</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">log</span><span>(</span><span style="color:#ff79c6;">~~</span><span>{}); +</span><span style="font-style:italic;color:#66d9ef;">console</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">log</span><span>(</span><span style="color:#ff79c6;">~~-</span><span style="color:#bd93f9;">5.5</span><span>); +</span><span style="font-style:italic;color:#66d9ef;">console</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">log</span><span>(</span><span style="color:#ff79c6;">~</span><span style="color:#f1fa8c;">&quot;Tudo bem?&quot;</span><span>); +</span></code></pre> +<p>NĆ£o sabe? <em>Wellā€¦</em></p> +<h2 id="o-operador-til">O operador til</h2> +<p>Ou melhor, o operador <em>bitwise NOT</em>.</p> +<p>Ɖ importante falar isso pois Ć© importante entender o que <em>bitwise</em> significa. Operadores bitwise sĆ£o especiais em JavaScript: eles tratam todos seus operandos como uma sequĆŖncia de 32 bits (0 e 1) ā€“ ou seja, trabalham com <strong>representaƧƵes binĆ”rias</strong> (nĆ£o decimais, como de praxe) de nossos operandos, e nos entregam valores nĆŗmericos como se nada tivesse acontecido.</p> +<p>O <em>NOT</em> significa que todos os bits do operando serĆ£o invertidos (0 vira 1, 1 vira 0). Parece inĆŗtil quando nĆ£o estamos trabalhando com nĆŗmeros binĆ”rios, mas as aplicaƧƵes criativas tornam o operador mais interessante.</p> +<h3 id="regras-do">Regras do <code>~</code></h3> +<ol> +<li>Quando a expressĆ£o Ć© <code>null</code> ou <code>undefined</code>ā€¦ 0.</li> +<li>Objetos sĆ£o convertidos para strings.</li> +<li>Strings sĆ£o convertidas para nĆŗmeros, se possĆ­vel. Quando nĆ£o Ć© possĆ­velā€¦ 0.</li> +<li>Valores booleanos sĆ£o tratados como nĆŗmeros (0 para <code>false</code>, 1 para <code>true</code>).</li> +<li><em>Floating-points</em> sĆ£o convertidos excluindo a parte fracionada.</li> +<li>Todo nĆŗmero inteiro <em>n</em> Ć© convertido para -(n + 1).</li> +</ol> +<p>As duas Ćŗltimas regras sĆ£o as mais importantes, pois elas implicam nas principais aplicaƧƵes do operador. JĆ” temos a resposta de alguns:</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="font-style:italic;color:#66d9ef;">console</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">log</span><span>(</span><span style="color:#ff79c6;">~</span><span style="color:#bd93f9;">8.2</span><span>); </span><span style="color:#6272a4;">// =&gt; -9 +</span><span style="font-style:italic;color:#66d9ef;">console</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">log</span><span>(</span><span style="color:#ff79c6;">~</span><span style="color:#bd93f9;">false</span><span>); </span><span style="color:#6272a4;">// =&gt; -1 +</span><span style="font-style:italic;color:#66d9ef;">console</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">log</span><span>(</span><span style="color:#ff79c6;">~</span><span style="color:#f1fa8c;">&quot;Tudo bem?&quot;</span><span>); </span><span style="color:#6272a4;">// =&gt; -1 +</span></code></pre> +<p class="note"> +<p>Os nĆŗmeros foram convertidos de acordo com a fĆ³rmula -(n + 1). -9 Ć© resultado de - 8 - 1, por exemplo.</p> +</p> +<h3 id="dupla-negacao">Dupla negaĆ§Ć£o</h3> +<p>Podemos usar dois operadores til (<em>double bitwise NOT</em>). Aqui, basta entender o trabalho do outro til: reinverter os bits.</p> +<p>Considerando <code>~n</code>, como anteriormente, temos -(n + 1) = <strong>- n - 1</strong>. Considerando <code>~~n</code>, temos -[-(n + 1)] = <strong>n + 1</strong>.</p> +<p>Perceba que as equaƧƵes, quando somadas, se anulam. Pois essa Ć© a grande sacada de usar dois operadores til! Temos, entĆ£o:</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="font-style:italic;color:#66d9ef;">console</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">log</span><span>(</span><span style="color:#ff79c6;">~~</span><span style="color:#f1fa8c;">&quot;1&quot;</span><span>); </span><span style="color:#6272a4;">// =&gt; 1 +</span><span style="font-style:italic;color:#66d9ef;">console</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">log</span><span>(</span><span style="color:#ff79c6;">~~</span><span style="color:#f1fa8c;">&quot;5.9&quot;</span><span>); </span><span style="color:#6272a4;">// =&gt; 5 +</span><span style="font-style:italic;color:#66d9ef;">console</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">log</span><span>(</span><span style="color:#ff79c6;">~~</span><span>{}); </span><span style="color:#6272a4;">// =&gt; 0 +</span><span style="font-style:italic;color:#66d9ef;">console</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">log</span><span>(</span><span style="color:#ff79c6;">~~-</span><span style="color:#bd93f9;">5.5</span><span>); </span><span style="color:#6272a4;">// =&gt; -5 +</span></code></pre> +<h2 id="aplicacoes">AplicaƧƵes</h2> +<h3 id="truncar-numeros">Truncar nĆŗmeros</h3> +<p>Pelo fato do operador converter removendo a parte fracionada, utilizĆ”-lo para truncar nĆŗmeros de forma fĆ”cil Ć© a aplicaĆ§Ć£o mais comum:</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="font-style:italic;color:#8be9fd;">let </span><span style="color:#ffffff;">data </span><span style="color:#ff79c6;">= </span><span style="color:#bd93f9;">7.8926152</span><span>; +</span><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">integer </span><span style="color:#ff79c6;">= ~~</span><span style="color:#ffffff;">data</span><span>; +</span><span> +</span><span style="font-style:italic;color:#66d9ef;">console</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">log</span><span>(</span><span style="color:#ffffff;">integer</span><span>); </span><span style="color:#6272a4;">// =&gt; 7 +</span></code></pre> +<p class="note"> +<p>Embora o <code>~~</code> tenha sido, por muito tempo, usado no lugar de <code>Math.floor()</code>, o mĆ©todo mais parecido com ele que temos em JavaScript hoje Ć© o <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/trunc"><code>Math.trunc()</code></a> do ES2015.</p> +</p> +<h3 id="converter-string-para-numero">Converter string para nĆŗmero</h3> +<p>Uma aplicaĆ§Ć£o simples que se baseia em uma das regras de funcionamento do til: converter strings para nĆŗmeros sempre que possĆ­vel; afinal, Ć© com nĆŗmeros que o operador trabalha.</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="font-style:italic;color:#8be9fd;">let </span><span style="color:#ffffff;">data </span><span style="color:#ff79c6;">= </span><span style="color:#f1fa8c;">&quot;2&quot;</span><span>; +</span><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">dataAsNumber </span><span style="color:#ff79c6;">= ~~</span><span style="color:#ffffff;">data</span><span>; +</span><span> +</span><span style="font-style:italic;color:#66d9ef;">console</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">log</span><span>(</span><span style="color:#ffffff;">dataAsNumber</span><span>); </span><span style="color:#6272a4;">// =&gt; 2 +</span></code></pre> +<h3 id="verificar-a-existencia-de-um-item-no-array">Verificar a existĆŖncia de um item no array</h3> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="font-style:italic;color:#8be9fd;">let </span><span style="color:#ffffff;">women </span><span style="color:#ff79c6;">= </span><span>[</span><span style="color:#f1fa8c;">&quot;Ada Lovelace&quot;</span><span>, </span><span style="color:#f1fa8c;">&quot;Joan of Arc&quot;</span><span>, </span><span style="color:#f1fa8c;">&quot;Marie Curie&quot;</span><span>]; +</span><span> +</span><span style="color:#ff79c6;">if </span><span>(</span><span style="color:#ff79c6;">~</span><span style="color:#ffffff;">women</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">indexOf</span><span>(</span><span style="color:#f1fa8c;">&quot;Ada Lovelace&quot;</span><span>)) { +</span><span> </span><span style="font-style:italic;color:#66d9ef;">console</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">log</span><span>(</span><span style="color:#f1fa8c;">&quot;Ada Lovelace was such an important woman!&quot;</span><span>); +</span><span>} +</span></code></pre> +<p>Ɖ difĆ­cil de compreender humanamente que o <code>if</code> estĆ” verificando se Ada Lovelace estĆ” incluĆ­da no array <code>women</code>, mas Ć© exatamente isso que estĆ” acontecendo. VocĆŖ entendeu a razĆ£o pela qual isso funciona?</p> +<p class="note"> +<p>PoderĆ­amos verificar sem o <code>~</code>, mas nĆ£o funcionaria em casos em que o item do array Ć© o primeiro (Ć­ndice zero, e 0 retorna <code>false</code> como booleano). O operador til viabiliza essa verificaĆ§Ć£o, em razĆ£o da conversĆ£o de um nĆŗmero inteiro <em>n</em> para -(n + 1).</p> +</p> +<p>O equivalente humano, utilizando <a href="https://lodash.com/">Lodash</a> (<code>_</code>), seria:</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="font-style:italic;color:#8be9fd;">let </span><span style="color:#ffffff;">women </span><span style="color:#ff79c6;">= </span><span>[</span><span style="color:#f1fa8c;">&quot;Ada Lovelace&quot;</span><span>, </span><span style="color:#f1fa8c;">&quot;Joan of Arc&quot;</span><span>, </span><span style="color:#f1fa8c;">&quot;Marie Curie&quot;</span><span>]; +</span><span> +</span><span style="color:#ff79c6;">if </span><span>(</span><span style="color:#50fa7b;">_</span><span>(</span><span style="color:#ffffff;">women</span><span>)</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">contains</span><span>(</span><span style="color:#f1fa8c;">&quot;Ada Lovelace&quot;</span><span>)) { +</span><span> </span><span style="font-style:italic;color:#66d9ef;">console</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">log</span><span>(</span><span style="color:#f1fa8c;">&quot;Ada Lovelace was such an important woman!&quot;</span><span>); +</span><span>} +</span></code></pre> +<h2 id="performance">Performance</h2> +<p>Usar <code>~~</code> em vez de <code>Math.floor</code> ou <code>Math.trunc</code> Ć© geralmente mais rĆ”pido. Dependendo da <em>JavaScript engine</em> do navegador e do caso de uso, no entanto, pode nĆ£o fazer muita diferenƧa e atĆ© ser mais lento. Veja o <a href="http://jsperf.com/tilde-vs-floor">teste no JSPerf</a>.</p> +<p>De qualquer forma, a pĆ©ssima performance de quem lĆŖ um cĆ³digo com o desumano <code>~</code> pode nĆ£o valer o ganho de performance ā€“ que Ć© ignorĆ”vel de tĆ£o mĆ­nimo ā€“ em uma aplicaĆ§Ć£o.</p> +<h2 id="consideracoes">ConsideraƧƵes</h2> +<p>No geral, operadores bitwise, principalmente <code>~</code>, <code>|</code> e <code>&amp;</code>, possuem aplicaƧƵes interessantes e bastante criativas.</p> +<p>Quanto ao <code>~~</code>, nĆ£o acredito que chegarĆ” a se popularizar como aconteceu com o <code>!!</code>, que converte para um valor booleano. Em anos, a prĆ”tica com til nunca se tornou realmente popular, talvez pelo fato de ser um operador bitwise ā€“ e, portanto, pouco compreendido ā€“ e ter casos de uso bastante excĆŖntricos.</p> +<p>Ficam Ć  tĆ­tulo de curiosidade suas aplicaƧƵes bastante criativas. ;-)</p> + + + + + O Que HĆ” de Errado com a "Cultura jQuery" + 2015-09-20T09:56:05+00:00 + 2015-09-20T09:56:05+00:00 + + + + + Unknown + + + + + + /blog/o-que-ha-de-errado-com-a-cultura-jquery/ + + <p class="summary">Este nĆ£o Ć© um artigo sobre jQuery. Este Ć© um artigo sobre ferramentas, sim, mas Ć©, principalmente, um artigo sobre <b>anĆ”lise</b> e o protagonismo do desenvolvedor front-end nesse processo.</p> +<h2 id="resumo">Resumo</h2> +<p><strong>AplicaƧƵes variam.</strong> Aprenda a definir a arquitetura da sua aplicaĆ§Ć£o. Aprenda a reconhecer a necessidade de uma SPA (<em>Single Page Application</em>).</p> +<p>A ā€œcultura jQueryā€ te afasta de tudo isso, e, portanto, distancia vocĆŖ do seu papel enquanto desenvolvedor front-end.</p> +<hr> +<h2 id="introducao">IntroduĆ§Ć£o</h2> +<p>Se existe uma cultura nas agĆŖncias digitais do Brasil que Ć© unĆ¢nime, Ć© a cultura do jQuery. NĆ£o a cultura de utilizar todo o poder da biblioteca, no entanto, mas o hĆ”bito intrĆ­nseco de importar o <code>jqueryX.X.X.min.js</code> em todo projeto.</p> +<p>(Sim, em 2015.)</p> +<p>Sobre o que hĆ” de errado, serei sucinta, pois, para esse artigo, espero um pĆŗblico-alvo preguiƧoso e acomodado.</p> +<h2 id="o-que-ha-de-errado">O que hĆ” de errado</h2> +<p>ā€¦em usar jQuery em 2015? O que hĆ” de errado em importar jQuery ao iniciar o meu projeto?</p> +<p>Analisando superficialmente, <strong>nada</strong>.</p> +<p>Mas isso tem dado brecha a uma zona de conforto profunda e, na minha experiĆŖncia, com raĆ­zes difĆ­ceis de arrancar. Essa cultura se expande e transcende aquilo que lhe deu origem. Portanto, perceba:</p> +<p><strong>Este nĆ£o Ć© um artigo sobre jQuery.</strong></p> +<p>A comunidade de AngularJS Ć© um exemplo de que isso nĆ£o Ć© sobre jQuery. Muitos migraram dele ao Angular sem abandonar a cultura. O resultado? Bem, muito tem sido dito sobre cĆ³digo Angular legado, que ninguĆ©m quer dar manutenĆ§Ć£o. A escolha errada jĆ” foi feita, e isso Ć© demasiadamente penoso para a manutenĆ§Ć£o de uma aplicaĆ§Ć£o complexa.</p> +<p>O fato Ć© que a <strong>cultura nĆ£o mudou.</strong> Ainda se adota biblioteca ou framework em escala sem pensar duas vezes.</p> +<h2 id="aprendendo-a-evitar">Aprendendo a evitar</h2> +<p><strong>Deve-se saber quando abranger uma visĆ£o holĆ­stica do projeto, e quando separar responsabilidades.</strong></p> +<p>A separaĆ§Ć£o de responsabilidades se daria pela anĆ”lise dos requisitos da aplicaĆ§Ć£o e dos desafios gerados, que trazem consigo o que chamo de ā€œsubproblemasā€ (<em>necessidades que surgem durante a anĆ”lise do desafio</em>), que devem ser solucionados separadamente. A visĆ£o holĆ­stica ajudaria a estruturar os componentes de forma consistente em um sistema, definindo uma arquitetura.</p> +<p>Falando de desenvolvimento front-end moderno (e, portanto, falando de front-end <strong>modular</strong> e de unidades encapsuladas e independentes, os componentes), essa separaĆ§Ć£o de responsabilidades torna-se ainda mais fĆ”cil! Vejamos, abaixo, alguns subproblemas que surgem durante a anĆ”lise de requisitos, apenas para exemplificar o que quero dizer quando trato a decisĆ£o de ferramentas como uma soluĆ§Ć£o para um subproblema.</p> +<p class="note"> +<p>Os exemplos a seguir nĆ£o explicam o front-end modular na prĆ”tica. Adianto, no entanto, ferramentas como <a href="http://browserify.org/">Browserify</a> ou <a href="https://webpack.github.io/">Webpack</a>, que fazem parte do <em>tooling</em> necessĆ”rio.</p> +</p> +<h3 id="1-resiquicoes-ajax">1. ResiquiƧƵes Ajax</h3> +<p><strong>Subproblema</strong>: escrever Ajax em JavaScript Ć© pouco intuitivo, difĆ­cil de ler e escrever.</p> +<p><strong>SoluĆ§Ć£o possĆ­vel</strong>: encapsular, no componente um mĆ³dulo como <a href="https://github.com/ded/reqwest">Reqwest</a> e <a href="https://github.com/jakutis/httpinvoke">httpinvoke</a>. VocĆŖ pode, inclusive, utilizar <em>apenas</em> o Ajax do <a href="https://www.npmjs.com/package/jquery">jQuery</a> (e nĆ£o o jQuery inteiro!).</p> +<h3 id="2-manipulacao-excessiva-do-dom">2. ManipulaĆ§Ć£o excessiva do DOM</h3> +<p><strong>Subproblemas</strong>: manipular DOM com JavaScript pode ser bastante exaustivo. TambĆ©m, manipular em um nĆ­vel excessivo Ć© extremamente custoso para a performance da aplicaĆ§Ć£o.</p> +<p><strong>SoluĆ§Ć£o possĆ­vel</strong>: <a href="https://github.com/Matt-Esch/virtual-dom">Virtual DOM</a>, que estĆ” embutido em bibliotecas como <a href="https://facebook.github.io/react/">React</a> e <a href="https://lhorie.github.io/mithril/">Mithril</a>. Ou, se precisar mesmo do DOM, considere pacotes como <a href="https://github.com/ded/qwery">qwery</a> ou <a href="https://github.com/bevacqua/dominus">Dominus</a>, junto com <a href="https://www.npmjs.com/package/domready">domready</a>.</p> +<p class="note"> +<p>E se precisĆ”ssemos de Ajax no React, por exemplo? <a href="http://facebook.github.io/react/docs/tutorial.html#getting-started">Este mau exemplo</a> na documentaĆ§Ć£o do React importa o jQuery inteiro. Como vocĆŖ faria? ;-)</p> +</p> +<h3 id="sobre-arquitetura">Sobre arquitetura</h3> +<p>Esse tĆ³pico deve ser tratado durante a visĆ£o holĆ­stica do projeto, isso Ć©, da aplicaĆ§Ć£o enquanto sistema de componentes. O <strong>subproblema</strong> seria a necessidade de estrutura que uma aplicaĆ§Ć£o requere.</p> +<p>Para isso, vocĆŖ nĆ£o precisa usar aquilo que Ć© tradicional (diretamente: <strong>vocĆŖ nĆ£o precisa usar MVC</strong>). Existem outras implementaƧƵes de arquiteturas que nĆ£o a implementaĆ§Ć£o feita pelo seu framework amado. Existem outras arquiteturas que nĆ£o <em>Model-View-Controller</em>.</p> +<p>Basicamente? Tenha um conhecimento decente de arquiteturas front-end (sugiro abrir a mente com <a href="https://facebook.github.io/react/blog/2014/05/06/flux.html">Flux</a>, que jĆ” possui bastante materiais e implementaƧƵes da arquitetura disponĆ­veĆ­s), e nĆ£o um conhecimento aprofundado de MVC.</p> +<h2 id="conclusao">ConclusĆ£o</h2> +<p>ConheƧa o projeto e saiba como analisar seus requisitos. O resultado deve ser uma descriĆ§Ć£o explĆ­cita da sua aplicaĆ§Ć£o, com subproblemas jĆ” reconhecidos e, entĆ£o, soluƧƵes possĆ­veis, todas envolvidas por uma soluĆ§Ć£o possĆ­vel maior, que Ć© a da arquitetura (definida durante a anĆ”lise holĆ­stica). Parece chato, mas vira hĆ”bito e acaba funcionando muito bem.</p> +<p><strong>Lembre-se de que existem habilidades que a documentaĆ§Ć£o de uma ferramenta <em>nunca</em>_ te ajudarĆ” a desenvolver.</strong></p> +<p>Com o tempo, vocĆŖ vai saber quando adotar um framework especĆ­fico em escala, quando optar por bibliotecas monolĆ­ticas, e terĆ”, inclusive, seus preferidos a ponto de nĆ£o ter sempre que definir soluƧƵes possĆ­veis para subproblemas que aplicaƧƵes tĆŖm em comum.</p> +<p>(Em alguns projetos, vocĆŖ enxergarĆ” padrƵes, por exemplo: <a href="https://github.com/ded/qwery">qwery</a>, <a href="https://www.npmjs.com/package/domready">domready</a> e <a href="https://www.npmjs.com/package/lodash">lodash</a> sĆ£o usados juntos frequentemente.)</p> +<p>Um dia, no entanto, suas ferramentas falharĆ£o, outras ferramentas se adaptĆ£o melhor Ć  realidade de seus projetos, e, entĆ£o, o ciclo de anĆ”lise recomeƧa. E vocĆŖ jĆ” sabe como proceder.</p> +<h3 id="seja-curioso">Seja curioso</h3> +<p>No mais, seja curioso sobre arquiteturas de software, padrƵes de projeto, <em>tooling</em> ā€” basta ser leitor(a). Seja curioso tambĆ©m sobre opiniƵes, principalmente quando elas tratam de desafios que ainda nĆ£o tivemos. A <strong>visĆ£o crĆ­tica</strong> Ć© ideal para abandonar a cultura jQuery.</p> +<p><strong>O estudo permite que as soluƧƵes possĆ­veis surjam mais intuitivamente.</strong></p> +<p>A prĆ”tica virĆ” com os desafios, e nesses desafios Ć© que deve entrar o seu protagonismo de apresentar soluƧƵes possĆ­veis.</p> +<h2 id="notas">Notas</h2> +<p>Esse Ć© um rascunho de pensamentos que venho acumulando hĆ” algum tempo em razĆ£o de experiĆŖncias de trabalho que tive, e confesso que eles podem ter sido apresentados de forma confusa, embora eu tenha me esforƧado. Mas isso aqui nĆ£o era para ser receita de bolo, de verdade! AtĆ© mesmo os exemplos citados nĆ£o devem passar de exemplos.</p> +<p>A minha abordagem possui falhas, e uma deles Ć© que exige de quem desenvolve um conhecimento vasto de ferramentas, quando se usava apenas uma para tudo. (Para isso, recomendo um recurso disponĆ­vel no <a href="https://www.npmjs.com">npm</a> e mecanismos de busca: a busca.)</p> +<p>Mas perceba que o conhecimento vasto Ć© apenas de ferramentas. O conhecimento exigido pelas ferramentas em si acaba sendo menor do que o exigido por aquelas <em>all-in-one</em> como jQuery e AngularJS. O fato de encapsularmos dependĆŖncias considerando a necessidade de cada componente no front-end Ć© um modo de mantermos a curva de aprendizagem fragmentada.</p> +<p>De acordo com o que venho experimentando, desenvolver essa mentalidade tem retornado experiĆŖncias maravilhosas e, inclusive, gerado menos cĆ³digo legado. Basta apenas aplicĆ”-la Ć  Engenharia de Software com bom senso.</p> +<h2 id="conteudo-sugerido">ConteĆŗdo sugerido</h2> +<p>Os complementos abaixo sĆ£o apenas para despertar a curiosidade em relaĆ§Ć£o aos conceitos apresentados neste artigo, e nĆ£o devem substituir o estudo necessĆ”rio para deixar de lado, na prĆ”tica, a ā€œcultura jQueryā€.</p> +<ul> +<li><a href="https://jsperf.com/virtual-dom-vs-real-dom">JSPerf: Real DOM vs Virtual DOM</a></li> +<li><a href="http://www.ebaytechblog.com/2014/10/02/dont-build-pages-build-modules/">Donā€™t Build Pages, Build Modules</a></li> +<li><a href="http://www.infoq.com/news/2014/05/facebook-mvc-flux">MVC Does Not Scale, Use Flux Instead</a></li> +<li><a href="https://medium.com/@milankinen/good-bye-flux-welcome-bacon-rx-23c71abfb1a7">Goodbye Flux, welcome Bacon/rx?</a></li> +<li>E, humildemente, o meu prĆ³prio blog, pois pretendo falar mais sobre arquiteturas de aplicaĆ§Ć£o e front-end modular (que adoro!) na teoria e prĆ”tica.</li> +</ul> +<hr /> +<p><strong>Se vocĆŖ entendeu a razĆ£o pela qual a ā€œcultura jQueryā€ distancia vocĆŖ do seu papel, a mensagem foi entregue com sucesso.</strong></p> + + + + + A Guide to Favicons and Touch Icons + 2015-09-06T10:53:00+00:00 + 2015-09-06T10:53:00+00:00 + + + + + Unknown + + + + + + /blog/a-guide-to-favicons-and-touch-icons/ + + <div class="summary"> +<p>Favicon is a simplified visual element associated with a particular website, page or event, which you once found only in your browserā€™s address bar or bookmarks. Nowadays, the scenario is different: <strong>they are everywhere</strong>.</p> +</div> +<h2 id="introduction">Introduction</h2> +<p>Favicons provide a important visual indicator to people, and help them to easily associate your content (which can be a <em>website</em>, a <em>particular page</em> or even <em>events</em> like a new message) when browsing.</p> +<p>Formerly, they, also called shortcut icons or bookmark icons, were just tiny pieces of art designed to help users to browse through their tabs or bookmarks. Today, shortcut icons can also provide an app-like link on operational systems (Windows 8, Android, OS X and so on), and should therefore be considered for achieving a pleasant cross-platform experience.</p> +<p>This is a guide for using favicons today, the right way. At the end of this article, Iā€™m sure youā€™ll be excited about SVG favicons.</p> +<!-- If you don't want to understand such a thing, just [jump to the bulletproof solutions](#Bulletproof_favicons). --> +<h2 id="usage">Usage</h2> +<p>Favicons in different dimensions are needed, so devices and browsers can pick the picture that fits best based on <code>sizes</code> attribute (little exception for Mozilla Firefox, which always gets the last favicon declared and scale it if necessary).</p> +<p>The images are not requested when not used. As said, browsers will get only what fits them best, therefore itā€™s important to provide the favicon in the required dimensions to avoid ugly scaled images.</p> +<h3 id="general">General</h3> +<pre data-lang="html" style="background-color:#282a36;color:#f8f8f2;" class="language-html "><code class="language-html" data-lang="html"><span style="color:#6272a4;">&lt;!-- I&#39;m lazy --&gt; +</span><span>&lt;</span><span style="color:#ff79c6;">link </span><span style="color:#50fa7b;">rel</span><span>=</span><span style="color:#f1fa8c;">&quot;icon&quot; </span><span style="color:#50fa7b;">href</span><span>=</span><span style="color:#f1fa8c;">&quot;favicon.png&quot; </span><span>/&gt; +</span><span> +</span><span style="color:#6272a4;">&lt;!-- Browser tabs --&gt; +</span><span>&lt;</span><span style="color:#ff79c6;">link </span><span style="color:#50fa7b;">rel</span><span>=</span><span style="color:#f1fa8c;">&quot;icon&quot; </span><span style="color:#50fa7b;">href</span><span>=</span><span style="color:#f1fa8c;">&quot;favicon-16x16.png&quot; </span><span style="color:#50fa7b;">sizes</span><span>=</span><span style="color:#f1fa8c;">&quot;16x16&quot; </span><span>/&gt; +</span><span> +</span><span style="color:#6272a4;">&lt;!-- Safari on OS X, IE10 Metro --&gt; +</span><span>&lt;</span><span style="color:#ff79c6;">link </span><span style="color:#50fa7b;">rel</span><span>=</span><span style="color:#f1fa8c;">&quot;icon&quot; </span><span style="color:#50fa7b;">href</span><span>=</span><span style="color:#f1fa8c;">&quot;favicon-32x32.png&quot; </span><span style="color:#50fa7b;">sizes</span><span>=</span><span style="color:#f1fa8c;">&quot;32x32&quot; </span><span>/&gt; +</span><span> +</span><span style="color:#6272a4;">&lt;!-- Google TV --&gt; +</span><span>&lt;</span><span style="color:#ff79c6;">link </span><span style="color:#50fa7b;">rel</span><span>=</span><span style="color:#f1fa8c;">&quot;icon&quot; </span><span style="color:#50fa7b;">href</span><span>=</span><span style="color:#f1fa8c;">&quot;favicon-96x96.png&quot; </span><span style="color:#50fa7b;">sizes</span><span>=</span><span style="color:#f1fa8c;">&quot;96x96&quot; </span><span>/&gt; +</span><span> +</span><span style="color:#6272a4;">&lt;!-- Chrome on Android --&gt; +</span><span>&lt;</span><span style="color:#ff79c6;">link </span><span style="color:#50fa7b;">rel</span><span>=</span><span style="color:#f1fa8c;">&quot;icon&quot; </span><span style="color:#50fa7b;">href</span><span>=</span><span style="color:#f1fa8c;">&quot;favicon-192x192.png&quot; </span><span style="color:#50fa7b;">sizes</span><span>=</span><span style="color:#f1fa8c;">&quot;192x192&quot; </span><span>/&gt; +</span></code></pre> +<p class="note"> +<p>No need for <code>type="image/png"</code> when using HTML5.</p> +</p> +<p>Youā€™ll need to provide a manifest in order to Chrome on Androidā€™s icon to work properly. See <a href="https://gist.github.com/diessica/44ddce58c6094ce64d1d"><code>manifest.json</code> example</a>.</p> +<pre data-lang="html" style="background-color:#282a36;color:#f8f8f2;" class="language-html "><code class="language-html" data-lang="html"><span>&lt;</span><span style="color:#ff79c6;">link </span><span style="color:#50fa7b;">rel</span><span>=</span><span style="color:#f1fa8c;">&quot;manifest&quot; </span><span style="color:#50fa7b;">href</span><span>=</span><span style="color:#f1fa8c;">&quot;manifest.json&quot; </span><span>/&gt; +</span></code></pre> +<h4 id="lacking-of-png-support-on-ie-a-workaround">Lacking of PNG support on IE: a workaround</h4> +<p>Internet Explorer until version 11 and Safari donā€™t support PNG favicons. However, you can provide a fallback for IE up to 9:</p> +<pre data-lang="html" style="background-color:#282a36;color:#f8f8f2;" class="language-html "><code class="language-html" data-lang="html"><span style="color:#6272a4;">&lt;!--[if IE]&gt; &lt;link rel=&quot;shortcut icon&quot; href=&quot;favicon.ico&quot; /&gt; &lt;![endif]--&gt; +</span></code></pre> +<p class="note"> +<p>Notice the <code>shortcut</code>, which is a non-standard. Also, providing this fallback within a conditional comment is necessary; otherwise Chrome will use the ICO favicon, even if it supports PNG ones.</p> +</p> +<p><strong>I donā€™t recommend it</strong>, though, because IE 10 doesnā€™t support conditional comments (so it wonā€™t get any favicon, as seen that it doesnā€™t support PNG too), and also because it encourages the use of the non-standard and confusing <code>shortcut</code>.</p> +<p>Luckily, you can workaround everything just placing a <code>favicon.ico</code> in the root directory (the browser will look for it <em>automagically</em>). Then <code>link</code> only the PNG favicon and donā€™t worry.</p> +<h3 id="web-clip-bookmarks">Web Clip bookmarks</h3> +<p>iOS users can add websites to their home screen ā€“Ā shortcuts called ā€œWeb Clip bookmarksā€. The default icon is a thumbnail screenshot of the page, but developers can specify one instead.</p> +<p>You will need to provide a lot of dimensions in order to support both new devices and older (iOS6 and prior), however.</p> +<p>Thereā€™s a no-HTML way and a HTML way to provide those icons. Itā€™s up to you.</p> +<h4 id="no-html-touch-icon-file">No-HTML: Touch Icon file</h4> +<p>Add a <code>apple-touch-icon-*.png</code> file, where <code>*</code> is the size to the root directory, instead. iOS Safari will look for the appropriate icon size, and if it doesnā€™t find any that fits best, itā€™ll use <code>apple-touch-icon.png</code>.</p> +<h4 id="link-tags">Link tags</h4> +<p>You can reuse the image of another favicon specifying a <code>href</code> (not possible while using the solution above).</p> +<pre data-lang="html" style="background-color:#282a36;color:#f8f8f2;" class="language-html "><code class="language-html" data-lang="html"><span style="color:#6272a4;">&lt;!-- Non-retina iPhone pre iOS 7 --&gt; +</span><span>&lt;</span><span style="color:#ff79c6;">link </span><span style="color:#50fa7b;">rel</span><span>=</span><span style="color:#f1fa8c;">&quot;apple-touch-icon&quot; </span><span style="color:#50fa7b;">sizes</span><span>=</span><span style="color:#f1fa8c;">&quot;57x57&quot; </span><span style="color:#50fa7b;">href</span><span>=</span><span style="color:#f1fa8c;">&quot;apple-touch-icon-57x57.png&quot; </span><span>/&gt; +</span><span> +</span><span style="color:#6272a4;">&lt;!-- Non-retina iPad pre iOS 7 --&gt; +</span><span>&lt;</span><span style="color:#ff79c6;">link </span><span style="color:#50fa7b;">rel</span><span>=</span><span style="color:#f1fa8c;">&quot;apple-touch-icon&quot; </span><span style="color:#50fa7b;">sizes</span><span>=</span><span style="color:#f1fa8c;">&quot;60x60&quot; </span><span style="color:#50fa7b;">href</span><span>=</span><span style="color:#f1fa8c;">&quot;apple-touch-icon-60x60.png&quot; </span><span>/&gt; +</span><span>&lt;</span><span style="color:#ff79c6;">link </span><span style="color:#50fa7b;">rel</span><span>=</span><span style="color:#f1fa8c;">&quot;apple-touch-icon&quot; </span><span style="color:#50fa7b;">sizes</span><span>=</span><span style="color:#f1fa8c;">&quot;72x72&quot; </span><span style="color:#50fa7b;">href</span><span>=</span><span style="color:#f1fa8c;">&quot;apple-touch-icon-72x72.png&quot; </span><span>/&gt; +</span><span> +</span><span style="color:#6272a4;">&lt;!-- Non-retina iPad iOS 7 --&gt; +</span><span>&lt;</span><span style="color:#ff79c6;">link </span><span style="color:#50fa7b;">rel</span><span>=</span><span style="color:#f1fa8c;">&quot;apple-touch-icon&quot; </span><span style="color:#50fa7b;">sizes</span><span>=</span><span style="color:#f1fa8c;">&quot;76x76&quot; </span><span style="color:#50fa7b;">href</span><span>=</span><span style="color:#f1fa8c;">&quot;apple-touch-icon-76x76.png&quot; </span><span>/&gt; +</span><span> +</span><span style="color:#6272a4;">&lt;!-- Retina iPhone pre iOS 7 --&gt; +</span><span>&lt;</span><span style="color:#ff79c6;">link +</span><span> </span><span style="color:#50fa7b;">rel</span><span>=</span><span style="color:#f1fa8c;">&quot;apple-touch-icon&quot; +</span><span> </span><span style="color:#50fa7b;">sizes</span><span>=</span><span style="color:#f1fa8c;">&quot;114x114&quot; +</span><span> </span><span style="color:#50fa7b;">href</span><span>=</span><span style="color:#f1fa8c;">&quot;apple-touch-icon-114x114.png&quot; +</span><span>/&gt; +</span><span> +</span><span style="color:#6272a4;">&lt;!-- Retina iPhone iOS 7 --&gt; +</span><span>&lt;</span><span style="color:#ff79c6;">link +</span><span> </span><span style="color:#50fa7b;">rel</span><span>=</span><span style="color:#f1fa8c;">&quot;apple-touch-icon&quot; +</span><span> </span><span style="color:#50fa7b;">sizes</span><span>=</span><span style="color:#f1fa8c;">&quot;120x120&quot; +</span><span> </span><span style="color:#50fa7b;">href</span><span>=</span><span style="color:#f1fa8c;">&quot;apple-touch-icon-120x120.png&quot; +</span><span>/&gt; +</span><span> +</span><span style="color:#6272a4;">&lt;!-- Retina iPad pre iOS 7 --&gt; +</span><span>&lt;</span><span style="color:#ff79c6;">link +</span><span> </span><span style="color:#50fa7b;">rel</span><span>=</span><span style="color:#f1fa8c;">&quot;apple-touch-icon&quot; +</span><span> </span><span style="color:#50fa7b;">sizes</span><span>=</span><span style="color:#f1fa8c;">&quot;144x144&quot; +</span><span> </span><span style="color:#50fa7b;">href</span><span>=</span><span style="color:#f1fa8c;">&quot;apple-touch-icon-144x144.png&quot; +</span><span>/&gt; +</span><span> +</span><span style="color:#6272a4;">&lt;!-- Retina iPad iOS 7 --&gt; +</span><span>&lt;</span><span style="color:#ff79c6;">link +</span><span> </span><span style="color:#50fa7b;">rel</span><span>=</span><span style="color:#f1fa8c;">&quot;apple-touch-icon&quot; +</span><span> </span><span style="color:#50fa7b;">sizes</span><span>=</span><span style="color:#f1fa8c;">&quot;152x152&quot; +</span><span> </span><span style="color:#50fa7b;">href</span><span>=</span><span style="color:#f1fa8c;">&quot;apple-touch-icon-152x152.png&quot; +</span><span>/&gt; +</span><span> +</span><span style="color:#6272a4;">&lt;!-- iOS 8 --&gt; +</span><span>&lt;</span><span style="color:#ff79c6;">link +</span><span> </span><span style="color:#50fa7b;">rel</span><span>=</span><span style="color:#f1fa8c;">&quot;apple-touch-icon&quot; +</span><span> </span><span style="color:#50fa7b;">sizes</span><span>=</span><span style="color:#f1fa8c;">&quot;180x180&quot; +</span><span> </span><span style="color:#50fa7b;">href</span><span>=</span><span style="color:#f1fa8c;">&quot;apple-touch-icon-180x180.png&quot; +</span><span>/&gt; +</span></code></pre> +<p class="note"> +<p>Using <code>apple-touch-icon-precomposed</code> instead of <code>apple-touch-icon</code>, which prevents iOS icons defaults like rounded corners and reflective shine, isnā€™t necessary, as seen that there isnā€™t <em>shiny effects</em> on iOS 7 and up anymore.</p> +</p> +<h3 id="windows-tiles">Windows Tiles</h3> +<p>Tiles are icons that appear on the Start screen, linked as apps. By default, the image on the tile is the websiteā€™s favicon or a default IE11 logo.</p> +<p class="note">To cover a wide range of devices, use an image 1.8 times the standard tile size so the image can be scaled up or down as needed.</p> +<p>Thereā€™s a no-HTML way and a HTML way to provide those icons. Itā€™s up to you, again.</p> +<h4 id="no-html-browser-config-file">No-HTML: Browser config file</h4> +<p>Provide a <code>browserconfig.xml</code> file and save it at the root of your server. Internet Explorer 11 will automatically read the file when the user pins the website. See <a href="https://gist.github.com/diessica/73a4d53cd26b4d35f410"><code>browserconfig.xml</code> example</a>.</p> +<h4 id="metadata-tags">Metadata tags</h4> +<p><code>msapplication-TileColor</code> is the background color of the tile, and <code>msapplication-TileImage</code> is the icon, which can be tiny (70 Ɨ 70px), square (150 Ɨ 150px), wide (310 Ɨ 150px) or large (310 Ɨ 310px).</p> +<pre data-lang="html" style="background-color:#282a36;color:#f8f8f2;" class="language-html "><code class="language-html" data-lang="html"><span style="color:#6272a4;">&lt;!-- Windows Tile --&gt; +</span><span>&lt;</span><span style="color:#ff79c6;">meta </span><span style="color:#50fa7b;">name</span><span>=</span><span style="color:#f1fa8c;">&quot;msapplication-TileColor&quot; </span><span style="color:#50fa7b;">content</span><span>=</span><span style="color:#f1fa8c;">&quot;#000&quot; </span><span>/&gt; +</span><span>&lt;</span><span style="color:#ff79c6;">meta </span><span style="color:#50fa7b;">name</span><span>=</span><span style="color:#f1fa8c;">&quot;msapplication-TileImage&quot; </span><span style="color:#50fa7b;">content</span><span>=</span><span style="color:#f1fa8c;">&quot;tile-icon.png&quot; </span><span>/&gt; +</span><span> +</span><span style="color:#6272a4;">&lt;!-- Different Windows Tiles (optional) --&gt; +</span><span>&lt;</span><span style="color:#ff79c6;">meta </span><span style="color:#50fa7b;">name</span><span>=</span><span style="color:#f1fa8c;">&quot;msapplication-square70x70logo&quot; </span><span style="color:#50fa7b;">content</span><span>=</span><span style="color:#f1fa8c;">&quot;tile-icon_tiny.png&quot; </span><span>/&gt; +</span><span>&lt;</span><span style="color:#ff79c6;">meta </span><span style="color:#50fa7b;">name</span><span>=</span><span style="color:#f1fa8c;">&quot;msapplication-square150x150logo&quot; </span><span style="color:#50fa7b;">content</span><span>=</span><span style="color:#f1fa8c;">&quot;tile-icon_square.png&quot; </span><span>/&gt; +</span><span>&lt;</span><span style="color:#ff79c6;">meta </span><span style="color:#50fa7b;">name</span><span>=</span><span style="color:#f1fa8c;">&quot;msapplication-wide310x150logo&quot; </span><span style="color:#50fa7b;">content</span><span>=</span><span style="color:#f1fa8c;">&quot;tile-icon_wide.png&quot; </span><span>/&gt; +</span><span>&lt;</span><span style="color:#ff79c6;">meta </span><span style="color:#50fa7b;">name</span><span>=</span><span style="color:#f1fa8c;">&quot;msapplication-square310x310logo&quot; </span><span style="color:#50fa7b;">content</span><span>=</span><span style="color:#f1fa8c;">&quot;tile-icon_large.png&quot; </span><span>/&gt; +</span></code></pre> +<h2 id="bulletproof-favicons">Bulletproof favicons</h2> +<ul> +<li>For Touch Icons, add <code>apple-touch-icon.png</code> and <code>apple-touch-icon-*.png</code> files, where <code>*</code> is the size, to the root directory.</li> +<li>For IE support, add a <code>favicon.ico</code> file with both 16 Ɨ 16px and 32 Ɨ 32px resources to the root directory.</li> +<li>For Windows Tiles, add a <code>browserconfig.xml</code> to the root directory.</li> +<li>For Chrome on Android icon, add a <code>manifest.json</code> to the root directory.</li> +<li>Add the following HTML to <code>&lt;head&gt;</code>:</li> +</ul> +<pre data-lang="html" style="background-color:#282a36;color:#f8f8f2;" class="language-html "><code class="language-html" data-lang="html"><span style="color:#6272a4;">&lt;!-- Chrome on Android --&gt; +</span><span>&lt;</span><span style="color:#ff79c6;">link </span><span style="color:#50fa7b;">rel</span><span>=</span><span style="color:#f1fa8c;">&quot;icon&quot; </span><span style="color:#50fa7b;">href</span><span>=</span><span style="color:#f1fa8c;">&quot;favicon-192x192.png&quot; </span><span style="color:#50fa7b;">sizes</span><span>=</span><span style="color:#f1fa8c;">&quot;192x192&quot; </span><span>/&gt; +</span><span>&lt;</span><span style="color:#ff79c6;">link </span><span style="color:#50fa7b;">rel</span><span>=</span><span style="color:#f1fa8c;">&quot;manifest&quot; </span><span style="color:#50fa7b;">href</span><span>=</span><span style="color:#f1fa8c;">&quot;manifest.json&quot; </span><span>/&gt; +</span><span> +</span><span style="color:#6272a4;">&lt;!-- Google TV --&gt; +</span><span>&lt;</span><span style="color:#ff79c6;">link </span><span style="color:#50fa7b;">rel</span><span>=</span><span style="color:#f1fa8c;">&quot;icon&quot; </span><span style="color:#50fa7b;">href</span><span>=</span><span style="color:#f1fa8c;">&quot;favicon-96x96.png&quot; </span><span style="color:#50fa7b;">sizes</span><span>=</span><span style="color:#f1fa8c;">&quot;96x96&quot; </span><span>/&gt; +</span><span> +</span><span style="color:#6272a4;">&lt;!-- Safari on OS X, IE10 Metro --&gt; +</span><span>&lt;</span><span style="color:#ff79c6;">link </span><span style="color:#50fa7b;">rel</span><span>=</span><span style="color:#f1fa8c;">&quot;icon&quot; </span><span style="color:#50fa7b;">href</span><span>=</span><span style="color:#f1fa8c;">&quot;favicon-32x32.png&quot; </span><span style="color:#50fa7b;">sizes</span><span>=</span><span style="color:#f1fa8c;">&quot;32x32&quot; </span><span>/&gt; +</span><span> +</span><span style="color:#6272a4;">&lt;!-- Browser tabs --&gt; +</span><span>&lt;</span><span style="color:#ff79c6;">link </span><span style="color:#50fa7b;">rel</span><span>=</span><span style="color:#f1fa8c;">&quot;icon&quot; </span><span style="color:#50fa7b;">href</span><span>=</span><span style="color:#f1fa8c;">&quot;favicon-16x16.png&quot; </span><span style="color:#50fa7b;">sizes</span><span>=</span><span style="color:#f1fa8c;">&quot;16x16&quot; </span><span>/&gt; +</span></code></pre> +<p class="note"> +<p>Order matters here! Mozilla Firefox ignores <code>sizes</code> and always get the last favicon for the browser tabs. :-(</p> +</p> +<p>Or you can add all the favicons through <code>meta</code> and <code>link</code> tags.</p> +<h2 id="favicon-as-svg">Favicon as SVG</h2> +<p class="note"> +<p>Not encouraged as an unique solution, as seen that isnā€™t <a href="http://caniuse.com/#feat=link-icon-svg">widely supported</a> yet.</p> +</p> +<p>Iā€™m excited about this:</p> +<pre data-lang="html" style="background-color:#282a36;color:#f8f8f2;" class="language-html "><code class="language-html" data-lang="html"><span>&lt;</span><span style="color:#ff79c6;">link </span><span style="color:#50fa7b;">rel</span><span>=</span><span style="color:#f1fa8c;">&quot;icon&quot; </span><span style="color:#50fa7b;">href</span><span>=</span><span style="color:#f1fa8c;">&quot;favicon.svg&quot; </span><span style="color:#50fa7b;">sizes</span><span>=</span><span style="color:#f1fa8c;">&quot;any&quot; </span><span style="color:#50fa7b;">type</span><span>=</span><span style="color:#f1fa8c;">&quot;image/svg+xml&quot; </span><span>/&gt; +</span></code></pre> +<h2 id="final-words">Final words</h2> +<p>Iā€™m sure you are now excited about SVG support for favicons. Providing a lot of different images is quite boring.</p> +<p>I encourage you to support favicons everywhere (or at least retina-ready ones), but unfortunately thereā€™s no human-friendly way to do it nowadays. Use <a href="https://www.npmjs.com/package/favicons">favicons package</a> on npm or, if you are not comfortable with the command line, refer to <a href="http://realfavicongenerator.net">RealFaviconGenerator</a>.</p> +<p>Donā€™t be lazy.</p> +<h2 id="references">References</h2> +<ul> +<li><a href="https://developer.android.com/training/tv/index.html#favicons">Android Documentation</a></li> +<li><a href="https://developer.apple.com/library/ios/documentation/AppleApplications/Reference/SafariWebContent/ConfiguringWebApplications/ConfiguringWebApplications.html">Apple Documentation</a></li> +<li><a href="http://realfavicongenerator.net/faq">RealFaviconGenerator FAQ</a></li> +<li><a href="https://mathiasbynens.be/notes/touch-icons">Everything you always wanted to know about touch icons</a></li> +<li><a href="http://caniuse.com/#feat=link-icon-svg">SVG favicons support</a></li> +<li><a href="http://caniuse.com/#feat=link-icon-png">PNG favicons support</a></li> +<li><a href="http://iconhandbook.co.uk/reference/chart/">Icon handbook</a></li> +<li><a href="https://msdn.microsoft.com/en-us/library/dn455106.aspx">Creating custom tiles for IE11 websites</a></li> +</ul> + + + + + Como Eu Vi a BrazilJS 2015 + 2015-08-26T02:10:32+00:00 + 2015-08-26T02:10:32+00:00 + + + + + Unknown + + + + + + /blog/como-eu-vi-a-braziljs-2015/ + + <p>Ɖ mais experiente que volto de mais uma BrazilJS, evento que acontece na cidade onde nasci desde <a href="http://braziljs.com.br/2012">2012</a>. Aqui, compartilho nĆ£o um relatĆ³rio tĆ©cnico das palestras, nĆ£o acusaƧƵes do que foi ruim ou bom, mas minhas visƵes, em conjunto, sobre a conferĆŖncia e a comunidade.</p> +<p>Importante observar que <strong>nĆ£o</strong> seleciono aqui a ā€œnataā€ do evento. NĆ£o Ć© minha intenĆ§Ć£o desmerecer qualquer acontecimento. Meu objetivo com esse texto Ć© somente compartilhar o meu ponto de vista sobre o que penso que deve ser comentado.</p> +<h2 id="o-primeiro-dia">O primeiro dia</h2> +<p>O meu dia comeƧou localizando onde seria o evento. Neste ano, foi no BarraShoppingSul; um shopping que, considerando os outros da cidade, Ć© de difĆ­cil acesso mesmo para quem mora hĆ” alguns quilĆ“metros de Porto Alegre.</p> +<p>O Centro de ConvenƧƵes, ao menos, foi fĆ”cil de achar, e o <em>check-in</em> ocorreu como esperado: pontual. As meninas que forneceram minha credencial estavam de Ć³timo humor ā€” e olha que era um dos primeiros horĆ”rios da manhĆ£ de sexta! Ano passado, o meu <em>check-in</em> foi feito pelo Jaydson, o que fez eu me perguntar onde estaria ele, se nĆ£o credenciando os participantes do evento.</p> +<p>ā€¦E, na verdade, ele tinha se tornado um Power Ranger junto com o Felipe. E Power Rangers nĆ£o fazem <em>check-in</em>. Descobri isso da pior maneira.</p> +<h3 id="uma-abertura-idiota">Uma abertura idiota</h3> +<p>Dois desenvolvedores, os organizadores desse evento que trouxe mais de mil pessoas para o mesmo lugar, brincando de ā€œlutinhaā€ na frente de todo mundo, vestidos de Power Rangers sĆ³ porque o JavaScript fez 20 anos. <strong>Essa foi a abertura da BrazilJS</strong>, e eu nĆ£o mudaria nada.</p> +<p>Muita gente riu. Muita gente aplaudiu. Eu ri e aplaudi, e aplaudiria de novo, pois, sim, brincaram, mas tambĆ©m fizeram um trabalho muito sĆ©rio. Ainda vestidos de Power Rangers, falaram um pouco da histĆ³ria da conferĆŖncia e das expectativas para esse ano, finalizando com uma mensagem sobre a importĆ¢ncia da diversidade e, sobretudo, do respeito.</p> +<p>Os eventos que se seguiram mostraram que, sim, o trabalho era sĆ©rio.</p> +<h3 id="christian-heillman">Christian Heillman</h3> +<blockquote> +<p>We are there for them. Not they for us.</p> +</blockquote> +<p>Com uma camiseta do Brasil, Christian chegou com um dos assuntos mais importantes na atualidade, e que estĆ” dando muito o que falar: <em>pushing the web forward</em>. Palavras de protagonismo, reiteraĆ§Ć£o do <strong>nosso papel</strong>, motivaĆ§Ć£o para acreditar na web e no nosso trabalho, e, o mais importante: como isso deve ser feito. Falou, claro, sobre o ECMAScript 6, sobre o Babel, e fez uma anĆ”lise de como resolvemos os problemas atualmente.</p> +<blockquote> +<p>We all know the DOM is slow, terrible and to blame for all our problems. Did we allot it to say that way and still be a problem as we <strong>abstracted its issues away?</strong></p> +</blockquote> +<p>Acredito que essa essa frase foi pesada para muita gente, principalmente em quem estĆ” deprimido de tanto <em>estudar</em> soluƧƵes. Christian mostra que, ao trabalharmos com web, nĆ£o somos apenas desenvolvedores ou designers (ao menos nĆ£o deverĆ­amos ser). Somos tambĆ©m <strong>web makers</strong>, e esse Ć© o principal problema de simplesmente abstrair e deixar para lĆ”.</p> +<p>Ɖ fĆ”cil entender a razĆ£o dessa abordagem. Heillman trabalha no time de desenvolvimento do Microsoft Edge, o novo e surpreendente navegador padrĆ£o do Windows 10, e esse Ć© o ponto de vista dele enquanto <em>browser maker</em>: somos a representaĆ§Ć£o mĆ”xima do protagonismo, e, por isso, desenvolver nĆ£o deve limitar-se a <em>frameworks</em> ou <em>libraries</em>. Estamos em uma posiĆ§Ć£o em que inovar sempre que possĆ­vel Ć© visto como uma contribuiĆ§Ć£o, e ele ensina a entender esse ponto de vista desde a analogia feita logo nos primeiros slides. NĆ£o devemos esperar que a inovaĆ§Ć£o venha apenas de grandes companhias.</p> +<p>NĆ£o disse para pararmos de usar ES6 com Babel. NĆ£o disse para usarmos ES6 em produĆ§Ć£o e beber Ć”gua de coco na praia. Mas nĆ£o Ć© mentira que existem casos em que podemos, se assim desejarmos, relatar o que estĆ” de errado e o que faz falta, e Ć© justamente aĆ­ que o nosso protagonismo Ć© mĆ”ximo.</p> +<p>Os argumentos foram reĆŗnidos, as situaƧƵes em que podemos nos tornar <em>web makers</em> foram apresentadas, e tudo em prol de provar o nosso protagonismo.</p> +<blockquote> +<p>You are a creator of the next web!</p> +</blockquote> +<p>Sem dĆŗvidas, uma das melhores palestras que jĆ” assisti na minha vida. Ɖ difĆ­cil relatar uma interpretaĆ§Ć£o detalhada sobre a mensagem do Christian, mas, aos que jĆ” se sentiram no dever de fazer a web um lugar melhor alguma vez e nunca deixaram de acreditar nessa mĆ­dia, acho que essas minhas palavras foram mais que o suficiente para compreender o pensamento dele. Simples e sensacional.</p> +<h3 id="use-lowlevel">Use lowlevel</h3> +<p>Tive dificuldades em acompanhar o raciocĆ­nio do Douglas Campos algumas vezes, e noto que isso se deu em razĆ£o de ele nĆ£o estar falando a lĆ­ngua nativa. NĆ£o entro aqui no mĆ©rito das palestras em InglĆŖs ou PortuguĆŖs (para mim tanto faz desde que o palestrante consiga passar a mensagem de forma fluente na lĆ­ngua escolhida), mas reforƧo a importĆ¢ncia de fazer a escolha certa, pois a tua escolha afeta um pĆŗblico que estĆ” confiando na tua capacidade enquanto transmissor.</p> +<p>Douglas falou sobre compiladores, e engajou os desenvolvedores a entender <em>how things work under the hood</em>, explorando conceitos como AST (<em>Abstract Syntax Tree</em>), um assunto que estĆ” finalmente chamando a atenĆ§Ć£o em JavaScript, tanto que nĆ£o foi a primeira vez que foi abordado na BrazilJS.</p> +<p>Acredito que o questionamento que o palestrante buscou provocar no pĆŗblico nĆ£o teve ĆŖxito. Os 30 minutos, infelizmente, nĆ£o foram bem aproveitados e nĆ£o atenderam Ć s perguntas que o Douglas tentou provocar e responder. Ficou a sensaĆ§Ć£o de uma mensagem subentendida, no entanto:</p> +<blockquote> +<p>Itā€™s really important for us to take a look at the things we donā€™t necessarily like.</p> +</blockquote> +<h3 id="javascript-at-spotify">JavaScript at Spotify</h3> +<p>Felipe Ribeiro juntou os desafios encontrados durante a transiĆ§Ć£o do Spotify (nativo com C++ para hĆ­brido), e o resultado foi uma palestra bastante completa sobre arquitetura e engenharia de software. Diversificou bastante a programaĆ§Ć£o da conferĆŖncia, e mostrou que devemos analisar a necessidade de re-escrita de cĆ³digo em uma aplicaĆ§Ć£o complexa sob uma Ć³tica criteriosa que equilibra <strong>utilidade</strong>, <strong>valor</strong> e <strong>esforƧo necessĆ”rio</strong>.</p> +<h4 id="desafios">Desafios</h4> +<p>Os desafios foram bastante interessantes. Um deles foi o <strong>gerenciamento de memĆ³ria</strong> no Spotify, jĆ” que se trata de uma aplicaĆ§Ć£o que nĆ£o Ć© descartada com a mesma frequĆŖncia de um site. Outro, a <strong>organizaĆ§Ć£o do cĆ³digo</strong>, que era excessivamente fragmentado, o que prejudicava a padronizaĆ§Ć£o (diferentes versƵes de mĆ³dulos), manutenĆ§Ć£o (atualizaĆ§Ć£o em ā€œefeito cascataā€) e integraĆ§Ć£o contĆ­nua do projeto.</p> +<h4 id="releases">Releases</h4> +<p>O Spotify estabeleceu uma cultura colaborativa de testes (sempre gostei dessa abordagem!). Os empregados usam somente versƵes experimentais da aplicaĆ§Ć£o, ajudando a testar e agilizar os <em>hotfixes</em>. O release Ć© gradual, e Ć© distribuĆ­do na medida em que a versĆ£o vai apresentando estabilidade aos usuĆ”rios que jĆ” possuem acesso.</p> +<h3 id="a-saga-dos-12-topicos-de-acessibilidade">A saga dos 12 tĆ³picos de acessibilidade</h3> +<p>A primeira vez que conheci o Reinaldo Ferraz foi no Front in POA em 2012. Na Ć©poca, acessibilidade era mais novidade para as pessoas do que Sass. Todos conheciam Sass, ninguĆ©m conhecia WCAG.</p> +<p>Lembro de ter sido uma das palestras mais marcantes e diferentes do evento, e nĆ£o foi diferente na BrazilJS. Esta foi a mensagem que ficou:</p> +<blockquote><p>"Aplicar tĆ©cnicas de acessibilidade em um site com usabilidade ruim Ć© como passar batom em um porco. NĆ£o importa o quanto vocĆŖ passe, ele continuarĆ” sendo um porco."</p><footer>ā€” <cite><a href="http://webaim.org/blog/accessibility-lipstick-on-a-usability-pig/">Acessibility Lipstick on a Usability Pig</a></cite></footer></blockquote> +<h3 id="500-days-of-open-source">500 days of open source</h3> +<p>Uma palestra que dividiu bastante o pĆŗblico. Na verdade, acredito que o Raphael Amorim deu o melhor dele para fazer o discurso significar exatamente o que ele queria que significasse. O Raphael sabe se comunicar muito bem, e paciĆŖncia foi o Ćŗnico requisito para captar a mensagem.</p> +<p>Vi muita dedicaĆ§Ć£o na apresentaĆ§Ć£o que ele fez. Organizou os aprendizados e os desafios de seguir Ć  risca <a href="http://ejohn.org/blog/write-code-every-day/">a proposta do John Resig</a>, e os apresentou mostrando que ā€œpreencher grade de contribuiƧƵesā€ ou ā€œse sentir no dever todo diaā€ nĆ£o Ć© o suficiente para progredir. Inclusive, para quem acredita que isso Ć© o suficiente, apresentou o <a href="https://github.com/avinassh/rockstar">Rockstar</a>.</p> +<p>Esse tipo de palestra Ć© <strong>essencial</strong>, e eu nĆ£o estou disposta a discutir isso com ninguĆ©m. Havia mais de mil pessoas no mesmo lugar, e, por mais que nĆ£o pareƧa, Ć© uma minoria que contribui ou gerencia algum projeto open source, e tambĆ©m Ć© uma minoria que contribui hĆ” tempo o suficiente para passar por todos os desafios que o Raphael passou. Foi uma palestra sobre open source, mas tambĆ©m sobre esforƧo e saber o que estĆ” te movendo para se esforƧar mais: <strong>criar</strong>.</p> +<p>(Entendi o trocadilho no nome, a propĆ³sito.)</p> +<h3 id="david-bryant">David Bryant</h3> +<blockquote> +<p>Happy birthday, JavaScript!</p> +</blockquote> +<p>Terminou o primeiro dia de BrazilJS tal como o Christian o iniciou: fazendo-nos acreditar no que trabalhamos. David Bryant, que faz parte do <a href="https://www.mozilla.org/en-US/about/leadership/"><em>leadership team da Mozilla</em></a>, falou sobre a evoluĆ§Ć£o do JavaScript atĆ© o seu aniversĆ”rio de 20 anos, e em como devemos acreditar na web em detrimento da plataforma nativa. Para isso, lembrou da palestra Nick Desaulniers, anterior a dele, que mostrava quanto esforƧo tem sido feito para que a web alcance a plataforma nativa.</p> +<p>David, representando a Mozilla, deixou Ć³bvia a mensagem: <em>a web Ć© a melhor plataforma</em>.</p> +<h2 id="o-segundo-dia">O segundo dia</h2> +<h3 id="what-can-you-build-with-a-log">What can you build with a log</h3> +<p>James comeƧa explicando sua motivaĆ§Ć£o: a impermancĆŖncia e a centralizaĆ§Ć£o do conteĆŗdo sĆ£o coisas negativas da web. O que podemos fazer sobre isso? UĆ©, abrir o Vim, e construir meu cliente torrent, Flickr, Twitterā€¦</p> +<p>O Substack Ć© uma pessoa extremamente simples e humilde. Ɖ impossĆ­vel nĆ£o achĆ”-lo, no mĆ­nimo, adorĆ”vel. Um dos <em>live codings</em> mais fluĆ­dos e espontĆ¢neos que jĆ” assisti.</p> +<h3 id="reduce-seu-novo-melhor-amigo">Reduce: seu novo melhor amigo</h3> +<p>A Ju GonƧalves explicou o uso do <code>reduce()</code> na prĆ”tica. (Na prĆ”tica mesmo, para sair da BrazilJS usando, caso nunca tenha usado.)</p> +<p>O tema escolhido complementou muito bem a palestra de programaĆ§Ć£o funcional do Jacob Page, anterior a dela. O formato ficou perfeito para 30 minutos (a propĆ³sito, a ideia de abordar apenas o <code>reduce()</code> foi muito legal!), e deu para aprofundar bastante em algo que deve fazer parte do dia a dia. SĆ³ fiquei com a sensaĆ§Ć£o de que 5 minutos a mais ajudariam ela a guiar os exemplos com mais calma. O tempo estava bastante inflexĆ­vel nesse quesito.</p> +<p>Enfim, a Ju sabe o que faz. NĆ£o a conhecia pessoalmente ainda, mas conheƧo o trabalho e o entusiasmo dela e apostaria nela de longe, tal como a organizaĆ§Ć£o da conferĆŖncia, sem dĆŗvidas, fez.</p> +<h3 id="ecmascript-6-o-que-ha-de-novo-o-que-mudou-o-que-tem-de-bacana-ou-de-estranho">ECMAScript 6: O que HĆ” de Novo, O que Mudou, O que tem de Bacana ou de Estranho!</h3> +<p>TĆ­tulo engraƧado.</p> +<p>Quem foi na BrazilJS do ano passado sabe muito bem quem Ć© Jonathan Sampson. Em 2014, <a href="https://youtu.be/MMOZOkGfGGg?t=80">ele deu um nĆ³ na cabeƧa do Daniel Filho</a> ao falar PortuguĆŖs durante a entrevista.</p> +<p>No entanto, ano passado ele palestrou em InglĆŖs. Neste ano, ele falou sobre o ES6 totalmente em <strong>PortuguĆŖs</strong>, e fez muita gente rir com coisas simples, como, por exemplo, referir-se aos que nĆ£o entendiam <em>hoisting</em> de variĆ”veis como ā€œ<strong>chorƵes</strong> do Stack Overflowā€, ou atĆ© mesmo perguntar como se traduz <em>replace</em> (todo mundo sabe que Ć© ā€œsubstchitutituirā€, no caso).</p> +<h3 id="javascript-robotics-a-nodebots-show">JavaScript Robotics: A NodeBots show</h3> +<p>JuliĆ”n Duque Ć© uma pessoa admirĆ”vel. Eu fico realmente muito alegre vendo o envolvimento dele com projetos como a <a href="http://nodeschool.io">NodeSchool</a>. Pelo tĆ³pico da palestra, dĆ” para ver como ele acredita bastante em JavaScript.</p> +<p>Como o <a href="https://twitter.com/seldo/status/635195901951107072">Laurie disse</a>, o trabalho feito foi sensacional. Mereceu todos os aplausos recebidos, tanto pela apresentaĆ§Ć£o quanto pelos projetos paralelos que organizou.</p> +<p>E <a href="https://twitter.com/julian_duque/status/635209141217296385">ele fala PortuguĆŖs</a> (nĆ£o sĆ³ no Twitter).</p> +<h3 id="brendan-eich">Brendan Eich</h3> +<p>NĆ£o estive na BrazilJS 2012, entĆ£o esse foi o meu primeiro encontro com aquele conhecemos como <strong>criador do JavaScript</strong>.</p> +<p>A palestra dele foi engraƧada, motivacional e tambĆ©m tĆ©cnica. Falou sobre como foi criar o JavaScript em 10 dias, deu explicaƧƵes sobre o <a href="http://www.wtfjs.com/">wtfjs</a>, e mostrou o quanto valeu a pena acreditar no JavaScript.</p> +<p>Terminou com a frase que foi a grande mensagem da BrazilJS 2015: <em>always bet on JS</em>.</p> +<h2 id="o-fim">O fim</h2> +<p>O evento acabou com um show de rock e cerveja artesanal. NĆ£o sou uma pessoa agitada, nem gosto de beber cerveja, nem queria me arriscar a chegar tarde em casa (voltaria de Ć“nibus), entĆ£o me limitei a finalizar meu dia indo falar com o Daniel Filho, que estava com outras duas pessoas, o Leonardo Balter e o <a href="http://igorapa.com/fui-aprender-ingles.html">Igor-que-foi-aprender-InglĆŖs</a>.</p> +<p>(Conversar com o Leonardo faz bem para a mente, pois ele nĆ£o sĆ³ se dispƵe a te ouvir como tambĆ©m te recebe bem. Se um dia encontrĆ”-lo, inicie uma conversa, talvez vocĆŖ ganhe um grande amigo.)</p> +<p>Saindo do BarraShoppingSul, lembro que, fora do shopping, aquele Ć© um lugar deserto. <strong>Deserto</strong>. Em direĆ§Ć£o a parada, com meu computador na mochila, encontro um homem que promete nĆ£o me assaltar e que sĆ³ quer dinheiro para ir para casa. Dou o que tenho para ajudar, e ele insiste que eu dĆŖ mais, afirmando <em>saber</em> que eu tenho mais. Nego gentilmente, e entro no T4 para ir embora logo. E, aos que nĆ£o conhecem Porto Alegre, o T4 Ć© simplesmente <a href="http://zh.clicrbs.com.br/rs/porto-alegre/noticia/2014/12/a-rotina-do-t4-o-onibus-campeao-de-assaltos-em-porto-alegre-4658335.html">o Ć“nibus mais inseguro da cidade</a>.</p> +<p>Era um assaltante. Isso foi me dito no Ć“nibus por uma moƧa, que disse tambĆ©m que tive sorte de nĆ£o ter sido assaltada. NĆ£o entendi o que me salvou, se foi a distĆ¢ncia que mantive do homem, se foi o fato de eu nĆ£o estar desatenta no celularā€¦ Enfim, cheguei em casa bem e feliz com os dois dias que se passaram.</p> +<h2 id="notas-sobre-o-espaco">Notas sobre o espaƧo</h2> +<ul> +<li>O lugar onde a conferĆŖncia ocorreu Ć© legal, pareceu bem mais aberto que o Bourbon Country e nĆ£o distancia as pessoas de quem palestra. O Teatro do Bourbon Country Ć© confortĆ”vel, exageradamente belo, possui uma Ć³tima acĆŗstica; mas, alĆ©m de enjoar, valoriza muito quem estĆ” palestrando, pois Ć© um espaƧo para dar palestras e nada mais. Todo o networking que acontece ali Ć© fora de onde as palestas ocorrem.</li> +<li>O espaƧo nĆ£o Ć© mais aberto no sentido de <strong>nĆ£o te sufocar</strong>. O local fica no subsolo do shopping, portanto, nĆ£o hĆ” acesso fĆ”cil e sem demora a rua, como havia no Bourbon Country. Lembro bem de ver o sol na BrazilJS do ano passado. Parece pouco, mas Ć© muito importante quando se fica dois dias no mesmo lugar, com luz artificial e tal. Isso simplesmente dĆ” muita abertura para acelerar a fadiga, ainda mais que vocĆŖ acaba comendo no shopping pela facilidade (pois a Ćŗnica coisa que tem no bairro do Barra Ć© o prĆ³prio Barra, sĆ©rio), entĆ£o vocĆŖ nunca sai dali. Sinceramente, durante essa BrazilJS, eu esqueci que orbitĆ”vamos ao redor de uma estrela chamada Sol. (Esse parĆ”grafo Ć© muito pessoal, realmente nĆ£o espero que ninguĆ©m concorde comigo com meus exageros, e de nenhuma forma exijo que sejam levados em consideraĆ§Ć£o.)</li> +<li>Muitas pessoas levam notebooks e o EspaƧo BrazilJS foi uma Ć³tima ideia para lidar com isso. Conciliou o Ćŗtil (reconferir palestras, programar durante <em>coffee break</em>) ao agradĆ”vel (nĆ£o ficar no computador durante palestras). Ɖ muito legal ter um lugar para ficar com o notebook, embora eu nĆ£o recomende levar caso vĆ” embora de Ć“nibus, como vivenciei.</li> +</ul> +<h2 id="notas-finais">Notas finais</h2> +<ul> +<li>Foi difĆ­cil comer e beber no primeiro dia. Percebi que, em vez de as pessoas organizarem-se em filas, muitas ficavam no entorno da mesa do <em>coffee break</em>, e isso dificultou muito o fluxo. No segundo dia, no entanto, foi bem mais organizado.</li> +<li>Os organizadores nĆ£o param. EstĆ£o sempre envolvidos com o evento, resolvendo pendĆŖncias e atendendo a feedbacks. Houve dedicaĆ§Ć£o integral por parte do Daniel, Felipe e Jaydson em fazer uma conferĆŖncia confortĆ”vel para todos. O segundo dia nĆ£o foi mais tranquilo porque simplesmente foi e a a conferĆŖncia deste ano nĆ£o foi mais diversa porque simplesmente foi. AgradeƧo a eles por isso.</li> +<li>Percebi uma mudanƧa de formato em vĆ”rios aspectos neste ano, e a principal delas foi a <strong>reduĆ§Ć£o da duraĆ§Ć£o das palestras</strong>. Bastante notĆ”vel. 30 minutos por padrĆ£o, e aproximadamente 1 hora para <em>keynotes</em>. Gostei bastante, jĆ” que possibilitou uma transiĆ§Ć£o bem saudĆ”vel entre assuntos e palestrantes, o que ajuda muito a digerir o conteĆŗdo. A BrazilJS dura 2 dias inteiros que terminam cansativos, e Ć© fato que isso acelera o cansaƧo, mesmo quando a apresentaĆ§Ć£o estĆ” muito interessante.</li> +<li>Quanto mais eu comia o chocolate da Mozilla, mais eu queria. Tive de comer 7 seguidos para satisfazer o meu consumo desenfreado de aƧĆŗcar. E nĆ£o recomendo para ninguĆ©m.</li> +<li>A quantidade de homens Ć© avassaladora. Embora as iniciativas em apoio Ć  diversidade tenham sido realmente efetivas (vi, por exemplo, mais mulheres neste ano), sabe-se bem que uma mulher na BrazilJS Ć© <strong>uma mulher em meio a homens</strong>. Ɖ o que a proporĆ§Ć£o permite afirmar.</li> +<li>NĆ£o havia camisetas da BrazilJS para mim, e isso me deixou um pouco triste, pois elas estavam muito bonitas neste ano. Segundo o Eu Compraria, a confecĆ§Ć£o foi apenas de versƵes masculinas da camiseta. No entanto, o problema nĆ£o Ć© a versĆ£o ser masculina, o problema Ć© que o tamanho P da versĆ£o masculina Ć© gigante em mim. AtĆ© a vendedora ficou com dĆ³ da minha situaĆ§Ć£o. :-(</li> +<li>O BarraShoppingSul Ć© um shopping completo e muito espaƧoso, mas o bairro onde ele estĆ” Ć© bastante inseguro e difĆ­cil de acessar caso vocĆŖ nĆ£o esteja vindo de carro.</li> +<li>O Daniel Filho Ć© um apresentador muito legal.</li> +<li>A BrazilJS 2015 foi Ć³tima, e isso me deixa bastante ansiosa para a conferĆŖncia de 2016.</li> +</ul> +<p>AtĆ© o prĆ³ximo ano!</p> + + + + + Multiline Sass Comments + 2015-08-17T00:00:00+00:00 + 2015-08-17T00:00:00+00:00 + + + + + Unknown + + + + + + /blog/multiline-sass-comments/ + + <p>Since the beginning of this year, Iā€™ve created a lot of different boilerplates for projects. Working as a freelancer makes you challenge yourself everyday to find out what fits better while working. Currently, itā€™s sometimes Stylus, sometimes Sass.</p> +<p>Stylus is flexible, and I love it. Sass isnā€™t, but itā€™s cool anyway. Sometimes I find it hard to bear its inflexibility, though.</p> +<p>On GitHub, thereā€™s a closed <a href="https://github.com/sass/sass/issues/338">issue about multiline comments on Sass</a> (<em>a Stylus feature!</em>), where I shared a solution for multiline Sass comments. A lot of people still donā€™t agree.</p> +<p>I just want people on community to know it, because it needs to be discussed.</p> +<h2 id="solution">Solution</h2> +<p>Start writing the comment as if it were single-line (<code>//</code>), then just follow its indentation. <a href="https://github.com/sass/sass/issues/338#issuecomment-131855911">Example</a>.</p> +<pre data-lang="css" style="background-color:#282a36;color:#f8f8f2;" class="language-css "><code class="language-css" data-lang="css"><span>// Multine comment +</span><span> Indent the </span><span style="color:#ff79c6;">text +</span><span> And this will be </span><span style="color:#ff79c6;">a</span><span> comment too +</span></code></pre> +<p>Is it available on Sass docs? Let me know!</p> + + + + + Desmitificando Seletores Complexos + 2013-11-28T00:00:00+00:00 + 2013-11-28T00:00:00+00:00 + + + + + Unknown + + + + + + /blog/desmitificando-seletores-complexos/ + + <p>Se existem recursos no CSS que a total compreensĆ£o se restringe a uma parcela de desenvolvedores, esses sĆ£o os combinadores filhos (&gt;), irmĆ£os adjacentes (+) e adjacentes gerais (~).</p> +<p>Sem dĆŗvidas, esses 3 combinadores sĆ£o tĆ£o poderosĆ­ssimos quanto mal-explicados. Ɖ importante compreendĆŖ-los integralmente e hĆ” dois bons motivos para isso: o seletor descendente nĆ£o dĆ” conta de tudo e, o Ć³bvio: o CSS estĆ” evoluindo.</p> +<h2 id="x-y">X &gt; Y</h2> +<blockquote> +<p>Todo filho Ć© necessariamente descendente, mas nem todo descendente Ć© necessariamente filho.</p> +<footer>ā€” <cite>Eu, sobre famĆ­lia</cite></footer> +</blockquote> +<p>Para que Y seja alvo da seleĆ§Ć£o, nĆ£o importa a posiĆ§Ć£o; basta que seja descendente direto de X - isso Ć©, filho. Em outras palavras, basta que esteja interno diretamente ao elemento pai - e seja somente descendente dele. Isso quer dizer que Y nĆ£o serĆ” alvo caso esteja interno a um elemento Z, mesmo que este esteja interno a X. Por essa razĆ£o o combinador ā€œ&gt;ā€ Ć© tambĆ©m chamado de <strong>direto</strong>, pois nĆ£o admite elementos internos indiretamente.</p> +<h3 id="seletor-descendente-vs-seletor-filho">Seletor descendente vs. seletor filho</h3> +<p>Lembrando da frase dita no inĆ­cio desse tĆ³pico, vocĆŖ jĆ” entende a diferenƧa. Enquanto o <strong>descendente</strong> (X Y) herda as propriedades aos elementos direta e indiretamente internos (filhos, netos, bisnetosā€¦), o alvo do <strong>combinador filho</strong> sĆ£o os filhos unicamente diretos - sim, falar isso Ć© redundante. O que faz todo sentido, afinal, um filho Ć© tanto filho quanto descendente; e o neto, bisneto, trineto nĆ£o Ć© um filho, mas Ć© descendente.</p> +<h4 id="na-pratica">Na prĆ”tica</h4> +<p>Imaginemos um artigo e seus respectivos parĆ”grafos. Dentro desse artigo, haverĆ” uma seĆ§Ć£o de informaƧƵes que nĆ£o estarĆ” diretamente relacionada ao artigo. Como o que se quer destacar Ć© a leitura do artigo, seus parĆ”grafos terĆ£o mais ĆŖnfase de alguma forma.</p> +<h5 id="html">HTML</h5> +<pre data-lang="html" style="background-color:#282a36;color:#f8f8f2;" class="language-html "><code class="language-html" data-lang="html"><span>&lt;</span><span style="color:#ff79c6;">article</span><span>&gt; +</span><span> &lt;</span><span style="color:#ff79c6;">h1</span><span>&gt;TĆ­tulo do artigo&lt;/</span><span style="color:#ff79c6;">h1</span><span>&gt; +</span><span> &lt;</span><span style="color:#ff79c6;">p</span><span>&gt;Primeiro parĆ”grafo&lt;/</span><span style="color:#ff79c6;">p</span><span>&gt; +</span><span> &lt;</span><span style="color:#ff79c6;">p</span><span>&gt;Segundo parĆ”grafo&lt;/</span><span style="color:#ff79c6;">p</span><span>&gt; +</span><span> &lt;</span><span style="color:#ff79c6;">aside</span><span>&gt; +</span><span> &lt;</span><span style="color:#ff79c6;">h2</span><span>&gt;InformaƧƵes&lt;/</span><span style="color:#ff79c6;">h2</span><span>&gt; +</span><span> &lt;</span><span style="color:#ff79c6;">p</span><span>&gt;Lorem ipsum dolor sit amet, consectetur adipisicing elit.&lt;/</span><span style="color:#ff79c6;">p</span><span>&gt; +</span><span> &lt;/</span><span style="color:#ff79c6;">aside</span><span>&gt; +</span><span> &lt;</span><span style="color:#ff79c6;">p</span><span>&gt;Terceiro parĆ”grafo&lt;/</span><span style="color:#ff79c6;">p</span><span>&gt; +</span><span>&lt;/</span><span style="color:#ff79c6;">article</span><span>&gt; +</span></code></pre> +<h5 id="css">CSS</h5> +<pre data-lang="css" style="background-color:#282a36;color:#f8f8f2;" class="language-css "><code class="language-css" data-lang="css"><span style="color:#ff79c6;">article </span><span>&gt; </span><span style="color:#ff79c6;">p </span><span>{ +</span><span> </span><span style="font-style:italic;color:#66d9ef;">font-style</span><span>: </span><span style="color:#6be5fd;">italic</span><span>; +</span><span>} +</span></code></pre> +<p>Assim, somente os parĆ”grafos que sĆ£o filhos diretos do elemento <strong>article</strong> serĆ£o estilizados.</p> +<h2 id="x-y-1">X + Y</h2> +<p>Se para ser alvo do seletor filho a posiĆ§Ć£o era irrelevante, para ser alvo de um <strong>seletor irmĆ£o adjacente</strong> sua posiĆ§Ć£o Ć© critĆ©rio decisivo. O elemento Y deve ser o primeiro elemento apĆ³s X, com ambos dentro de um mesmo elemento Z (pai). O nome, portanto, Ć© bem autoexplicativo: sĆ£o <strong>irmĆ£os</strong> por possuĆ­rem o mesmo pai (no caso, Z) e <strong>adjacentes</strong> por estarem necessariamente prĆ³ximos.</p> +<h4 id="na-pratica-1">Na prĆ”tica 1</h4> +<p>Supondo um artigo constituĆ­do por um tĆ­tulo e 3 parĆ”grafos. O primeiro parĆ”grafo apĆ³s o tĆ­tulo servirĆ” como uma introduĆ§Ć£o ao artigo e, portanto, deve ser destacado com um aumento no tamanho da fonte.</p> +<h5 id="html-1">HTML</h5> +<pre data-lang="html" style="background-color:#282a36;color:#f8f8f2;" class="language-html "><code class="language-html" data-lang="html"><span>&lt;</span><span style="color:#ff79c6;">article</span><span>&gt; +</span><span> </span><span style="color:#6272a4;">&lt;!-- Z --&gt; +</span><span> &lt;</span><span style="color:#ff79c6;">h1</span><span>&gt;TĆ­tulo do artigo&lt;/</span><span style="color:#ff79c6;">h1</span><span>&gt; +</span><span> </span><span style="color:#6272a4;">&lt;!-- X --&gt; +</span><span> &lt;</span><span style="color:#ff79c6;">p</span><span>&gt;Lorem ipsum dolor sit amet, consectetur adipisicing elit.&lt;/</span><span style="color:#ff79c6;">p</span><span>&gt; +</span><span> </span><span style="color:#6272a4;">&lt;!-- Y --&gt; +</span><span> &lt;</span><span style="color:#ff79c6;">p</span><span>&gt;Debitis sint aperiam numquam nisi animi porro in reprehenderit!&lt;/</span><span style="color:#ff79c6;">p</span><span>&gt; +</span><span> &lt;</span><span style="color:#ff79c6;">p</span><span>&gt;Magnam atque placeat fuga sed eligendi maxime neque labore. Doloribus?&lt;/</span><span style="color:#ff79c6;">p</span><span>&gt; +</span><span>&lt;/</span><span style="color:#ff79c6;">article</span><span>&gt; +</span></code></pre> +<h5 id="css-1">CSS</h5> +<pre data-lang="css" style="background-color:#282a36;color:#f8f8f2;" class="language-css "><code class="language-css" data-lang="css"><span style="color:#ff79c6;">h1 </span><span>+ </span><span style="color:#ff79c6;">p </span><span>{ +</span><span> </span><span style="font-style:italic;color:#66d9ef;">font-size</span><span>: </span><span style="color:#bd93f9;">20</span><span style="color:#ff79c6;">px</span><span>; +</span><span>} +</span></code></pre> +<h4 id="na-pratica-2">Na prĆ”tica 2</h4> +<p>O <strong>checkbox hack</strong> funciona com o uso do combinador irmĆ£o adjacente.</p> +<h4 id="html-2">HTML</h4> +<pre data-lang="html" style="background-color:#282a36;color:#f8f8f2;" class="language-html "><code class="language-html" data-lang="html"><span>&lt;</span><span style="color:#ff79c6;">input </span><span style="color:#50fa7b;">type</span><span>=</span><span style="color:#f1fa8c;">&quot;checkbox&quot; </span><span style="color:#50fa7b;">id</span><span>=</span><span style="color:#f1fa8c;">&quot;hider&quot; </span><span>/&gt; +</span><span>&lt;</span><span style="color:#ff79c6;">div</span><span>&gt;Hide me if you can!&lt;/</span><span style="color:#ff79c6;">div</span><span>&gt; +</span><span>&lt;</span><span style="color:#ff79c6;">label </span><span style="color:#50fa7b;">for</span><span>=</span><span style="color:#f1fa8c;">&quot;hider&quot;</span><span>&gt;Esconder div&lt;/</span><span style="color:#ff79c6;">label</span><span>&gt; +</span></code></pre> +<h4 id="css-2">CSS</h4> +<pre data-lang="css" style="background-color:#282a36;color:#f8f8f2;" class="language-css "><code class="language-css" data-lang="css"><span style="color:#ff79c6;">input</span><span>[</span><span style="color:#50fa7b;">type</span><span style="color:#ff79c6;">=</span><span style="color:#f1fa8c;">&quot;checkbox&quot;</span><span>] { +</span><span> </span><span style="font-style:italic;color:#66d9ef;">display</span><span>: </span><span style="color:#6be5fd;">none</span><span>; </span><span style="color:#6272a4;">/* Esconde o checkbox */ +</span><span>} +</span><span style="color:#ff79c6;">input</span><span>:checked + </span><span style="color:#ff79c6;">div </span><span>{ +</span><span> </span><span style="font-style:italic;color:#66d9ef;">display</span><span>: </span><span style="color:#6be5fd;">none</span><span>; </span><span style="color:#6272a4;">/* Quando o checkbox for checado, a div serĆ” escondida */ +</span><span>} +</span></code></pre> +<h2 id="x-y-2">X ~ Y</h2> +<p>Seletor do <strong>CSS 3</strong>, o combinador <strong>adjacente geral</strong> tem uma definiĆ§Ć£o bem semelhante ao irmĆ£o adjacente. Para que Y seja alvo, os elementos X e Y devem ser filhos de um mesmo elemento (irmĆ£os) e X deve preceder Y, direta ou indiretamente - isso Ć©, para que Y seja alvo, esse precedimento nĆ£o precisa ser imediato.</p> +<h4 id="na-pratica-3">Na prĆ”tica</h4> +<p>Esse combinador contorna algumas inflexibilidades do <strong>combinador irmĆ£o adjacente</strong>. Ainda com o exemplo do <strong>checkbox hack</strong>, podemos personalizar o elemento de forma nĆ£o tĆ£o especĆ­fica quanto Ć  sua posiĆ§Ć£o:</p> +<h4 id="html-3">HTML</h4> +<pre data-lang="html" style="background-color:#282a36;color:#f8f8f2;" class="language-html "><code class="language-html" data-lang="html"><span>&lt;</span><span style="color:#ff79c6;">input </span><span style="color:#50fa7b;">type</span><span>=</span><span style="color:#f1fa8c;">&quot;checkbox&quot; </span><span style="color:#50fa7b;">id</span><span>=</span><span style="color:#f1fa8c;">&quot;shower&quot; </span><span>/&gt; +</span><span>&lt;</span><span style="color:#ff79c6;">label </span><span style="color:#50fa7b;">for</span><span>=</span><span style="color:#f1fa8c;">&quot;shower&quot;</span><span>&gt;Mostrar div&lt;/</span><span style="color:#ff79c6;">label</span><span>&gt; +</span><span>&lt;</span><span style="color:#ff79c6;">div</span><span>&gt;Hide me if you can!&lt;/</span><span style="color:#ff79c6;">div</span><span>&gt; +</span><span>&lt;</span><span style="color:#ff79c6;">div</span><span>&gt;Hide me too if you can!&lt;/</span><span style="color:#ff79c6;">div</span><span>&gt; +</span></code></pre> +<h4 id="css-3">CSS</h4> +<pre data-lang="css" style="background-color:#282a36;color:#f8f8f2;" class="language-css "><code class="language-css" data-lang="css"><span style="color:#ff79c6;">input</span><span>[</span><span style="color:#50fa7b;">type</span><span style="color:#ff79c6;">=</span><span style="color:#f1fa8c;">&quot;checkbox&quot;</span><span>], +</span><span style="color:#ff79c6;">div </span><span>{ +</span><span> </span><span style="font-style:italic;color:#66d9ef;">display</span><span>: </span><span style="color:#6be5fd;">none</span><span>; </span><span style="color:#6272a4;">/* Esconde o checkbox e a div, por padrĆ£o */ +</span><span>} +</span><span style="color:#ff79c6;">input</span><span>:checked ~ </span><span style="color:#ff79c6;">div </span><span>{ +</span><span> </span><span style="font-style:italic;color:#66d9ef;">display</span><span>: </span><span style="color:#6be5fd;">block</span><span>; </span><span style="color:#6272a4;">/* Quando o checkbox for checado, a div aparecerĆ” */ +</span><span>} +</span></code></pre> +<h2 id="conclusao">ConclusĆ£o</h2> +<p>As linguagens CSS e HTML foram documentadas para serem intuitivas: os elementos formam famĆ­lias com outros elementos pais, filhos, descendentes, irmĆ£osā€¦. Isso fica claro no nome dos seletores, que tĆŖm papel importante na compreensĆ£o do combinador; afinal, caso o desenvolvedor entenda que irmĆ£os tem o mesmo pai e que filhos sĆ£o descendentes diretos do pai, ele poderĆ” tirar um bom proveito do nome dos combinadores para compreender seus funcionamentos.</p> +<blockquote> +<p>[ā€¦] In both cases, non-element nodes (e.g. text between elements) are ignored when considering adjacency of elements.<footer> <cite><span>W3C</span>, sobre <a href="http://www.w3.org/TR/css3-selectors/">Selectors Level 3</a></cite></footer></p> +</blockquote> +<p>HĆ” uma grande confusĆ£o - e com razĆ£o - entre os seletores irmĆ£os adjacentes e irmĆ£os gerais. Essa confusĆ£o se origina nĆ£o sĆ³ de suas classificaƧƵes como <a href="http://www.w3.org/TR/css3-selectors/#sibling-combinators">seletores de combinaĆ§Ć£o</a>, mas em seus comportamento e definiĆ§Ć£o semelhantes. Tanto Ć© verdade que o combinador adjacente geral (~) se comportarĆ” muitas vezes como um irmĆ£o adjacente (+), com a diferenƧa de que o adjacente geral Ć© menos exigente quanto Ć  posiĆ§Ć£o do elemento-alvo.</p> +<p>O uso serĆ”, portanto, facultativo em diversas situaƧƵes. E, nesse caso, a minha recomendaĆ§Ć£o Ć© dar prioridade ao combinador adjacente, visto que Ć© um seletor do CSS 2.1 e, portanto, compatĆ­vel com uma maior gama de browsers. :-)</p> +<h2 id="referencias">ReferĆŖncias</h2> +<ul> +<li><strong>W3C</strong>. <a href="http://www.w3.org/TR/CSS21/selector.html">Selectors</a></li> +<li><strong>W3C</strong>. <a href="http://www.w3.org/TR/css3-selectors/">Selectors Level 3</a>, 29 setembro de 2011</li> +</ul> + + + + diff --git a/badges/browser.png b/badges/browser.png new file mode 100644 index 0000000..ad15ed9 Binary files /dev/null and b/badges/browser.png differ diff --git a/badges/github.gif b/badges/github.gif new file mode 100644 index 0000000..23b963f Binary files /dev/null and b/badges/github.gif differ diff --git a/badges/js.png b/badges/js.png new file mode 100644 index 0000000..61ce5cb Binary files /dev/null and b/badges/js.png differ diff --git a/badges/nocookie.png b/badges/nocookie.png new file mode 100644 index 0000000..3bc8237 Binary files /dev/null and b/badges/nocookie.png differ diff --git a/badges/rss.gif b/badges/rss.gif new file mode 100644 index 0000000..52e845e Binary files /dev/null and b/badges/rss.gif differ diff --git a/badges/screen.gif b/badges/screen.gif new file mode 100644 index 0000000..27c8f78 Binary files /dev/null and b/badges/screen.gif differ diff --git a/badges/smile.gif b/badges/smile.gif new file mode 100644 index 0000000..8db76ed Binary files /dev/null and b/badges/smile.gif differ diff --git a/badges/trapped.gif b/badges/trapped.gif new file mode 100644 index 0000000..098dd54 Binary files /dev/null and b/badges/trapped.gif differ diff --git a/blog/5-bibliotecas-essenciais-para-desenvolver-react-apps/index.html b/blog/5-bibliotecas-essenciais-para-desenvolver-react-apps/index.html new file mode 100644 index 0000000..ae9fc18 --- /dev/null +++ b/blog/5-bibliotecas-essenciais-para-desenvolver-react-apps/index.html @@ -0,0 +1,79 @@ +5 Bibliotecas Essenciais para Desenvolver React Apps | DiĆ©ssica Gurskas
diessi.caBlogMisc
March 21, 2016

5 Bibliotecas Essenciais para Desenvolver React Apps

O conjunto de ferramentas, boilerplates e bibliotecas disponĆ­veis formam um ecossistema incrĆ­vel em torno do React.

No meio de tudo, existem ferramentas que sĆ£o comuns ā€“ e essenciais ā€“Ā a diversas aplicaƧƵes, independente de suas arquiteturas. Cito cinco delas.

1. classnames

Muitas vezes, no React, um estado representarĆ” um comportamento visual do componente (ā€œselecionadoā€, ā€œpressionadoā€, ā€œfocadoā€), normalmente associado a uma classe CSS.

Um botĆ£o e seus estados disabled e hovered, por exemplo, ficariam assim:

<button
+  type="submit"
+  onMouseOver={...}
+  className={classNames('button', this.props.className, {
+    'button--disabled': this.state.isDisabled,
+    'button--hovered': this.state.isHovered
+  })}
+/>
+

Perceba que o Classnames facilita a manipulaĆ§Ć£o condicional de classes com React, removendo vĆ”rios blocos de if/else do seu cĆ³digo.

2. react-router

Se vocĆŖ estĆ” desenvolvendo uma Single-page Application, vocĆŖ precisarĆ” sincronizar a interface do usuĆ”rio com a URL.

O React Router Ć© a melhor soluĆ§Ć£o de rotas para aplicaƧƵes desenvolvidas com React, e isso se deve bastante a sua API declarativa e pensada para componentes.

Considere a seguinte configuraĆ§Ć£o de rotas:

import React from "react";
+import { render } from "react-dom";
+import { Router, Route, browserHistory } from "react-router";
+
+import App from "components/App";
+import Homepage from "screens/Homepage";
+import About from "screens/About";
+import Contact from "screens/Contact";
+
+render(
+  <Router history={browserHistory}>
+    <Route path="/" component={App}>
+      <IndexRoute component={Homepage} />
+      <Route path="about" component={About} />
+      <Route path="contact" component={Contact} />
+    </Route>
+  </Router>,
+  document.getElementById("react-root")
+);
+

Perceba que hĆ” uma instĆ¢ncia inicial da rota e outras rotas aninhadas, formando uma hierarquia. Essa hierarquia Ć© a essĆŖncia do React Router.

Considere que temos um App (App.js):

import React, { Component } from 'react'
+import { IndexLink, Link } from 'react-router'
+
+class App extends Component {
+  render() {
+    return (
+      <div>
+        <nav>
+          <IndexLink to="/">Homepage</li>
+          <Link to="/about">About</Link>
+          <Link to="/contact">Contact</Link>
+        </nav>
+
+        <div>
+          {this.props.children}
+        </div>
+      </div>
+    )
+  }
+}
+
+export default App
+

Dica: O componente acima nĆ£o tem um estado prĆ³prio, portanto, ele Ć© um Pure Component (ou Dumb Component). Componentes sob estas condiƧƵes podem ā€“ e devem ā€“Ā ser transformados em Stateless Functional Components. ^[Sugiro a leitura de Functional Stateless Components in React 0.14]

Uma explicaĆ§Ć£o rĆ”pida: Todas as subrotas da rota do componente App (os <Route> dentro de <Route>) terĆ£o seus componentes transferidos como props para o componente App (e por isso o this.props.children) ao entrar na rota atravĆ©s do <Link>.

A documentaĆ§Ć£o do React Router dispensa quaisquer outras explicaƧƵes!

3. react-helmet

Dificilmente vocĆŖ usarĆ” o React Router sem o Helmet. O Helmet te dĆ”, no prĆ³prio componente, o controle do head do documento.

Um caso de uso simples Ć© alterar o tĆ­tulo do documento, Ćŗtil quando a aplicaĆ§Ć£o entra em uma nova rota:

<Helmet title="Carrinho de Compras" />
+

4. jsx-control-statements

JSX facilita a escrita da marcaĆ§Ć£o do componente e torna seu cĆ³digo mais fĆ”cil de ler e entender. Mas e quando a renderizaĆ§Ć£o do componente Ć© condicional? E quando renderizamos componentes dinamicamente?

Seu cĆ³digo termina provavelmente assim:

<div>
+  {todos.map(function (todo, index) {
+    return <TodoItem data={todo} key={index} />;
+  })}
+</div>
+

E assim:

<div>{condition && <span></span>}</div>
+

Ou de uma das vĆ”rias outras formas: condicionais inline, operaƧƵes ternĆ”rias, funƧƵes para renderizar componentes condicionalmenteā€¦ PrĆ”ticas que, em grande escala, podem prejudicar a legibilidade do cĆ³digo. E Ć© na legibilidade que o jsx-control-statements vence.

O primeiro exemplo, por exemplo, ficaria assim:

<div>
+  <For each="todo" index="index" of={todos}>
+    <TodoItem data={todo} key={index} />
+  </For>
+</div>
+

5. axios ou Fetch API

NĆ£o Ć© uma dependĆŖncia apenas de aplicaƧƵes React, mas vocĆŖ provavelmente vai precisar de um cliente HTTP. (Um cliente HTTP de gente adulta, que nĆ£o Ć© o $.ajax.) Existem duas Ć³timas opƧƵes: axios e o fetch (ā€œWHATWG Fetch APIā€).

axios

Uma biblioteca maravilhosa.

A API do axios Ć© completa: tĆŖm interceptadores de requisiĆ§Ć£o, mĆŗltiplas requisiƧƵes em paraleloā€¦ E suas requisiƧƵes retornam lindas promises.

Fazendo uma requisiĆ§Ć£o POST:

import axios from "axios";
+
+axios
+  .post(
+    "/api/pets",
+    { name: "Bard", cat: false },
+    { headers: { "X-Custom-Header": "foobar" } }
+  )
+  .then(() => console.log("Pet salvo com sucesso!"))
+  .catch((response) => console.log(response));
+

Fetch API

O fetch, por outro lado, jĆ” Ć© um living standard, e, nesse momento, tem suporte bĆ”sico nos navegadores Firefox, Chrome e Opera. Ɖ recomendado, no entanto, o uso de um polyfill, por ser uma tecnologia ainda experimental.

A mesma requisiĆ§Ć£o POST ficaria assim:

fetch("/api/pets", {
+  method: "post",
+  headers: { "X-Custom-Header": "foobar" },
+  body: { name: "Bard", cat: false },
+})
+  .then(() => console.log("Pet salvo com sucesso!"))
+  .catch((response) => console.log(response));
+

VocĆŖ pode saber mais sobre o Fetch API no Mozilla Developer Network.

ConsideraƧƵes

Embora eu tenha citado apenas cinco, existem diversas bibliotecas e componentes que descomplicam o processo de desenvolvimento de uma aplicaĆ§Ć£o com React. Sem dĆŗvidas, Ć© um dos ecossistemas mais relevantes que front-end jĆ” teve.

Destaco que nĆ£o cobri um tĆ³pico que, quando se trata de React, Ć© bastante pertinente: formulĆ”rios. Lidar com formulĆ”rios no React Ć© complicado. Nesse primeiro momento, resolvi deixar o tema de lado para nĆ£o fugir da proposta do artigo.

\ No newline at end of file diff --git a/blog/a-better-es2015-and-jsx-workflow-in-vs-code/index.html b/blog/a-better-es2015-and-jsx-workflow-in-vs-code/index.html new file mode 100644 index 0000000..e815371 --- /dev/null +++ b/blog/a-better-es2015-and-jsx-workflow-in-vs-code/index.html @@ -0,0 +1,7 @@ +A Better ES2015+ and JSX Workflow in VS Code | DiƩssica Gurskas
diessi.caBlogMisc
October 30, 2016

A Better ES2015+ and JSX Workflow in VS Code

Lately Iā€™ve been trying VS Code, a code editor based on Electron. Since then, it really surprised me and itā€™s been a nice coding experience.

Butā€¦

By default, JS syntax highlighting and ES2015+ and JSX support donā€™t work as expected.

Iā€™ve tried to workaround it by using:

  1. Atom grammar. JSX support was pretty bad.
  2. A development branch of VS Code colorization, which is delivered as an extension. Finally got JSX to work properly, but syntax highlighting was still missing something.

So, no success.

Improving your VS Code workflow

After much trial and error, I came up with a better JS workflow in VS Code.

1. Fix JS syntax highlighting

Install the Sublime Babel extension and make sure youā€™re using one of the suggested color themes. (I like Charcoal Oceanic Next!)

2. Use ā€œJavaScript Reactā€ in .js files

VS Code only uses ā€œJavaScript Reactā€ syntax in .jsx files. Add the following to your User (or Workspace) Settings:

"files.associations": {
+  "*.js": "javascriptreact"
+}
+

3. Enable Emmet for JSX

(Thatā€™s a plus!)

VS Code uses Emmet by default, but doesnā€™t enable it for .jsx files. Add the following to your User Settings:

"emmet.syntaxProfiles": {
+  "javascript": "jsx"
+}
+

Letā€™s improve VS Code!

There has been improvements for JS grammar already, but itā€™s still not perfect.

Fortunately, VS Code is an open source project and can be improved by developers like us! Letā€™s not leave it like this. Give useful feedback and help!

Happy coding!

\ No newline at end of file diff --git a/blog/a-bit-on-random-numbers-in-javascript/index.html b/blog/a-bit-on-random-numbers-in-javascript/index.html new file mode 100644 index 0000000..49f6c91 --- /dev/null +++ b/blog/a-bit-on-random-numbers-in-javascript/index.html @@ -0,0 +1,10 @@ +A Bit on Random Numbers in JavaScript | DiƩssica Gurskas
diessi.caBlogMisc
November 15, 2016

A Bit on Random Numbers in JavaScript

Math.random() is a JavaScript function that outputs a random number in the range [0, 1) (from 0 up to 1, but doesnā€™t include 1). Itā€™s the main source of randomness in JavaScript.

Although the output looks random, itā€™s actually not.

Behind the Scenes

Math.random() uses a pseudo-random number generator (PRNG). Those algorithms work completely determined by a initial value called ā€œseedā€.

Given a seed, the sequence of random numbers is deterministic.

Every PRNG requires a seed, which generally is the current system time in milliseconds. Yeah, simple as that.

Speaking of JavaScript language, the PRNG algorithm to deal with the seed is left up to implementors1. The algorithm powering V8ā€™s Math.random() was very poor quality until last year (2015), and implementations between engines were pretty inconsistent.

But the scenario has changed. Currently, JavaScript Engines such as SpiderMonkey, V8, Webkit and Chakra all implements Xorshift128+ algorithm2, faster than the previous one.

Secure Randomness

Although randomness was improved in most JavaScript engines, it isnā€™t trustworthy as seen that standard PRNGs are highly predictable after a certain period. Thatā€™s where Web Crypto API shines!

Web Cryptography API introduces window.crypto.getRandomValues, a cryptographically secure pseudo-random number generator (CSPNG), whose output is impossible or highly improbable to distinguish from a truly random one.

Example

// Array containing two 32-bit integers
+const arr = new Int32Array(2);
+
+// Override array integers with random values
+const random = crypto.getRandomValues(arr);
+
+for (let i = 0; i < random.length; i++) {
+  console.log(random[i]);
+}
+

Of course it comes at a performance cost, so make sure you really need secure random numbers in your program.

Conclusion

If you need apparent randomnessā€“less and speed, youā€™d probably better off using Math.random(). If you need high-quality randomness, such as in cryptography applications, hashing or statistics, go for a CSPNG such as window.crypto.getRandomValues instead.

\ No newline at end of file diff --git a/blog/a-cascata-das-variaveis-do-css/index.html b/blog/a-cascata-das-variaveis-do-css/index.html new file mode 100644 index 0000000..183b85f --- /dev/null +++ b/blog/a-cascata-das-variaveis-do-css/index.html @@ -0,0 +1,45 @@ +A Cascata das VariƔveis do CSS | DiƩssica Gurskas
diessi.caBlogMisc
May 30, 2016

A Cascata das VariƔveis do CSS

Suporte | EspecificaĆ§Ć£o

Muito embora todos os seres humanos do Planeta Terra tenham odiado sua sintaxe, as variĆ”veis finalmente chegaram ao CSSĀ ā€“Ā e elas sĆ£o mais poderosas do que vocĆŖ imagina!

MotivaĆ§Ć£o

O desenvolvimento de grandes aplicaƧƵes web implica inevitavelmente em grandes folhas de estilo, que devem ser organizadas de forma que facilite a manutenĆ§Ć£o. Muitos valores definidos para propriedades sĆ£o repetidos, quando poderiam ser reutilizados e padronizados, de forma compartilhada, pela folha de estilo.

Nesse contexto, surgem as variĆ”veis no CSS, tambĆ©m chamadas de Custom PropertiesĀ ā€“Ā pois, tecnicamente, Ć© isso que elas sĆ£o.

DefiniĆ§Ć£o

As Custom Properties sĆ£o propriedades CSS customizadas (ou seja, vocĆŖ configura o seu valor) iniciadas com --, de nome case-sensitive, e que sĆ£o utilizadas no documento atravĆ©s da funĆ§Ć£o var(). Por serem propriedades, Ć© importante compreender que seu comportamento Ć© idĆŖntico ao de uma propriedade qualquer do CSS (guarde essa informaĆ§Ć£o!).

Exemplo

:root {
+  --colorPrimary: purple;
+}
+
+a {
+  color: var(--colorPrimary);
+}
+

(Eu nĆ£o conheƧo ninguĆ©m que gosta da ideia esplĆŖndida do --. Mas elas nĆ£o vĆ£o deixar de iniciar com -- se vocĆŖ reclamar. Inclusive, isso jĆ” foi discutido o suficiente.)

A funĆ§Ć£o var()

Quem viabiliza o uso de Custom Properties? Ela:

var( <custom-property-name> [, <declaration-value> ]? )
+

O primeiro parĆ¢metro Ć© o nome da propriedade, e o segundo, opcional, Ć© o valor a ser usado como fallback caso o primeiro argumento seja invĆ”lido (por exemplo: uma variĆ”vel com 20px sendo usada como valor de um background, ou variĆ”vel inexistente).

Escopo

Cascata, especificidade, heranƧaā€¦ Esses conceitos sĆ£o muito importantes para entender o poder das variĆ”veis do CSS ā€“ e do CSS no geral, eu diria.

Aqui, uma das informaƧƵes mais importantes deste artigo: As Custom Properties seguem regras de cascata tal como qualquer outra propriedade do CSS.

Por isso, quando quisermos que a variĆ”vel esteja disponĆ­vel ā€œglobalmenteā€ (para todos os seletores), a declaramos no seletor :root, que Ć© o prĆ³prio documento HTML. Isso acontece pois o efeito cascata do CSS permite que todos seus descendentes herdem a propriedade. Legal, nĆ©?

A propriedade customizada, tal como qualquer outra propriedade, pode ser sobreescrita atravƩs de seletores. Seu valor serƔ definido de acordo com a especifidade deles.

A implementaĆ§Ć£o de Custom Properties do CSSNext nĆ£o segue regras de cascata. Apenas variĆ”veis declaradas no :root sĆ£o vĆ”lidas. :-(

Exemplo

:root {
+  --bgColor: indianred;
+}
+
+div {
+  --bgColor: darkseagreen;
+}
+
+#wow {
+  --bgColor: darkcyan;
+}
+
+* {
+  background-color: var(--bgColor);
+}
+

Nesse caso:

  • Todos os elementos sĆ£o vermelhos.
  • Exceto elementos div e seus filhos, que seriam verdes.
  • Exceto o elemento com id wow e seus filhos, que seriam ciano.

As Ćŗltimas versƵes do Firefox e Chrome jĆ” implementaram as variĆ”veis nativas do CSS. Se estiver utilizando algum desses navegadores, o exemplo abaixo ilustrarĆ” o funcionamento do CSS acima.

JS Bin on jsbin.com

Manipulando variƔveis CSS com JavaScript

Outra informaĆ§Ć£o valiosa sobre as variĆ”veis do CSS Ć© a possibilidade de acessĆ”-las e alterĆ”-las via JavaScript, usando a interface CSSStyleDeclaration para interagir com propriedades.

Exemplo

Considerando:

:root {
+  --my-color: darkcyan;
+  background-color: var(--my-color);
+}
+

VocĆŖ pode obter o valor da propriedade --my-color, atravĆ©s do window.getComputedStyle() e getPropertyValue().

const myColor = getComputedStyle(document.body).getPropertyValue("--my-color");
+console.log(myColor); // => darkcyan
+

VocĆŖ pode alterar o valor da variĆ”vel, atravĆ©s do setProperty() do objeto style:

document.body.style.setProperty("--my-color", "tomato");
+

ConheƧa o CSSStyleDeclaration abrindo o DevTools e digitando getComputedStyle(document.body) no console.

Curiosidades

  • VocĆŖ nĆ£o pode armazenar nomes de propriedades do CSS como Custom Properties.
div {
+  --myProperty: overflow;
+  var(--myProperty): hidden; /* Erro de sintaxe */
+}
+

ā€¦Em compensaĆ§Ć£o, vocĆŖ pode armazenar qualquer outra coisa (e usĆ”-las com JavaScript!):

--foo: if (x > 5) this.width = 10;
+
  • VocĆŖ nĆ£o pode formar valores com variĆ”veis.
div {
+  --myContainerWidth: 300;
+  width: var(--myContainerWidth) px; /* Valor invƔlido */
+  /* => 300 px, em vez de 300px */
+}
+

ā€¦Ao menos que vocĆŖ use calc():

div {
+  --myContainerWidth: 300;
+  width: calc(var(--myContainerWidth) * 1px); /* => width: 300px; */
+}
+

ConsideraƧƵes Finais

As Custom Properties abriram novas possibilidades para o uso de variĆ”veis em folhas de estilo. Depois de diversas especificaƧƵes e sintaxes (nem sempre foi --, acredite!), elas estĆ£o finalmente em fase de implementaĆ§Ć£o nos navegadores.

Tem interesse em se aprofundar em outras novas funcionalidades do CSS? Acompanhe a sƩrie O CSS do Futuro!

\ No newline at end of file diff --git a/blog/a-fantastica-diversidade-do-front-end/index.html b/blog/a-fantastica-diversidade-do-front-end/index.html new file mode 100644 index 0000000..478c1d3 --- /dev/null +++ b/blog/a-fantastica-diversidade-do-front-end/index.html @@ -0,0 +1 @@ +A FantƔstica Diversidade do Front-end | DiƩssica Gurskas
diessi.caBlogMisc
April 09, 2016

A FantƔstica Diversidade do Front-end

Os diferentes perfis de desenvolvedores front-end Ć© um tĆ³pico que frequente em fĆ³runs de discussĆ£o. Quais perfis o mercado espera? Como posso me definir enquanto desenvolvedor(a) front-end?

Vi, recentemente, uma vaga no Facebook para Front-end Engineer com foco em Acessibilidade. Pensei ā€œFoco em acessibilidade? Que especĆ­fico!ā€, e, segundos depois, todas as discussƵes que jĆ” tive sobre os perfis de desenvolvedores front-end me vieram Ć  mente.

Falar sobre esse assunto Ć© falar sobre como interpretar vagas de emprego sem entrar em desespero.

Mesmo Papel, Diversas Habilidades

Estuda Motion Design a fim de desenvolver nĆ£o sĆ³ sites, mas experiĆŖncias fantĆ”sticas? Estuda UX Design e prĆ”ticas de Acessibilidade a fim de desenvolver produtos que engajam o mĆ”ximo de pessoas possĆ­vel? Estuda padrƵes de arquitetura de software a fim de desenvolver aplicaƧƵes web complexas e escalĆ”veis no client-side?

VocĆŖ pode estudar e gostar todos; estudar mais um mais do que o outro; trabalhar com um, mas tender a outro; e pode atĆ© mesmo nĆ£o focar em nenhum dos que eu citei acima. Em qualquer uma das possibilidades, vocĆŖ provavelmente nĆ£o deixarĆ” de ser um profissional da Ć”rea de front-end ā€“Ā mas terĆ”, com certeza, um mercado especĆ­fico e uma carreira que se basearĆ£o nas suas escolhas profissionais.

Existe uma diversidade incrƭvel de habilidades na Ɣrea de desenvolvimento front-end.

Somos o intermediĆ”rio entre o back-end e o design, mas nosso papel Ć© transformar o web design em uma experiĆŖncia real. Essa (grande) responsabilidade faz com que desenvolvamos diversas habilidades, e algumas sĆ£o inegavelmente desenvolvidas em maior ou menor nĆ­vel. Nesse desnĆ­vel, encontramos de Motion Designers a JavaScript Developers, cada um com seu espaƧo em times e projetos especĆ­ficos.

E nĆ£o hĆ” nada de errado nisso. O surgimento dessas especializaƧƵes ā€“ que podem (e devem) ser escolhidas por vocĆŖĀ ā€“ Ć© apenas um resultado da complexidade atual do desenvolvimento front-end.

Confie nas Suas Habilidades

(ou ā€œVocĆŖ NĆ£o Precisa Ser o Candidato Perfeito Para Todas as Vagas de Front-end Existentesā€.)

Por que eu disse que falar sobre esse assunto Ć© falar sobre como interpretar vagas de emprego sem entrar em desespero?

Pense: VocĆŖ Ć© experiente, estuda com frequĆŖncia, mas, ocasionalmente, procura vagas de emprego e se vĆŖ insuficiente. Ok, convenhamos, a possibilidade existe: vocĆŖ nĆ£o estar atingindo os requisitos mĆ­nimos das vagas pode sim ser um sinal de que algo estĆ” errado. Mas provavelmente nĆ£o Ć© o caso.

Talvez vocĆŖ esteja procurando vagas para um perfil que nĆ£o Ć© o seu. NĆ£o precisamos aceitar ter expertises variadas como Ć© exigido; afinal, muitas vagas na Ć”rea de TI viram piada justamente por esse motivo. Desde que vocĆŖ entenda a multidisciplinaridade como mais valiosa que qualquer disciplina, apenas abrace o que prefere e se aprofunde, torne-se uma referĆŖncia nisso.

No fim, suas preferĆŖncias moldarĆ£o vocĆŖ como profissional. Elas farĆ£o com que vocĆŖ seja incluĆ­do(a) ou excluĆ­do(a) de vĆ”rias oportunidades, o que, por consequĆŖncia, moldarĆ” sua carreira.

Estude o que gosta, reconheƧa suas preferĆŖncias, confie nas suas habilidades, e, entĆ£o, procure vagas sem entrar em desespero.

Perfis de Desenvolvedores Front-end

No fĆ³rum do Front-end Brasil, foi proposta a divisĆ£o de separar profissionais de front-end que desenvolvem a camada de apresentaĆ§Ć£o dos que arquitetam aplicaƧƵes que interagem com back-end. Concordo com a divisĆ£o. Tenho uma visĆ£o bem definida, com base nas exigĆŖncias atuais do mercado internacional.

Dois Perfis: Uma Proposta

Front-end Developer

A ponte entre o design e o front-end. (ā€œUI Developerā€ Ć© um nome alternativo.)

Habilidades
  • ProficiĆŖncia em HTML semĆ¢ntico, CSS e JavaScript a nĆ­vel de desenvolvimento da camada de apresentaĆ§Ć£o da aplicaĆ§Ć£o.
  • PrincĆ­pios e boas prĆ”ticas de User Experience Design.
  • PrincĆ­pios e boas prĆ”ticas de Acessibilidade.
  • ProficiĆŖncia em metodologias de organizaĆ§Ć£o do CSS como OOCSS, SMACSS e BEM.
  • NoƧƵes de User Interface Design.
  • NoƧƵes de Motion Design.
  • NoƧƵes de back-end, geralmente a nĆ­vel de integraĆ§Ć£o com CMS.
Responsabilidades
  • Planejamento e desenvolvimento da camada de apresentaĆ§Ć£o da aplicaĆ§Ć£o.
  • ImplementaĆ§Ć£o do live styleguide, junto ao designer.
  • Metodologia e estrutura a ser usada no CSS.
  • ParticipaĆ§Ć£o no processo de Design (pois Development is Design).

Front-end Engineer

A ponte entre o front-end e o back-end. (Dependendo do projeto, ā€œJavaScript Developerā€ pode ser mais apropriado.)

Habilidades
  • ProficiĆŖncia em HTML e CSS, mas sua especializaĆ§Ć£o Ć© JavaScript.
  • ProficiĆŖncia em Design Patterns e padrƵes de arquitetura de software.
  • Conhecimento de modelo cliente-servidor, HTTP, REST.
  • PrincĆ­pios e boas prĆ”ticas de Performance.
  • PrincĆ­pios e boas prĆ”ticas de SeguranƧa.
  • NoƧƵes de estratĆ©gias de desenvolvimento, como IntegraĆ§Ć£o ContĆ­nua (CI).
Responsabilidades
  • Planejamento e desenvolvimento da aplicaĆ§Ć£o JavaScript.
  • AutomatizaĆ§Ć£o das tarefas.
  • Tooling da aplicaĆ§Ć£o.
  • ImplementaĆ§Ć£o de uma metodologia de testes.

NĆ£o concordo com o nome ā€œFront-end Designerā€, sugerido pelo Brad Frost. Ainda que desenvolvedores front-end participem do processo de design, tornar funcional a camada de apresentaĆ§Ć£o Ć© uma etapa do desenvolvimento de software ā€“Ā nĆ£o do design. O fato do desenvolvimento front-end ser erroneamente considerado mais programaĆ§Ć£o do que design, quando deveria ser os dois, Ć© um argumento que nĆ£o justifica o nome.

ā€¦Qual Deles?

Normalmente temos um pouco dos dois, mas sempre um mais do que o outro. Nesse caso, uma boa maneira de explicitar o seu papel sem desmerecer o outro Ć© falar sobre suas habilidades, em vez de se apegar a um rĆ³tulo.

Dificilmente um rĆ³tulo resumirĆ” todo o seu conhecimento.

Eu nĆ£o me apego a isso, por exemplo. Mesmo exercendo a funĆ§Ć£o de Front-end Engineer atualmente, continuo me denominando ā€œFront-end Developerā€.

A Vaga Ideal Para Suas Habilidades

Ɖ utĆ³pico esperar que todos desenvolvedores front-end sejam bons UX Designers, Motion Designers, JavaScript Developersā€¦ Isso nĆ£o existe. As empresas procuram diferentes perfis de desenvolvedores front-end. E elas nem sempre sabem disso.

As empresas nĆ£o simplesmente procuram um Front-end Developer ou um Front-end Engineer. Existem vagas bastante hĆ­bridas, como Front-end Engineers com foco em UX ou Acessibilidade, ou atĆ© mesmo Front-end Developers com noƧƵes de arquiteturas como MVC. Plenamente possĆ­vel e vĆ”lido!

Cabe a vocĆŖ identificar se Ć© ideal Ć  vaga de emprego que quer se candidatar e se suas habilidades sĆ£o compatĆ­veis com a expectativa da empresa. ƀ empresa, cabe a identificaĆ§Ć£o do seu perfil, a fim de alocar vocĆŖ em um projeto e time que explorem suas habilidades.

Ɖ o cenĆ”rio perfeito, pelo menos.

Lembre-se da Nossa EssĆŖncia

Independente de como vocĆŖ se posiciona e rotula, dos projetos que trabalha e do caminho que quer seguir, o front-end nĆ£o deixarĆ” de orbitar ao redor da trinca HTML, CSS e JavaScript.

Enquanto vocĆŖ possuir interesse nessas trĆŖs linguagens, os seus outros interesses apenas moldarĆ£o o seu caminho profissional.

E, temos sorte: na Ɣrea de front-end, a diversidade de caminhos Ʃ fantƔstica.

\ No newline at end of file diff --git a/blog/a-guide-to-favicons-and-touch-icons/index.html b/blog/a-guide-to-favicons-and-touch-icons/index.html new file mode 100644 index 0000000..e435a35 --- /dev/null +++ b/blog/a-guide-to-favicons-and-touch-icons/index.html @@ -0,0 +1,83 @@ +A Guide to Favicons and Touch Icons | DiƩssica Gurskas
diessi.caBlogMisc
September 06, 2015

A Guide to Favicons and Touch Icons

Favicon is a simplified visual element associated with a particular website, page or event, which you once found only in your browserā€™s address bar or bookmarks. Nowadays, the scenario is different: they are everywhere.

Introduction

Favicons provide a important visual indicator to people, and help them to easily associate your content (which can be a website, a particular page or even events like a new message) when browsing.

Formerly, they, also called shortcut icons or bookmark icons, were just tiny pieces of art designed to help users to browse through their tabs or bookmarks. Today, shortcut icons can also provide an app-like link on operational systems (Windows 8, Android, OS X and so on), and should therefore be considered for achieving a pleasant cross-platform experience.

This is a guide for using favicons today, the right way. At the end of this article, Iā€™m sure youā€™ll be excited about SVG favicons.

Usage

Favicons in different dimensions are needed, so devices and browsers can pick the picture that fits best based on sizes attribute (little exception for Mozilla Firefox, which always gets the last favicon declared and scale it if necessary).

The images are not requested when not used. As said, browsers will get only what fits them best, therefore itā€™s important to provide the favicon in the required dimensions to avoid ugly scaled images.

General

<!-- I'm lazy -->
+<link rel="icon" href="favicon.png" />
+
+<!-- Browser tabs -->
+<link rel="icon" href="favicon-16x16.png" sizes="16x16" />
+
+<!-- Safari on OS X, IE10 Metro -->
+<link rel="icon" href="favicon-32x32.png" sizes="32x32" />
+
+<!-- Google TV -->
+<link rel="icon" href="favicon-96x96.png" sizes="96x96" />
+
+<!-- Chrome on Android -->
+<link rel="icon" href="favicon-192x192.png" sizes="192x192" />
+

No need for type="image/png" when using HTML5.

Youā€™ll need to provide a manifest in order to Chrome on Androidā€™s icon to work properly. See manifest.json example.

<link rel="manifest" href="manifest.json" />
+

Lacking of PNG support on IE: a workaround

Internet Explorer until version 11 and Safari donā€™t support PNG favicons. However, you can provide a fallback for IE up to 9:

<!--[if IE]> <link rel="shortcut icon" href="favicon.ico" /> <![endif]-->
+

Notice the shortcut, which is a non-standard. Also, providing this fallback within a conditional comment is necessary; otherwise Chrome will use the ICO favicon, even if it supports PNG ones.

I donā€™t recommend it, though, because IE 10 doesnā€™t support conditional comments (so it wonā€™t get any favicon, as seen that it doesnā€™t support PNG too), and also because it encourages the use of the non-standard and confusing shortcut.

Luckily, you can workaround everything just placing a favicon.ico in the root directory (the browser will look for it automagically). Then link only the PNG favicon and donā€™t worry.

Web Clip bookmarks

iOS users can add websites to their home screen ā€“Ā shortcuts called ā€œWeb Clip bookmarksā€. The default icon is a thumbnail screenshot of the page, but developers can specify one instead.

You will need to provide a lot of dimensions in order to support both new devices and older (iOS6 and prior), however.

Thereā€™s a no-HTML way and a HTML way to provide those icons. Itā€™s up to you.

No-HTML: Touch Icon file

Add a apple-touch-icon-*.png file, where * is the size to the root directory, instead. iOS Safari will look for the appropriate icon size, and if it doesnā€™t find any that fits best, itā€™ll use apple-touch-icon.png.

You can reuse the image of another favicon specifying a href (not possible while using the solution above).

<!-- Non-retina iPhone pre iOS 7 -->
+<link rel="apple-touch-icon" sizes="57x57" href="apple-touch-icon-57x57.png" />
+
+<!-- Non-retina iPad pre iOS 7 -->
+<link rel="apple-touch-icon" sizes="60x60" href="apple-touch-icon-60x60.png" />
+<link rel="apple-touch-icon" sizes="72x72" href="apple-touch-icon-72x72.png" />
+
+<!-- Non-retina iPad iOS 7 -->
+<link rel="apple-touch-icon" sizes="76x76" href="apple-touch-icon-76x76.png" />
+
+<!-- Retina iPhone pre iOS 7 -->
+<link
+  rel="apple-touch-icon"
+  sizes="114x114"
+  href="apple-touch-icon-114x114.png"
+/>
+
+<!-- Retina iPhone iOS 7 -->
+<link
+  rel="apple-touch-icon"
+  sizes="120x120"
+  href="apple-touch-icon-120x120.png"
+/>
+
+<!-- Retina iPad pre iOS 7 -->
+<link
+  rel="apple-touch-icon"
+  sizes="144x144"
+  href="apple-touch-icon-144x144.png"
+/>
+
+<!-- Retina iPad iOS 7 -->
+<link
+  rel="apple-touch-icon"
+  sizes="152x152"
+  href="apple-touch-icon-152x152.png"
+/>
+
+<!-- iOS 8 -->
+<link
+  rel="apple-touch-icon"
+  sizes="180x180"
+  href="apple-touch-icon-180x180.png"
+/>
+

Using apple-touch-icon-precomposed instead of apple-touch-icon, which prevents iOS icons defaults like rounded corners and reflective shine, isnā€™t necessary, as seen that there isnā€™t shiny effects on iOS 7 and up anymore.

Windows Tiles

Tiles are icons that appear on the Start screen, linked as apps. By default, the image on the tile is the websiteā€™s favicon or a default IE11 logo.

To cover a wide range of devices, use an image 1.8 times the standard tile size so the image can be scaled up or down as needed.

Thereā€™s a no-HTML way and a HTML way to provide those icons. Itā€™s up to you, again.

No-HTML: Browser config file

Provide a browserconfig.xml file and save it at the root of your server. Internet Explorer 11 will automatically read the file when the user pins the website. See browserconfig.xml example.

Metadata tags

msapplication-TileColor is the background color of the tile, and msapplication-TileImage is the icon, which can be tiny (70 Ɨ 70px), square (150 Ɨ 150px), wide (310 Ɨ 150px) or large (310 Ɨ 310px).

<!-- Windows Tile -->
+<meta name="msapplication-TileColor" content="#000" />
+<meta name="msapplication-TileImage" content="tile-icon.png" />
+
+<!-- Different Windows Tiles (optional) -->
+<meta name="msapplication-square70x70logo" content="tile-icon_tiny.png" />
+<meta name="msapplication-square150x150logo" content="tile-icon_square.png" />
+<meta name="msapplication-wide310x150logo" content="tile-icon_wide.png" />
+<meta name="msapplication-square310x310logo" content="tile-icon_large.png" />
+

Bulletproof favicons

  • For Touch Icons, add apple-touch-icon.png and apple-touch-icon-*.png files, where * is the size, to the root directory.
  • For IE support, add a favicon.ico file with both 16 Ɨ 16px and 32 Ɨ 32px resources to the root directory.
  • For Windows Tiles, add a browserconfig.xml to the root directory.
  • For Chrome on Android icon, add a manifest.json to the root directory.
  • Add the following HTML to <head>:
<!-- Chrome on Android -->
+<link rel="icon" href="favicon-192x192.png" sizes="192x192" />
+<link rel="manifest" href="manifest.json" />
+
+<!-- Google TV -->
+<link rel="icon" href="favicon-96x96.png" sizes="96x96" />
+
+<!-- Safari on OS X, IE10 Metro -->
+<link rel="icon" href="favicon-32x32.png" sizes="32x32" />
+
+<!-- Browser tabs -->
+<link rel="icon" href="favicon-16x16.png" sizes="16x16" />
+

Order matters here! Mozilla Firefox ignores sizes and always get the last favicon for the browser tabs. :-(

Or you can add all the favicons through meta and link tags.

Favicon as SVG

Not encouraged as an unique solution, as seen that isnā€™t widely supported yet.

Iā€™m excited about this:

<link rel="icon" href="favicon.svg" sizes="any" type="image/svg+xml" />
+

Final words

Iā€™m sure you are now excited about SVG support for favicons. Providing a lot of different images is quite boring.

I encourage you to support favicons everywhere (or at least retina-ready ones), but unfortunately thereā€™s no human-friendly way to do it nowadays. Use favicons package on npm or, if you are not comfortable with the command line, refer to RealFaviconGenerator.

Donā€™t be lazy.

References

\ No newline at end of file diff --git a/blog/a-minimal-workspace-on-macos/index.html b/blog/a-minimal-workspace-on-macos/index.html new file mode 100644 index 0000000..0b7e27e --- /dev/null +++ b/blog/a-minimal-workspace-on-macos/index.html @@ -0,0 +1,29 @@ +A Minimal Workspace on macOS | DiƩssica Gurskas
diessi.caBlogMisc
May 04, 2017

A Minimal Workspace on macOS

Ask me for a screenshot of my desktop and all you get is a wallpaper ā€“ if Iā€™m using any. Everything else is hidden, unless actually requested by me.

Thatā€™s the way I work on macOS. The minimal way.

My macOS desktop. This + Spotlight = life. šŸ˜Ž

In my workspace, there are no desktop items, app icons, time clock, battery percentage, transition delays, distracting animations, dashboards or context menus.

Too much information makes it easy for me to get stimulated and then distracted. So I like it minimal.

Recipe for the minimal šŸ‘Œ

Get rid of everything you can. Hide. Disable. Assume everything is useless, not useful. (I actually use this approach for life.)

Youā€™ll get frustrated sometimes, because there are simple things you want so bad to get rid of but then found out itā€™s impossible unless you hack things. SRLSY GOTTA LOVE APPLE šŸ˜šŸ˜šŸ˜

Well, letā€™s begin! Follow the steps below and type the commands in a terminal. If youā€™re not familiar with a terminal, Iā€™m pretty sure itā€™s possible to find those settings in ā€œSystem Preferencesā€ as well.

(ā€¦But I highly recommend you to open a terminal and start typing around because SRSLY USING A TERMINAL IS LIKE KNOWLEDGE AND POWER 4 UR ENTIRE LIFE!!!!!!!!)

Hide your desktop

Itā€™s easier to live without than to live with it. Disable it and it wonā€™t be something you have to clean up anymore!

defaults write com.apple.finder CreateDesktop -bool false
+

Hide your dock

Itā€™ll be only shown when you hover it.

defaults write com.apple.dock autohide -bool true
+

Other cool things you can do too to keep your dock clean are:

# Minimize windows into their application's icon
+defaults write com.apple.dock minimize-to-application -bool true
+
+# Wipe all (default) app icons from the Dock
+defaults write com.apple.dock persistent-apps -array
+

Because I initialise apps from Spotlight, I really donā€™t mind not having any app in my dock. Sometimes I ask myself why do I have a dock at all. šŸ¤”

Andā€¦ Launchpad. WHY?????? šŸ˜­

Hide your menu bar

Itā€™ll be only shown when you hover it.

defaults write NSGlobalDomain _HIHideMenuBar -bool true
+

I really like this one, but if you feel it's too radical for you, try hiding only menu bar icons with Vanilla (recommended) or Bartender.

Disable dashboard

Why does it even exist? šŸ˜’

# Disable Dashboard
+defaults write com.apple.dashboard mcx-disabled -bool true
+
+# Don't show Dashboard as a Space
+defaults write com.apple.dock dashboard-in-overlay -bool true
+

Disable and/or speed up animations

Saving some time because I donā€™t think those really add anything to my user experience on macOS.

# Disable window animations and Get Info animations
+defaults write com.apple.finder DisableAllAnimations -bool true
+
+# Remove the auto-hiding Dock delay
+defaults write com.apple.dock autohide-delay -float 0
+
+# Remove the animation when hiding/showing the Dock
+defaults write com.apple.dock autohide-time-modifier -float 0
+
+# Don't animate opening applications from the Dock
+defaults write com.apple.dock launchanim -bool false
+
+# Speed up Mission Control animations
+defaults write com.apple.dock expose-animation-duration -float 0.1
+

Finally, restart system stuff:

killall Finder; killall Dock; killall SystemUIServer
+

And thatā€™s it! šŸŽ‰ Life-changing commands for sure. Now just donā€™t forget cleaning your actual desk too.

For more on the way I work, my dotfiles are worth-checking!

Sorry for using too many emojis. Just shipped this feature here on my blog and I can't help myself! šŸ˜¬

\ No newline at end of file diff --git a/blog/archive/i-travelled-to-photographs/index.html b/blog/archive/i-travelled-to-photographs/index.html new file mode 100644 index 0000000..c3dacba --- /dev/null +++ b/blog/archive/i-travelled-to-photographs/index.html @@ -0,0 +1 @@ +I Travelled to Photographs | DiƩssica Gurskas
diessi.caBlogMisc
April 19, 2017

I Travelled to Photographs

February was ending.

Usually, such thing would mean regular summer days. However, it wasnā€™t summer or even a regular day ā€“ this was something else.

February 25th was winter. In that cold afternoon, I ended up into a place Iā€™ll never forget: photographs from my phoneā€™s gallery.


My steps were slow.

Red bricks erected the walls of houses built on top of an equally red-bricked avenue.

The windows of the houses were made of a wood strategically white-colored to match the brickā€™s white grouts. With such detail, it was pretty easy to forgive the toughness those bricks carried.

Houses ended themselves in grey roofing shingles. The roofs were all hipped. Houses with hip roofs, gotta love them!, I thought to myself. (Imagine the ā€œVā€ letter upside down on top of a square ā€“ thatā€™s a house with a hip roof.)

Showing a winter that was already leaving, dark trees with dry twigs were in contrast against a white sky ā€“ the whitest Iā€™d ever seen in my life. Damn! The whole picture looked like a painting, while the white sky worked as the canvas board on which all that was drawn.

I remember walking and trying to get everything I could, until a freezing wind blew abruptly into my face. It was February, though. From where I come, February meant summer, not freezing winds. Why was February that cold?

In an attempt to clear things up, I told myself what I believed that was true: Youā€™re just looking at photographs from your phoneā€™s gallery. Thereā€™s no need to get this excited! Ok. So I was home and looking at the ā€œWallpapersā€ album I had on my phone.

A moment later, I found myself facing a large and wonderful canal, in which someone was solitary paddling a boat to somewhere. What a view.

Then, self-awareness hit me again: Wait. Isnā€™t my smartphone in my pocket? How could I be possibly looking at photographs on it?

I immediately started touching my entire body in a desperate hunt for my phone. And there it was. In my fucking coat. It wasnā€™t really possible for me to see photographs on my phone ā€“ that shit was in my pocket all the time.

Besides, why would I be wearing a coat on summer? And, if I was already wearing a coat, how could I be still cold? How inappropriate were my clothes for that weather? Only a person who sensed that winter solely with the eyes would underestimate its coldness like that!

The boat was really leaving through the canal. The view wasnā€™t photographs. What was all that, then?

I got my phone from my pocket, turned off airplane mode, and opened the Maps app. Come on, where am I?

ā€œNoorder Amstelkanaalā€, I read. Wow.

All of a sudden, February 25th was a cold winter in Amsterdam. My very first one.

Noorder Amstelkanaal
Someone solitary paddling a boat to somewhere in Noorder Amstelkanaal, an Amsterdam's canal.

I guess I travelled to photographs.

\ No newline at end of file diff --git a/blog/catalysis/index.html b/blog/catalysis/index.html new file mode 100644 index 0000000..3d85f0d --- /dev/null +++ b/blog/catalysis/index.html @@ -0,0 +1 @@ +Catalysis | DiƩssica Gurskas
diessi.caBlogMisc
April 13, 2017

Catalysis

As a High School student, I remember always finding Chemistry something between the boring and intriguing. Still, it isnā€™t hard to find myself wondering about the science concepts Iā€™ve learned at that time.

Lately, Iā€™ve been particularly thinking about catalysis.


In Chemistry, catalysis is the acceleration of a reaction due to the participation of a substanceĀ ā€“ the ā€œcatalystā€.

The way a catalyst induces a reaction to happen faster is intriguing. Curiously, it neither gives the reaction more energy nor change its environmental conditions. Catalysts have an even better strategy: they lower the amount of energy required for the reaction to take place.

Diagrama representando conhecimento como ele realmente Ć©
Uncatalyzed reaction (solid) vs. catalyzed reaction (dashed). The highest point is the energy required for the reaction to happen.

In a catalysed reaction, then, the same product is obtained for less energy. Bringing this concept to our lives is quite thought-provoking.

Sometimes it isnā€™t possible for us to achieve something because it demands more time or energy than what we currently have. To deal with this, we then try looking for them in our livesĀ ā€“ which mostly means depriving yourself of things.

However, matter of fact is that optimising isnā€™t always about getting rid of things in your life. If we think of catalysis, we can manage it differently.

What if the problem werenā€™t the lack of energy or time, but that weā€™re in need of too much of them in order to get things done? Having a catalyst would totally figure it out. Without something that pushes us forward, weā€™ll always require more energy for the product we want to get.

At this point, you may think your catalyst is your motivation. Motivation is out of our control though ā€“ which makes it a goal, not a source. Itā€™s also too ephemeral, and a catalyst mustnā€™t ever be consumed by an unique reaction, just like in Chemistry. We canā€™t count on being motivated!

So it goes more like what habitual and practical things in life would give you productivity for less. Is it everyday meditation? A partner by your side? Self-confidence? Inspiring weekends without thinking of work at all? Eating healthy? Going out for a walk every day?

You have to mind what pushes your forward. Catalysts themselves cannot make a reaction happen that wouldnā€™t happen on its own, but they sure make it occur under less extreme conditions. Itā€™s an improvement when youā€™re already motivated.

So, whatā€™s your catalyst?

\ No newline at end of file diff --git a/blog/choose-life-in-berlin/index.html b/blog/choose-life-in-berlin/index.html new file mode 100644 index 0000000..6cc5fbd --- /dev/null +++ b/blog/choose-life-in-berlin/index.html @@ -0,0 +1 @@ +Choose Life šŸ‡©šŸ‡Ŗ | DiĆ©ssica Gurskas
diessi.caBlogMisc
May 12, 2017

Choose Life šŸ‡©šŸ‡Ŗ

Choose life. Choose a job. Choose a career. Choose relocation. Choose giving life a fresh1 beginning. Choose an one-way flight ticket. Choose fitting your entire life in a 23 kg suitcase. Choose getting rid of all your crap. Choose a higher Human Development Index. Choose being thousands of kilometers far away. Choose devastating your loved ones. Choose different bureaucracies you still donā€™t understand. Choose calling another place home. Choose not fitting in (you never did anyway!). Choose saying goodbye to places, food and friends, then choose new places, food, and friends. Choose memories. Choose developing new tastes. Choose being forced to develop social skills. Choose ignorance. Choose mundane and boring activities as exciting adventures. Choose not speaking your mother language. Choose limited self-expression. Choose missing the food from your country, and especially your mumā€™s. Choose letting part of your heart be elsewhere. Choose adapting 24/7. Choose wondering what the fuck you are doing. And choose getting the answer as soon as you go outside. Choose not understanding jokes from natives. Choose recognising you can do anything, anywhere. Choose not knowing if you should. Choose the bittersweet feeling of moving abroad. Choose to be afraid. Choose your future. Choose life.

But why wouldnā€™t I want to do a thing like that?

I chose to choose life. And the reasons? There are no reasons. Who needs reasons when youā€™ve got Berlin?2

1

See HelloFresh, which helped me relocating to Berlin.

2

The entire essay is inspired by Mark Rentonā€™s ā€œChoose Lifeā€ speech from Trainspotting, a movie that makes me think a lot about life choices.

\ No newline at end of file diff --git a/blog/como-eu-vi-a-braziljs-2015/index.html b/blog/como-eu-vi-a-braziljs-2015/index.html new file mode 100644 index 0000000..727f0f2 --- /dev/null +++ b/blog/como-eu-vi-a-braziljs-2015/index.html @@ -0,0 +1 @@ +Como Eu Vi a BrazilJS 2015 | DiƩssica Gurskas
diessi.caBlogMisc
August 26, 2015

Como Eu Vi a BrazilJS 2015

Ɖ mais experiente que volto de mais uma BrazilJS, evento que acontece na cidade onde nasci desde 2012. Aqui, compartilho nĆ£o um relatĆ³rio tĆ©cnico das palestras, nĆ£o acusaƧƵes do que foi ruim ou bom, mas minhas visƵes, em conjunto, sobre a conferĆŖncia e a comunidade.

Importante observar que nĆ£o seleciono aqui a ā€œnataā€ do evento. NĆ£o Ć© minha intenĆ§Ć£o desmerecer qualquer acontecimento. Meu objetivo com esse texto Ć© somente compartilhar o meu ponto de vista sobre o que penso que deve ser comentado.

O primeiro dia

O meu dia comeƧou localizando onde seria o evento. Neste ano, foi no BarraShoppingSul; um shopping que, considerando os outros da cidade, Ʃ de difƭcil acesso mesmo para quem mora hƔ alguns quilƓmetros de Porto Alegre.

O Centro de ConvenƧƵes, ao menos, foi fĆ”cil de achar, e o check-in ocorreu como esperado: pontual. As meninas que forneceram minha credencial estavam de Ć³timo humor ā€” e olha que era um dos primeiros horĆ”rios da manhĆ£ de sexta! Ano passado, o meu check-in foi feito pelo Jaydson, o que fez eu me perguntar onde estaria ele, se nĆ£o credenciando os participantes do evento.

ā€¦E, na verdade, ele tinha se tornado um Power Ranger junto com o Felipe. E Power Rangers nĆ£o fazem check-in. Descobri isso da pior maneira.

Uma abertura idiota

Dois desenvolvedores, os organizadores desse evento que trouxe mais de mil pessoas para o mesmo lugar, brincando de ā€œlutinhaā€ na frente de todo mundo, vestidos de Power Rangers sĆ³ porque o JavaScript fez 20 anos. Essa foi a abertura da BrazilJS, e eu nĆ£o mudaria nada.

Muita gente riu. Muita gente aplaudiu. Eu ri e aplaudi, e aplaudiria de novo, pois, sim, brincaram, mas tambĆ©m fizeram um trabalho muito sĆ©rio. Ainda vestidos de Power Rangers, falaram um pouco da histĆ³ria da conferĆŖncia e das expectativas para esse ano, finalizando com uma mensagem sobre a importĆ¢ncia da diversidade e, sobretudo, do respeito.

Os eventos que se seguiram mostraram que, sim, o trabalho era sƩrio.

Christian Heillman

We are there for them. Not they for us.

Com uma camiseta do Brasil, Christian chegou com um dos assuntos mais importantes na atualidade, e que estĆ” dando muito o que falar: pushing the web forward. Palavras de protagonismo, reiteraĆ§Ć£o do nosso papel, motivaĆ§Ć£o para acreditar na web e no nosso trabalho, e, o mais importante: como isso deve ser feito. Falou, claro, sobre o ECMAScript 6, sobre o Babel, e fez uma anĆ”lise de como resolvemos os problemas atualmente.

We all know the DOM is slow, terrible and to blame for all our problems. Did we allot it to say that way and still be a problem as we abstracted its issues away?

Acredito que essa essa frase foi pesada para muita gente, principalmente em quem estĆ” deprimido de tanto estudar soluƧƵes. Christian mostra que, ao trabalharmos com web, nĆ£o somos apenas desenvolvedores ou designers (ao menos nĆ£o deverĆ­amos ser). Somos tambĆ©m web makers, e esse Ć© o principal problema de simplesmente abstrair e deixar para lĆ”.

Ɖ fĆ”cil entender a razĆ£o dessa abordagem. Heillman trabalha no time de desenvolvimento do Microsoft Edge, o novo e surpreendente navegador padrĆ£o do Windows 10, e esse Ć© o ponto de vista dele enquanto browser maker: somos a representaĆ§Ć£o mĆ”xima do protagonismo, e, por isso, desenvolver nĆ£o deve limitar-se a frameworks ou libraries. Estamos em uma posiĆ§Ć£o em que inovar sempre que possĆ­vel Ć© visto como uma contribuiĆ§Ć£o, e ele ensina a entender esse ponto de vista desde a analogia feita logo nos primeiros slides. NĆ£o devemos esperar que a inovaĆ§Ć£o venha apenas de grandes companhias.

NĆ£o disse para pararmos de usar ES6 com Babel. NĆ£o disse para usarmos ES6 em produĆ§Ć£o e beber Ć”gua de coco na praia. Mas nĆ£o Ć© mentira que existem casos em que podemos, se assim desejarmos, relatar o que estĆ” de errado e o que faz falta, e Ć© justamente aĆ­ que o nosso protagonismo Ć© mĆ”ximo.

Os argumentos foram reĆŗnidos, as situaƧƵes em que podemos nos tornar web makers foram apresentadas, e tudo em prol de provar o nosso protagonismo.

You are a creator of the next web!

Sem dĆŗvidas, uma das melhores palestras que jĆ” assisti na minha vida. Ɖ difĆ­cil relatar uma interpretaĆ§Ć£o detalhada sobre a mensagem do Christian, mas, aos que jĆ” se sentiram no dever de fazer a web um lugar melhor alguma vez e nunca deixaram de acreditar nessa mĆ­dia, acho que essas minhas palavras foram mais que o suficiente para compreender o pensamento dele. Simples e sensacional.

Use lowlevel

Tive dificuldades em acompanhar o raciocĆ­nio do Douglas Campos algumas vezes, e noto que isso se deu em razĆ£o de ele nĆ£o estar falando a lĆ­ngua nativa. NĆ£o entro aqui no mĆ©rito das palestras em InglĆŖs ou PortuguĆŖs (para mim tanto faz desde que o palestrante consiga passar a mensagem de forma fluente na lĆ­ngua escolhida), mas reforƧo a importĆ¢ncia de fazer a escolha certa, pois a tua escolha afeta um pĆŗblico que estĆ” confiando na tua capacidade enquanto transmissor.

Douglas falou sobre compiladores, e engajou os desenvolvedores a entender how things work under the hood, explorando conceitos como AST (Abstract Syntax Tree), um assunto que estĆ” finalmente chamando a atenĆ§Ć£o em JavaScript, tanto que nĆ£o foi a primeira vez que foi abordado na BrazilJS.

Acredito que o questionamento que o palestrante buscou provocar no pĆŗblico nĆ£o teve ĆŖxito. Os 30 minutos, infelizmente, nĆ£o foram bem aproveitados e nĆ£o atenderam Ć s perguntas que o Douglas tentou provocar e responder. Ficou a sensaĆ§Ć£o de uma mensagem subentendida, no entanto:

Itā€™s really important for us to take a look at the things we donā€™t necessarily like.

JavaScript at Spotify

Felipe Ribeiro juntou os desafios encontrados durante a transiĆ§Ć£o do Spotify (nativo com C++ para hĆ­brido), e o resultado foi uma palestra bastante completa sobre arquitetura e engenharia de software. Diversificou bastante a programaĆ§Ć£o da conferĆŖncia, e mostrou que devemos analisar a necessidade de re-escrita de cĆ³digo em uma aplicaĆ§Ć£o complexa sob uma Ć³tica criteriosa que equilibra utilidade, valor e esforƧo necessĆ”rio.

Desafios

Os desafios foram bastante interessantes. Um deles foi o gerenciamento de memĆ³ria no Spotify, jĆ” que se trata de uma aplicaĆ§Ć£o que nĆ£o Ć© descartada com a mesma frequĆŖncia de um site. Outro, a organizaĆ§Ć£o do cĆ³digo, que era excessivamente fragmentado, o que prejudicava a padronizaĆ§Ć£o (diferentes versƵes de mĆ³dulos), manutenĆ§Ć£o (atualizaĆ§Ć£o em ā€œefeito cascataā€) e integraĆ§Ć£o contĆ­nua do projeto.

Releases

O Spotify estabeleceu uma cultura colaborativa de testes (sempre gostei dessa abordagem!). Os empregados usam somente versƵes experimentais da aplicaĆ§Ć£o, ajudando a testar e agilizar os hotfixes. O release Ć© gradual, e Ć© distribuĆ­do na medida em que a versĆ£o vai apresentando estabilidade aos usuĆ”rios que jĆ” possuem acesso.

A saga dos 12 tĆ³picos de acessibilidade

A primeira vez que conheci o Reinaldo Ferraz foi no Front in POA em 2012. Na Ʃpoca, acessibilidade era mais novidade para as pessoas do que Sass. Todos conheciam Sass, ninguƩm conhecia WCAG.

Lembro de ter sido uma das palestras mais marcantes e diferentes do evento, e nĆ£o foi diferente na BrazilJS. Esta foi a mensagem que ficou:

"Aplicar tĆ©cnicas de acessibilidade em um site com usabilidade ruim Ć© como passar batom em um porco. NĆ£o importa o quanto vocĆŖ passe, ele continuarĆ” sendo um porco."

500 days of open source

Uma palestra que dividiu bastante o pĆŗblico. Na verdade, acredito que o Raphael Amorim deu o melhor dele para fazer o discurso significar exatamente o que ele queria que significasse. O Raphael sabe se comunicar muito bem, e paciĆŖncia foi o Ćŗnico requisito para captar a mensagem.

Vi muita dedicaĆ§Ć£o na apresentaĆ§Ć£o que ele fez. Organizou os aprendizados e os desafios de seguir Ć  risca a proposta do John Resig, e os apresentou mostrando que ā€œpreencher grade de contribuiƧƵesā€ ou ā€œse sentir no dever todo diaā€ nĆ£o Ć© o suficiente para progredir. Inclusive, para quem acredita que isso Ć© o suficiente, apresentou o Rockstar.

Esse tipo de palestra Ć© essencial, e eu nĆ£o estou disposta a discutir isso com ninguĆ©m. Havia mais de mil pessoas no mesmo lugar, e, por mais que nĆ£o pareƧa, Ć© uma minoria que contribui ou gerencia algum projeto open source, e tambĆ©m Ć© uma minoria que contribui hĆ” tempo o suficiente para passar por todos os desafios que o Raphael passou. Foi uma palestra sobre open source, mas tambĆ©m sobre esforƧo e saber o que estĆ” te movendo para se esforƧar mais: criar.

(Entendi o trocadilho no nome, a propĆ³sito.)

David Bryant

Happy birthday, JavaScript!

Terminou o primeiro dia de BrazilJS tal como o Christian o iniciou: fazendo-nos acreditar no que trabalhamos. David Bryant, que faz parte do leadership team da Mozilla, falou sobre a evoluĆ§Ć£o do JavaScript atĆ© o seu aniversĆ”rio de 20 anos, e em como devemos acreditar na web em detrimento da plataforma nativa. Para isso, lembrou da palestra Nick Desaulniers, anterior a dele, que mostrava quanto esforƧo tem sido feito para que a web alcance a plataforma nativa.

David, representando a Mozilla, deixou Ć³bvia a mensagem: a web Ć© a melhor plataforma.

O segundo dia

What can you build with a log

James comeƧa explicando sua motivaĆ§Ć£o: a impermancĆŖncia e a centralizaĆ§Ć£o do conteĆŗdo sĆ£o coisas negativas da web. O que podemos fazer sobre isso? UĆ©, abrir o Vim, e construir meu cliente torrent, Flickr, Twitterā€¦

O Substack Ć© uma pessoa extremamente simples e humilde. Ɖ impossĆ­vel nĆ£o achĆ”-lo, no mĆ­nimo, adorĆ”vel. Um dos live codings mais fluĆ­dos e espontĆ¢neos que jĆ” assisti.

Reduce: seu novo melhor amigo

A Ju GonƧalves explicou o uso do reduce() na prƔtica. (Na prƔtica mesmo, para sair da BrazilJS usando, caso nunca tenha usado.)

O tema escolhido complementou muito bem a palestra de programaĆ§Ć£o funcional do Jacob Page, anterior a dela. O formato ficou perfeito para 30 minutos (a propĆ³sito, a ideia de abordar apenas o reduce() foi muito legal!), e deu para aprofundar bastante em algo que deve fazer parte do dia a dia. SĆ³ fiquei com a sensaĆ§Ć£o de que 5 minutos a mais ajudariam ela a guiar os exemplos com mais calma. O tempo estava bastante inflexĆ­vel nesse quesito.

Enfim, a Ju sabe o que faz. NĆ£o a conhecia pessoalmente ainda, mas conheƧo o trabalho e o entusiasmo dela e apostaria nela de longe, tal como a organizaĆ§Ć£o da conferĆŖncia, sem dĆŗvidas, fez.

ECMAScript 6: O que HĆ” de Novo, O que Mudou, O que tem de Bacana ou de Estranho!

Tƭtulo engraƧado.

Quem foi na BrazilJS do ano passado sabe muito bem quem Ć© Jonathan Sampson. Em 2014, ele deu um nĆ³ na cabeƧa do Daniel Filho ao falar PortuguĆŖs durante a entrevista.

No entanto, ano passado ele palestrou em InglĆŖs. Neste ano, ele falou sobre o ES6 totalmente em PortuguĆŖs, e fez muita gente rir com coisas simples, como, por exemplo, referir-se aos que nĆ£o entendiam hoisting de variĆ”veis como ā€œchorƵes do Stack Overflowā€, ou atĆ© mesmo perguntar como se traduz replace (todo mundo sabe que Ć© ā€œsubstchitutituirā€, no caso).

JavaScript Robotics: A NodeBots show

JuliĆ”n Duque Ć© uma pessoa admirĆ”vel. Eu fico realmente muito alegre vendo o envolvimento dele com projetos como a NodeSchool. Pelo tĆ³pico da palestra, dĆ” para ver como ele acredita bastante em JavaScript.

Como o Laurie disse, o trabalho feito foi sensacional. Mereceu todos os aplausos recebidos, tanto pela apresentaĆ§Ć£o quanto pelos projetos paralelos que organizou.

E ele fala PortuguĆŖs (nĆ£o sĆ³ no Twitter).

Brendan Eich

NĆ£o estive na BrazilJS 2012, entĆ£o esse foi o meu primeiro encontro com aquele conhecemos como criador do JavaScript.

A palestra dele foi engraƧada, motivacional e tambƩm tƩcnica. Falou sobre como foi criar o JavaScript em 10 dias, deu explicaƧƵes sobre o wtfjs, e mostrou o quanto valeu a pena acreditar no JavaScript.

Terminou com a frase que foi a grande mensagem da BrazilJS 2015: always bet on JS.

O fim

O evento acabou com um show de rock e cerveja artesanal. NĆ£o sou uma pessoa agitada, nem gosto de beber cerveja, nem queria me arriscar a chegar tarde em casa (voltaria de Ć“nibus), entĆ£o me limitei a finalizar meu dia indo falar com o Daniel Filho, que estava com outras duas pessoas, o Leonardo Balter e o Igor-que-foi-aprender-InglĆŖs.

(Conversar com o Leonardo faz bem para a mente, pois ele nĆ£o sĆ³ se dispƵe a te ouvir como tambĆ©m te recebe bem. Se um dia encontrĆ”-lo, inicie uma conversa, talvez vocĆŖ ganhe um grande amigo.)

Saindo do BarraShoppingSul, lembro que, fora do shopping, aquele Ć© um lugar deserto. Deserto. Em direĆ§Ć£o a parada, com meu computador na mochila, encontro um homem que promete nĆ£o me assaltar e que sĆ³ quer dinheiro para ir para casa. Dou o que tenho para ajudar, e ele insiste que eu dĆŖ mais, afirmando saber que eu tenho mais. Nego gentilmente, e entro no T4 para ir embora logo. E, aos que nĆ£o conhecem Porto Alegre, o T4 Ć© simplesmente o Ć“nibus mais inseguro da cidade.

Era um assaltante. Isso foi me dito no Ć“nibus por uma moƧa, que disse tambĆ©m que tive sorte de nĆ£o ter sido assaltada. NĆ£o entendi o que me salvou, se foi a distĆ¢ncia que mantive do homem, se foi o fato de eu nĆ£o estar desatenta no celularā€¦ Enfim, cheguei em casa bem e feliz com os dois dias que se passaram.

Notas sobre o espaƧo

  • O lugar onde a conferĆŖncia ocorreu Ć© legal, pareceu bem mais aberto que o Bourbon Country e nĆ£o distancia as pessoas de quem palestra. O Teatro do Bourbon Country Ć© confortĆ”vel, exageradamente belo, possui uma Ć³tima acĆŗstica; mas, alĆ©m de enjoar, valoriza muito quem estĆ” palestrando, pois Ć© um espaƧo para dar palestras e nada mais. Todo o networking que acontece ali Ć© fora de onde as palestas ocorrem.
  • O espaƧo nĆ£o Ć© mais aberto no sentido de nĆ£o te sufocar. O local fica no subsolo do shopping, portanto, nĆ£o hĆ” acesso fĆ”cil e sem demora a rua, como havia no Bourbon Country. Lembro bem de ver o sol na BrazilJS do ano passado. Parece pouco, mas Ć© muito importante quando se fica dois dias no mesmo lugar, com luz artificial e tal. Isso simplesmente dĆ” muita abertura para acelerar a fadiga, ainda mais que vocĆŖ acaba comendo no shopping pela facilidade (pois a Ćŗnica coisa que tem no bairro do Barra Ć© o prĆ³prio Barra, sĆ©rio), entĆ£o vocĆŖ nunca sai dali. Sinceramente, durante essa BrazilJS, eu esqueci que orbitĆ”vamos ao redor de uma estrela chamada Sol. (Esse parĆ”grafo Ć© muito pessoal, realmente nĆ£o espero que ninguĆ©m concorde comigo com meus exageros, e de nenhuma forma exijo que sejam levados em consideraĆ§Ć£o.)
  • Muitas pessoas levam notebooks e o EspaƧo BrazilJS foi uma Ć³tima ideia para lidar com isso. Conciliou o Ćŗtil (reconferir palestras, programar durante coffee break) ao agradĆ”vel (nĆ£o ficar no computador durante palestras). Ɖ muito legal ter um lugar para ficar com o notebook, embora eu nĆ£o recomende levar caso vĆ” embora de Ć“nibus, como vivenciei.

Notas finais

  • Foi difĆ­cil comer e beber no primeiro dia. Percebi que, em vez de as pessoas organizarem-se em filas, muitas ficavam no entorno da mesa do coffee break, e isso dificultou muito o fluxo. No segundo dia, no entanto, foi bem mais organizado.
  • Os organizadores nĆ£o param. EstĆ£o sempre envolvidos com o evento, resolvendo pendĆŖncias e atendendo a feedbacks. Houve dedicaĆ§Ć£o integral por parte do Daniel, Felipe e Jaydson em fazer uma conferĆŖncia confortĆ”vel para todos. O segundo dia nĆ£o foi mais tranquilo porque simplesmente foi e a a conferĆŖncia deste ano nĆ£o foi mais diversa porque simplesmente foi. AgradeƧo a eles por isso.
  • Percebi uma mudanƧa de formato em vĆ”rios aspectos neste ano, e a principal delas foi a reduĆ§Ć£o da duraĆ§Ć£o das palestras. Bastante notĆ”vel. 30 minutos por padrĆ£o, e aproximadamente 1 hora para keynotes. Gostei bastante, jĆ” que possibilitou uma transiĆ§Ć£o bem saudĆ”vel entre assuntos e palestrantes, o que ajuda muito a digerir o conteĆŗdo. A BrazilJS dura 2 dias inteiros que terminam cansativos, e Ć© fato que isso acelera o cansaƧo, mesmo quando a apresentaĆ§Ć£o estĆ” muito interessante.
  • Quanto mais eu comia o chocolate da Mozilla, mais eu queria. Tive de comer 7 seguidos para satisfazer o meu consumo desenfreado de aƧĆŗcar. E nĆ£o recomendo para ninguĆ©m.
  • A quantidade de homens Ć© avassaladora. Embora as iniciativas em apoio Ć  diversidade tenham sido realmente efetivas (vi, por exemplo, mais mulheres neste ano), sabe-se bem que uma mulher na BrazilJS Ć© uma mulher em meio a homens. Ɖ o que a proporĆ§Ć£o permite afirmar.
  • NĆ£o havia camisetas da BrazilJS para mim, e isso me deixou um pouco triste, pois elas estavam muito bonitas neste ano. Segundo o Eu Compraria, a confecĆ§Ć£o foi apenas de versƵes masculinas da camiseta. No entanto, o problema nĆ£o Ć© a versĆ£o ser masculina, o problema Ć© que o tamanho P da versĆ£o masculina Ć© gigante em mim. AtĆ© a vendedora ficou com dĆ³ da minha situaĆ§Ć£o. :-(
  • O BarraShoppingSul Ć© um shopping completo e muito espaƧoso, mas o bairro onde ele estĆ” Ć© bastante inseguro e difĆ­cil de acessar caso vocĆŖ nĆ£o esteja vindo de carro.
  • O Daniel Filho Ć© um apresentador muito legal.
  • A BrazilJS 2015 foi Ć³tima, e isso me deixa bastante ansiosa para a conferĆŖncia de 2016.

AtĆ© o prĆ³ximo ano!

\ No newline at end of file diff --git a/blog/computer-and-human-languages/index.html b/blog/computer-and-human-languages/index.html new file mode 100644 index 0000000..abca7a1 --- /dev/null +++ b/blog/computer-and-human-languages/index.html @@ -0,0 +1,45 @@ +Computer and Human Languages | DiƩssica Gurskas
diessi.caBlogMisc
June 20, 2018

Computer and Human Languages

Basic knowledge of computer languages (mainly JavaScript) is assumed.

Some time ago, a friend of mine asked how skilled Iā€™d say I was with JavaScript. I told him I was fluent.

ā€“Ā Fluent? What does it mean to be fluent?

ā€“Ā Well, think Portuguese. ā€“Ā We both speak Portuguese ā€” I donā€™t know every word, but I do know the language enough to express anything I need somehow.

It turned out that ā€œfluentā€ was just the perfect word.


Fluency is a powerful and straightforward concept to express your ability with a language. When it comes to human languages, itā€™s the ability to fully communicate your intentions to a human; for computer languages, the ability to fully communicate your intentions to a computer.

That line of thought is shared in one of the most important and revolutionary introductory books to Computer Science. In Structure and Interpretation of Computer Programs, right before introducing Lisp (the programming language used throughout the book) a similar analogy is made:

Just as our everyday thoughts are usually expressed in our natural language (such as English, French, or Japanese), and descriptions of quantitative phenomena are expressed with mathematical notations, our procedural thoughts will be expressed in Lisp. 1

For both kinds of languages, the levels are the same: one cannot communicate; can poorly do it (beginner); can do it (native/fluent), or can brilliantly do it (think book authors, public speakers, and Software Engineers in a senior level).

Why do they match so well?

They match because the linguistics of computer and natural languages wonderfully intersect. Both consist of syntax, semantics and pragmatics functions, found in the core of theoretical linguistics.

In their ecosystem, we can also find syntax trees and different style guides.

Syntax

Syntax is the set of rules that govern how language elements are combined to form a valid expression.

In English, the basic rule is that elements like nouns, verbs and punctuation marks must follow the subject-verb-object order to produce a valid sentence. In JavaScript, a programming language, to produce a valid conditional statement, elements such as if, parenthesis, braces, comparison operators (===, <= ) must be combined in a certain order too.

In the same way that ā€œDo they car a put?ā€ (??) is not valid English, the following code is not valid JavaScript:

if {1 === 2} (
+  return true
+)
+// => SyntaxError: missing ( before condition
+
+add x y = x + y  // u can't use elm's lambda syntax on js, no
+

And just like a pedant friend would do when you write shitty English, the computer will throw a syntax error when running your program. Forgot closing a brace? Wrote an if statement condition using curly braces instead of parenthesis? Well, SyntaxError!

This, however, is valid JavaScript:

if (1 === 2) {
+    return true
+} // "if (1 === 2) return true" is also fine!
+
+const add = (x, y) => x + y
+

In HTML there are syntax rules too. Adding a div inside ul, for instance, is invalid. An unordered list in HTML (ul) only allows list items as children, such as li ā€“Ā and div is not one.

Languages have different degrees of syntax strictness, which is what usually makes some harder to grasp than others. Think the German language ā€“ German imposes very strict rules for articles: they may vary in number, gender, and function. English, on the other hand, has a definite (the) and an indefinite article (a/an)Ā ā€“ and thatā€™s it.

The same applies to computer languages: some happen to be extremely strict when it comes to syntax, while others are designed for greater syntactic flexibility, letting you achieve the same result in different ways. Think semicolons: they are optional when ending statements in JavaScript, but mandatory in C.

Semantics

Semantics is what the language expression evaluates to. In human languages, expressions evaluate to thoughts, questions, answers; while computers evaluate expressions to CPU instructions that comprise a programā€™s flow.

Consider the following English statement:

The ant ran over the car.

I donā€™t know what ants you are familiar with, but even though the sentence contains the necessary elements in correct order and grammar, that doesnā€™t make sense. The statement is syntactically correct but semantically wrong ā€“Ā we canā€™t conceive a meaning from it.

(ā€œThe car ran over the antā€, however, would be definitely more acceptable to our ears.)

We can relate semantics to computer languages in several ways (like ā€œsolving the wrong problemā€, basically), but the ā€œsemanticā€ word bubbles up more often when we think about HTML. Consider the following markup:

<span>What is a fruit?</span>
+<div>
+    A fruit is something that humans eat. Some examples of fruits are:
+    watermelon, pineapple and apples.
+</div>
+

The elements span and div do exist in the language and are validly marked in this case (I didnā€™t do >div<, right?), so the browser will understand and show it accordingly to the user. The syntax is correct; yet, span and divs are non-semantic elements, so computers wonā€™t get any meaning from it. Again, syntactically correct but semantically wrong.

That text, though, is clearly a title and a paragraph. With a bit of HTML knowledge, we can communicate this in a meaningful way to computers! The language provides elements to achieve that.

The following code improves the previous markup for better semantics.

<h1>What is a fruit?</h1>
+<p>
+    A fruit is something that humans eat. Some examples of fruits are:
+    watermelon, pineapple and apples.
+</p>
+

The element h1 is being used to communicate the main title, and p communicates the paragraph. Both syntax and semantics make sense now!

Pragmatics

Pragmatics is what the language expression evaluates to within its interactional context ā€“Ā which might totally affect semantics and syntax.

In a natural language, the context is essentially built around the cultural aspects of the speaker, place, time, manner, and several others unpredictable aspects that humans introduce when communicating.

For computer languages, we can see pragmatics as the methodology or implementation used when approaching a problem: composition vs. inheritance, functional vs. imperative, picking a Design Pattern etc.

Consider the following examples:

  • A child saying that the food is horrible to a beginner that started cooking just recently.
  • A new joiner in the company filters items in an JavaScript array using forEach, but the team expected filter to be used ā€“Ā a more functional approach.
  • A programmer implements Fibonacci with recursion instead of iteration.
  • Your friend uses a very erudite language to add a cake recipe on the internet.

What do they all have in common? By themselves, they are neither right or wrong ā€“ unless you consider the context in which they were approached in.

Having either syntax or semantic skills wonā€™t help you understand whatā€™s wrong, since pragmatics is more about whatā€™s appropriate within a context. Some approaches are more elegant, antiquated, or dialect-basedĀ than others, and we can only tell how valid they are considering what we are trying to achieve.

Syntax trees

Both kinds of languages can be represented using syntax trees, a concept that reuses the mathematical concept of partially ordered sets.

Human languages are analysed through the Concrete Syntax Tree (ā€œCSTā€), a context-free analysis that tells us about the function of each language token (word, punctuation etc) used.

This is the Concrete Syntax Tree for the previous sentence, ā€œThe water drank a glass of Mary.ā€:

Concrete Syntax Tree of the sentence 'The water drank a glass of Mary.'
Concrete Syntax Tree for a sentence in a human language, where "S" stands for "sentence", "N" for "noun", "V" for "verb", and P for "phrase". See Wikipedia on Parse Trees for more information.

Computer languages are also represented using syntax trees! When the code (high-level) gets translated into instructions for the computer (low-level), a program called compiler make uses of them. The Concrete Syntax Trees for a program contains a lot of detailed information, from whitespaces to language expressions, so you can imagine a CST for a real-world JavaScript program as something really lengthy.

What compilers do might be tough to understand at first, but think of this program inside us that converts languages to meaning ā€“ our internal compiler. Kids improve their compilers while communicating with their families, so every day they get to understand their mother language even more. If you understand English yet struggle with German, we can say your German compiler is pretty bad and has to be improved.

The compiler simplifies the CST down to the expressions that truly represent the program after syntax analysis. Thatā€™s where the Abstract Syntax Tree (AST) comes in: the syntax tree that actually lies at the heart of semantic definitions!

Letā€™s consider the following JavaScript program:

let x = 0
+
+if (x) {
+    x++
+}
+

This is the Abstract Syntax Tree for it:

Concrete Syntax Tree of the sentence 'The water drank a glass of Mary.'
Abstract Syntax Tree for a JavaScript program.

Itā€™s really about the essentials when considering language grammar. If a whitespace means nothing in a language, that wonā€™t show up in the AST.

Compare that against a Concrete Syntax Tree for another program of similar size, which is way more detailed, and therefore more useful in a language-specification level.

Style guides

When the same expression can be written in several ways because the language is not strict enough about it, style guides aim to answer the question of which style to go for. Curiously, style guides of writing are just as useful for programmers as they are for journalists!

Letā€™s say Iā€™m telling someone my favourite fruits. I could do it in different ways:

My favourite fruits are watermelon, bananas and strawberries.
+
+// or using the Oxford comma
+My favourite fruits are watermelon, bananas, and strawberries.
+

The Oxford comma comes from the Oxford Style Guide.

In JavaScript, you can write a JavaScript object in different ways too:

const hero = {
+    firstName: "Ada",
+    lastName: "Lovelace",
+    birthYear: 1815,
+    superPower: "computers",
+}
+
+// or comma-first style
+const hero = {
+    firstName: "Ada",
+    lastName: "Lovelace",
+    birthYear: 1815,
+    superPower: "computers",
+}
+

Either way, thereā€™s no definite rule. They mean the same, only changing their style of writing.

Some examples of style guides are Airbnbā€™s Style guide, for writing JavaScript; and Chicago style guide, for general writing.

Where they donā€™t match

The programmer, like the poet, works only slightly removed from pure thought-stuff. He builds his castles in the air, from air, creating by exertion of the imagination. [ā€¦] Yet the program construct, unlike the poetā€™s words, is real in the sense that it moves and works, producing visible outputs separately from the construct itself. It prints results, draws pictures, produces sounds, moves arms. 2

Even with all the similarities, programming languages are still artificial, while human languages are natural. Computers are rigorous, wonā€™t allow you to be ambiguous, and only get what you mean if you put it the right way.

You wonā€™t have filler words in a computer language, because computers donā€™t benefit from your thought process. Humans do benefit, though, and Iā€™d even say that those communication imperfections is what connects us to others.

Apart from that, a programming language is an interface between you and a computer, while a natural language is an interface between you and another human being. You are communicating to a computer, but as a human ā€“ and you probably wonā€™t be the only one doing it.

Writing in a way thatā€™s meaningful for both is therefore part of the writing process ā€“ and probably the most demanding one.

Final thoughts

Just like experienced programmers look at documentation and easily apply language features to create pieces of software, fluent English speakers would look at the dictionary and easily come up with phrases.

Because both computer and natural languages share linguistic structures, speaking about programming skills in terms of fluency works just as well.

After all, fluency is all about how easily our intentions are expressed with a language.


As a next reading, I'd highly recommend Exploring the Linguistics Behind Regular Expressions if you are interested in the linguistics of computer languages.


Follow the discussion thread on Reddit

1

ā€œProgramming in Lispā€ in ā€œStructure and Interpretation of Computer Programsā€, 1979.

2

Fred Brooks. ā€œThe Mythical Man-Month: Essays on Software Engineeringā€, 1975, page 7.

\ No newline at end of file diff --git a/blog/creativity/index.html b/blog/creativity/index.html new file mode 100644 index 0000000..14bf6c6 --- /dev/null +++ b/blog/creativity/index.html @@ -0,0 +1 @@ +Creativity | DiƩssica Gurskas
diessi.caBlogMisc
February 05, 2018

Creativity

In a life where, by default, thereā€™s no meaning at all, I value creating above all. If Iā€™m creating, thatā€™s a meaningful day.

Lately, Iā€™ve been pondering on the phenomenon of creativity and why creative people are so inspiring to be around. They just broaden my perception of the universe profoundly. What really happens?

The Phenomenon

In an interview in the late 1990s1, Steve Jobs said something that years later would be seen as one of the most simple but accurate definitions of creativity:

Creativity is just connecting things.

And he followed with something I couldnā€™t help but relate: ā€œWhen you ask creative people how they did something, they feel a little guilty because they didnā€™t really do it, they just saw something. It seemed obvious to them after a while. [ā€¦]ā€.

In the wake of being called creative, I was used to responding with the most unfair answer ever: ā€œBut everything I did was mixing stuff from here and there!?!ā€œ. It turns out, however, that ā€œmixing stuffā€ actually describes precisely the process creative people go through.

And when Steve Jobs said that, he was mixing stuff as well! He most likely got inspired by James Webb Youngā€™s conception of idea, presented in his book A Technique for Producing Ideas, from the 1940s.

An idea is nothing more nor less than a new combination of old elements [and] the capacity to bring old elements into new combinations depends largely on the ability to see relationships.

For James to suggest that, well, guess what? He was inspired by Pareto's idea of the "speculator", a personality type characterized by a constant preoccupation with the possibilities of new combinations of old elements. (Which sort of proves his own point on "ideas as a combination of old elements".)

Creatives are just so overloaded with elements to mix that those overflow and flow out of their heads, and they canā€™t help but inspire everyone around.

They reframe experiences and mix their elements to be synthesised into something valuable and unique. From songs, painting, programming to scientific theories ā€“ all of them comes from mixtures. When the mixture feels good, either as a homogeneous or heterogeneous result, itā€™s then a creation.

The Creation, The Weird

Creativity comics
Creativity, by Alex Norris.

When the creation distances itself too much from its origin elements (which are things people are already aware of, most likely), itā€™s perceived as weird, rather than authentic. But thatā€™s when we truly innovate! To come up with the weird, though, we have to limit ourselves to certain existing elements ā€“ an outstanding habit people like Alan Turing had.

Alan Turing was an inspiring computer scientist. Among other cool stuff, he proposed humans to consider the question "Can computers think?", and also designed cryptanalytical machines, crucial to cracking German encoded communication during the World War II. Cool stuff!

As described by James Wilkinson, who worked closely with him, Turing avoided looking at previous work on a topic just so he could invent something truly original, truly weird.

ā€Turing had a strong predilection for working things out from first principles, usually in the first instance without consulting any previous work on the subject, and no doubt it was this habit which gave his work that characteristically original flavor.ā€œ 2

Finally, the ones who release their creations end up turning into painters, mathematicians, writers, architects, sculptors, programmers, musicians. Itā€™s a process that happens in absolutely every realm of thinking and work.

And you know what?

ā€¦Itā€™s Been Shown by Nature

When Young and Steve Jobs pointed out that the creative process wasnā€™t magic, they, again, didnā€™t do anything ā€œnewā€ either. That definition has been shown by Nature for a long time, and, as early as 450 B.C, the philosopher Anaxagoras described it:

Wrongly do the Greeks suppose that something3 begins or ceases to be; for nothing comes into being or is destroyed; but all is an aggregation or secretion of pre-existing things; so that all becoming might more correctly be called becoming mixed, and all corruption, becoming separate.

That might remember you of the Law of Conservation of Mass, later defined by the chemist Antoine Lavoisier.

Just like in the creative process, Nature has always found a way out of its problems by coming up with solutions from pre-existing elements. Even the Planet Earth has transformed from a violent, molten rock to a supporter of life by using what the Universe had already provided!

Its process of creation was the same as the humanā€™s creative process for the discovery of fire, the invention of the wheel, shitty and useful startup ideas, the Pink Floydā€™s Echoes song, and all quotes in this post: mixing, connecting, combining ā€œstuffā€. From the Planet Earth to what youā€™re reading right now, the laws that ruled their creations were, in essence, the same.

2

James H. Wilkinson, ā€œSome Comments from a Numerical Analystā€, 1970. Turing Award lecture, Journal of the ACM. February 1971.

3

Iā€™ve deliberately changed ā€œaughtā€, an archaic English word, to ā€œsomethingā€ for the sake of readability.

\ No newline at end of file diff --git a/blog/dental-health-and-habits/index.html b/blog/dental-health-and-habits/index.html new file mode 100644 index 0000000..779ba7b --- /dev/null +++ b/blog/dental-health-and-habits/index.html @@ -0,0 +1 @@ +Dental Health and Habits | DiƩssica Gurskas
diessi.caBlogMisc
December 21, 2017

Dental Health and Habits

Brushing teeth is a good habit. An easy-to-build one, Iā€™d say, thanks to the immediate reward given by the refreshing sensation. After brushing, you feel clean right away.

On the other hand, flossing teeth isnā€™t a habit as easy to build. After flossing, what comes to mind is how dirty your teeth still were even though you just brushed, not how cleaner they became. Thereā€™s no such thing as a fresh sensation in your mouth.

When you finish brushing your teeth, theyā€™re still dirty ā€“Ā no doubt. However, itā€™s still gratifying, since youā€™re fooled by the menthol ability to trigger the cooling sensation.Ā (Hence the human inclination to brushing rather than flossing!?)

In terms of dental health, though, flossing teeth is more effective on cleaning than brushing1, even if it doesnā€™t feel like it. Thereā€™s no immediate reward in flossing, but definitely a long-term one.

What am I trying to say? Apart from dental health advice, that sort of reminds me that we shouldnā€™t rely on feeling instantaneously compensated as a fuel to build habits. After all, some things just need the long-term to pay off; for we to benefit from them.

1

Iā€™ve read that at some point in my life but donā€™t remember where. You can find some resources out there, such as ā€œWhatā€™s More Important: Flossing or Brushing?ā€. Anyway, I think weā€™re safe assuming that flossing is, at least, as important as brushing.

\ No newline at end of file diff --git a/blog/desmitificando-seletores-complexos/index.html b/blog/desmitificando-seletores-complexos/index.html new file mode 100644 index 0000000..373685f --- /dev/null +++ b/blog/desmitificando-seletores-complexos/index.html @@ -0,0 +1,46 @@ +Desmitificando Seletores Complexos | DiƩssica Gurskas
diessi.caBlogMisc
November 28, 2013

Desmitificando Seletores Complexos

Se existem recursos no CSS que a total compreensĆ£o se restringe a uma parcela de desenvolvedores, esses sĆ£o os combinadores filhos (>), irmĆ£os adjacentes (+) e adjacentes gerais (~).

Sem dĆŗvidas, esses 3 combinadores sĆ£o tĆ£o poderosĆ­ssimos quanto mal-explicados. Ɖ importante compreendĆŖ-los integralmente e hĆ” dois bons motivos para isso: o seletor descendente nĆ£o dĆ” conta de tudo e, o Ć³bvio: o CSS estĆ” evoluindo.

X > Y

Todo filho Ć© necessariamente descendente, mas nem todo descendente Ć© necessariamente filho.

ā€” Eu, sobre famĆ­lia

Para que Y seja alvo da seleĆ§Ć£o, nĆ£o importa a posiĆ§Ć£o; basta que seja descendente direto de X - isso Ć©, filho. Em outras palavras, basta que esteja interno diretamente ao elemento pai - e seja somente descendente dele. Isso quer dizer que Y nĆ£o serĆ” alvo caso esteja interno a um elemento Z, mesmo que este esteja interno a X. Por essa razĆ£o o combinador ā€œ>ā€ Ć© tambĆ©m chamado de direto, pois nĆ£o admite elementos internos indiretamente.

Seletor descendente vs. seletor filho

Lembrando da frase dita no inĆ­cio desse tĆ³pico, vocĆŖ jĆ” entende a diferenƧa. Enquanto o descendente (X Y) herda as propriedades aos elementos direta e indiretamente internos (filhos, netos, bisnetosā€¦), o alvo do combinador filho sĆ£o os filhos unicamente diretos - sim, falar isso Ć© redundante. O que faz todo sentido, afinal, um filho Ć© tanto filho quanto descendente; e o neto, bisneto, trineto nĆ£o Ć© um filho, mas Ć© descendente.

Na prƔtica

Imaginemos um artigo e seus respectivos parĆ”grafos. Dentro desse artigo, haverĆ” uma seĆ§Ć£o de informaƧƵes que nĆ£o estarĆ” diretamente relacionada ao artigo. Como o que se quer destacar Ć© a leitura do artigo, seus parĆ”grafos terĆ£o mais ĆŖnfase de alguma forma.

HTML
<article>
+  <h1>TĆ­tulo do artigo</h1>
+  <p>Primeiro parƔgrafo</p>
+  <p>Segundo parƔgrafo</p>
+  <aside>
+    <h2>InformaƧƵes</h2>
+    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit.</p>
+  </aside>
+  <p>Terceiro parƔgrafo</p>
+</article>
+
CSS
article > p {
+  font-style: italic;
+}
+

Assim, somente os parĆ”grafos que sĆ£o filhos diretos do elemento article serĆ£o estilizados.

X + Y

Se para ser alvo do seletor filho a posiĆ§Ć£o era irrelevante, para ser alvo de um seletor irmĆ£o adjacente sua posiĆ§Ć£o Ć© critĆ©rio decisivo. O elemento Y deve ser o primeiro elemento apĆ³s X, com ambos dentro de um mesmo elemento Z (pai). O nome, portanto, Ć© bem autoexplicativo: sĆ£o irmĆ£os por possuĆ­rem o mesmo pai (no caso, Z) e adjacentes por estarem necessariamente prĆ³ximos.

Na prƔtica 1

Supondo um artigo constituĆ­do por um tĆ­tulo e 3 parĆ”grafos. O primeiro parĆ”grafo apĆ³s o tĆ­tulo servirĆ” como uma introduĆ§Ć£o ao artigo e, portanto, deve ser destacado com um aumento no tamanho da fonte.

HTML
<article>
+  <!-- Z -->
+  <h1>TĆ­tulo do artigo</h1>
+  <!-- X -->
+  <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit.</p>
+  <!-- Y -->
+  <p>Debitis sint aperiam numquam nisi animi porro in reprehenderit!</p>
+  <p>Magnam atque placeat fuga sed eligendi maxime neque labore. Doloribus?</p>
+</article>
+
CSS
h1 + p {
+  font-size: 20px;
+}
+

Na prƔtica 2

O checkbox hack funciona com o uso do combinador irmĆ£o adjacente.

HTML

<input type="checkbox" id="hider" />
+<div>Hide me if you can!</div>
+<label for="hider">Esconder div</label>
+

CSS

input[type="checkbox"] {
+  display: none; /* Esconde o checkbox */
+}
+input:checked + div {
+  display: none; /* Quando o checkbox for checado, a div serĆ” escondida */
+}
+

X ~ Y

Seletor do CSS 3, o combinador adjacente geral tem uma definiĆ§Ć£o bem semelhante ao irmĆ£o adjacente. Para que Y seja alvo, os elementos X e Y devem ser filhos de um mesmo elemento (irmĆ£os) e X deve preceder Y, direta ou indiretamente - isso Ć©, para que Y seja alvo, esse precedimento nĆ£o precisa ser imediato.

Na prƔtica

Esse combinador contorna algumas inflexibilidades do combinador irmĆ£o adjacente. Ainda com o exemplo do checkbox hack, podemos personalizar o elemento de forma nĆ£o tĆ£o especĆ­fica quanto Ć  sua posiĆ§Ć£o:

HTML

<input type="checkbox" id="shower" />
+<label for="shower">Mostrar div</label>
+<div>Hide me if you can!</div>
+<div>Hide me too if you can!</div>
+

CSS

input[type="checkbox"],
+div {
+  display: none; /* Esconde o checkbox e a div, por padrĆ£o */
+}
+input:checked ~ div {
+  display: block; /* Quando o checkbox for checado, a div aparecerĆ” */
+}
+

ConclusĆ£o

As linguagens CSS e HTML foram documentadas para serem intuitivas: os elementos formam famĆ­lias com outros elementos pais, filhos, descendentes, irmĆ£osā€¦. Isso fica claro no nome dos seletores, que tĆŖm papel importante na compreensĆ£o do combinador; afinal, caso o desenvolvedor entenda que irmĆ£os tem o mesmo pai e que filhos sĆ£o descendentes diretos do pai, ele poderĆ” tirar um bom proveito do nome dos combinadores para compreender seus funcionamentos.

[ā€¦] In both cases, non-element nodes (e.g. text between elements) are ignored when considering adjacency of elements.

HĆ” uma grande confusĆ£o - e com razĆ£o - entre os seletores irmĆ£os adjacentes e irmĆ£os gerais. Essa confusĆ£o se origina nĆ£o sĆ³ de suas classificaƧƵes como seletores de combinaĆ§Ć£o, mas em seus comportamento e definiĆ§Ć£o semelhantes. Tanto Ć© verdade que o combinador adjacente geral (~) se comportarĆ” muitas vezes como um irmĆ£o adjacente (+), com a diferenƧa de que o adjacente geral Ć© menos exigente quanto Ć  posiĆ§Ć£o do elemento-alvo.

O uso serĆ”, portanto, facultativo em diversas situaƧƵes. E, nesse caso, a minha recomendaĆ§Ć£o Ć© dar prioridade ao combinador adjacente, visto que Ć© um seletor do CSS 2.1 e, portanto, compatĆ­vel com uma maior gama de browsers. :-)

ReferĆŖncias

\ No newline at end of file diff --git a/blog/dont-blame-it-on-react-or-redux/index.html b/blog/dont-blame-it-on-react-or-redux/index.html new file mode 100644 index 0000000..a0a48b3 --- /dev/null +++ b/blog/dont-blame-it-on-react-or-redux/index.html @@ -0,0 +1 @@ +Don't Blame it on React or Redux | DiƩssica Gurskas
diessi.caBlogMisc
March 18, 2017

Don't Blame it on React or Redux

What most people donā€™t know when they first get into Redux is that, just like React, Redux itself is meant to be simple. And as seen that simplicity is a goal, both React and Redux wonā€™t and donā€™t want to tell you how to solve everything.

They wonā€™t tell you how to deal with side effects, or what HTTP request library you should use. Thatā€™s completely delegated to the JavaScript ecosystem.

React and Redux alone donā€™t do much for really complex web applications.

React indirectly delegates state management problems to solutions like Flux. On the other hand, Redux, for instance, delegates dealing with async stuff or even the too-much-boilerplate problem that people complain.

But what motivates React and Redux to be that way? Some reasons I can think of are:

  • Both libraries are highly focused on their principles, not the built-in stuff. The efficiency of them is on the why and how, not the what.
  • They aim to be a great fit for both simple and large applications, so the ā€œplug-in-playā€ approach is followed. (A framework wouldnā€™t ever do everything a programmer needs anywayā€¦)
  • Diversity of solutions. Because React and Redux are more like ā€œplug-in-playā€, the ā€œpluginsā€ (tools, libraries, middlewares) will evolve by themselves. For instance: axios, a HTTP request library, will evolve in parallel to Redux itselfĀ ā€“ which certainly make things move forward faster!

If your applicationā€™s state is messy, donā€™t blame it on React. If you find yourself writing too much boilerplate, donā€™t blame it on Redux. React and Redux donā€™t really do much, but this is by design.

React is awesome not just because it makes it possible to turn a large and complex application into simple components.

Redux is awesome not just because it makes it effortless to deal with and share state throughout an application.

Theyā€™re also awesome because of their great and diverse ecosystem. So, when you buy into React or Redux, itā€™s better for you to buy into their ecosystem too.

\ No newline at end of file diff --git a/blog/encadeamento-de-metodos-em-javascript/index.html b/blog/encadeamento-de-metodos-em-javascript/index.html new file mode 100644 index 0000000..21351e0 --- /dev/null +++ b/blog/encadeamento-de-metodos-em-javascript/index.html @@ -0,0 +1,63 @@ +Encadeamento de MƩtodos em JavaScript | DiƩssica Gurskas
diessi.caBlogMisc
August 06, 2016

Encadeamento de MĆ©todos em JavaScript

Popular em diversas bibliotecas JavaScript, o encadeamento de mĆ©todos (ā€œmethod chainingā€) Ć© uma tĆ©cnica usada para invocar diversos mĆ©todos em um mesmo objeto.

Com o objetivo de melhorar a legibilidade do cĆ³digo, a tĆ©cnica Ć© vastamente utilizada na API da jQuery, o que certamente influenciou na popularidade da biblioteca.

Se vocĆŖ jĆ” utilizou jQuery, o estilo do cĆ³digo abaixo pode ser familiar:

$("#my-element")
+  .css("background", "purple")
+  .height(100)
+  .animate({ height: 250 })
+  .find("input")
+  .fadeIn(200)
+  .val("")
+  .end();
+

No exemplo acima, uma Ćŗnica declaraĆ§Ć£o faz vĆ”rias coisas. No entanto, uma boa prĆ”tica com method chaining Ć© fazer somente uma aĆ§Ć£o por declaraĆ§Ć£o. ;-)

Perceba que vĆ”rios mĆ©todos sĆ£o invocados no objeto $('#my-element'), sem a necessidade de repetĆ­-lo. JĆ” sem Method Chaining, Ć© necessĆ”rio fazer a referĆŖncia diversas vezes:

const myElement = $("#my-element");
+myElement.css("background", "purple");
+myElement.height(100);
+myElement.fadeIn(200);
+

Exemplo

Vamos criar um contador Counter:

class Counter {
+  constructor() {
+    this.value = 0;
+  }
+
+  increase() {
+    this.value += 1;
+  }
+
+  decrease() {
+    this.value -= 1;
+  }
+
+  log() {
+    console.log(this.value);
+  }
+}
+

Agora, vamos instanciar um contador e usar seus mƩtodos:

const counter = new Counter();
+counter.increase();
+counter.log(); // => 1
+counter.decrease();
+counter.log(); // => 0
+

Perceba que Ć© necessĆ”rio fazer vĆ”rias declaraƧƵes para interagir com a instĆ¢ncia, o que prejudica a legibilidade do cĆ³digo.

E se tentarmos usar Method Chainingā€¦

new Counter().increase().log();
+// > TypeError: Cannot read property 'log' of undefined
+

Perceba que log() estĆ” sendo executado em new Counter().increase(), que, por sua vez, estĆ” retornando undefined. Portanto, ainda nĆ£o Ć© possĆ­vel interagir com Counter dessa forma.

Como Encadear MĆ©todos

Para evitar a repetiĆ§Ć£o do objeto, Ć© necessĆ”rio que seus mĆ©todos retornem o prĆ³prio objeto.

Veja este exemplo com Promises:

getJSON("users.json")
+  .then(JSON.parse)
+  .then((response) => console.log("Olha o JSON!", response))
+  .catch((error) => console.log("Falhou!", error));
+

Isso sĆ³ Ć© possĆ­vel pois os mĆ©todos then() and catch() sempre retornam outras promises. Assim, podemos dizer que as Promises sĆ£o fluent APIs, tal como a jQuery.

Quem Lembra do this?

Para os mƩtodos serem encadeados, serƔ necessƔrio retornar o contexto (this) em cada mƩtodo.

Em JavaScript, this sempre se refere ao contexto de execuĆ§Ć£o de funĆ§Ć£o.

No caso de um mĆ©todo, que Ć© uma funĆ§Ć£o de um objeto, refere-se ao prĆ³prio objeto.

Exemplo com Method Chaining Pattern

Para implementar o encadeamento de mƩtodos na classe Counter, apenas retornamos seu contexto a cada mƩtodo:

class Counter {
+  constructor() {
+    this.value = 0;
+  }
+  increase() {
+    this.value += 1;
+    return this; // Aqui!
+  }
+  decrease() {
+    this.value -= 1;
+    return this; // Aqui!
+  }
+  log() {
+    console.log(this.value);
+    return this; // E aqui!
+  }
+}
+

Agora, ao executar new Counter().increase(), o retorno jĆ” nĆ£o serĆ” mais undefined.

ā€¦E, portanto, Ć© possĆ­vel fazer method chaining!

new Counter()
+  .increase()
+  .log() // => 1
+  .decrease()
+  .log(); // => 0
+

ConclusĆ£o

No universo de APIs orientadas a objetos, o encadeamento de mĆ©todos Ć© uma tĆ©cnica incrĆ­vel se o seu objetivo Ć© tornar o cĆ³digo mais expressivo e fluente.

No geral, fluent APIs sĆ£o sim interessantes de se entender e implementar, e vocĆŖ pode ter certeza disso analisando o primeiro exemplo com jQuery do inĆ­cio deste artigo. Ɖ fantĆ”stico! Mas Ć© importante entender que o encadeamento de mĆ©todos nem sempre tornarĆ” as coisas mais fĆ”ceis (debugar, por exemplo, se torna mais difĆ­cil), e, portanto, a maneira aparentemente ā€œmĆ”gicaā€ com que elas funcionam nĆ£o deve ser sempre levada em consideraĆ§Ć£o.

\ No newline at end of file diff --git a/blog/expressive-javascript-conditionals/index.html b/blog/expressive-javascript-conditionals/index.html new file mode 100644 index 0000000..7a7081d --- /dev/null +++ b/blog/expressive-javascript-conditionals/index.html @@ -0,0 +1,165 @@ +Expressive JavaScript Conditionals (for Humans) | DiƩssica Gurskas
diessi.caBlogMisc
October 30, 2017

Expressive JavaScript Conditionals (for Humans)

Conditionals! As programmers, we write at least one every day. Easy to write, horrible to read, and sometimes it seems as though thereā€™s no way to work around that.

Today, Iā€™m happy to share some patterns Iā€™ve learned over time and have spread heavily in code reviews. Letā€™s rethink conditionals to make the most out of a languageā€™s power of expression ā€“Ā in the case of this article, JavaScript.

Patterns for Conditionals

First, to put you in the mood, a quote from Literate Programming1, by Donald Knuth.

The practitioner of literate programming can be regarded as an essayist, whose main concern is with exposition and excellence of style. Such an author, with thesaurus in hand, chooses the names of variables carefully and explains what each variable means. He or she strives for a program that is comprehensible because its concepts have been introduced in an order that is best for human understanding, using a mixture of formal and informal methods that reinforce each other.

That sums up the approach for this post: purely aimed at how to write code for people to read. Performance doesnā€™t matter now, since 1) thatā€™s not the goal and 2) I donā€™t believe in premature optimisation.

Iā€™ll briefly talk about each pattern, but whatā€™s more important here is to read the code carefully and get something out of it (as if it were poetry or something!).

1. Variables that hold conditions

When your condition is made up of an expression (or many of them), you can store it within meaningful-named variables.

Letā€™s say, to illustrate, that our program holds some data about a fruit and we have to check whether that fruit is a banana. We could do this:

const fruit = {
+    colors: ["yellow", "green"],
+    sweet: true,
+}
+
+if (fruit.sweet === true && fruit.colors.some((color) => color === "yellow")) {
+    alert("do your stuff šŸŒ")
+    return "is banana"
+}
+

Or we could store our conditions in variables!

const fruit = {
+    colors: ["yellow", "green"],
+    sweet: true,
+}
+
+const isSweet = fruit.sweet === true // or just `fruit.sweet`
+const isYellow = fruit.colors.some((color) => color === "yellow")
+const isBanana = isYellow && isSweet
+
+if (isBanana) {
+    alert("do your stuff šŸŒ")
+    return "is banana"
+}
+

Not all conditions need to be in a variable. fruit.sweet, for instance, is quite expressive by its own.

This way, if we or our workmates need to know what makes a fruit a banana in our program, itā€™s just a matter of checking out the variable itself. The logic for how conditions evaluate will be there, behind a meaningful name.

Itā€™s even more useful for composing and reusing conditions.

Filtering arrays

In the previous example, all variables were conditions based on the fruit object, for didactic purposes. Commonly, though, those variables actually store (pure) functions that take any fruit and test against it. I'm changing that to fit this example.

Letā€™s say weā€™ve got an array of fruits and we need to filter all the bananas out of it.

const fruits = [
+    {
+        colors: ["yellow", "green"],
+        sweet: true,
+    },
+    {
+        colors: ["red"],
+        sweet: false, // don't know what kind of fruit this'd be
+    },
+]
+
+const isSweet = (fruit) => fruit.sweet === true
+
+const isYellow = (fruit) => fruit.colors.some((color) => color === "yellow")
+
+const isBanana = (fruit) => isSweet(fruit) && isYellow(fruit)
+
+const bananas = fruits.filter(isBanana)
+

So expressive! I love the way that I can read that last line and even a kid (a non-programmer one!) can understand. (Yes, Iā€™ve tried that.)

The currying technique would help introduce expressiveness without the verbosity for isBanana. An optional appendix at the end of the article elaborates more on that, if youā€™re curious.

Thatā€™s it. Hold on to that one though ā€“ itā€™s the foundation for whatā€™s next.

2. Define value conditionally

Still considering the variables from the example above, this could also be done:

const myFruit = isYellow && isSweet && "banana"
+return myFruit
+

The value for the myFruit variable will only be assigned to ā€œbananaā€ if those conditions are true. Pretty useful for when values are defined conditionally!

That saves you from if (isYellow && isSweet) [...], and itā€™s quite expressive, Iā€™d say. An expressive expression. šŸ‘Œ

3. Define value conditionally with fallback

Conditionals, a comic from xkcd
xkcd: Conditionals

What if we want something else in case itā€™s not a banana? Instead of an if (isBanana) [...] with else, go for the ternary operator.

const isBanana = isYellow && isSweet
+const myFruit = isBanana ? "is banana" : "is other stuff"
+return myFruit
+

Some additional but important advice Iā€™d give regarding ternary expressions:

  • Make them as compound as possible.
  • Do NOT nest them. Donā€™t pretend the nesting is readable ā€“Ā itā€™s not even human to do that.
  • Donā€™t avoid writing if statements because you want to look smart.

4. Check for all conditions

Weā€™ve (finally) found out that checking for isYellow and isSweet isnā€™t enough to make sure the fruit is a banana. After all, yellow pepper is both sweet and yellow and itā€™s still not a banana, right?

Right. We then add more checks to the isBanana variable, and this time theyā€™re ugly ones: they check whether the fruit is either from Brazil or Ecuador, both top banana producing countries.

const fruit = {
+    colors: ["yellow", "green"],
+    sweet: true,
+    countries: [
+        {
+            name: "Brazil",
+            topProducer: true, // i'm brazilian and therefore biased
+        },
+        {
+            name: "Ecuador",
+            topProducer: false,
+        },
+    ],
+}
+
+const isSweet = fruit.sweet === true // or just `fruit.sweet`
+const isYellow = fruit.colors.some((color) => color === "yellow")
+const isBrazilian = fruit.countries.find((i) => i.name === "Brazil")
+const isEcuadorian = fruit.countries.find((i) => i.name === "Ecuador")
+const isBanana = isYellow && isSweet && isBrazilian && isEcuadorian
+
+if (isBanana) {
+    alert("do your stuff!11 šŸŒ")
+    console.log("now this is really a banana")
+}
+

Did you see how big isBanana is getting? Weā€™d have to start breaking lines in those && to improve readability, which, personally, I donā€™t like doing.

If refactoring the booleans into new variables isnā€™t an option anymore, what about storing the conditions in an array and testing every item for truthiness?

Use the power of arrayā€™s every:

const isBanana = [isYellow, isSweet, isEcuadorian, isBrazilian].every(Boolean) // or `x => x === true`
+

Repetitive friendly reminder: don't store every condition in a variable. Remember you can always add the condition itself to the array.

You can even turn that into a snippet:

const all = (arr) => arr.every(Boolean)
+
+const isBanana = all([isYellow, isSweet, isEcuadorian, isBrazilian])
+

I donā€™t know how useful that looks for you, but, in everyday work, I really appreciate doing it.

5. Check for any condition

What if weā€™ve got crazy and weā€™re fine considering something a banana when itā€™s either yellow, Brazilian or sweet?

Use the power of arrayā€™s some:

const isBanana = [isYellow, isSweet, isBrazilian].some(Boolean) // or `x => x === true`
+

Yeah, yeah, I know, you can just use the OR operator.

If any of them evaluates to true, profit! ā€“Ā itā€™s a banana. šŸŒ

const any = (arr) => arr.some(Boolean)
+
+const isBanana = any([isYellow, isSweet, isBrazilian])
+

In other words, being a Brazilian means youā€™re a banana! It doesnā€™t sound any bad to me honestly.

Pretty similar to Ramdaā€™s either. šŸ˜Ž

6. Early return

We want something special for when the banana is Brazilian! else conditions would do the trick, wouldnā€™t they?

const fruit = {
+    colors: ["yellow", "green"],
+    sweet: true,
+    countries: [
+        {
+            name: "Brazil",
+            topProducer: true, // i'm brazilian and therefore biased
+        },
+        {
+            name: "Ecuador",
+            topProducer: false,
+        },
+    ],
+}
+
+const isSweet = fruit.sweet === true // or just `fruit.sweet`
+const isYellow = fruit.colors.some((color) => color === "yellow")
+const isBrazilian = fruit.countries.find((i) => i.name === "Brazil")
+const isEcuadorian = fruit.countries.find((i) => i.name === "Ecuador")
+const isBanana = isYellow && isSweet
+
+if (isBanana && isBrazilian) {
+    // first true case!
+    alert("i am a brazilian banana i love football šŸŒ")
+} else if (isBanana && isEcuadorian) {
+    alert("i am an ecuadorian banana do not mess with me šŸŒ")
+} else {
+    alert("a normal banana from somewhere else")
+}
+

Alternatively, THOOOUGH, we can early return (nothing at all, i.e. undefined), which will make our code stops its flow at that point.

if (isBanana && isBrazilian) {
+    alert("i am a brazilian banana i love football šŸŒ")
+    return // sTAAAAHP!!!1
+}
+
+if (isBanana && isEcuadorian) {
+    alert("i am an ecuadorian banana do not mess with me šŸŒ")
+    return // DON'T GO ANY FURTHER, JAVASCRIPT!11
+}
+
+// or do, whatever
+alert("a normal banana from somewhere else")
+

Those checks could also be refactored into a variable named isBrazilianBanana. I found it too much for this example though, so this is just a friendly reminder that your conditions can always be composable.

Keep in mind that early returns might make the flow of your program confusing. Different from when youā€™re using else conditions, itā€™s not explicit that the conditionals are from the same logical group anymore.

7. Check for the same variable

Letā€™s get the colour of the fruits! Each fruit has one.

Hmmmā€¦ Different cases that require different handling, but all handled cases depend on the same thing. What do we do? We conditionally check for its value and handle the case depending on that.

const getFruitColor = (fruit) => {
+    if (fruit === "banana") {
+        return "is yellow"
+    } else if (fruit === "apple") {
+        return "is red"
+    } else if (fruit === "orange") {
+        return "is orange"
+    }
+}
+
+getFruitColor("banana") // => is yellow
+

This code would benefit from early returns, and, of course, the switch statement.

Or we donā€™t. Because, alternatively, we can create a getter function (getFruitColor) that:

  1. inputs a key (fruit), and
  2. outputs the value that was assigned to that key in a specific map (fruitColors).

Like this:

const fruitColors = {
+    banana: 'is yellow'
+    apple: 'is red',
+    orange: 'is orange',
+}
+
+const getFruitColor = fruit => fruitColors[fruit]
+
+getFruitColor('banana') // fruitColors['banana'] => is yellow
+

Simplifying, since that map isnā€™t useful outside of the getter itself anyway:

const getFruitColor = fruit => ({
+    banana: 'is yellow'
+    apple: 'is red',
+    orange: 'is orange',
+}[fruit]
+
+getFruitColor('banana') // => is yellow
+

This is a very common technique I first saw on a blog post from Angus Croll in 2010. I love the simplicity of it.

Nowadays thereā€™s even more freedom with this technique, considering features such as computed property names for objects. But donā€™t get too creative with that! Go for whatā€™s more readable and expressive for you AND the people you work with.

Appendix: Currying, because verbosity isnā€™t expressiveness

This is an additional reading and requires familiarity with curried functions. For further reading on the currying technique, I recommend the "Currying" chapter of the book Mostly Adequate Guide to Functional Programming, or A Beginnerā€™s Guide to Currying, as a more beginner-friendly introduction.

Letā€™s reconsider:

  1. the problem from the 1st, where we had an array of fruits and had to create a function that checks whether the fruit passed to it was a banana, and
  2. the all util from the 4th pattern.

Check for all conditions, revisited

Imagine if we had a lot of conditions for isBanana. We could use && or even all.

const isBanana = (fruit) =>
+    isBanana(fruit) &&
+    isSweet(fruit) &&
+    isEcuadorian(fruit) &&
+    isBrazilian(fruit)
+// or
+const isBanana = (fruit) =>
+    all([
+        isYellow(fruit),
+        isSweet(fruit),
+        isEcuadorian(fruit),
+        isBrazilian(fruit),
+    ])
+

Itā€™s meaningful, easy to read, but introduces too much verbosity. The currying technique could help us introduce more meaning without being verbose. With some changes in the all util, that could be boiled down to:

const isBanana = all([isSweet, isYellow, isEcuadorian, isBrazilian])
+// no explicit fruit here, and still works!
+const bananas = fruits.filter(isBanana)
+

Notice weā€™re not explicitly passing fruit anymore. How do we do that? By making all a curried function. There are some ways to achieve that, hereā€™s one:

const all = (conditions) => (currentItem) =>
+    conditions.map((condition) => condition(currentItem)).every(Boolean)
+

It takes the array of conditions and returns a function that takes the current item and calls each condition with that (as argument!). At the end, we check whether they all evaluated to true. Itā€™s not magic, itā€™s CURRYING!!!112

Thatā€™s, of course, a simplistic implementation, which has costed me an array (from map). Whatā€™s important to get is how we play with function arguments under the hood to achieve currying.

You can curry your functions using Ramdaā€™s curry (or Lodashā€™s, whatever); or, if youā€™re interested on that as an util, Ramdaā€™s all and its source are really worth-checking!

Final considerations

By striving for conditionals as expressions other than statements, you write code in a functional approach. Code with a clearer sense of what itā€™s being checked without having to unearth to its foundations. Code thatā€™s easier and faster for people to reason about.

But if your code is fine with an if rather than an object lookup or a ternary operator, just stick to it.

Itā€™d break the whole purpose of this post if those patterns were used for looking smart. However, if refactoring your conditionals with them would lead to a more expressive codebase, go for it! Play with the patterns, compound them. Use your creativity to communicate well.

Itā€™s a language, after all.

1

A programming paradigm first introduced by Donald Knuth, with the goal of providing an alternative, human, perspective on the programmerā€™s motivation. Read the article.

2

It may seem more magic than currying sometimes. JavaScript isnā€™t a purely functional language, so such techniques arenā€™t as popular as they are in Haskell community, for instance. Simplicity conflicts with easiness here.

\ No newline at end of file diff --git a/blog/fetch-npm-package-without-npm-install/index.html b/blog/fetch-npm-package-without-npm-install/index.html new file mode 100644 index 0000000..c8e9fc6 --- /dev/null +++ b/blog/fetch-npm-package-without-npm-install/index.html @@ -0,0 +1,8 @@ +Fetch a npm package on GitHub without npm install | DiƩssica Gurskas
diessi.caBlogMisc
August 25, 2024

Fetch a npm package on GitHub without npm install

The other day, a npm package was released broken to a private GitHub registry and it wouldnā€™t install:

> npm install @company/my-package
+This error happened while installing the dependencies of @company/my-package@0.0.34
+
+another-package is not in the npm registry, or you have no permission to fetch it.
+

The error message is clear: the released package @company/my-package Iā€™m trying to install depends on a package another-package expected to exist in the npm registry somewhere. But another-package is not there. I already knew those packages came from a monorepo, so likely another-package was only an internal dependency in the monorepo, left unreleased. I wanted to inspect the package contents before releasing any fix to be sure, but couldnā€™t rely on npm install for that. There used to be an option to download npm packages via GitHub UI, but thatā€™s no longer the case.

Finding the package tarball

One can read the packageā€™s metadata to find a download URL for the packageā€™s latest version. Hereā€™s how:

  1. (For private GitHub registries) Grab a classic GitHub token with packages:read permissions (hereafter {GITHUB_TOKEN}).

  2. The URL of a npm package published to GitHub is https://npm.pkg.github.com/{PACKAGE_NAME}. Use that to fetch the package metadata, which contains the package tarball URL.

> curl -L -H "Authorization: Bearer {GITHUB_TOKEN}" "https://npm.pkg.github.com/@company%2Fmy-package" |  grep -o '"tarball":"[^"]*"'
+"tarball":"https://npm.pkg.github.com/download/@company/my-package/0.0.34/3d0304f38791214b09ec92a2262ca1697f"
+
  1. Download the package using the tarball URL.
> curl -L -H "Authorization: Bearer {GITHUB_TOKEN}" "https://npm.pkg.github.com/download/@company/my-package/0.0.34/3d0304f38791214b09ec92a2262ca1697f" | tar zx
+

That will download the package to your current folder, and you may inspect the package contents now. :-)

\ No newline at end of file diff --git a/blog/guitar-rig-macos-mojave-setup/index.html b/blog/guitar-rig-macos-mojave-setup/index.html new file mode 100644 index 0000000..3f3411f --- /dev/null +++ b/blog/guitar-rig-macos-mojave-setup/index.html @@ -0,0 +1,4 @@ +Setup for Audio Interface with Guitar Rig 5 on macOS Mojave | DiƩssica Gurskas
diessi.caBlogMisc
August 18, 2019

Setup for Audio Interface with Guitar Rig 5 on macOS Mojave

Setting up Guitar Rig 5 on macOS Mojave seems not to be straightforward.

Although I had gotten the signals to be sent from my guitar to the audio interface and from the interface to Guitar Rig, somehow itā€™d still not work. Instead of using my audio interface as the input and output device on Guitar Rig, I had to set up an ā€œaggregate deviceā€.

This how you can do it too.

(My specs, just so you know:)

macOS Mojave Version 10.10.14
+Guitar Rig Pro 5.2.2
+Audio Interface Steinberg UR22mkII
+

Audio MIDI setup

  1. Open ā€œAudio MIDI setupā€ in your Mac. (Itā€™s a tiny secret sound manager shipped along with the system, youā€™ll find it.)

  2. At the very bottom of the app, there is a small + (ā€œplusā€) button wherein you should select ā€œCreate an aggregate deviceā€.

  3. Set up your ā€œaggregate deviceā€ with your 1) audio inteface and 2) speakers/headphones/whatever ā€“Ā which should be all shown up there, given the setup is correct. Remember to give your device a remarkable name ā€“ I suggest FUCK COMPUTERS AND AUDIO.

Audio MIDI Setup app open showing audio device with both devices'
My custom device in Audio MIDI Setup on macOS.
  1. Go back to Guitar Rig. In the context menu ā€œFileā€, go to ā€œAudio and MIDI Settingsā€. In the ā€œAudioā€ tab, select your aggregate device as the device, instead of only the audio interface as you were doing before; then configure input/output as expected in the ā€œRoutingā€ tab.

Should work! If it doesnā€™t, this guide by Native Instruments on how to troubleshoot audio and others guides on the website might help. Depending on your audio interface, make sure the right driver setup is in place ā€“Ā you can try out ASIO4ALL.

Guitar Rig app showing its custom amps

If it still doesnā€™t work, I am sorry and prolly have no idea. Have fun.

\ No newline at end of file diff --git a/blog/horizontal-and-vertical-align-anything-with-css/index.html b/blog/horizontal-and-vertical-align-anything-with-css/index.html new file mode 100644 index 0000000..8c1ff36 --- /dev/null +++ b/blog/horizontal-and-vertical-align-anything-with-css/index.html @@ -0,0 +1,17 @@ +Horizontal and Vertical Align Anything with CSS | DiƩssica Gurskas
diessi.caBlogMisc
November 06, 2016

Horizontal and Vertical Align Anything with CSS

Using translate() is one of the easiest ways^[Flexbox also provides a great solution. See Solved by Flexbox: Vertical Centering] to instantly horizontal and vertical align any element with CSS without knowing its dimensions.

Vertical Align

You probably know the ā€œvertical align with just 3 lines of CSSā€ trick, which uses translateY().

.my-element {
+  position: absolute;
+  top: 50%;
+  transform: translateY(-50%);
+}
+

Horizontal Align

But did you know itā€™s also possible to use translate() to horizontal align elements?

.my-element {
+  position: absolute;
+  left: 50%;
+  transform: translateX(-50%);
+}
+

Vertical and Horizontal Align

ā€‹ Mixing both, we can horizontal and vertical align anything!

.my-element {
+  position: absolute;
+  left: 50%;
+  top: 50%;
+  transform: translateX(-50%) translateY(-50%);
+}
+

See JSBin.

\ No newline at end of file diff --git a/blog/how-i-lock-my-bike-in-berlin/index.html b/blog/how-i-lock-my-bike-in-berlin/index.html new file mode 100644 index 0000000..48d595b --- /dev/null +++ b/blog/how-i-lock-my-bike-in-berlin/index.html @@ -0,0 +1 @@ +How I Lock My Bike in Berlin | DiƩssica Gurskas
diessi.caBlogMisc
August 30, 2018

How I Lock My Bike in Berlin

1 year with a bike in Berlin, and counting...

I bought a bike 2 months after moving to Berlin, and a really good lock 1 day after.

With no clue about the theft scene in Europe ā€“ Berlin, in special ā€“, I did myself some research on /r/berlin, /r/bycicling and a few other places around the internet. What I did find out? Well, the numbers on bike theft are quite concerning.

Nevertheless, after witnessing some people getting their bikes stolen, I feel privileged to say that itā€™s been more than 1 year Iā€™ve got my bike. If that is because of my good lock or my good luck, Iā€™ll never know.

But I can tell you about the lock.

My lock setup

I generally agree that you should invest as much as you can afford in your lock setup. Iā€™ve put a considerable amount of money on mine because I deeply care ā€“ in other words, I have no psychological resilience when it comes to bicycles so losing mine would definitely get me in tears.

If you care about numbers without any trustable source, I've seen recommended somewhere that you should be investing between 10%-20% of the bike price in a lock. šŸ¤·

Therefore, considering the price of having to go home by feet and with tears in my eyes, I did the best I could and went for the Kryptonite Evolution Mini-7 with Double Loop Cable (highly recommend you to check their website for more information).

I make sure my bikeā€™s frame and both wheels are locked to a fixed rack ā€“ cemented into the ground, ideally.

Yellow bike in a parking space locked with a U-lock and a flexible steel cable.
My tiny yellow bike parked and properly locked at the office's parking space! Locking up the U-lock to the front wheel instead is a good alternative. Also, I often wrap the steel cable through the rack.

I had considered the Kryptnonite's New York Fahgettaboutdit, but I found it way too heavy and the safety factor difference didn't pay off for me at that time. I'd recommend it if an extra weight is no problem for you though.

For I still have my bike after 1 year, I am honestly happy with my choice. The lock came with:

  • Three keys with an unique number. For your information, Kryptonite has a system where every key gets a number, so you can order replacements online in case you mess up.
  • A handy mount made by Kryptonite: Transit FlexFrame U-Bracket (not visible in the photo because itā€™s in the top tube), so I donā€™t have to carry the U-lock in my backpack or whatever.
  • Manuals that I didnā€™t read and got recycled.
  • 1 year coverage according to the Kryptonteā€™s Anti-theft Program, because the security rating is high enough.

Iā€™ve read a couple complaints about the lock not fitting both the wheel and frame to most city racks, however Iā€™ve managed to do it in most racks around Berlin. Itā€™s definitely not the most flexible and spacious lock, but thieves would love some extra space to do their work too, so I think itā€™s just the size it should be after all.

In the worst-case scenario, there is always the Sheldon Method lock strategy ā€“ or its modified version ā€“ anyway!

What bike locks are about

When looking for a lock, instead of (only) asking yourself whatā€™s the best lock ever, ask ā€œHow much trouble am I putting a thief into with my lock strategy?ā€.

It hasnā€™t been enough stressed that locks do NOT prevent determined thieves with their lock pics, cable cutters, bolt cutters and angle grinders to steal you bike. Period.

Locks do, though, make it harder for thieves to pick your bike, by increasing the ā€œriskā€ factor in the risk/reward calculation done before they attempt to steal.

Itā€™s all about making it harder. And how do you do that? By having a diverse lock setup, and, just as important: by being extremely careful on where and how to park.

Donā€™t think just U-lock: saddle locks, wheel locks might be worth-checking too! One awesome lock is just one at the end of the day, and the more tools the thief needs to carry out, the better.

Looking further

Some articles Iā€™ve read last year and that might be interesting if you own a bike and want to learn more on how to keep it safe.

There are a lot of cool videos out on YouTube too, e.g. ā€œHow to Lock your Bikeā€ from GCN.

Have a nice ride! šŸš²

\ No newline at end of file diff --git a/blog/how-to-exclude-css-images-anything-from-unit-tests/index.html b/blog/how-to-exclude-css-images-anything-from-unit-tests/index.html new file mode 100644 index 0000000..be48e11 --- /dev/null +++ b/blog/how-to-exclude-css-images-anything-from-unit-tests/index.html @@ -0,0 +1,27 @@ +How to Exclude CSS, Images, Anything from Unit Tests | DiƩssica Gurskas
diessi.caBlogMisc
November 19, 2016

How to Exclude CSS, Images, Anything from Unit Tests

Your app needs all those require, but your unit tests may not.

When developing web applications, we deal with assets that our JavaScript tests donā€™t have to be aware of.

If using Webpack, which enables different imports in your JavaScript files, youā€™ve configured loaders that your test runner probably know nothing about. Therefore, that SVG image in your React component and the imported CSS will both be parsed like JavaScript in your tests. A lot of confusing errors will be thrown, of course.

So letā€™s learn to exclude anything your unit tests, from styles (CSS, Sass), images (PNG, SVG), to other specific imports (like SVG images as React components).

Hook your require() calls

By intercepting require() calls, you can make your testing framework ignore what you want to be ignored the way you want it to be ignored.

Itā€™s also useful in isomorphic setups.

Return an empty module

It all comes to returning an empty module for unwanted imports. It looks like this:

module.exports = "";
+

Jest

For Jest, configure moduleNameMapper to return the empty module for specific extensions. Example:

"jest": {
+  "moduleNameMapper": {
+    "\\.(css|jpg|png)$": "<rootDir>/empty-module.js"
+  }
+}
+

Other testing frameworks

require-hacker is an option for hooking require() calls.

You can also use built-in compilers (like moduleNameMapper in Jest or Mocha compilers), or even only import ignore-styles into your testing framework (which is preconfigured).

Iā€™ll stick to require-hacker and custom configuration because thereā€™s more flexibility.

Get it from npm:

npm install require-hacker --save-dev
+

Configure

Create a JavaScript file and set custom handlers for specific extensions using require-hackerā€™s hook() method.

Assuming you want to ignore CSS and PNG files, always return an empty module for them:

import requireHacker from "require-hacker";
+requireHacker.hook("png", () => 'module.exports = ""');
+requireHacker.hook("css", () => 'module.exports = ""');
+

Because youā€™re smart, youā€™ll store all extensions in a variable and forEach them, so thereā€™s no need to repeat yourself. Example.

Import into your test runner

Let your favourite testing framework know about the require hacking! Some examples, assuming a ignore-utils.js file:

Mocha

Add to your mocha.opts, or use the --require flag:

mocha --require ./ignore-utils
+
ava

Add to your package.json:

"ava": {
+  "require": [
+    "./ignore-utils"
+  ]
+}
+

Now some files will be treated like shit in your JavaScript testsĀ ā€“ which is AWESOME!

Bonus: React null component

You donā€™t need to load that boring SVG icon of a house to test that critical feature in a React component, right?

Right. In case youā€™re using svg-inline-loader, which transform your SVG files into React components, you cannot just return an empty module because your test case would be actually expecting a React component. Things will break. Annoying errors will be shown.

So, instead of returning an empty module for SVG files, return an empty React component. Letā€™s set a custom handler for that!

Configure

This example uses require-hacker. For Jest, export a React null component and set it in moduleNameMapper.

import requireHacker from "require-hacker";
+
+const reactNullComponent = `
+  require('react').createClass({
+    render() {
+      return null;
+    }
+  })
+`;
+requireHacker.hook("svg", () => `module.exports = ${reactNullComponent}`);
+

Conclusion

Iā€™ve spent a lot of time figuring out how to make everything work, because:

  1. At the beginning, it was quite confusing to get what was clearly going on.
  2. Thereā€™s a ton of options out there (Webpack null loaders; ignore-styles, which also provide custom handlers; babel-plugin-transform-require-ignoreā€¦).
  3. I didnā€™t want to handle all the ignored extensions the same say.

Yeahā€¦ Sometimes our JavaScript unit tests just know too much.

\ No newline at end of file diff --git a/blog/how-to-spy-on-a-prop-with-jest/index.html b/blog/how-to-spy-on-a-prop-with-jest/index.html new file mode 100644 index 0000000..42bcb46 --- /dev/null +++ b/blog/how-to-spy-on-a-prop-with-jest/index.html @@ -0,0 +1,17 @@ +How to Spy on a React Prop with Jest | DiƩssica Gurskas
diessi.caBlogMisc
October 31, 2019

How to Spy on a React Prop with Jest

When we want to test whether a prop has been called, mocking the prop in the component is usually the preferred way. This is how it goes with Jest and Enzyme:

const buy = jest.fn();
+const wrapper = enzyme.shallow(<button onClick={buy}>Buy</button>);
+
+wrapper.simulate("click");
+
+expect(buy).toBeCalled();
+

You may also want to spy on the prop directly, when the component is tested along with a provider passing down its props.

const wrapper = enzyme.shallow(
+  <ClickProvider>
+    <button>Buy</button>
+  </ClickProvider>
+);
+const buy = jest.spyOn(wrapper.instance().props, "onClick");
+
+wrapper.simulate("click");
+
+expect(buy).toBeCalled();
+

I am using Enzyme however you should be able to spy on similarly using other testing librariesĀ ā€“Ā just make sure you are spying on a function in the props coming from the component prototype (as in wrapper.instance()).

Thatā€™s all. Just posting it here cuz I couldnā€™t find it easily anywhere else.

\ No newline at end of file diff --git a/blog/i-m-tired-of-beautiful-looking-interfaces/index.html b/blog/i-m-tired-of-beautiful-looking-interfaces/index.html new file mode 100644 index 0000000..c8d7a36 --- /dev/null +++ b/blog/i-m-tired-of-beautiful-looking-interfaces/index.html @@ -0,0 +1 @@ +I'm Tired of Beautiful-Looking User Interfaces | DiƩssica Gurskas
diessi.caBlogMisc
October 23, 2016

I'm Tired of Beautiful-Looking User Interfaces

What if the user interface is more beautiful-looking than usable, understandable, and intuitive?

The visual aspects of an user interface play an essential role in organising information. Once youā€™ve got the resources, however, that turns out to be the easiest part of an Interface Design process.

Sure we like things that look nice, but looking nice doesnā€™t compensate a bad product design. Visual communication should not compensate flaws.

If you spend most of the time looking for visual inspiration rather than conducting research, doing usability tests, and studying metrics such as business goals and conversion rates, you will probably come up with a interface that only looks beautiful.

And Iā€™m tired of beautiful-looking interfaces.

\ No newline at end of file diff --git a/blog/index.html b/blog/index.html new file mode 100644 index 0000000..2cec953 --- /dev/null +++ b/blog/index.html @@ -0,0 +1 @@ +Blog | DiƩssica Gurskas
diessi.caBlogMisc
\ No newline at end of file diff --git a/blog/isolation-tank/index.html b/blog/isolation-tank/index.html new file mode 100644 index 0000000..8b7f587 --- /dev/null +++ b/blog/isolation-tank/index.html @@ -0,0 +1 @@ +I've Sensory-Deprived Myself In a Tank | DiƩssica Gurskas
diessi.caBlogMisc
December 02, 2018

I've Sensory-Deprived Myself In a Tank

I struggle every day trying not to be one step ahead. Living everywhere else but the present and leaping through time have become part of how my brain is wired, so I often find myself not experiencing much anymore.

A while ago, a friend told me about his sensory-deprivation experience in some kind of pool, the so-called Isolation Tank. No sight, no hearing, no touch, no taste, no smell ā€“ the idea of getting absolutely no input from anywhere struck me as a way to get my perception back on track. I decided to try it out.

On a sunny Saturday of November, I, along with my endless stream of thoughts, floated for 1 hour straight in a soundproof egg-shaped tub shallowly filled up with salt water. This is my report.

Getting In

With my bathing suit on and no expectations of anything, I showered, got into the tub and sealed down its cover. My body floated easily on that water that thermically felt like my own skin, and a relaxing sound was playing in the background up to the moment my surroundings got all pitch-black.

The first 15 minutes were all about withstanding how restlessly my mind wanted to get out of there. Iā€™ve had done meditation before, but 1 hour was something else. I recalled I worked 8 hours a day, 5 days a week, and therefore I should be making the most out of my Saturday instead. Leisure time! In modern life, that usually means stimulation by means of binge-drinking with friends, uplifting music, delicious food, watching heart-breaking moviesā€¦. Quite the opposite of soul-crushingly doing nothing.

The mind just plays a lot of games on you all the time. It tricked me into being physically irritated by the water, its salt, that bogus zero-gravity environment, and that Iā€™d be better off giving up for my own survival Ā ā€“ at least, that was how my body anxiously (over-)reacted to it. But there was actually no physiological danger or whatsoever; truth be told, I was way safer than I had ever been throughout that week. I quit panicking.

I came upon different phases of denial, approval and mind-numbness from that onwards. Saw myself bringing up problems and drifting them away. Tried to work out situations I had no control over. Missed music, so made my own by tapping on the water. Went hyper-focused on how I had performed socially last week to what was going to happen in the next few weeks when I eventually hand over my old apartmentā€™s keys to that spiteful Hausmeister who hates my German.

My thoughts just went on super randomly. After a while, I could draw the exact line where each one ended, and got mindful about my weary physical overreactions to them.

Towards the end, I sank into something else: weightlessness, timelessness, solitude were emerging from that isolation. Things started losing shape. Didnā€™t perceive water. I was either a floating head or a floating body. I had to touch my thighs, boobs, neck just to relieve myself from the uncertainty that being so relaxed made me feel about where I was.

I wanted to come back down to Earth from wherever I was, and, surprisingly, to be myself ā€“ the way I was. Then time was up.

Getting Out

I showered again to wash the salt off. The spa provided a relaxation lounge that was essential to ease the transition, sinceĀ I had neither desire nor need (important!) to rush anywhere. Hung out there for 1 hour.

The readjusting was an interesting and unexpected phase to me. Had an apple and felt how crispy in sound and taste it was. Drank a glass of water and sensed it going right down through. Read a book and couldnā€™t make sense of why we humans have ever brought up speed reading techniques in the first place.

Stepping out of the spa, I got savagely welcomed by a gloomy afternoon1 undergoing that life I was used to every day. A lot was happening out there: lights of apartments being turned on and out, cars groaning, people running around, traffic noise, the cozy energy of having my friend by my side, sharper textures of the sidewalksā€™ cobblestones, and the joy of a having a sky whose amount of stars doesnā€™t depend on the many times we screw up as human beings, thankfully.

Berlin-Schƶneberg is quite chill so thatā€™s helped to readjust. I was sensible and my thoughts were vivid and receptive ā€“Ā pretty much the actual poetic mood I strive for, where I settle and listen to whatā€™s being said in order to write it down. A mood that is ā€œhighly disturbed by Philosophyā€, as Goethe brilliantly summed up to Schiller once:

ā€œI am still hoping for poetic hours, and philosophy, in my case, disturbs the poetic mood, probably because it drives me into the object, for I am never able to keep myself in a purely speculative mood, but have immediately to try and form a distinct conception, and on this account at once fly out into nature. [ā€¦]2

I had finally my mind drifted towards just as much of the world as it was going on.

Lessons Learned

My poetic mood didnā€™t last muchĀ ā€“ it wore off the day after.

Iā€™ve realized how much we are externally stimulated and easily adapt to it as if it were natural. On top of that, we are internally stimulated by our worries and whatnot: have I paid my taxes? Am I persuading a career? Does my family still love even though I am thousands of kilometers from them? Have I been eating healthy enough?

It turns out itā€™s clear why we donā€™t feel much anymore. Our brain gets wired to parallelising stimuli, and we have less and less coming from our body to the head than the other way around. Apart from that, our experience of the world is barely passive: we actively generate it with our biases, mental models, what and how much we consume. Mind shortcuts are crucial, but might restrain us from genuinely experiencing life, getting us to either ignore ou hyper-focus unconsciously.

I, now, have a better grasp of what Erling Kagge meant in Silence: In the Age of Noise, written after he had spent fifty days walking solo in Antarctica: ā€œEverything seemed completely flat and white. [ā€¦] Eventually, in complete isolation, I began to notice that nothing was completely flat after all. The ice and snow formed small and large abstract shapes. The uniform whiteness was transformed into countless shades of white. [ā€¦]ā€

Meditation is the absolute protagonist here, but floating got me into a different flow, and faster. The topic of sensory deprivation is definitely worth-exploring. Think like: If you ditch sugar for a while, it tastes sweeter afterwards. ;-)

This is pretty much what floating offers: sensory starvation and you on your own. You may waste your time and never get to anything, or make even most out of that 1 hour than me.

Personally, I canā€™t wait to do nothing again.


1

Just another Autumn day in Berlin.

2

Goethe (and Friedrich Schiller). Correspondence Between Schiller and Goethe from 1794 to 1805. Translated by George H. Calvert.

\ No newline at end of file diff --git a/blog/journaling/index.html b/blog/journaling/index.html new file mode 100644 index 0000000..797cd47 --- /dev/null +++ b/blog/journaling/index.html @@ -0,0 +1 @@ +What I've Learned by Simply Journaling | DiƩssica Gurskas
diessi.caBlogMisc
April 20, 2020

What I've Learned by Simply Journaling

In 2018, circumstances inevitably changed and I began taking up much more in life. I was under stress, regardless of being on the safe side, and the patterns that kept me grounded were no longer holding up.

Back then, seeing the big picture was unattainable with the stress snowballing and skewing my perspective. Dwelling in my head, paving the way to learned helplessness, I decided to try out journaling.

More than a year later, I can finally say alles gut. Although circumstances havenā€™t changed much, I certainly handle them better. I keep journaling as of today, and am excited to share my setup and (hopefully) motivating takeaways!

How I Journal

I did not go for the traditional diary format. I decided to Bullet Journal, a flexible journal method founded in quick lifelogging by means of a pen, paper, and bullet points.

Pen and paper pull me out of my head and let me continuously evolve my notebook as my needs change, since there is no predefined template. As for bullet points, we all know their efficacy: hasty logging and later reviewing at a glimpse.

Method

Peek into Bullet Journal official page for an overview, as I won't dive into the framework basics.

The Bullet Journal framework is made out of four fundamental ā€œcollectionsā€: Index, Daily Log, Monthly Log, and Future Log, plus custom collections you find valuable. After a while of tinkering around, I came to some insights and tweaks.

  • Index turned out useful when I added custom collections, as those usually end up scattered across the journal and thus hard to find.

  • Daily Logs is where I keep track of notes, events, tasks, thoughts, and ideas. (All mixed together, which portrays a day accurately if you ask me.) I recommend using signifiers and nesting (for a tree-like view) in bullet points to convey meaning with ease, as Bullet Journal suggests.

  • Monthly Log didnā€™t work for me. I steer towards weekly or quarterly ranges. Also, my online calendar is more practical so I couldnā€™t bother drawing calendars every month.

  • Future Logs are useful to migrate tasks or events to upcoming months, for when you donā€™t get something done but canā€™t ā€œnevermindā€ it either.

As for custom collections, the Bullet Journal ecosystem is huge! Iā€™ve seen stuff of all kinds out there: finance/sleep/food/water trackers, recipes, trip planning, doodles, and whatnot. Yet, these are the ones I always come back to:

  • Diaries: longer diary entries or brain dumps without the limitation of bullet points, for when I feel like it.
  • Habit Trackers: a simple daily tracker to monitor or develop habits across weeks, e.g. meditation, alcohol intake, call family.
  • Weekly Logs: my weekly variation of ā€œMonthly Logā€, with upcoming events and small goals for the week. Usually done on Sunday or Monday.
  • Quarterly Logs: my quarterly variation of ā€œMonthly Logā€, with upcoming events and big goals for the quarter.
  • Year Retrospective: a straightforward year review regarding what did and did not go well, what to keep or let go from last year etc. I journal spontaneously throughout the day, but mostly in mornings or evenings. I do it every day, even when I donā€™t feel like it. In the long run, thatā€™s gotten me to fathom my anxieties by having them logged as well as what was up days before. It goes a long way to flip through logs of piled up chores, social isolation, binge drinking, and sleep deprivation, to later find yourself taking down ā€œI am anxious. Canā€™t do shitā€.

Be that as it may, I donā€™t keep it all gloomy. With my throughput in mind, I may also soften up my daily logs with receipts from exquisite restaurants I come across, cute post-its from friends, or even silly useless quotes from fortune cookies.

At last, I have to say Iā€™m not really a big planner so you can see thatā€™s not what I optimise my journal for. All I strive for is a little awareness of whatever Iā€™m doing for the time being. I enjoy a spontaneous and organic life, and thatā€™s gotten me far enough to make me happy.

Pen & Paper

Notebooks on desk. On the left: Camel brown notebook with bear symbol on cover. On the right: Forest green notebook with deer symbol on cover.
My 2019 journal (left) and 2020 journal (right).

In 2019, I used an A5+ (slightly wider than regular A5) dot-grid notebook. Itā€™s bulky to carry around but I donā€™t regret it: the pages are wide enough to encourage writing. The quality of its pleasing yellow paper is outstanding, thick enough to prevent ink from leaking through. I ended 2019 with a few pages empty.

This year, I went for something more portable: an A6 dot-grid notebook. It took me a while to get used to the size constraints, and Iā€™ve been certainly more straightforward with my logs. I am pretty sure I will have no pages left this time. (Wondering what was the advantage of it all as Iā€™m not going anywhere anyway thanks to COVID-19.)

As for pens, I use different colours of a 0.4 mm fineliner.

What Iā€™ve Learned

I'd not assume these stem necessarily from the way I set myself up. Audio or video recordings, traditional diary, and other journal formats are worth exploring and might help just as well.

  • Less overwhelm, more time. To truly chill out when life gets overwhelming, you gotta plan ahead. Especially in already busy weeks, I use my journal to put down chores I commit to get done, prioritising what I signify as deadline-sensitive. Before, with my tendency to overfocus, Iā€™d take up activities without planning and end up neglecting my responsibilities and needs. Imagine how far this can go!

  • Emotional awareness. Iā€™ve gained a grasp of the phenomenology of my emotions and the lens through which I see life, markedly my cognitive distortions on stressful days. Attitudes like pessimism inevitably surface as you jot down negative thoughts all the time. Being mindful allowed me to reframe negative views, and turn obstacles into opportunities.

  • Better retainment. Itā€™s easy to fall into the trap of ā€œI have a bad memoryā€ when one has been busy and mooning for so long. Leading a busy life mindlessly is not what I strive for, and journaling only feeds into that: I hold dear people, moments, promises, and no longer miss so many appointments (planning helped here too!).

  • Constant assessment. Journaling is a tool to assess the present as well as the past and the future. By peeping into where Iā€™ve been, what did/didnā€™t go well, or who I have been with, for instance, I can ponder more sensibly on my growth and relationships. Early feedback on my own life, sort of, to leverage self-improvement in relationships, health, work, and so on.

Pitfalls

  • Perfectionism. Obsession over constant logging or perfection is right at the door for you to slip into. On social media (Pinterest, YouTube), everyoneā€™s journal seems visually-appealing every day without fail. Even Bullet Journal, a method dead straightforward, can be a rabbit hole. Remind yourself to solve your problem in a way that enhances your daily life, not burdens it. You gain absolutely nothing from buying into slices of life people sell online.

  • Habit-building. When not a habit, journaling is just another chore. Make it effortless and engaging: establish a routine (if thatā€™s your thing), designate it a place where itā€™s always within reach, or tailor the framework to your needs. If you enjoy drawing once in a while, why not? If you have no patience for 29872 different pen colours, why do it? If you want to write about your day with your partner in bullet points instead of coming up with a best-seller love story, who cares?

  • Procrastination. Journaling constantly nudges you to look back at your life and how youā€™ve been spending your time and energy. That can be challenging and wonā€™t change. For starters, you might come to the unpleasant realisation that you self-sabotage, or that a certain relationship is fading away. If you are avoidant, you will most likely put off journaling often; not because of the method or routine, but fear of what you may find ā€“ fertile soil for procrastination.

  • For pen & paperā€¦ No backup. Some companies have tried, but whatā€™s hand-written wonā€™t sync with a cloud server. You do carry the weight if traveling or taking it to work, and itā€™s probably gone if you spill coffee on it. I, though, think the trade-off is worth it and havenā€™t looked back.

Final Takeaway šŸ„”

I am all for simplicity, yet that didnā€™t keep my mind from boggling when I realised such a simple tool turned out to be a game-changer. Starting off was not easy, but the benefits showed up and kept me motivated ā€“ a rewarding feeling I wouldnā€™t expect so hastily while building a new habit. Today, itā€™s just effortless and natural.

Ultimately, I hope this stimulates you to try journaling in whatever way and to deem simple tools as helpful to uncomplicate and improve our lives.

References

\ No newline at end of file diff --git a/blog/learning-vim/index.html b/blog/learning-vim/index.html new file mode 100644 index 0000000..3568831 --- /dev/null +++ b/blog/learning-vim/index.html @@ -0,0 +1,8 @@ +Learning vim: From VS Code to neovim (Part 1) | DiƩssica Gurskas
diessi.caBlogMisc
September 29, 2024

Learning vim: From VS Code to neovim (Part 1)

Iā€™ve been a VS Code user for years, but today, I am giving vim (motions & editor) another try. Why?

  • I love keyboard navigation, and vim motions invite you to use your entire keyboard not only to type, going beyond the Ctrl+Shift+Command+Fn+^+{+/ hell.
  • neovimā€™s plugin ecosystem is GOLD for keyboard enthusiasts e.g. stevearc/oil.nvim.
  • Thereā€™s a gap between my terminal and VS Code. No matter what extensions I throw at it, I canā€™t bridge it. Since I spend a lot of time in the terminal anyway, why not edit in it too?

Disclaimer: Not a beginner tutorial. Rather a (hopefully inspiring) diary of my vim journey. But if you're curious, I've dropped some learning resources below.

Today I learned

which vim editor?

Many editors support vim motions, including VS Code itself. Technically, I could just make my VS Code more keyboard-centric without switching editors. But right now, Iā€™m exploring neovim, and learning vim motions across both VS Code and neovim. neovim is cute: small, fast, portable, extendable, widely supported, and not again owned by Microsoft.

vim kinda has 4 modes

  • insert mode (i key; also other keys, see ā€œthe normal modeā€): where you type and insert text, just like a traditional text editor.
  • visual mode (v key): where you select/highlight text visually, handy for copying/deleting/moving.
  • normal mode (esc key): where you navigate around the file, most of the time and most efficiently. Keys become ā€œmotionsā€ and ā€œoperatorsā€ that move the cursor and act on text (deleting, finding, replacing).
  • command-line mode (: key): execute commands on vim, mostly editor-related, e.g. saving files, exiting vim.

Traditional text editors offer ways to do the above in a permanent ā€œinsert modeā€, but vim separates that across modes. Many mistakes happen because youā€™re not in the mode you thought you were, it helped me that the ā€œnormalā€ mode cursor looks different than the other modes.

the normal mode

Thereā€™s nothing normal about the normal mode, so I will say again: in vimā€™s normal mode, keys turn into ā€œmotionsā€ (move you around the file) and ā€œoperatorsā€ (act on text, e.g. deleting, finding, replacing). Think of it as a mode with permanently enabled ā€œCmdā€ or ā€œCtrlā€ keys which you use to move around in a regular text editor (I hope?).

  1. navigating up (k), down (j), left (h), right (k). (Try not to press l with your pinky finger)
  2. creating new lines under the cursor (o) and above (O)
  3. jumping to next word (w), end of the word (e), or previous word (b)
  4. jumping around lines of code with gg (line 0), G (end of file), {line number you wanna go to}G, {N}j to go down N lines, {N}k to go up N lines
  5. inserting before cursor (i), inserting after cursor (a), insert in the beginning of line (I) or end of line (A)
  6. jumping to beginning of the line (0), end of line ($), or beginning of word (_)
  7. replacing a char (r) or word (R), deleting current character (x), deleting (d) e.g. a line (dd), next word (dw), previous word (db), basically a lot of the commands Iā€™ve already learned above
  8. searching within a line with f(character), plus next (n) and previous (N) occurrence
  9. undo (u), redo (ctl+r). Pretty damn important, you make mistakes all the time.

I practiced these commands in roughly that order, moving on once I felt mostly accurate, though still slow. It might seem like a lot, but itā€™s easier when itā€™s about muscle memory and not memorizing a cheatsheet. Once you start combining motions and operators, things get fun. For example: I already use j to move down, could 10j jump down 10 lines? Yes (first I tried j10 lol). Deleting 3 words backwards? d3b.

little vim config

Feeling a bit lost in my editor, had to change some things. I said earlier I was curious about the ecosystem, but now Iā€™m a little overwhelmed. For now, keeping it minimal:

-- ~/.config/nvim/init.lua
+local o = vim.opt
+
+o.number = true -- Print the line number in front of each line
+o.syntax = "on" -- When this option is set, the syntax with this name is loaded.
+o.mouse = "a" -- Enable the use of the mouse. "a" you can use on all modes
+o.termguicolors = true
+

(By the way, neovim uses Lua for configuration, if youā€™re wondering where the good old vimrc wentā€¦)

References for SLOW DIGESTION ONLY

Thatā€™s all for now

Back in my teenage years, I tried to learn vim and quickly gave up. Coding was already confusing enough, and I figured, ā€œwhatā€™s the point of typing faster if I donā€™t even know what to type?ā€. Which was pretty wise, in hindsight. Pretty sure I peaked in wisdom right there.

Jokes aside (it was not a joke), Iā€™m still far from hyper-productive on vim. But I wrote this blog post with it, felt focused and felt plenty of fun, which is productive enough I guess? Whether this is novelty, or the vim advantage, only time will tell. Plenty of people go from VS Code to neovim and then back again. Who knows.

Now, the text column width on this editor has been full screen since I started this post, and Iā€™m on the edge of installing zen-mode.nvim. Just gotta figure out what is this lazy nvim vs. packer thing.

:wq

\ No newline at end of file diff --git a/blog/long-time-no-see/index.html b/blog/long-time-no-see/index.html new file mode 100644 index 0000000..455f75e --- /dev/null +++ b/blog/long-time-no-see/index.html @@ -0,0 +1 @@ +Long Time No See | DiƩssica Gurskas
diessi.caBlogMisc
June 30, 2023

Long Time No See

In the past three years, a wild mix of stuff dragged me away from writing. More time šŸŒ³ offline ā›°ļø, which was great. Then a demanding role in a small team, the chaotic grip of a global pandemic, increasing perfectionism, and a blossoming and ultimately collapsing relationship ā€“ which all conspired to shake up my pursuits and thrust me into an introspective whirlwind. And as if that wasnā€™t difficult enough, I lost two yearsā€™ worth of drafts in a backup blunder.

Whenever I attempted to restart, I found myself entangled in a web of what still resonated with me and what no longer did. But hey, listing more excuses would only scratch the surface. I recognize now, after seeing how little it takes for me to be back, that parts of me were simply in disarray. Yet, as I come together again, so does my motivation to reclaim what I enjoy, and make time for it despite the busyness and excuses.

So, last night, I did what I do best: I embarked on an in-one-sitting endeavor! I migrated this blog to Zola (a speedy static generator written in Rust), so this WeBpAg3 remains therefore static and snappy af, joining the <512 kB club. Letting my creativity flow with Tailwind, I gave my WeBpAg3 an extravagant-outrageous look, and made sure itā€™s accessible. I rewrote my introduction like a million times. I sifted through my writings, organising and archiving some, and lo and behold!: I stumbled upon those lost drafts hidden away in the depths of my physical backups. Pretty thrilling. As a friend once told me, good things happen when good things happen.

Long time no see! It all feels quite nice, if you ask me. šŸ˜‰

\ No newline at end of file diff --git a/blog/mass-deleting-files-from-slack/index.html b/blog/mass-deleting-files-from-slack/index.html new file mode 100644 index 0000000..81b91bd --- /dev/null +++ b/blog/mass-deleting-files-from-slack/index.html @@ -0,0 +1,4 @@ +Mass Deleting Files from Slack | DiƩssica Gurskas
diessi.caBlogMisc
April 17, 2016

Mass Deleting Files from Slack

Slack comes with limited file storage, so you eventually run out of space. Deleting files isnā€™t easy though: there is no way to bulk delete them using the web interface.

Slack forces you to delete one by one.

And although Slack can force humans, it canā€™t force JavaScript. So JavaScript to the rescue!

How to delete multiple files from Slack

In order to free up space, youā€™ll need;

Installing

Open your terminal and install slack-delete-files package globally using Node Package Manager:

$ npm install -g slack-delete-files
+

Running

$ slack-delete-files
+

Youā€™ll be asked for your Slack token and whether you want to delete all files or only files older than 30 days.

Done!

Your space is probably back!

After deleting, you can uninstall the package:

$ npm uninstall -g slack-delete-files
+

Contribute on GitHub.

\ No newline at end of file diff --git a/blog/multiline-sass-comments/index.html b/blog/multiline-sass-comments/index.html new file mode 100644 index 0000000..5c42393 --- /dev/null +++ b/blog/multiline-sass-comments/index.html @@ -0,0 +1,4 @@ +Multiline Sass Comments | DiƩssica Gurskas
diessi.caBlogMisc
August 17, 2015

Multiline Sass Comments

Since the beginning of this year, Iā€™ve created a lot of different boilerplates for projects. Working as a freelancer makes you challenge yourself everyday to find out what fits better while working. Currently, itā€™s sometimes Stylus, sometimes Sass.

Stylus is flexible, and I love it. Sass isnā€™t, but itā€™s cool anyway. Sometimes I find it hard to bear its inflexibility, though.

On GitHub, thereā€™s a closed issue about multiline comments on Sass (a Stylus feature!), where I shared a solution for multiline Sass comments. A lot of people still donā€™t agree.

I just want people on community to know it, because it needs to be discussed.

Solution

Start writing the comment as if it were single-line (//), then just follow its indentation. Example.

// Multine comment
+   Indent the text
+   And this will be a comment too
+

Is it available on Sass docs? Let me know!

\ No newline at end of file diff --git a/blog/my-hacking-adventure-in-lithuania/index.html b/blog/my-hacking-adventure-in-lithuania/index.html new file mode 100644 index 0000000..ae1dbe4 --- /dev/null +++ b/blog/my-hacking-adventure-in-lithuania/index.html @@ -0,0 +1 @@ +My Hacking Adventure in Lithuania | DiƩssica Gurskas
diessi.caBlogMisc
February 15, 2018

My Hacking Adventure in Lithuania

Exploring the country where my surname came from and hacking collaboratively at Science Hack Day Vilnius!

I love to hack stuff, and, this year, Iā€™ve been pushing myself to do more of that along with people.

Thatā€™s how I found a hackathon called Science Hack Day, a weekend event with the goal of ā€œmaking weird, silly or serious things with scienceā€1 in collaboration with others. Although I missed the Berlin edition for just a few days after it happened in November, another event was about to come ā€“Ā this time, in Lithuania, where my surname ā€œGurskasā€ came from.

There it was the perfect replacement: the Science Hack Day Vilnius 2018 would be my great excuse to explore the country where my grandfather was born.

Right on the last minute, I got a bedroom in a cheap hotel booked, and my flight and event tickets ready. All set for the hacking adventure!

Welcome to Vilnius

Approximately 2 hours from Berlin by plane, there I was: Vilnius, the capital of Lithuania. A modest city, so small you can pretty much explore everything by feet.

Temperatures were more negative than in Berlin. Winter, and the city wasnā€™t the most colourful either, so the atmosphere was somewhat dark ā€“ even though the snow was painting all buildings, houses, and streets in a shining white.

The cold was totally dismissible as soon as I met the Lithuanians, warm and welcoming people who seemed to lead a simple life.

Science Hack Day Vilnius 2018

Trophies for different prize categories
Trophies for different prize categories. (Photo: Raitis Gocentas)

A Science Hack Day is a 2-day event run by volunteers. Since itā€™s a hackathon, itā€™s pretty hectic and leaves you exhausted at the end. However, also since itā€™s a hackathon, itā€™s remarkably rewarding at the end.

These were my days!

First Day

Early on Saturday, I walked to Technarium, where the event would happen. Itā€™s a laid-back and community-operated hackerspace in Vilnius, where technology enthusiasts work or co-work on their projects and share knowledge. My perfect habitat, sort of.

Technarium space
Technarium. (Photo: Raitis Gocentas)

I found a seat in the middle of a diverse crowd of enthusiasts: kids, teenagers, and adults (in which you could also find scientists and professors). I had forgotten to adjust my clock to the local timezone when I arrived in Lithuania ā€“ 1 hour ahead of Berlin ā€“, so I was kinda late and the talks on open science had already started.

With honestly no idea on how all thatā€™d end up (a feeling Iā€™m used to, since I always do unexpected stuff to myself anyway), I was watching the talks and telling myself that the worst that could happen was that Iā€™d have no idea and no team, and would end up just exploring what others were building. It didnā€™t sound any bad at all! Being around creative people is always appreciated anyway.

Electronic hackable badge and stickers from Science Hack Day Vilnius 2018
Electronic hackable badge and some stickers I got for joining the event! The badge features a WiFi-enabled micro-controller and MicroPython, for some hardware hacking fun. Check the badge's GitHub repository.

After the talks, it was time for people to pitch about their potential projects. Most ideas involved Biology, Programming, Physics, Chemistry ā€“Ā anything related to (science) hacking! One of the ideas, from a team of 3 guys, was to build an audio visualiser.

ā€œWe need a Python engineer who understands some audio engineeringā€, they said, in Lithuanian (thanks person who was real-time translating everything!). Luckily, in a beautiful coincidence, I love music, Python, and also have been playing with spectrum analysis for audio visualisation in the last year ā€“ so I decided to take a shot and ask them to join the team.

They said they had no idea how to get the input from a microphone, and that they knew more about the hardware part, Arduino, and manipulating those machines in the hackerspace to come up with a cool design for our project. Iā€™m just bad at things that require manual work that isnā€™t with the keyboard, so my manual help would be typing Python for 2 days on my laptop. They accepted it. So far, we had:

  • the idea;
  • an Arduino Nano;
  • a power supply;
  • long LED strip lights;
  • an acrylic sheet.

Since Arduino Nano isnā€™t powerful enough for that computation, itā€™d be only used for data acquisition, and the spectrometer would live in our Python program in my laptop, computing the Fourier transform of the audio signals.

By the end of the day, we managed to get input from the microphone, analyse its signals in the frequency domain with Python, and start mapping that data to be sent to our Arduino over a serial interface. Some libraries we played with were: pyaudio, numpy, pyserial, matplotlib.

Second Day

Now with the clock correctly set (thanks to my friend that asked what timezone I was in, otherwise I wouldnā€™t ever know), I was on my way to Technarium again, walking over and under snow in that early Sunday morning.

A day in the Science Hack Day Vilnius was a day with Lithuanian hearty lunch, black coffee, and hard work around kind people. (By the way, if you ever end up there, try the kibinai ā€“ I ate one filled with spinach and will never forget how it smelled and tasted.)

Most people there were Lithuanians and I didnā€™t know anything about their language besides ā€œlabas vakarasā€2 (ā€œgood eveningā€), so I felt like an outsider sometimes. My teammates and other Lithuanians in the event ā€“Ā including kids ā€“, though, were friendly and spoke English flawlessly, and fortunately even translated some stuff into English for me.

Curious fact: A teenager at the event told me that my surname was "wrong" ā€“Ā in Lithuania, single women get a different surname suffix, so my name should be Gurskaite ("skaite" suffix, instead of ā€“kas). In Brazil, of course, they didnā€™t know that and only cloned my grandfatherā€™s surname ā€“ with the "kas" suffix, since he was a man: Gurskas.

More talks in the morning on open hardware and software. They introduced everyone to GitHub, and many people, even students, were already familiar with it. The importance given to open source was impressive! That made me really happy.

Time flew on the second day! We had got the data we needed, and the next step was to decide on what would be more fun: to map amplitudes from the maximum frequency to RGB values for all LEDs, or map each LED to a frequency and change its colour depending on the amplitude? We picked up the latter, and got our LEDs to blink.


One of my teammates was learning Programming. He told me he didnā€™t know what programming languages to really sit down and learn, as seen that there were a lot of them out there. True, and a nice question! I gave him a biased answer, of course: ā€œgo for Python or JavaScriptā€. My reasons? Way more fun. Besides beginner-friendly, those languages have the most interesting, welcoming and lively ecosystems I know these days.


We were running out of time. While 2 of my teammates were building the LED tower, the other and I were testing the code and trying to improve our algorithm, everything at the same time. Eventually, we got our LEDs to blink the way we wanted them to, and the clock pointed 18:00 sharp. Time for presenting!

Laser project presentation
Project showing how lasers work. It emitted sounds too! (Photo: Raitis Gocentas)

Teams came up with a lot of cool things! Projects related to lasers, contactless payment systems security tests, shopping-cart-rocket launch (#SpaceXLithuania!), plant-watering automation, posters with LEDs crafted by kids celebrating the 100th year of the Lithuanian as an independent countryā€¦ And ours, of course.

Presenting the LED tower to the public
Two of my teammates (one's missing!) and me. I was weirdly concentrated uttering different notes to show how LEDs reacted to frequencies. (Photo: Raitis Gocentas)

There were different category prizes, and we won as the Best Data Hack!

I got the honor to take home not just this LED-powered trophy below, but also a memorable experience I had the pleasure to share with people I didnā€™t know in a country I didnā€™t know.

A trophy for Best Data Hack 2018 and a Raspberry Pi
A trophy for the Best Data Hack 2018 and a Raspberry Pi. Our prizes for having fun!

The Hack Day ended with a science show by N2!Ā Lots of fun with liquid nitrogen and eating cookies at temperatures close to the absolute zero. My teammates, Physics students, knew a lot of the science behind that stuff so I got some extra explanations! (I have to say, though, that one of my greatest learnings of that day was to not to chew those cookies slowly ā€“ they stick to your tongue in a TORTURING way.)

N2 science show group playing with fire
Playing with fire. Literally. (Photo: Raitis Gocentas)

Itā€™s always truly amazing to experience closely how creative and curious humans are! The event was awesome, well-organised, and, last but not least, fun. Organisers provided us all the materials (food included!), borrowing me even the single USB-C adapter they had!

Clearly, the only intent behind Science Hack Days is for people to share and learn openly. And that has been achieved just right.

Final words

Open knowledge is one of the most valuable things in this world. I have no doubt.

Iā€™m happy to have picked such an eccentric travel destination for my weekend, and really grateful for everything I saw and everyone Iā€™ve met on the way.

Gurskas written in snow
I don't feel my fingertips anymore since I did that. Writing in the snow: definitely NOT encouraged!

Lithuania was freezing, yes, but people were warm.

2

Special thanks to my father, who taught me that, otherwise I wouldnā€™t know anything really.

\ No newline at end of file diff --git a/blog/o-css-do-futuro/index.html b/blog/o-css-do-futuro/index.html new file mode 100644 index 0000000..a8ccda8 --- /dev/null +++ b/blog/o-css-do-futuro/index.html @@ -0,0 +1,2 @@ +O CSS do Futuro | DiƩssica Gurskas
diessi.caBlogMisc
May 29, 2016

O CSS do Futuro

JĆ” existem especificaƧƵes garantindo funcionalidades incrĆ­veis para o CSS: variĆ”veis; uma nova sintaxe para media queries; nesting; novos seletores, valores e propriedades. E vocĆŖ pode usĆ”-las, hoje.

Neste artigo, introduzo uma sĆ©rie de artigos relacionados Ć s principais funcionalidades do CSS do futuro, alĆ©m da ferramenta CSSNext, que permite que vocĆŖ as utilize sem esperar o suporte do navegador.

(A fins didĆ”ticos, Ć© possĆ­vel assemelhar o CSSNext ao Babel, que, por sua vez, tambĆ©m permite desenvolver com o JavaScript do futuro ao transpilar o cĆ³digo JavaScript da prĆ³xima geraĆ§Ć£o para um cĆ³digo suportado pelos navegadores atuais.)

Ao final desse artigo, vocĆŖ saberĆ” como desenvolver, hoje, com o CSS do futuro.


IntroduĆ§Ć£o ao PostCSS

O CSSNext estĆ” relacionado com PostCSS. Mas o que Ć© o PostCSS, afinal?

O PostCSS Ć© apenas uma ferramenta que permite (prĆ© ou pĆ³s) processar o CSS atravĆ©s de plugins em JavaScript. Um desses plugins Ć© o CSSNextĀ ā€“ assim como, por exemplo, o Autoprefixer, que trabalha na etapa de pĆ³s-processamento do CSS, adicionando vendor prefixes.

A transformaĆ§Ć£o de estilos Ć© viabilizada de forma integralmente agnĆ³stica: nada Ć© dito sobre como e com o que serĆ” feito. Com o PostCSS, vocĆŖ Ć© responsĆ”vel pelo workflow de processamento do estilo. Ɖ possĆ­vel utilizar funcionalidades prĆ©-processadas e/ou sintaxe do Sass, minificar e adicionar vendor prefixes ā€“Ā tudo de forma ā€œplugĆ”velā€!

Como o PostCSS nunca Ć© utilizado sozinho, o prĆ³ximo passo Ć© plugar o CSSNext a ele.

Como usar o CSSNext

Se vocĆŖ quiser apenas testar as funcionalidades dos novos mĆ³dulos do CSS, vocĆŖ pode brincar com o CSSNext no navegador.

No workflow

Em um ambiente de desenvolvimento, Ć© necessĆ”rio usĆ”-lo com o PostCSS. A documentaĆ§Ć£o do CSSNext guia vocĆŖ para configurĆ”-lo em seu workflow, seja com Webpack, Browserify, Gulp, Grunt, [ā€¦], ou interface de linha de comando.

Em todos os casos, a configuraĆ§Ć£o se resume a passar um array com os processadores desejados para o PostCSS. Nesse caso, o processador a ser plugado Ć© apenas o postcss-cssnext:

$ npm install postcss-cssnext --save-dev
+

Principais Funcionalidades

Aprofunde-se nas principais funcionalidades do CSS do Futuro atravƩs dos artigos abaixo. Abra o playground do CSSNext e bons estudos!

\ No newline at end of file diff --git a/blog/o-que-ha-de-errado-com-a-cultura-jquery/index.html b/blog/o-que-ha-de-errado-com-a-cultura-jquery/index.html new file mode 100644 index 0000000..6cd9bfa --- /dev/null +++ b/blog/o-que-ha-de-errado-com-a-cultura-jquery/index.html @@ -0,0 +1 @@ +O Que HƔ de Errado com a "Cultura jQuery" | DiƩssica Gurskas
diessi.caBlogMisc
September 20, 2015

O Que HĆ” de Errado com a "Cultura jQuery"

Este nĆ£o Ć© um artigo sobre jQuery. Este Ć© um artigo sobre ferramentas, sim, mas Ć©, principalmente, um artigo sobre anĆ”lise e o protagonismo do desenvolvedor front-end nesse processo.

Resumo

AplicaƧƵes variam. Aprenda a definir a arquitetura da sua aplicaĆ§Ć£o. Aprenda a reconhecer a necessidade de uma SPA (Single Page Application).

A ā€œcultura jQueryā€ te afasta de tudo isso, e, portanto, distancia vocĆŖ do seu papel enquanto desenvolvedor front-end.


IntroduĆ§Ć£o

Se existe uma cultura nas agĆŖncias digitais do Brasil que Ć© unĆ¢nime, Ć© a cultura do jQuery. NĆ£o a cultura de utilizar todo o poder da biblioteca, no entanto, mas o hĆ”bito intrĆ­nseco de importar o jqueryX.X.X.min.js em todo projeto.

(Sim, em 2015.)

Sobre o que hĆ” de errado, serei sucinta, pois, para esse artigo, espero um pĆŗblico-alvo preguiƧoso e acomodado.

O que hĆ” de errado

ā€¦em usar jQuery em 2015? O que hĆ” de errado em importar jQuery ao iniciar o meu projeto?

Analisando superficialmente, nada.

Mas isso tem dado brecha a uma zona de conforto profunda e, na minha experiĆŖncia, com raĆ­zes difĆ­ceis de arrancar. Essa cultura se expande e transcende aquilo que lhe deu origem. Portanto, perceba:

Este nĆ£o Ć© um artigo sobre jQuery.

A comunidade de AngularJS Ć© um exemplo de que isso nĆ£o Ć© sobre jQuery. Muitos migraram dele ao Angular sem abandonar a cultura. O resultado? Bem, muito tem sido dito sobre cĆ³digo Angular legado, que ninguĆ©m quer dar manutenĆ§Ć£o. A escolha errada jĆ” foi feita, e isso Ć© demasiadamente penoso para a manutenĆ§Ć£o de uma aplicaĆ§Ć£o complexa.

O fato Ć© que a cultura nĆ£o mudou. Ainda se adota biblioteca ou framework em escala sem pensar duas vezes.

Aprendendo a evitar

Deve-se saber quando abranger uma visĆ£o holĆ­stica do projeto, e quando separar responsabilidades.

A separaĆ§Ć£o de responsabilidades se daria pela anĆ”lise dos requisitos da aplicaĆ§Ć£o e dos desafios gerados, que trazem consigo o que chamo de ā€œsubproblemasā€ (necessidades que surgem durante a anĆ”lise do desafio), que devem ser solucionados separadamente. A visĆ£o holĆ­stica ajudaria a estruturar os componentes de forma consistente em um sistema, definindo uma arquitetura.

Falando de desenvolvimento front-end moderno (e, portanto, falando de front-end modular e de unidades encapsuladas e independentes, os componentes), essa separaĆ§Ć£o de responsabilidades torna-se ainda mais fĆ”cil! Vejamos, abaixo, alguns subproblemas que surgem durante a anĆ”lise de requisitos, apenas para exemplificar o que quero dizer quando trato a decisĆ£o de ferramentas como uma soluĆ§Ć£o para um subproblema.

Os exemplos a seguir nĆ£o explicam o front-end modular na prĆ”tica. Adianto, no entanto, ferramentas como Browserify ou Webpack, que fazem parte do tooling necessĆ”rio.

1. ResiquiƧƵes Ajax

Subproblema: escrever Ajax em JavaScript Ć© pouco intuitivo, difĆ­cil de ler e escrever.

SoluĆ§Ć£o possĆ­vel: encapsular, no componente um mĆ³dulo como Reqwest e httpinvoke. VocĆŖ pode, inclusive, utilizar apenas o Ajax do jQuery (e nĆ£o o jQuery inteiro!).

2. ManipulaĆ§Ć£o excessiva do DOM

Subproblemas: manipular DOM com JavaScript pode ser bastante exaustivo. TambĆ©m, manipular em um nĆ­vel excessivo Ć© extremamente custoso para a performance da aplicaĆ§Ć£o.

SoluĆ§Ć£o possĆ­vel: Virtual DOM, que estĆ” embutido em bibliotecas como React e Mithril. Ou, se precisar mesmo do DOM, considere pacotes como qwery ou Dominus, junto com domready.

E se precisĆ”ssemos de Ajax no React, por exemplo? Este mau exemplo na documentaĆ§Ć£o do React importa o jQuery inteiro. Como vocĆŖ faria? ;-)

Sobre arquitetura

Esse tĆ³pico deve ser tratado durante a visĆ£o holĆ­stica do projeto, isso Ć©, da aplicaĆ§Ć£o enquanto sistema de componentes. O subproblema seria a necessidade de estrutura que uma aplicaĆ§Ć£o requere.

Para isso, vocĆŖ nĆ£o precisa usar aquilo que Ć© tradicional (diretamente: vocĆŖ nĆ£o precisa usar MVC). Existem outras implementaƧƵes de arquiteturas que nĆ£o a implementaĆ§Ć£o feita pelo seu framework amado. Existem outras arquiteturas que nĆ£o Model-View-Controller.

Basicamente? Tenha um conhecimento decente de arquiteturas front-end (sugiro abrir a mente com Flux, que jĆ” possui bastante materiais e implementaƧƵes da arquitetura disponĆ­veĆ­s), e nĆ£o um conhecimento aprofundado de MVC.

ConclusĆ£o

ConheƧa o projeto e saiba como analisar seus requisitos. O resultado deve ser uma descriĆ§Ć£o explĆ­cita da sua aplicaĆ§Ć£o, com subproblemas jĆ” reconhecidos e, entĆ£o, soluƧƵes possĆ­veis, todas envolvidas por uma soluĆ§Ć£o possĆ­vel maior, que Ć© a da arquitetura (definida durante a anĆ”lise holĆ­stica). Parece chato, mas vira hĆ”bito e acaba funcionando muito bem.

Lembre-se de que existem habilidades que a documentaĆ§Ć£o de uma ferramenta nunca_ te ajudarĆ” a desenvolver.

Com o tempo, vocĆŖ vai saber quando adotar um framework especĆ­fico em escala, quando optar por bibliotecas monolĆ­ticas, e terĆ”, inclusive, seus preferidos a ponto de nĆ£o ter sempre que definir soluƧƵes possĆ­veis para subproblemas que aplicaƧƵes tĆŖm em comum.

(Em alguns projetos, vocĆŖ enxergarĆ” padrƵes, por exemplo: qwery, domready e lodash sĆ£o usados juntos frequentemente.)

Um dia, no entanto, suas ferramentas falharĆ£o, outras ferramentas se adaptĆ£o melhor Ć  realidade de seus projetos, e, entĆ£o, o ciclo de anĆ”lise recomeƧa. E vocĆŖ jĆ” sabe como proceder.

Seja curioso

No mais, seja curioso sobre arquiteturas de software, padrƵes de projeto, tooling ā€” basta ser leitor(a). Seja curioso tambĆ©m sobre opiniƵes, principalmente quando elas tratam de desafios que ainda nĆ£o tivemos. A visĆ£o crĆ­tica Ć© ideal para abandonar a cultura jQuery.

O estudo permite que as soluƧƵes possƭveis surjam mais intuitivamente.

A prƔtica virƔ com os desafios, e nesses desafios Ʃ que deve entrar o seu protagonismo de apresentar soluƧƵes possƭveis.

Notas

Esse Ć© um rascunho de pensamentos que venho acumulando hĆ” algum tempo em razĆ£o de experiĆŖncias de trabalho que tive, e confesso que eles podem ter sido apresentados de forma confusa, embora eu tenha me esforƧado. Mas isso aqui nĆ£o era para ser receita de bolo, de verdade! AtĆ© mesmo os exemplos citados nĆ£o devem passar de exemplos.

A minha abordagem possui falhas, e uma deles Ć© que exige de quem desenvolve um conhecimento vasto de ferramentas, quando se usava apenas uma para tudo. (Para isso, recomendo um recurso disponĆ­vel no npm e mecanismos de busca: a busca.)

Mas perceba que o conhecimento vasto Ć© apenas de ferramentas. O conhecimento exigido pelas ferramentas em si acaba sendo menor do que o exigido por aquelas all-in-one como jQuery e AngularJS. O fato de encapsularmos dependĆŖncias considerando a necessidade de cada componente no front-end Ć© um modo de mantermos a curva de aprendizagem fragmentada.

De acordo com o que venho experimentando, desenvolver essa mentalidade tem retornado experiĆŖncias maravilhosas e, inclusive, gerado menos cĆ³digo legado. Basta apenas aplicĆ”-la Ć  Engenharia de Software com bom senso.

ConteĆŗdo sugerido

Os complementos abaixo sĆ£o apenas para despertar a curiosidade em relaĆ§Ć£o aos conceitos apresentados neste artigo, e nĆ£o devem substituir o estudo necessĆ”rio para deixar de lado, na prĆ”tica, a ā€œcultura jQueryā€.


Se vocĆŖ entendeu a razĆ£o pela qual a ā€œcultura jQueryā€ distancia vocĆŖ do seu papel, a mensagem foi entregue com sucesso.

\ No newline at end of file diff --git a/blog/o-til-no-javascript/index.html b/blog/o-til-no-javascript/index.html new file mode 100644 index 0000000..efb3e82 --- /dev/null +++ b/blog/o-til-no-javascript/index.html @@ -0,0 +1,33 @@ +O Til no JavaScript | DiƩssica Gurskas
diessi.caBlogMisc
October 31, 2015

O Til no JavaScript

Incompreendido, o operador til (~) Ć© um mistĆ©rio que ninguĆ©m discute. Primeiro, pois Ć© um operador bitwise, e, segundo, pois seus casos de uso sĆ£o bastante misteriososā€¦

VocĆŖ consegue dizerā€¦

em valor e tipo de dado, o que serƔ impresso no console nas situaƧƵes abaixo?

console.log(~~"1");
+console.log(~8.2);
+console.log(~false);
+console.log(~~"5.9");
+console.log(~~{});
+console.log(~~-5.5);
+console.log(~"Tudo bem?");
+

NĆ£o sabe? Wellā€¦

O operador til

Ou melhor, o operador bitwise NOT.

Ɖ importante falar isso pois Ć© importante entender o que bitwise significa. Operadores bitwise sĆ£o especiais em JavaScript: eles tratam todos seus operandos como uma sequĆŖncia de 32 bits (0 e 1) ā€“ ou seja, trabalham com representaƧƵes binĆ”rias (nĆ£o decimais, como de praxe) de nossos operandos, e nos entregam valores nĆŗmericos como se nada tivesse acontecido.

O NOT significa que todos os bits do operando serĆ£o invertidos (0 vira 1, 1 vira 0). Parece inĆŗtil quando nĆ£o estamos trabalhando com nĆŗmeros binĆ”rios, mas as aplicaƧƵes criativas tornam o operador mais interessante.

Regras do ~

  1. Quando a expressĆ£o Ć© null ou undefinedā€¦ 0.
  2. Objetos sĆ£o convertidos para strings.
  3. Strings sĆ£o convertidas para nĆŗmeros, se possĆ­vel. Quando nĆ£o Ć© possĆ­velā€¦ 0.
  4. Valores booleanos sĆ£o tratados como nĆŗmeros (0 para false, 1 para true).
  5. Floating-points sĆ£o convertidos excluindo a parte fracionada.
  6. Todo nĆŗmero inteiro n Ć© convertido para -(n + 1).

As duas Ćŗltimas regras sĆ£o as mais importantes, pois elas implicam nas principais aplicaƧƵes do operador. JĆ” temos a resposta de alguns:

console.log(~8.2); // => -9
+console.log(~false); // => -1
+console.log(~"Tudo bem?"); // => -1
+

Os nĆŗmeros foram convertidos de acordo com a fĆ³rmula -(n + 1). -9 Ć© resultado de - 8 - 1, por exemplo.

Dupla negaĆ§Ć£o

Podemos usar dois operadores til (double bitwise NOT). Aqui, basta entender o trabalho do outro til: reinverter os bits.

Considerando ~n, como anteriormente, temos -(n + 1) = - n - 1. Considerando ~~n, temos -[-(n + 1)] = n + 1.

Perceba que as equaƧƵes, quando somadas, se anulam. Pois essa Ć© a grande sacada de usar dois operadores til! Temos, entĆ£o:

console.log(~~"1"); // => 1
+console.log(~~"5.9"); // => 5
+console.log(~~{}); // => 0
+console.log(~~-5.5); // => -5
+

AplicaƧƵes

Truncar nĆŗmeros

Pelo fato do operador converter removendo a parte fracionada, utilizĆ”-lo para truncar nĆŗmeros de forma fĆ”cil Ć© a aplicaĆ§Ć£o mais comum:

let data = 7.8926152;
+const integer = ~~data;
+
+console.log(integer); // => 7
+

Embora o ~~ tenha sido, por muito tempo, usado no lugar de Math.floor(), o mƩtodo mais parecido com ele que temos em JavaScript hoje Ʃ o Math.trunc() do ES2015.

Converter string para nĆŗmero

Uma aplicaĆ§Ć£o simples que se baseia em uma das regras de funcionamento do til: converter strings para nĆŗmeros sempre que possĆ­vel; afinal, Ć© com nĆŗmeros que o operador trabalha.

let data = "2";
+const dataAsNumber = ~~data;
+
+console.log(dataAsNumber); // => 2
+

Verificar a existĆŖncia de um item no array

let women = ["Ada Lovelace", "Joan of Arc", "Marie Curie"];
+
+if (~women.indexOf("Ada Lovelace")) {
+  console.log("Ada Lovelace was such an important woman!");
+}
+

Ɖ difĆ­cil de compreender humanamente que o if estĆ” verificando se Ada Lovelace estĆ” incluĆ­da no array women, mas Ć© exatamente isso que estĆ” acontecendo. VocĆŖ entendeu a razĆ£o pela qual isso funciona?

PoderĆ­amos verificar sem o ~, mas nĆ£o funcionaria em casos em que o item do array Ć© o primeiro (Ć­ndice zero, e 0 retorna false como booleano). O operador til viabiliza essa verificaĆ§Ć£o, em razĆ£o da conversĆ£o de um nĆŗmero inteiro n para -(n + 1).

O equivalente humano, utilizando Lodash (_), seria:

let women = ["Ada Lovelace", "Joan of Arc", "Marie Curie"];
+
+if (_(women).contains("Ada Lovelace")) {
+  console.log("Ada Lovelace was such an important woman!");
+}
+

Performance

Usar ~~ em vez de Math.floor ou Math.trunc Ć© geralmente mais rĆ”pido. Dependendo da JavaScript engine do navegador e do caso de uso, no entanto, pode nĆ£o fazer muita diferenƧa e atĆ© ser mais lento. Veja o teste no JSPerf.

De qualquer forma, a pĆ©ssima performance de quem lĆŖ um cĆ³digo com o desumano ~ pode nĆ£o valer o ganho de performance ā€“ que Ć© ignorĆ”vel de tĆ£o mĆ­nimo ā€“ em uma aplicaĆ§Ć£o.

ConsideraƧƵes

No geral, operadores bitwise, principalmente ~, | e &, possuem aplicaƧƵes interessantes e bastante criativas.

Quanto ao ~~, nĆ£o acredito que chegarĆ” a se popularizar como aconteceu com o !!, que converte para um valor booleano. Em anos, a prĆ”tica com til nunca se tornou realmente popular, talvez pelo fato de ser um operador bitwise ā€“ e, portanto, pouco compreendido ā€“ e ter casos de uso bastante excĆŖntricos.

Ficam Ơ tƭtulo de curiosidade suas aplicaƧƵes bastante criativas. ;-)

\ No newline at end of file diff --git a/blog/omg-climate/index.html b/blog/omg-climate/index.html new file mode 100644 index 0000000..4484429 --- /dev/null +++ b/blog/omg-climate/index.html @@ -0,0 +1 @@ +OMG Climate: Reflecting Together on the Climate Catastrophe | DiƩssica Gurskas
diessi.caBlogMisc
May 30, 2019

OMG Climate: Reflecting Together on the Climate Catastrophe

NASA's illustration of Planet Earth warming process across the years
Credits: NASAā€™s Scientific Visualization Studio/Kathryn Mersmann.

Planet Earth, May 2019. The UK has announced a state of emergency for climate change and Canada considers the same; we are more confident about our model to capture rising global temperatures, and students all around the world walk out of school protesting the lack of climate action. Yet, not enough of us are genuinely concerned about the role weā€™ve played on this catastrophe.

A Saturday afternoon of May and a few square meters in Berlin were what a couple of people needed to openā€“Ā and voluntarily discuss how we impact the Planet to change and how those changes impact us. Topics ranged from radical solarpunk utopiaĀ to more down-to-earth and short-term ideas within our generationā€™s reach today: musings about climate change awareness, sustainability policies for companies, traveling sustainably, tech tools for political change, and how to get out of our bubbles and active listen to other realities.

In this post, Iā€™ll be sharing my personal notes on that engaging and constructive afternoon. There will be, also, references at the end of this post so you can keep yourself posted.

Pitching and picking topics for discussion

OMG Climate is an unconference, meaning that attendees proactively come up with the agenda and topics to be discussed. To kick it off, we got instructed to pitch topics for discussion thatā€™d be prioritised also by ourselves into tracks, attended based off our preferences. Everyone was expected to have at least a certain knowledge, even if rather tacit, about the challenges weā€™re facing right now with the climate emergency.

These were the tracks of the first OMG Climate:

  • Track 1: ā€œLow-carbon travelā€ / ā€œGreen Mafiaā€ / ā€œHow do you sleep at night? Coping with climate anxietyā€
  • Track 2: ā€œTech tools for political actionā€ / ā€œCircular economies: Re-use and techā€ / ā€œCompany sustainability policy templateā€
  • Track 3: ā€œSolarpunk, imagination and excitementā€ / ā€œCO2 Offsets as an API and tracking carbonā€ / ā€œClimate change awareness in developing countriesā€

We had enough attendees for tracks to make for productive discussions. Listening and talking to one another, while facilitated by a volunteer, did the job on keeping up an constructive flow between finding root causes and ways to take action.

People sitting in a circle, listening attentively to one
During the "Green Mafia" discussion.

Iā€™ve joined ā€œLow-carbon travelā€, ā€œGreen mafiaā€, and ā€œClimate change awareness in developing countriesā€, so these are the ones I have more insights about. Towards the end, we all got together to wrap it up, and I have to say: all tracks were interesting, so donā€™t restrain yourself to this post!

The following notes don't reflect directly what's happened or everything that's been said in the event, it's rather my personal perspective. They are also somewhat vague, but I hope you can benefit from them somehow.

Low-carbon travel

Air travel, even when occasional, has an environmental impact difficult to make up for no matter how many bamboo toothbrushes we gift our friends, how often we commute by bike or how vegan is our diet.

With low airplane ticket prices getting more popular than ever and enabling people to travel more, how can we make traveling sustainable when not traveling to begin with is not an option? That was the question we kicked off the ā€œlow-carbon travelā€ discussion with.

Meeting notes

Piece of paper sticked to the wall with sketches
Collective sketch notes about the low-carbon travel track
  • In our circle, everyone seemed to have access to the privilege that is air flying.
  • We began exploring traveling by breaking it down into traveling for work vs. pleasure.
  • Ground travel might be an option; however, itā€™s rather time-consuming and hence less appealing in a capitalist society where time translates to money. How can we shift the paradigm?
  • Instead of seeing longer trips as wasted time, we should begin seeing the journey as part of the trip.
  • Traveling less: We often optimise our trips to visit as many places as possible; instead, we can optimise for depth and start going to fewer places for a longer time. Think: going to a European country and making the most of it, instead of going to 999 different countries just because they are 1-hour-flight away from each other.
  • Share practical solutions for people to make trade-offs, EcoCost rather than overwhelming scientific evidence.
  • What if companies supported employees whose carbon footprint is the least?
  • Green travel agencies and flying policies.
  • Search engines for flights obviously donā€™t suggest alternative ways to get to a place when a plane is definitely not the best option.
  • BVG app, on the other hand, recommends walking instead of taking public transport sometimes.
  • Transport apps could also order route options by the least environmental impact.
  • The car industry should be ashamed of its climate record.
  • The train industry is not modernised and integrated, rather rigid.
  • Investment on 10 km of autobahn could pay off the renovation for bike lanes all over Berlin.
  • Globalisation vs. environmental footprint: IT workers immigrating usually go back to their countries often since they have the need and resources. I asked whether there was data available on how that situation in particular couldā€™ve increased our carbon emissions coming from aviation.
  • Business trips by train are possible only among those who have the privilege of a flexible work schedule, such as freelancers.
  • Making the most out of idle time: we tend to be more creative in idle times, while in a train; not hunching over a keyboard or in an office environment.
  • ā€œFast-moving home/officeā€ as an alternative to turn the journey time into productive time.
  • Frequent flyer levy: A fairer tax system according to how often people fly. Those that fly more should pay more. (More information: A Free Ride)
  • Airline campaigns often promote the image that everyone should become part of a group of young, urban frequent flyers, visiting another city every few weeks for very low costs.

Action points

  • everyone to shift mindsets in regard to traveling.
  • everyone to vote instead of buying a bamboo toothbrush.
  • everyone to use and promote tools with different options of transport within a route, instead of blindly going to specific train or flight websites.
  • everyone to keep consuming local goods.
  • airline companies to stop promoting flying as a status symbol.
  • travel agencies to work out more sustainable ways to travel and consider it in their branding.

Green Mafia

How corporate interests and ideologues work to undermine science and make countries doubt about the risks of climate change? Think what stopped Australia, 25 years ago, to act on climate change.

We should fight back! We mused about beating off lobby groups representing the coal, car, oil, electricity, and aluminium industries using their same sneaky techniques, as a Green Mafia. An intriguing and fun topic!

The brainstorming served as a tool to get a grasp on the way those mafias function, and discuss whether the ethical approach is always the way to go when facing a crisis.

Meeting notes

Piece of paper sticked to the wall with sketches
Collective sketch notes about the Green Mafia track
  • Leverage civil disobedience and tools of intimidation to influence green policies for the climate, fight extreme wealth and weaken existing mafias such as the oil industry.
  • How far should one go with non-ethical practices, such as blackmailing or public shaming of those who harm the planet?
  • Whatā€™s ethics after all?
  • Could we use illegal money to fund our causes?
  • Could we use legal money to fund our cases? There are ways to get money from the state in licit ways such as from green parties.
  • What if we made the green cause as profitable for the mafia as oil?
  • Sell a belief system, or use an existing one such as ā€œharmony with natureā€.
  • Cyber hacking/hijacking internet algorithms to spread awareness instead of climate change denial and fake news as it happens today.

Awareness in developing countries

The rich, the poor and the Earth.

Worldā€™s richest 10% produce half of the global carbon emissions, while the poorest half contribute a mere 10%; but climate change affects the poorest people the most. Moreover, developing countries are the most responsible for climate change now, and vulnerable too.1

Coming from a developing country, I was looking forward to this topic! Apart from Brazil, we had people from India too. There was a range of issues that could be tackled within this track, such as the risk of massive displacements of people in developing countries, the need of support to adapt, environment destruction for the sake of economic prosperity, how to approach climate change education etc.

Meeting notes

  • We are building awareness, not ā€œteachingā€ others about climate change.
  • Climate change is an existential threat to life, but it seems rather remote if you think about poverty, disease and economic stagnation. How do we educate children for the long-term if, for some of them, not showing up at school tomorrow means not eating at all?
  • How do we let them know about the risk of massive displacements of people who have no resources whatsoever to move?
  • Just by existing in a developed country in Europe, our carbon footprint is more impactful than any developing country.
  • Indigenous people are already defenders and protectors of the environment more than we will ever be in our generation.
  • Economic development is a priority in developing countries, and politicians may ignore environmental impact for the sake of it. (See Brazilā€™s natural resources open for business, says Bolsonaro)
  • Developing countries idealisation of economic development, influenced by ā€œdeveloped world standardsā€: tall buildings and industries all over the place, where often we donā€™t see the green implications of ā€œsuccessā€.
  • What about a model of development thats puts together the simple living of developing countries with the green development of developed ones?
  • How waste affects developing countries; example of Philippines to sail garbage back to Canada.
  • We could shift the discussion to think about environmental impact in terms of social classes instead of countries. After all, rich lifestyles and ā€œstatusā€ in general damage the environment in untold ways.
  • The Swadeshi movement brought back self-manufactured clothing in India to boycott foreign goods, a part of a movement to liberate India from British control and industrialisation.
  • When teaching, consider whatā€™s in peopleā€™s context, reach and language instead of whatā€™s ā€œout thereā€.
  • We should actively listen more to those communities and whatā€™s happening in those countries. Sometimes, instead of thinking that there is something to be taught, we should rather learn from their realities so we can bring about a meaningful conversation.
  • This is a problem not to be approached by technology, remotely. Itā€™s rather about Politics and Education.

Action points

  • everyone to assure inclusivity, cooperation and engagement across boundaries, first and foremost.
  • countries to keep cooperating efforts internationally through policies, institutional frameworks for development and investments in infrastructure.

Conclusion

Well-led communities that strive for welcoming environments enable the best out of people. OMG Climate has shown that ā€“ its unconference format got everyone to take responsibility and engage towards constructive and meaningful discussions about climate change.

Participant presenting using microphone, all sketch notes of the unconference sticked to the wall, on background
Final presentations wrapping up the tracks.

Although most of us had a tech background, everyone seemed aware: tech alone will not solve all problems, but we are eager to address them either way.

Learn about Climate Change

More on OMG Climate

\ No newline at end of file diff --git a/blog/react-and-form-management-is-redux-form-worth-it/index.html b/blog/react-and-form-management-is-redux-form-worth-it/index.html new file mode 100644 index 0000000..3a98cea --- /dev/null +++ b/blog/react-and-form-management-is-redux-form-worth-it/index.html @@ -0,0 +1 @@ +React and Form Management: Is Redux Form Worth It? | DiƩssica Gurskas
diessi.caBlogMisc
May 21, 2018

React and Form Management: Is Redux Form Worth It?

This is an improvement over my answer to a question in a Brazilian forum: "is using Redux for forms worth it?", in Portuguese. It assumes previous knowledge with React and Redux, and also mentions Redux Form, a library for managing forms in React.

It depends.

I know ā€œit dependsā€ is far from an interesting answer, yet thatā€™s the perfect-generic answer to any ā€œis using X worth it?ā€ question. It really depends, yes, but more often you donā€™t need that.

Last year I picked Redux Form to build a multi-step form wizard, each step containing different forms, with its own fields and validations (some of them asynchronous!). In the end, all forms would be merged into one JavaScript object to be sent at some point.

So, Iā€™d like to share my experiences and hopefully help you to figure it out what your problem is, and help you to decide by telling you how Iā€™ve solved mine.

Where Redux Form thrives

Redux Form is useful for larger and more complex forms where ease of development, high control (especially), consistency, and persistence (especially) are required. There are advantages from:

  1. the state form being in the Redux store, and
  2. Redux Formā€™s abstraction itself.

Which are two different things. You might need both, just one, or none at all.

Ease of development

Considering you are using Redux Formā€™s Field and wrap your form in its higher-order component ā€“Ā youā€™re done. Your form will work out of the box.

Yes, you could also get to build forms in a productive way with only React, but I think it's still worth-mentioning that Redux Form makes it really painless.

High control

You can manipulate forms from anywhere in the application: you trigger Redux actions provided by Redux Form and thatā€™s all. No need to create your own Redux reducers and actions.

Redux Form is also flexible on what can be an input. Anything works as a field: custom 3rd-party inputs, a regular HTML input, a fancy select component without any standard form element at allā€¦ Just pass the right props to it.

You can set up validation at the form and field level, supporting either synchronous or asynchronous validation. The errors triggered are also in the store ā€“Ā which makes it sweet to give useful feedbacks for users from anywhere, and also to debug! šŸ‘Œ

Consistency

All forms have the same data structure so youā€™d have the exact same information for every form and its fields, such as field values, field/form validity and further information (is the field touched? Pristine? Dirty?) in the Redux store.

Of course you can build forms consistently just by using React itself, but using Redux Form definitely enforces it.

Persistence

Since the state is already in the Redux store, Redux Form is easily pluggable with tools from the ecosystem.

Letā€™s say you want to save drafts from userā€™s inputs so people can finish and submit the form later. Redux Form + redux-persist make it pretty easy: the rehydrate process in the Redux store autofills the UI like magic!

Where Redux Form might die

In the thread, someone mentioned the article Redux Form is dead. TL;DR: It's not fucking dead, as any library, framework and whatsoever that has an "X is dead" post for it.

Letā€™s not forget that the JavaScript community is flooded with ā€œX is deadā€ articles for everything in the ecosystem. That post, in particular, mentions valid points to consider such as ephemerality of the state (quoting Dan Abramov), performance issues within Redux Form, and the project maintenance/activity. I will go through them a bit.

Form data in the Redux store

Dan Abramov, creator of Redux, said: ā€œUse React for ephemeral state that doesnā€™t matter to the app globally and doesnā€™t mutate in complex ways. For example, a toggle in some UI element, a form input state. [ā€¦]ā€.

Which is completely accurate. Where your state should live in your app depends entirely on its ephemerality ā€“Ā how trivial it is for the application as a whole when it comes to reading, updating it and so on.

In the post, that quote is used to support the claim that Redux Form fucks up when stores all form data in the Redux store by default ā€“ a pretty bold design decision for sure.

However, Dan did not write that in stone ā€“ he never does and heā€™s clear about it. That should serve as an encouragement for developers to think better about where your applicationā€™s states should go into. So, yes, you should think twice ā€“ and that doesnā€™t kill Redux Form.

The state of a form wizard, whose input data persists until the end of the steps (in a session or local level, for instance), whose inputs may trigger UI changes, whose inputs gets touched and changed by external components, itā€™s definitely not as ephemeral as the state of a newsletter sign up or a contact form. In the former, the form state is important for the whole application. Just notice thatā€™s a very specific case.

Performance issues

Redux Form has reached a well-optimised (see redux-form #529 and redux-form #1405) state.

When it comes to performance, though, you should never rest easy anyway. If you measure and find that your forms are slow, you should find bottlenecks and optimise from that.

Project activity

Regarding the project activity, it is something to consider when deciding, and should always be. Is it active? Are there people maintaining it? Can YOU help to maintain it?

Yes, Erik (the author) has recently started working on another solution called Final Form, which moves the form state out of the Redux store. However, Redux Form is mature, still well maintained (check GitHub, and he even said it himself on Reddit), and its documentation is great.

Final words

Only if the state of your form is non-trivial enough to live in the Redux store, Iā€™d give it a chance for Redux Form, especially if you are considering making your own solution. Redux Form has suffered and evolved a lot and nowadays it has a very stable and mature API you can count on, Iā€™d say.

Other React form management solutions you should definitely be looking at are Formik and react-final-form, by Redux Formā€™s author. They donā€™t rely on Redux for state management and are most likely what you need now ā€“Ā or not.

The price is the abstraction, of course, it always is. šŸ™„ However, their everyday API is indeed minimal though, just be prepared to go through the documentation when you need to achieve specific stuff. In return, donā€™t forget youā€™ll get a consistent and solid structure to build forms upon.

Have fun building forms! šŸŽ‰

\ No newline at end of file diff --git a/blog/shared-variables-between-javascript-and-css/index.html b/blog/shared-variables-between-javascript-and-css/index.html new file mode 100644 index 0000000..27d1c9f --- /dev/null +++ b/blog/shared-variables-between-javascript-and-css/index.html @@ -0,0 +1,78 @@ +Shared Variables Between JavaScript and CSS | DiƩssica Gurskas
diessi.caBlogMisc
January 15, 2017

Shared Variables Between JavaScript and CSS

Because it assures consistency throughout the project and avoids magic numbers, sharing variables between JavaScript and CSS code may help you to keep your project codebase tidy and easier to reason about.

For this article, when talking about CSS, the word ā€œvariableā€ may mean custom property or custom media query.

Getting Started

First, create a object containing your variables and export it.

My JS file containing the object will be called variables.js.

export default {
+  mainColor: "#000",
+  secondaryColor: "#fff000",
+  fullHeight: "100vh",
+};
+

No magic is needed to use those variables in your JS filesĀ ā€“ just import them when you need it. But in order to communicate those variables to your CSS files and use them with var(), some magic is needed.

For this, I will be using cssnext, a PostCSS plugin, and injecting that object into our stylesheets as custom properties.

Webpack example:

import cssNext from "postcss-cssnext";
+import myVars from "./variables";
+
+module.exports = {
+  // Entry, loaders, plugins...
+
+  postcss: () => [
+    cssNext({
+      features: {
+        customProperties: { variables: myVars },
+      },
+    }),
+  ],
+};
+

Since Iā€™m just using postcss-cssnext API, itā€™s also possible to do it with the build tool of your choice. Check docs on passing options to cssnext features.

Getting Real-world with Breakpoints

Sharing breakpoints between JavaScript and your stylesheets is a great real-world example.

Itā€™s time for variables.js to grow then!

export const properties = {
+  mainColor: "#000",
+  secondaryColor: "#fff000",
+  fullHeight: "100vh",
+};
+
+export const mediaQueries = {
+  secondaryColor: "#fff000",
+  desktop: "(min-width: 1024px)",
+  tablet: "(min-width: 768px)",
+  mobile: "(min-width: 320px)",
+};
+

Because itā€™s not possible to create a media query containing a custom property, we need to inject mediaQueries as custom media queries.

Letā€™s update the previous Webpack example in order to let cssnext to know about both custom media queries and properties.

import cssNext from "postcss-cssnext";
+import { properties, mediaQueries } from "./variables";
+
+module.exports = {
+  // Entry, loaders, plugins...
+
+  postcss: () => [
+    cssNext({
+      features: {
+        customProperties: { variables: properties },
+        customMedia: { extensions: mediaQueries },
+      },
+    }),
+  ],
+};
+

Done! Some usage examples for CSS, JS and even React are provided below.

Usage

CSS Example

Using custom properties and custom media queries according to settings from variables.js file.

.banner {
+  background: red;
+  height: var(--fullHeight); /* Custom property */
+
+  @media (--desktop) {
+    /* Custom media query */
+    width: 50%;
+  }
+}
+

JavaScript example

Example below uses enquire.js library.

import enquire from "enquire.js";
+import { customMedia } from "./variables";
+
+enquire
+  .register(customMedia.tablet, () => {
+    console.log("Matched tablet resolution");
+  })
+  .register(customMedia.mobile, () => {
+    console.log("Matched mobile resolution");
+  });
+

React example

Rendering a component only on desktop resolutions.

Example below uses react-responsive library.

import MediaQuery from "react-responsive";
+import { customMedia } from "./variables";
+
+function DesktopOnlyComponent() {
+  /* (min-width: 1024px), according to variables.js */
+
+  return (
+    <MediaQuery query={customMedia.desktop}>
+      <p>My desktop-only component!</p>
+    </MediaQuery>
+  );
+}
+

Final Words

A non-consistent front-end codebase is just messy.

I really use this technique on everyday work, and itā€™s a cheap way to significantly improve the quality of the front-end codebase.

So, donā€™t underestimate it! Besides breakpoints, there are infinite possibilities for this, such as project colors, layout dimensions and other shared stuff that can easily get out of hand while working on a large project.

\ No newline at end of file diff --git a/blog/svg-images-as-react-components-with-webpack/index.html b/blog/svg-images-as-react-components-with-webpack/index.html new file mode 100644 index 0000000..c2cb664 --- /dev/null +++ b/blog/svg-images-as-react-components-with-webpack/index.html @@ -0,0 +1,48 @@ +SVG Images as React Components with Webpack | DiƩssica Gurskas
diessi.caBlogMisc
August 02, 2016

SVG Images as React Components with Webpack

If youā€™ve ever tried to load inline SVG (using svg-inline-loader) into React, you know it seriously hurts peopleā€™s eyes.

import React from "react";
+import IconRemove from "./icons/remove.svg";
+const RemoveButton = () => (
+  <button>
+    <div dangerouslySetInnerHTML={{ __html: IconRemove }} />
+    <span>Remove</span>
+  </button>
+);
+

So what if it looked like this instead?

import React from "react";
+import IconRemove from "./icons/remove.svg";
+const RemoveButton = () => (
+  <button>
+    <IconRemove />
+    <span>Remove</span>
+  </button>
+);
+

Much better, donā€™t you think?

Thatā€™s what svg-react-loader does. It process your SVG file and returns a React component, which is compiled with Babel (more on this below).

Using the Loader

npm install svg-react-loader --save-dev
+

Refer to Webpack docs for more information on loaders usage. Also, make sure you have installed svg-react-loaderā€™s dependencies.

1. In Module Request

The simplest method, although the configuration convention is preferred. Using svg-react-loader and babel-loader, import your icon just like:

import IconRemove from "babel!svg-react!./icons/remove.svg";
+

Add in your Webpack configuration fileā€™s loaders array.

{
+  test: /\.svg$/,
+  loader: 'babel!svg-react'
+}
+

Import your icon just like:

import IconRemove from "./icons/remove.svg";
+

Usage Examples

Loader in module request method (1):

import React from "react";
+import IconRemove from "babel!svg-react!./icons/remove.svg";
+const RemoveButton = () => (
+  <button>
+    <IconRemove />
+    <span>Remove</span>
+  </button>
+);
+

Loader in Webpack config file method (2):

import React from "react";
+import IconRemove from "./icons/remove.svg";
+const RemoveButton = () => (
+  <button>
+    <IconRemove />
+    <span>Remove</span>
+  </button>
+);
+

A Note on SVG Loaders

Sometimes, we donā€™t want all of our SVG files to be loaded as React components. If you use a SVG in a img element, for example, it may lead to conflicts. Fortunately, you can avoid them by being more specific in test regular expression:

{
+  test: /\.inline.svg$/,
+  loader: 'babel!svg-react'
+},
+{
+  test: /\.jpe?g$|\.gif$|\.png$|^(?!.*\.inline\.svg$).*\.svg$/,
+  loader: 'url'
+}
+

Now, only SVG files ending with .inline.svg will be loaded as React components. Youā€™re good to go!

\ No newline at end of file diff --git a/blog/tchau/index.html b/blog/tchau/index.html new file mode 100644 index 0000000..39f0bdc --- /dev/null +++ b/blog/tchau/index.html @@ -0,0 +1 @@ +Tchau | DiƩssica Gurskas
diessi.caBlogMisc
May 13, 2017

Tchau

de ViamĆ£o, Brasil para Berlim, Alemanha. šŸ‡©šŸ‡Ŗ

ā€“Ā Tu tem que ver o que Ć© pra ti, sabe? Se tu ficar aĆ­, tu provavelmente vai ficar nessa mesma por bastante tempo. Ɖ isso que tu quer?

ā€“ NĆ£o, meu sonho sempre foi morar fora, do paĆ­s.

ā€“ O meu tambĆ©m Ć©. Esse Ć© o meu foco, pra sempre. Eu nunca tirei isso da mente.

A memĆ³ria parece distante agora, mas nĆ£o faz muito tempo que eu tive essa conversa. 30 de MarƧo de 2016. JĆ” faz um pouco mais de um ano. FalĆ”vamos de indecisƵes, insatisfaƧƵes e mudanƧas, quando sonhos vieram Ć  tona.

Sonhos. Pessoalmente, penso neles como desejos fixos que habitam a nossa consciĆŖncia junto a outros desejos, mais efĆŖmeros, e que, assim que vocĆŖ os deixa de lado (nem que seja um pouco), inconvenientemente voltam a te atormentar; lembrar que eles ainda estĆ£o lĆ” e nĆ£o sĆ£o como os outros desejos.


Esse Ć© o meu foco, pra sempre. Eu nunca tirei isso da mente.

Palavras minhas. Confesso, me assustam. Ou melhor, me assustavam. O que me assusta mais agora Ć© o fato de eu ter lido isto em menos de um ano depois:

Iā€™m personally very happy to say that after everything weā€™ve heard and seen, we think youā€™re a great match for us and would love for you to join our team here in Berlin.

([ā€¦] Pessoalmente, estou muito feliz de dizer que, depois de tudo que nĆ³s ouvimos e vimos, achamos que vocĆŖ tem tudo a ver com a gente e gostarĆ­amos que se juntasse ao nosso time aqui em Berlim!)

O que seria para sempre o meu foco, o desejo que eu descorri por 30 linhas no meu LG R510 em uma carta de maio de 2012, aquilo que eu nunca havia tirado da mente, naquele momento surgia como uma oportunidade. Eu topei.

Foram vĆ”rios passos antes disso, e eu lembro de estar ansiosa antes de cada um deles. Encontrei pessoas maravilhosas durante o caminho, com um coraĆ§Ć£o tĆ£o grande como o meu. Tanto na vida quanto nessa entrevista em particular.

Nas entrevistas, o processo simplesmente fluiu. Penso e gosto de pensar que Ć© o que acontece quando os aspectos tĆ©cnicos sĆ£o vistos como meros meios necessĆ”rios para aquilo que realmente importa: criar.

Desde aquele momento atĆ© hoje, o dia do meu voo, o tempo pareceu nunca passar em alguns momentos, e, em outros, passar rĆ”pido demais. Mesmo com a percepĆ§Ć£o confusa do tempo, tenho certeza de que poder enviar a mensagem abaixo Ć© algo que eu nĆ£o imaginava para tĆ£o cedo.

Just got the call! [ā€¦] Thatā€™s an important moment of my life for sure. Iā€™m just, you know, happy. Thank you for this.

The call. A ligaĆ§Ć£o se referia a do Consulado Geral da Alemanha de Porto Alegre que recebi no dia 8 de maio, dizendo o que esperei 2 semanas (ou toda a minha vida?) para ouvir. O meu visto estava aprovado. Ali estava, sem dĆŗvidas, um momento importante da minha vida.

Do resto do telefonema, confesso, nĆ£o lembro muito. Minha maior memĆ³ria desses instantes foi a de andar com o coraĆ§Ć£o cheio atĆ© o centro de Porto Alegre como se fosse a Ćŗltima vez. E foi, pelo menos por um bom tempo.


Um sonho pode, afinal, terminar de 2 maneiras: sendo abandonado ou realizado.

Meu caso Ć© o segundo, e, sinceramente, nĆ£o estĆ” fĆ”cil acreditar. Se vocĆŖ me disser que a partir de hoje eu jĆ” nĆ£o moro mais onde cresci, que meu voo hoje Ć© sĆ³ de ida, essa informaĆ§Ć£o serĆ” processada de forma que ela nĆ£o faƧa sentido na minha realidade. Eu nĆ£o vou acreditar.

Por outro lado, nesse momento da minha vida em que a gratidĆ£o transcende o mĆ©rito, acredito em vĆ”rias outras coisas. A principal Ć© que sou o resultado do fenĆ“meno que acontece quando a oportunidade encontra o anseio: alguĆ©m, no passado, acreditou em mim; alguĆ©m, no presente, acredita em mim. E eu nĆ£o as deixei decepcionar.


Hoje estou voando para Berlim, a capital da Alemanha, para fazer o que amo na HelloFresh, que me ajudou em todo o processo. Sou grata por isso, por tudo.

Quanto Ć  realidade, nĆ£o Ć© que eu nĆ£o tenha medo. Eu tenho. Eu tive medo em todas as vezes que ousei. Desde o primeiro emprego que fui atrĆ”s no Brasil (no tĆ©dio do meu Ensino MĆ©dio), dos projetos alĆ©m do meu conhecimento, atĆ© o meu primeiro emprego fora do Brasilā€¦ eu tive medo em todos eles.

Eu sĆ³ jamais deixaria o sonho terminar do outro jeito, entĆ£o eu topei tudo mesmo assim.

\ No newline at end of file diff --git a/blog/the-bitter-reality-of-ebooks/index.html b/blog/the-bitter-reality-of-ebooks/index.html new file mode 100644 index 0000000..dd65a61 --- /dev/null +++ b/blog/the-bitter-reality-of-ebooks/index.html @@ -0,0 +1 @@ +The Bitter Reality of Ebooks and the Kindle Model | DiƩssica Gurskas
diessi.caBlogMisc
August 16, 2023

The Bitter Reality of Ebooks and the Kindle Model

A few years back, I jumped into the world of ebooks to broaden my reading without stacking so many physical books. I went with the ever-popular Kindle; yet the full weight of ā€œowningā€ ebooks, particularly from Amazon, was not something I understood.

ā€¦Until I decided to break up with Amazon, despite its convenience. You know the drill: Amazon exploits workers, aggressively avoids taxes, dominates markets, and I was just itching to explore alternative bookstores. The hiccup? My Kindle was firmly rooted and entangled in Amazonā€™s ecosystem. Without Amazon, I could no longer conveniently or legally read books on my Kindle, and without Kindle, I could not legally read books I once purchased on Amazon.

Hereā€™s what Iā€™ve learned while attempting to part ways.

It all begins with ā€œDRMā€

Digital Rights Management (ā€œDRMā€) might not be a household term, yet its fingerprints are everywhere. Ever wondered how we consume content via proprietary software, rather than owning the content?

Think Spotify (you never own the music), Netflix (you never own the film), Adobe Creative Cloud (you never own the software), Steam (you never own the game), and Amazon Kindle (you never own the ebook). You download those proprietary software on your device, not the content itself. While you may have a license to the content, but itā€™s not truly yours.

The use and distribution of the copyrighted content provided by those services (and many others) are restricted by DRM (ā€œDigital Rights Managementā€) technologies, implemented in various ways, increasingly restrictive and controversial. While DRM aims to address the legitimate need of copyright protection, it fundamentally reshapes the landscape of intellectual consumption, often at the expense of user privacy and freedom. For example:

  • Content Sharing: DRM often limits, or restricts altogether, the ability to share, lend and gift content outside of the same ecosystem.

  • Content Portability: DRM can authorise content to only a specific set of devices or apps, and restrict the supported file formats (even to a proprietary format). That limits content migration across platforms, technologies and devices that better suit you.

The points above reveal an alarming side-effect: dependency on the ecosystem, or "vendor lock-in", which is detrimental to individual freedom and market competition. When content is tightly bound to the platform, disengaging becomes challenging. And when you're limited to sharing only within an ecosystem, your social circle gets roped in too. Kinda seem like cute digital mutualism until it's a toxic relationship you can't leave.

  • Content Perpetuity: DRM cannot guarantee perpetual access to content. If a service or platform discontinues the content or themselves entirely, you may simply lose what you purchased. In fact, that has already happened, more than once or twice.

  • Content Geographical Restrictions: DRM can prevent access to certain content based on location. With the internet alone, we could technically provide equal access to cultural and educational resources ā€“ DRM kills that.

  • Content Offline Access: DRM often requires online authentication or periodic online checks. Not very nice in low connectivity areas or during travel.

  • Personal Identification: DRM requires authentication to consume content. By withholding identifiable information, DRM systems may also monitor behavior and consumption patterns and then profile you. Youā€™ve got nothing to hide? Well, perhaps it at least bothers you to have to login? (And if that keeps going on we might soon have login on physical books too?! And there will be no refresh token cookie irl?!?????)

All those ā€œside-effectsā€ (given they are actually unintended šŸ˜‰) of copyright protection through DRM conveniences corporations. Corporations may not only protect their profit but also actively profit through DRM, charging high customer cost while delivering zero customer value.

Finally, because DRM implementations vary so much, itā€™s nearly impossible to determine your rights without diving into lengthy terms of use agreements. The restrictions are rather obscured by clever marketing ā€“ youā€™ll soon see.

Leaving Amazon, and failing

Do you still remember I was trying to break up with Kindle? I get too hung up sometimes but letā€™s not forget why weā€™re both here, right!!?!

First things first, let me make it clear ā€“ I did not want to give up ebooks. Itā€™d been a pleasure to be able to dive into new literature and keep only the gems in my bedroom bookshelf. And I could also carry a multitude of stories effortlessly during my travels.

Secondly, I had no intention of trashing my Kindle. It was a fully functional piece of hardware, and it worked well.

So here was my grand plan: Iā€™d log out of my Amazon account on the Kindle, and source my ebooks somewhere else. Seems pretty straightforward, right? But the hurdles kicked in right from the very first step.

FuN fACt: Kindle sales are not very profitable to Amazon, as they hope to make up for it with e-book and app sales.

As it turns out, signing out of my Amazon account meant every single piece of content Iā€™d ever acquired through Kindle would vanish into thin air. On Kindle, your books are tied to your Amazon account.

That was an unforeseen repercussion. I naĆÆvely expected to hold rights over books Iā€™d purchased regardless of whether they were digitally or physically distributed. So I was disappointed and surprised ā€“ with myself, the state of things; both. And yes, I clearly had not read Kindle terms of use back when I got into the ecosystem (otherwise you wouldnā€™t be reading this! šŸ˜‰).

FINALLY reading Kindle Terms of Use

The latest Kindle Store Terms of Use (Last updated: November 30, 2022), determines a set of restrictions you buy into when you decide to buy Kindle and Kindle content, DRM-protected or not. The ā€œUse of Kindle Contentā€ section states a couple of DRM-ish things:

  1. ebooks are meant to be consumed only on Kindle, or Kindle apps.

Upon your download or access of Kindle Content and payment of any applicable fees (including applicable taxes), the Content Provider grants you a non-exclusive right to view, use, and display such Kindle Content an unlimited number of times (for Subscription Content, only as long as you remain an active member of the underlying membership or subscription program), solely through a Kindle Application or as otherwise permitted as part of the Service, solely on the number of Supported Devices specified in the Kindle Store, and solely for your personal, non-commercial use. [...]

  1. when you click ā€œBuy Nowā€1, you are actually buying a license i.e. renting.

Kindle Content is licensed, not sold, to you by the Content Provider. [...]

Coming from DRM-based services like Spotify or Netflix, where you subscribe for access to a collection of music or film, the Kindle model might be a surprise.

Within the Kindle ecosystem, you are able to buy individual content, which does evoke a stronger sense of direct ownership. Yet, when you do so, youā€™re essentially obtaining a license: every ebook is an one-off payment to a mini-subscription. And that was absolutely not straightforward or intuitive to me.

  1. you may not lend or sell your ebooks.

Unless specifically indicated otherwise, you may not sell, rent, lease, distribute, broadcast, sublicense, or otherwise assign any rights to the Kindle Content or any portion of it to any third party [...]

  1. your books might disappear anytime.

We may change, suspend, or discontinue the Service, in whole or in part, including adding or removing Subscription Content from a Service, at any time without notice.

(Funny enough, I checked Wayback Machine and noticed that one was amended around March 2015, after reports of disappearing ebooks years before. šŸ¤·)

ā€¦And embracing the sacrifice

Delving into the Kindleā€™s terms brought the truth crashing down on me: I never really had a choice to transition away from Amazon while retaining my content. Severing ties with Kindle came at a cost I hadnā€™t anticipated, and I felt very exploited for it.

Some might argue I actually had the ā€œchoiceā€ to enter Kindleā€™s ecosystem. And sure, itā€™s true ā€“ I did it willingly, no one coerced me into becoming a Kindle user. But, hey, thereā€™s a nuanced reality here you canā€™t brush aside: we make our individual choices within systems. Thereā€™s an entire environment lying behind the notion of individual choice.

Systems can be designed to subtly exert control or exploit personal choice in ways that arenā€™t always apparent. You canā€™t look at individual choice alone overseeing the environment in which those decisions are made. In no defensiveness, blaming on individual choice is, I dare to say, exactly how exploitative systems maintain their facade of legitimacy. And I donā€™t think being exploited or not should be a choice to be made.

Yeah, a bitter pill to swallow, but a new plan has to emerge out of my anger: to log out of my Amazon account, and therefore leave books Iā€™ve purchased behind, and use Kindle only as an e-reader, not a shop.

Leaving Amazon, and failing less

After logging out of my Amazon account, Iā€™m left with an anonymised Kindle (I hope). At this point I wonder if I even have the right to keep the hardware Iā€™ve purchased, but so far nobody hasnā€™t taken it away from me. šŸ˜‰ So, how can I rebuild my e-book library?

Using Kindle with other bookstores

Before buying ebooks elsewhere, one needs to understand what file formats are supported by Kindle. The file formats supported by Kindle are MOBI, PRC, PDF, and primarily the proprietary AZW, and the files may or may not be DRM-protected depending on the publisher. Only Amazon sells AZW books2. So my options are:

  • MOBI. But no bookstores sell them these days.
  • PDF. But formatting sucks for reading books.
  • PRC. I donā€™t know what that is.

So I have no options. \šŸ˜Ž/ Bookstores sell EPUB books, an open standard well supported by all e-readers in the market but Kindle. Fortunately, you can manually convert EPUB books into one of the Kindle-compatible formats above. Unfortunately, if the book is DRM-protected (very likely!), you would need to strip out DRM before conversion which is downright illegal LMAOOOOOO!!!!! This drives me CRAZY, but letā€™s move on.

For ebook format conversions, Amazon fortunately offers Kindle Previewer, a publishing software, but itā€™s just a little too bloated for my goal. So I went with Calibre, a free and open source e-book manager that does it all. It works wonders!

If you keep your Amazon account, importing EPUB into is easier with Send to Kindle. It's a more convenient option but it often messes up with the book formatting.

Ultimately, using non-Amazon ebooks on a Kindle device can involve various technical and legal considerations, especially when dealing with DRM-protected content. DRM-free book shopping is also limited ā€“ DRM is an industry standard! So using a Kindle without Amazon is not just very inconvenient, itā€™s barely legal. šŸ˜‰

The most promising plan seems to be tossing Kindle altogether, and choose an open standard e-reader with less hostile DRM platforms, but thatā€™s for another time.

Amazon caters for publishers, not consumers

It all makes sense when you put it all together. When traditional publishing giants contemplated the world of e-readers and online stores, they had to be a bit careful about it. With physical distribution, they already had a model that offered a clear sense of ownership and control. Then, remember the music industryā€™s digital transformation, marked by piracy and revenue decline3? Obviously publishers would be wary of a similar fate.

But in comes a compelling offer from Amazon: a tight grip on digital ownership of books, and a shortcut into an already profitable book marketplace. All or nothing. A captivating promise of control and access which publishers, late to digital transformation, did not pass up. And so seamlessly, Amazon paved the way towards market dominance. šŸ‘

Today, Amazon also positions itself as a platform for emerging writers and attracts independent publishers. So does Spotify for musicians, and Steam for game developers. For both publishers and consumers, content discovery is whatā€™s great about such platforms, despite their license model.

Alternatives like Bandcamp (music) and GOG.com (games) also promote publishersā€™ content. In contrast, their DRM-free4 model ethically caters to both consumers and publishers: the consumer has direct ownership to content, and publishers get their content secured, even earning more5. How does that work? Fingerprinting content files (i.e. watermarks), but above all, cultivating consumer trust and transparency, and a sense of community and support for artists.

Final words

While writing this, an analogy came to mind.

Picture when you buy a physical book from a store. You know that book will patiently await you right where you left it and not vanish into thin air, whether you frequent the store or it eventually shuts down. That store is unaware of your identity. It doesnā€™t know when you open or close the book, nor does it know which passages youā€™ve highlighted. You can even lend the book to a friend, regardless of whether they shop at the same store or if the store recognizes them. And that both of you can go buy books elsewhere later with no strings attached.

But I know thatā€™s kinda corny. Itā€™s an oversimplification. Digital content IS different, and copying files is far easier technically than producing physical copies. We do have new challenges.

Yet, while the analogy might not outright invalidate DRM as a solution, it can serve as a reminder of the current asymmetry of our digital rights today. A nudge to the way our essential rights are exploited within the current framework of digital copyright protection. And, ultimately, it extends an invitation to reimagine it from the ground up. Perhaps looking at how other platforms like Bandcamp have already done so brilliantly, perhaps radically starting at copyright itself.

Keep reading

ā€¦on how despite massive technical effort and corporate interest, DRM is a flawed security model.

1

As of 16/08/2023, Amazonā€™s checkout button for Kindle ebooks is labeled ā€œBuy Nowā€.

5

In comparison to Spotify, whose profit margin for publishers is often questioned. See Ben Sinano: Musicians Say Streaming Doesnā€™t Pay. Can the Industry Change?.

\ No newline at end of file diff --git a/blog/ttt/index.html b/blog/ttt/index.html new file mode 100644 index 0000000..3abaa66 --- /dev/null +++ b/blog/ttt/index.html @@ -0,0 +1 @@ +T. T. T. | DiƩssica Gurskas
diessi.caBlogMisc
April 01, 2018

T. T. T.

Put up in a place
where it's easy to see
the cryptic admonishment
Ā Ā Ā Ā Ā Ā T. T. T.

When you feel how depressingly
slowly you climb,
itā€™s well to remember that
Ā Ā Ā Ā Ā Ā Things Take Time.

Piet Hein

\ No newline at end of file diff --git a/blog/ui-components-that-abstract-mistakes/index.html b/blog/ui-components-that-abstract-mistakes/index.html new file mode 100644 index 0000000..3a15a70 --- /dev/null +++ b/blog/ui-components-that-abstract-mistakes/index.html @@ -0,0 +1,11 @@ +UI Components that Abstract Mistakes | DiƩssica Gurskas
diessi.caBlogMisc
October 14, 2017

UI Components that Abstract Mistakes

2017, October 14th.

A cloudy day 1 of Autumn in Berlin, probably something else in the place you live, and youā€™ve read the same date twice and this introduction actually doesnā€™t matter. But let me tell you about something that matters.

Everything is made up of <div>s and <span>s again, utterly hidden behind abstractions proudly called components. No one seems to remember (or do they?) the difference between p and span, let alone the point of using section rather than div.

Bad decisions ā€“ to not just to say bad and even invalid HTML markupĀ ā€“ are buried in components developers find awesome to compose user interfaces with. The web, and people, pay the price.


Creating components

From now on, to explain my point, I'll be assuming some familiarity with React (a JavaScript library), although this applies to any kind of component abstraction.

Letā€™s say you just started a brand new React web app. You need to create a button at some point, and, because itā€™s reused in other parts of the app, has custom styles and also a fancy icon, you decide to introduce a component with all that abstracted out. Nice! You could do it like this:

const Button = ({ onClick, children }) => (
+    <span class="my-horrible-button" onClick={onClick}>
+        <i class="my-terrible-font-awesome-icon"></i>
+        {children}
+    </span>
+)
+

The user interface is then composed as the following:

<h1>Brazilian Bananas (1 kg)</h1>
+<p>Sweet and healthy bananas!</p>
+<p>Absolutely the best.</p>
+<Button onClick={() => alert('šŸŒ')}>Buy $0.99</button>
+

It looks good! You were born for this, werenā€™t you?

Quite easy to miss whatā€™s wrong when components are just used like that. A button, isnā€™t it? The engineering team can easily grasp what that means and what that does, after all.

It could also be a <FormLabel /> or <Paragraph /> as span elements, or divs all over that place. Although they all work, mistakes are abstracted in components.

I specifically talk about markup as the mistake throughout this article, however it could be anything really. Components look inoffensive when you're using them.

The web isnā€™t your abstraction

Now that HTML is all abstracted through JavaScript libraries and frameworks (which is not wrong), I wonder whether developers only went for semantic elements for the sake of making markup more readable for themselves. With React, your <Header> now may be a div. Out of the abstraction, though, youā€™d think twice before going for a div to make a headerĀ ā€“ youā€™d rather use HTML5ā€™s header.

Because of the abstraction, output markup isnā€™t something we talk that much about anymore.

Did we really get the benefits of HTML5 and why new elements were introduced? Why button? 2 Whatā€™s header useful for? Why should one use section at all?

By the way, do you know how many occurrences of header, article, section I've found on Netflix's landing page? Zero. It's all div soup.

Matter of fact is that browser engines and people ā€“ nothing less thanĀ the ones who you really write code for ā€“ wonā€™t ever know about your abstractions. A screen reader wonā€™t know your ā€œbuttonā€ is actually a button3. (They will definitely get to know the span though, and that wonā€™t help.)

xkcd, comic #1444
xkcd: Tags

Also, itā€™s never been easier to write invalid markup without even realizing it! After React, it seems acceptable to place a button inside an anchor link, and even giant elephants inside span. Has anyone ever thought why they are considered invalid markup in the first place?

Donā€™t make it hard

Browsers and assistive technologies are smarter than ever4, indeed, yet they still count on developers to write code they can understand and people can benefit from. By doing so, you make it easy for:

  1. people, who will be able to navigate around the website, skipping over navigation sections or quickly jumping from one article to another5.
  2. yourself, so you donā€™t have to reimplement default browser behaviours.

Therefore, please: donā€™t waste features that technologies try to give users, and developers, out of the box.

Remember who you write code for.

1

If I had managed to publish this yesterday, the day would be sunny. Iā€™ve missed the opportunity to make the article seems a little happier.

2

The button element was first introduced in HTML4. (Source)

3

Whatā€™s wrong with using a non-semantic element as a button? Well, if the button is accessible, nothing really. But doing so demands extra work that nobody is up for, besides that fact that you canā€™t actually create a button.

4

Technologies may even process <span class="tel">123-456-7890</span> as a telephone, and allow for automatic dialling of it. See microformat for more information.

5

Why not, right? After all, articles are for independent pieces of content, e.g., an user-submitted comment or a forum post. (Source)

\ No newline at end of file diff --git a/blog/var-that-this-nah/index.html b/blog/var-that-this-nah/index.html new file mode 100644 index 0000000..4576b20 --- /dev/null +++ b/blog/var-that-this-nah/index.html @@ -0,0 +1,33 @@ +var that = this? Nah. | DiƩssica Gurskas
diessi.caBlogMisc
March 15, 2017

var that = this? Nah.

Tried JavaScript for some minutes? You probably already wrote the following.

var that = this;
+

(Or one of its variants, such as var self = this.)

Thatā€™s a pretty common pattern when you found yourself in a situation where:

  1. you have a function nested inside of an objectā€™s method, and
  2. you want to access the objectā€™s properties, but
  3. JavaScriptā€™s this is bound in an unexpected way.

Workarounding unexpected callback scope is one of the main situations where developers write var self = this.

Letā€™s assume a piece of code with a callback function.

function Requester(data, req) {
+  this.data = data;
+
+  req.done(function () {
+    console.log(this.data); // undefined
+  });
+}
+

Youā€™d expect this.data to be the data argument. Yet, JavaScript tells you that it is actually undefined.

So, because Stack Overflow says so, you do the following:

function Requester(data, req) {
+  this.data = data;
+  var self = this; // NOOOOOoOooo
+
+  req.done(function () {
+    console.log(self.data);
+  });
+}
+

And never stops doing it in your life.

Still do it? Iā€™m flattered to tell you that you donā€™t need that extra variable anymore.

Arrow functions

Go with arrow functions instead. Besides having a shorter syntax, arrow functions bind to the parent scope by default.

The scope that was firstly intuitive to you will work as expected now.

function Requester(data, req) {
+  this.data = data;
+
+  req.done(() => {
+    console.log(this.data); // intuitive as hell!
+  });
+}
+

You can count on them most of the time, but they also have unexpected behaviour in more advanced cases. After all, you're dealing with the `this` keyword. So don't just go around refactoring all anonymous functions into arrow ones and expecting everything to work.

You may also .bind()!

If for some reason (such as no support for IE) you canā€™t use them, check JavaScriptā€™s bind. Itā€™s not as awesome as arrow functions, but does the job.

function Requester(data, req) {
+  this.data = data;
+
+  req.done(
+    function () {
+      console.log(this.data);
+    }.bind(this)
+  );
+}
+
\ No newline at end of file diff --git a/blog/we-misunderstand-learning/index.html b/blog/we-misunderstand-learning/index.html new file mode 100644 index 0000000..c39d460 --- /dev/null +++ b/blog/we-misunderstand-learning/index.html @@ -0,0 +1 @@ +We Misunderstand Learning | DiƩssica Gurskas
diessi.caBlogMisc
September 19, 2024

We Misunderstand Learning

We misunderstand learning. We think learning happens as we consume information, so we insist on consumption, hoping it will make sense. Reading sparks new ideasā€”yet often we merely seek out validation for the ones we already have. We misunderstand learning. We cling to theory like a lifeline, as though it can stand on its own, while overlooking the experimental space where it transforms: practice. Perhaps we gamify it. (Unlearning our addictions is another matter entirely.) We escape the confusion that must lingerā€“it slips us that lingering isnā€™t forever. We misunderstand learning. Through edutainment, we satisfy the illusion of smooth progress, estimated reading times, chapter after chapter. True learning is too disjointed, unpredictable, and fraught with setbacks. We obsess over minimising gaps between repetitions, but are these gaps learning breaks, or learning itself? I recall the first time I picked up a guitar: my fingers aching to stretch, shredding like crazy against the strings. The morning after, I played the chordā€”not through conscious effort or passion, but because my fingers developed dexterity and calluses overnight. We misunderstand learning. Technique matters, yes, but some processes of embedding patterns are handled by our bodies in their own time. Others always seem to have it easier, so we feel ashamed. I wonā€™t lieā€“some do have it easier. But most often we donā€™t know, we werenā€™t there to see behind the ease, and nobodyā€™s quite vulnerable these days.

We misunderstand learning, but once, we were in intimate touch with it. Back when we hadnā€™t yet been subjected to environments of comparison, deadlines, narrow molds, and had our complexities and neuro-diversities amassed into pure functions. Iā€™m still not immune to this. At times, learning as an adult feels like a endless chase of the instinctive dance of curiosity it once was. Throw at it: Pomodoro timers, habit trackers and productivity hacks. Yet, itā€™s only when I sit down to an unmysterious learning practice and truly welcome confusion, chaos, and seeming non-productivity that I feel like I can dance with curiosity again, and learn.

\ No newline at end of file diff --git a/blog/working-better-with-git-for-a-clear-history/index.html b/blog/working-better-with-git-for-a-clear-history/index.html new file mode 100644 index 0000000..4f060f1 --- /dev/null +++ b/blog/working-better-with-git-for-a-clear-history/index.html @@ -0,0 +1,69 @@ +Working Better with Git for a Clear History | DiƩssica Gurskas
diessi.caBlogMisc
August 04, 2018

Working Better with Git for a Clear History

Your teammate worked on a few improvements in all forms of the companyā€™s website. At some point you, also a programmer, are asked for a code review.

This is the feature branchā€™s commit history you get in the Pull Request:

[290xx26] Resolve merge conflicts
+[9efxxf2] Refactor event listener for form fields
+[5d9xx5a] Update snapshots
+[948xxfa] Update dispatch event
+[f5xxea1] WIP
+[f8xxaae] Revert change
+[49xxf55e] Revert changes
+[02xxdf1] Update snapshots
+[21xx329] Pass down prop
+[28xxa865] Fix onChange event and add minimal design  in form
+[cfxx37c] U[date snapshots
+[cfxx36c] Update form to handle onChange event for autofill
+[242xx25] Fix another bug with onChange
+[f7xx738] Update form component
+[09xx868] Update snapshots
+

It seems like a lot, when actually those improvements are simply 1) fixing a bug with event handling and 2) introducing a minimal style to them. It just that it takes time to visualise that.

Indeed, committing often to a branch is a good practice1 and commits are supposed to be low-level rather than huge. However, a commit is applicable when you have a meaningful, self-contained batch of work to log to the history ā€“Ā and updating Jest snapshots is not it.

How about the following history?

[9efxxf2] Refactor event listener for form fields
+[cfxx37c] Add minimal design in form
+[cfxx36c] Update form to handle onChange event for autofill
+

That history communicates in a clear way what in the codebase has been changed in order to get the improvements done. If you want to know how itā€™s changed, itā€™s just a matter of checking out a particular commit.

Why a clear history matters

Apart from facilitating code reviews, since reviewers could grasp the context of the changes right at the first glimpse, a clear Git history is healthy for the project.

When commits started to reflect oneā€™s workflow rather than the work done itself, the history turns into a mess of both meaningful and meaningless logs, hard to navigate through and undo changes (since commits are ā€œcheckpointsā€ of work). Itā€™s highly likely that, as time goes by, developers will stop caring about the source code history as the powerful resource it is.

*The final Git history should reflect your work not the way you worked.

You begin to lose the benefit of source code management with a messy history, which was supposed to reflect how the codebase evolved over time.

A better relationship with Git

There are very common comprehensible reasons ā€“ yet not excuses at all! ā€“ for developers to unnecessarily commit. I can think of:

  1. ā€œI had to update snapshots/fix unit test/code formatting/a typo in something I introduced.ā€
  2. ā€œI had to merge master.ā€
  3. ā€œI wanted to save my work.ā€
  4. ā€œI donā€™t necessarily follow a clear flow ā€“ I am productive when I work in iterative way and usually do a lot of things at once.ā€

They can all be worked out by developing a better relationship with Git itself. That might take a while at first, but when itā€™s part of your daily workflow, you barely think about it at all. (I promise!)

First, letā€™s talk Git rebasing

Git rebase is a very powerful tool to reorganise your commits. It does a lot, so I wonā€™t get deep into it.

The command git rebase has an important tool you should get comfortable with: interactive rebase. Letā€™s say we want to reorganise the latest 3 commits:

git rebase --interactive HEAD~3
+

HEAD points to the current branch in your Git repository. You can use @ as an alias as well: @~3, or the commit hash.

Interactive rebase will provide you a text interface with the list of the commits (in this case, within the range HEAD~3..HEAD) that are about to be rebased and actions you can apply to them:

pick [242xx25] Fix another bug with onChange
+pick [f7xx738] Update form component
+pick [09xx868] Update snapshots
+
+# Rebase 242xx25..09xx868 onto 242xx25
+#
+# Commands:
+#  p, pick = use commit
+#  r, reword = use commit, but edit the commit message
+#  e, edit = use commit, but stop for amending
+#  s, squash = use commit, but meld into previous commit
+#  f, fixup = like "squash", but discard this commit's log message
+#  x, exec = run command (the rest of the line) using shell
+#
+# These lines can be re-ordered; they are executed from top to bottom.
+#
+# If you remove a line here THAT COMMIT WILL BE LOST.
+#
+# However, if you remove everything, the rebase will be aborted.
+#
+# Note that empty commits are commented out
+

pick just means that commit is included. It's the default.

Editing that file (either by applying actions to commits or reordering them) and closing it will reapply those commits to the branch. Weā€™ll explore some scenarios where that is useful.

Rebase instead of merge

The branch that you branched from has been updated (letā€™s call it master), so you need to fetch latest changes and merge that into yours with git pull. Instead of merging and introducing an ugly new commit for that, you can rebase and pretend that nothing ever happened in the first place.

git pull origin master --rebase
+

"Why isn't that the default then?", you might ask. I'd guess they didn't want to make a feature that rewrites history part of the default behaviour.

Squash commits when you can

You need to fix a typo, update a test, or include anything else that should have actually been part of a commit previously introduced. You can create a new commit and later squash it to the initial one with rebase.

git commit -m "Update contact form tests"
+git rebase -i HEAD~2 # act on top of latest 2 commits
+

Interactive rebase will show up, and you can mark that ā€œUpdate contact form testsā€ as the commit to be squashed into a previous one by changing pick to s (squash).

The squashed commit has to come exactly before the commit you want to squash into, so you might have to some reordering.

Fix up and save time

Using the --fixup flag along with the commit hash of the previous commit will mark a commit as a fix of an existing one. Then, when you rebase with --autosquash, they willā€¦ well, automatically get squashed.

Letā€™s say we have fixed a typo in the commit i2r923:

git commit --fixup i2r923
+git rebase --autosquash 9ef00f2  # one commit before above
+

You can configure Git to use the --autosquash flag by default when rebasing. I do that so you can check my dotfiles if you're curious.

Quite often, youā€™ll know how far youā€™re traveling from the current commit (HEAD). Instead of specifying hashes, you can just use HEAD as a reference to previous commits:

git commit --fixup HEAD            # fix 1 commit before HEAD
+git rebase --autosquash -i HEAD~1  # squash latest 2 commits
+

Stash to save your work in progress

You want to check or change other branchā€™s files, but donā€™t want to commit unfinished work either. You can stash your work in progress (ā€œWIPā€):

git stash
+

That stores everything from your working directory into stash. Itā€™s so useful in my day-to-day work that I honestly often cry using it.

On how to get your work back, name your WIPs, or stash specific files, refer to the docs on Git staging. No way I am better at explaining than the documentation itself!

Commit selected chunks of your work

Remember the ā€œI work in a very messy way, iterating between featuresā€ excuse? This helps. (It helped me yesterday when I refactored and introduced something new to it ā€“ should not be done altogether!Ā ā€“Ā  at the same time without noticing.)

Besides only adding a specific file to your commit with git add, you may want to add only a chunk of the fileā€™s code to a commit. That can be achieved with the --patch flag:

git add --patch
+

Thatā€™s another interface youā€™ll have to get comfortable with. You can also try out its --interactive option.

Using VS Code?

VS Code has a powerful built-in Git editor that allows you to add chunks of code to a commit. To stage specific lines to commit later, open VS Codeā€™s Git editor, select the lines of code you feel should go into a commit, and ā€œStage selected changesā€ by right-clicking on it.

Showing how to use 'Stage Selected Changes' in VS Code
Changed the whole thing but want to commit only a chunk of it? VS Code has got you covered.

The Command Palette also has a ā€œGit: Stage selected changesā€ option.

Rename commit messages for meaning

You had a look at the final history and found out your commit messages need some love. To change your latest commit (HEAD), you can just do git commit --amend; for other commits, youā€™ll have to rebase.

Letā€™s say you want to fix the latest 5 commits:

git rebase -i @~5
+

That will open up the interactive rebase youā€™re already familiar with. Find the commit you want, change pick to e (edit), and save and close the file; after Git rewinds to that commit, edit its message with git commit --amend, and run git rebase --continue when youā€™re done.

Got a clear history? Push it!

Commit Often, Perfect Later, Publish Once.1

Make sure that your branch has got a clear, readable and meaningful historyā€¦

git log --oneline
+

Then push it into the remote repository!

git push origin head
+

If you have already pushed (Y THO???!), you can (carefully) use the force option (-f) to rewrite the remote history.

Extra: Fixing the first history

Remember the first history? We can fix it. Itā€™s definitely harder to change it after itā€™s done, but totally doable with rebase -i. A possible solution would be:

squash [290xx26] Resolve merge conflicts
+pick [9efxxf2] Refactor event listener for form fields
+squash [5d9xx5a] Update snapshots
+squash [948xxfa] Update dispatch event
+delete [f5xxea1] WIP
+delete [f8xxaae] Revert change
+delete [49xxf55e] Revert changes
+squash [02xxdf1] Update snapshots
+squash [21xx329] Pass down prop
+pick [28xxa865] Fix onChange event and add minimal design  in form
+squash [cfxx37c] U[date snapshots
+pick [cfxx36c] Update form to handle onChange event for autofill
+fixup [242xx25] Fix another bug with onChange
+squash [f7xx738] Update form component
+squash [09xx868] Update snapshots
+

Be mindful about your decisions and make sure you are not losing work along the way. I deleted commits unused commits (WIP then reverted), squashed ā€œfixā€ and ā€œupdate testsā€ commits, and then picked only those that are meaningful batches of work.

I could have also split Fix onChange event and add minimal design in form into two separate commitsā€¦ But thatā€™s for a future post.

Final considerations

Nowadays, I can say for sure that Git helps me to work better. Those techniques youā€™ve learned are all part of my daily workflow.

There is always something I donā€™t know about Git though, so I keep exploring. I recommend you do to do the same, and you can start right from your command line:

git help -w reset
+

Finally, if somehow you donā€™t feel comfortable with moving around your work from the command line, Iā€™d recommend Git GUI clients2 ā€“ they are powerful and simplify visualising branches and its commits, especially when it gets tough3.

I hope you have better, more sane, work days after that!

2

Some clients I can think of: GitHubā€™s Git client (free), Git Kraken (free), Git Tower (paid).

3

It will get tough, because source code management is not easy. Anyhow, itā€™s always tougher when you care about things anyway. Easiest thing is not to care about anything at all.

\ No newline at end of file diff --git a/blog/writing-mode-in-vs-code/index.html b/blog/writing-mode-in-vs-code/index.html new file mode 100644 index 0000000..341c35e --- /dev/null +++ b/blog/writing-mode-in-vs-code/index.html @@ -0,0 +1,28 @@ +Writing Mode in VS Code | DiƩssica Gurskas
diessi.caBlogMisc
February 28, 2018

Writing Mode in VS Code

Iā€™m a big fan of writing. Iā€™m also a big fan of using my code editor and Markdown for that!

Screenshot of the VS Code in the zen mode without any clutter
My "writing mode" in VS Code, with the dark theme enabled.

Code editors are usually packed with a bunch of useful features, such as multi-selection, syntax highlighting, a file tree easy to operate, and sometimes even Markdown supportĀ ā€“ which I need for writing my articles, notes, to-do lists, and absolutely everything I can write using Markdown. I love having a consistent workflow and thatā€™s crucial to me, so why not?

After configuring my editor of choice, VS Code, to get rid of the coding mode clutter (and also after an important update on its zen mode ā¤ļø), Iā€™ve finally achieved a totally distraction-free writing experience!

Setting up the ā€œWriting Modeā€

1. User Settings

There are some important details to achieve total focus on writing. No line numbers, word wrap enabled, comfortable line height, no rulers, are some of them.

Since I only write in Markdown, I only set up those settings (and other tweaks) specifically for that language.

// github.com/diessica/dotfiles/blob/master/vscode/settings.json
+{
+  ....
+
+  "[markdown]": {
+    // force centering in zen mode
+    "zenMode.centerLayout": true,
+    // use the beautiful duospace font when available
+    "editor.fontFamily": "iA Writer Duospace, monospace",
+    // enable word wrap, since horizontal scroll while writing isn't human
+    "editor.wordWrap": true,
+    // i don't need line numbers, i'm not coding
+    "editor.lineNumbers": "off",
+    // light by default, but can be easily toggled to dark
+    "workbench.colorTheme": "Default Light+",
+    // i don't need rules, i'm not coding
+    "editor.rulers": [],
+    // larger text, to improve focus on writing
+    "editor.fontSize": 14,
+    // more comfortable line height
+    "editor.lineHeight": 25,
+    // disable editor suggestions based on previous words
+    "editor.quickSuggestions": false,
+  },
+
+  ...
+}
+

You can learn more about this file by checking the docs on "User and Workspace Settings".

Now, toggle zen mode in VS Code (see Keybindings, or View > Toggle Zen Mode) and check if that fits you!

2. Theme

Honestly, I think the default themes provided by VS Code do a great job. I use Dark+ as the dark theme; for light themes, either Quiet Light or Solarized Light.

If you don't like them, feel free to pick anything else, since most themes provide sufficient Markdown support anyway. Just don't procrastinate ā€“ a good theme won't make you a better writer.

3. Font

My font of choice for writing is the Duospace, designed by the people behind the text editor iaWriter. Itā€™s a free and beautiful font shaped for the perfect writing experience.

4. Extensions

Extra tips

  • VS Codeā€™s Markdown Preview is your friend ā€“Ā use it when youā€™re done with writing!
  • Configure the spell checker for your language, there are dictionary extensions for that available in the marketplace. I also have the Brazilian Portuguese package installed, for instance.
  • Like extensions? Keep exploring! The extension alex, for instance, catches insensitive, inconsiderate writing in texts.
  • Learn the Markdown keybindings provided by the All in One extension for a better workflow.

Happy writing! šŸŒŸ

\ No newline at end of file diff --git a/css/style.css b/css/style.css new file mode 100644 index 0000000..adacc3c --- /dev/null +++ b/css/style.css @@ -0,0 +1 @@ +/*! tailwindcss v3.2.4 | MIT License | https://tailwindcss.com*/*,:after,:before{border:0 solid #e5e7eb;box-sizing:border-box}:after,:before{--tw-content:""}html{-webkit-text-size-adjust:100%;font-feature-settings:normal;font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4}body{line-height:inherit;margin:0}hr{border-top-width:1px;color:inherit;height:0}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:JetBrains Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{border-collapse:collapse;border-color:inherit;text-indent:0}button,input,optgroup,select,textarea{color:inherit;font-family:inherit;font-size:100%;font-weight:inherit;line-height:inherit;margin:0;padding:0}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{color:#9ca3af;opacity:1}input::placeholder,textarea::placeholder{color:#9ca3af;opacity:1}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{height:auto;max-width:100%}[hidden]{display:none}*,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }.container{width:100%}@media (min-width:640px){.container{max-width:640px}}@media (min-width:768px){.container{max-width:768px}}@media (min-width:1024px){.container{max-width:1024px}}@media (min-width:1280px){.container{max-width:1280px}}@media (min-width:1536px){.container{max-width:1536px}}.prose{color:var(--tw-prose-body);max-width:65ch}.prose :where([class~=lead]):not(:where([class~=not-prose] *)){color:var(--tw-prose-lead);font-size:1.25em;line-height:1.6;margin-bottom:1.2em;margin-top:1.2em}.prose :where(a):not(:where([class~=not-prose] *)){color:var(--tw-prose-links);font-weight:500;text-decoration:underline}.prose :where(strong):not(:where([class~=not-prose] *)){color:var(--tw-prose-bold);font-weight:600}.prose :where(a strong):not(:where([class~=not-prose] *)){color:inherit}.prose :where(blockquote strong):not(:where([class~=not-prose] *)){color:inherit}.prose :where(thead th strong):not(:where([class~=not-prose] *)){color:inherit}.prose :where(ol):not(:where([class~=not-prose] *)){list-style-type:decimal;margin-bottom:1.25em;margin-top:1.25em;padding-left:1.625em}.prose :where(ol[type=A]):not(:where([class~=not-prose] *)){list-style-type:upper-alpha}.prose :where(ol[type=a]):not(:where([class~=not-prose] *)){list-style-type:lower-alpha}.prose :where(ol[type=A s]):not(:where([class~=not-prose] *)){list-style-type:upper-alpha}.prose :where(ol[type=a s]):not(:where([class~=not-prose] *)){list-style-type:lower-alpha}.prose :where(ol[type=I]):not(:where([class~=not-prose] *)){list-style-type:upper-roman}.prose :where(ol[type=i]):not(:where([class~=not-prose] *)){list-style-type:lower-roman}.prose :where(ol[type=I s]):not(:where([class~=not-prose] *)){list-style-type:upper-roman}.prose :where(ol[type=i s]):not(:where([class~=not-prose] *)){list-style-type:lower-roman}.prose :where(ol[type="1"]):not(:where([class~=not-prose] *)){list-style-type:decimal}.prose :where(ul):not(:where([class~=not-prose] *)){list-style-type:disc;margin-bottom:1.25em;margin-top:1.25em;padding-left:1.625em}.prose :where(ol>li):not(:where([class~=not-prose] *))::marker{color:var(--tw-prose-counters);font-weight:400}.prose :where(ul>li):not(:where([class~=not-prose] *))::marker{color:var(--tw-prose-bullets)}.prose :where(hr):not(:where([class~=not-prose] *)){border-color:var(--tw-prose-hr);border-top-width:1px;margin-bottom:3em;margin-top:3em}.prose :where(blockquote):not(:where([class~=not-prose] *)){border-left-color:var(--tw-prose-quote-borders);border-left-width:.25rem;color:var(--tw-prose-quotes);font-style:italic;font-weight:500;margin-bottom:1.6em;margin-top:1.6em;padding-left:1em;quotes:"\201C""\201D""\2018""\2019"}.prose :where(blockquote p:first-of-type):not(:where([class~=not-prose] *)):before{content:open-quote}.prose :where(blockquote p:last-of-type):not(:where([class~=not-prose] *)):after{content:close-quote}.prose :where(h1):not(:where([class~=not-prose] *)){color:var(--tw-prose-headings);font-size:2.25em;font-weight:800;line-height:1.1111111;margin-bottom:.8888889em;margin-top:0}.prose :where(h1 strong):not(:where([class~=not-prose] *)){color:inherit;font-weight:900}.prose :where(h2):not(:where([class~=not-prose] *)){color:var(--tw-prose-headings);font-size:1.5em;font-weight:700;line-height:1.3333333;margin-bottom:1em;margin-top:2em}.prose :where(h2 strong):not(:where([class~=not-prose] *)){color:inherit;font-weight:800}.prose :where(h3):not(:where([class~=not-prose] *)){color:var(--tw-prose-headings);font-size:1.25em;font-weight:600;line-height:1.6;margin-bottom:.6em;margin-top:1.6em}.prose :where(h3 strong):not(:where([class~=not-prose] *)){color:inherit;font-weight:700}.prose :where(h4):not(:where([class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;line-height:1.5;margin-bottom:.5em;margin-top:1.5em}.prose :where(h4 strong):not(:where([class~=not-prose] *)){color:inherit;font-weight:700}.prose :where(img):not(:where([class~=not-prose] *)){margin-bottom:2em;margin-top:2em}.prose :where(figure>*):not(:where([class~=not-prose] *)){margin-bottom:0;margin-top:0}.prose :where(figcaption):not(:where([class~=not-prose] *)){color:var(--tw-prose-captions);font-size:.875em;line-height:1.4285714;margin-top:.8571429em}.prose :where(code):not(:where([class~=not-prose] *)){color:var(--tw-prose-code);font-size:.875em;font-weight:600}.prose :where(code):not(:where([class~=not-prose] *)):before{content:"`"}.prose :where(code):not(:where([class~=not-prose] *)):after{content:"`"}.prose :where(a code):not(:where([class~=not-prose] *)){color:inherit}.prose :where(h1 code):not(:where([class~=not-prose] *)){color:inherit}.prose :where(h2 code):not(:where([class~=not-prose] *)){color:inherit;font-size:.875em}.prose :where(h3 code):not(:where([class~=not-prose] *)){color:inherit;font-size:.9em}.prose :where(h4 code):not(:where([class~=not-prose] *)){color:inherit}.prose :where(blockquote code):not(:where([class~=not-prose] *)){color:inherit}.prose :where(thead th code):not(:where([class~=not-prose] *)){color:inherit}.prose :where(pre):not(:where([class~=not-prose] *)){background-color:var(--tw-prose-pre-bg);border-radius:.375rem;color:var(--tw-prose-pre-code);font-size:.875em;font-weight:400;line-height:1.7142857;margin-bottom:1.7142857em;margin-top:1.7142857em;overflow-x:auto;padding:.8571429em 1.1428571em}.prose :where(pre code):not(:where([class~=not-prose] *)){background-color:transparent;border-radius:0;border-width:0;color:inherit;font-family:inherit;font-size:inherit;font-weight:inherit;line-height:inherit;padding:0}.prose :where(pre code):not(:where([class~=not-prose] *)):before{content:none}.prose :where(pre code):not(:where([class~=not-prose] *)):after{content:none}.prose :where(table):not(:where([class~=not-prose] *)){font-size:.875em;line-height:1.7142857;margin-bottom:2em;margin-top:2em;table-layout:auto;text-align:left;width:100%}.prose :where(thead):not(:where([class~=not-prose] *)){border-bottom-color:var(--tw-prose-th-borders);border-bottom-width:1px}.prose :where(thead th):not(:where([class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;padding-bottom:.5714286em;padding-left:.5714286em;padding-right:.5714286em;vertical-align:bottom}.prose :where(tbody tr):not(:where([class~=not-prose] *)){border-bottom-color:var(--tw-prose-td-borders);border-bottom-width:1px}.prose :where(tbody tr:last-child):not(:where([class~=not-prose] *)){border-bottom-width:0}.prose :where(tbody td):not(:where([class~=not-prose] *)){vertical-align:baseline}.prose :where(tfoot):not(:where([class~=not-prose] *)){border-top-color:var(--tw-prose-th-borders);border-top-width:1px}.prose :where(tfoot td):not(:where([class~=not-prose] *)){vertical-align:top}.prose{--tw-prose-body:#374151;--tw-prose-headings:#111827;--tw-prose-lead:#4b5563;--tw-prose-links:#111827;--tw-prose-bold:#111827;--tw-prose-counters:#6b7280;--tw-prose-bullets:#d1d5db;--tw-prose-hr:#e5e7eb;--tw-prose-quotes:#111827;--tw-prose-quote-borders:#e5e7eb;--tw-prose-captions:#6b7280;--tw-prose-code:#111827;--tw-prose-pre-code:#e5e7eb;--tw-prose-pre-bg:#1f2937;--tw-prose-th-borders:#d1d5db;--tw-prose-td-borders:#e5e7eb;--tw-prose-invert-body:#d1d5db;--tw-prose-invert-headings:#fff;--tw-prose-invert-lead:#9ca3af;--tw-prose-invert-links:#fff;--tw-prose-invert-bold:#fff;--tw-prose-invert-counters:#9ca3af;--tw-prose-invert-bullets:#4b5563;--tw-prose-invert-hr:#374151;--tw-prose-invert-quotes:#f3f4f6;--tw-prose-invert-quote-borders:#374151;--tw-prose-invert-captions:#9ca3af;--tw-prose-invert-code:#fff;--tw-prose-invert-pre-code:#d1d5db;--tw-prose-invert-pre-bg:rgba(0,0,0,.5);--tw-prose-invert-th-borders:#4b5563;--tw-prose-invert-td-borders:#374151;font-size:1rem;line-height:1.75}.prose :where(p):not(:where([class~=not-prose] *)){margin-bottom:1.25em;margin-top:1.25em}.prose :where(video):not(:where([class~=not-prose] *)){margin-bottom:2em;margin-top:2em}.prose :where(figure):not(:where([class~=not-prose] *)){margin-bottom:2em;margin-top:2em}.prose :where(li):not(:where([class~=not-prose] *)){margin-bottom:.5em;margin-top:.5em}.prose :where(ol>li):not(:where([class~=not-prose] *)){padding-left:.375em}.prose :where(ul>li):not(:where([class~=not-prose] *)){padding-left:.375em}.prose :where(.prose>ul>li p):not(:where([class~=not-prose] *)){margin-bottom:.75em;margin-top:.75em}.prose :where(.prose>ul>li>:first-child):not(:where([class~=not-prose] *)){margin-top:1.25em}.prose :where(.prose>ul>li>:last-child):not(:where([class~=not-prose] *)){margin-bottom:1.25em}.prose :where(.prose>ol>li>:first-child):not(:where([class~=not-prose] *)){margin-top:1.25em}.prose :where(.prose>ol>li>:last-child):not(:where([class~=not-prose] *)){margin-bottom:1.25em}.prose :where(ul ul,ul ol,ol ul,ol ol):not(:where([class~=not-prose] *)){margin-bottom:.75em;margin-top:.75em}.prose :where(hr+*):not(:where([class~=not-prose] *)){margin-top:0}.prose :where(h2+*):not(:where([class~=not-prose] *)){margin-top:0}.prose :where(h3+*):not(:where([class~=not-prose] *)){margin-top:0}.prose :where(h4+*):not(:where([class~=not-prose] *)){margin-top:0}.prose :where(thead th:first-child):not(:where([class~=not-prose] *)){padding-left:0}.prose :where(thead th:last-child):not(:where([class~=not-prose] *)){padding-right:0}.prose :where(tbody td,tfoot td):not(:where([class~=not-prose] *)){padding:.5714286em}.prose :where(tbody td:first-child,tfoot td:first-child):not(:where([class~=not-prose] *)){padding-left:0}.prose :where(tbody td:last-child,tfoot td:last-child):not(:where([class~=not-prose] *)){padding-right:0}.prose :where(.prose>:first-child):not(:where([class~=not-prose] *)){margin-top:0}.prose :where(.prose>:last-child):not(:where([class~=not-prose] *)){margin-bottom:0}.prose-sm{font-size:.875rem;line-height:1.7142857}.prose-sm :where(p):not(:where([class~=not-prose] *)){margin-bottom:1.1428571em;margin-top:1.1428571em}.prose-sm :where([class~=lead]):not(:where([class~=not-prose] *)){font-size:1.2857143em;line-height:1.5555556;margin-bottom:.8888889em;margin-top:.8888889em}.prose-sm :where(blockquote):not(:where([class~=not-prose] *)){margin-bottom:1.3333333em;margin-top:1.3333333em;padding-left:1.1111111em}.prose-sm :where(h1):not(:where([class~=not-prose] *)){font-size:2.1428571em;line-height:1.2;margin-bottom:.8em;margin-top:0}.prose-sm :where(h2):not(:where([class~=not-prose] *)){font-size:1.4285714em;line-height:1.4;margin-bottom:.8em;margin-top:1.6em}.prose-sm :where(h3):not(:where([class~=not-prose] *)){font-size:1.2857143em;line-height:1.5555556;margin-bottom:.4444444em;margin-top:1.5555556em}.prose-sm :where(h4):not(:where([class~=not-prose] *)){line-height:1.4285714;margin-bottom:.5714286em;margin-top:1.4285714em}.prose-sm :where(img):not(:where([class~=not-prose] *)){margin-bottom:1.7142857em;margin-top:1.7142857em}.prose-sm :where(video):not(:where([class~=not-prose] *)){margin-bottom:1.7142857em;margin-top:1.7142857em}.prose-sm :where(figure):not(:where([class~=not-prose] *)){margin-bottom:1.7142857em;margin-top:1.7142857em}.prose-sm :where(figure>*):not(:where([class~=not-prose] *)){margin-bottom:0;margin-top:0}.prose-sm :where(figcaption):not(:where([class~=not-prose] *)){font-size:.8571429em;line-height:1.3333333;margin-top:.6666667em}.prose-sm :where(code):not(:where([class~=not-prose] *)){font-size:.8571429em}.prose-sm :where(h2 code):not(:where([class~=not-prose] *)){font-size:.9em}.prose-sm :where(h3 code):not(:where([class~=not-prose] *)){font-size:.8888889em}.prose-sm :where(pre):not(:where([class~=not-prose] *)){border-radius:.25rem;font-size:.8571429em;line-height:1.6666667;margin-bottom:1.6666667em;margin-top:1.6666667em;padding:.6666667em 1em}.prose-sm :where(ol):not(:where([class~=not-prose] *)){margin-bottom:1.1428571em;margin-top:1.1428571em;padding-left:1.5714286em}.prose-sm :where(ul):not(:where([class~=not-prose] *)){margin-bottom:1.1428571em;margin-top:1.1428571em;padding-left:1.5714286em}.prose-sm :where(li):not(:where([class~=not-prose] *)){margin-bottom:.2857143em;margin-top:.2857143em}.prose-sm :where(ol>li):not(:where([class~=not-prose] *)){padding-left:.4285714em}.prose-sm :where(ul>li):not(:where([class~=not-prose] *)){padding-left:.4285714em}.prose-sm :where(.prose-sm>ul>li p):not(:where([class~=not-prose] *)){margin-bottom:.5714286em;margin-top:.5714286em}.prose-sm :where(.prose-sm>ul>li>:first-child):not(:where([class~=not-prose] *)){margin-top:1.1428571em}.prose-sm :where(.prose-sm>ul>li>:last-child):not(:where([class~=not-prose] *)){margin-bottom:1.1428571em}.prose-sm :where(.prose-sm>ol>li>:first-child):not(:where([class~=not-prose] *)){margin-top:1.1428571em}.prose-sm :where(.prose-sm>ol>li>:last-child):not(:where([class~=not-prose] *)){margin-bottom:1.1428571em}.prose-sm :where(ul ul,ul ol,ol ul,ol ol):not(:where([class~=not-prose] *)){margin-bottom:.5714286em;margin-top:.5714286em}.prose-sm :where(hr):not(:where([class~=not-prose] *)){margin-bottom:2.8571429em;margin-top:2.8571429em}.prose-sm :where(hr+*):not(:where([class~=not-prose] *)){margin-top:0}.prose-sm :where(h2+*):not(:where([class~=not-prose] *)){margin-top:0}.prose-sm :where(h3+*):not(:where([class~=not-prose] *)){margin-top:0}.prose-sm :where(h4+*):not(:where([class~=not-prose] *)){margin-top:0}.prose-sm :where(table):not(:where([class~=not-prose] *)){font-size:.8571429em;line-height:1.5}.prose-sm :where(thead th):not(:where([class~=not-prose] *)){padding-bottom:.6666667em;padding-left:1em;padding-right:1em}.prose-sm :where(thead th:first-child):not(:where([class~=not-prose] *)){padding-left:0}.prose-sm :where(thead th:last-child):not(:where([class~=not-prose] *)){padding-right:0}.prose-sm :where(tbody td,tfoot td):not(:where([class~=not-prose] *)){padding:.6666667em 1em}.prose-sm :where(tbody td:first-child,tfoot td:first-child):not(:where([class~=not-prose] *)){padding-left:0}.prose-sm :where(tbody td:last-child,tfoot td:last-child):not(:where([class~=not-prose] *)){padding-right:0}.prose-sm :where(.prose-sm>:first-child):not(:where([class~=not-prose] *)){margin-top:0}.prose-sm :where(.prose-sm>:last-child):not(:where([class~=not-prose] *)){margin-bottom:0}.visible{visibility:visible}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.right-0{right:0}.top-0{top:0}.z-10{z-index:10}.z-20{z-index:20}.mx-auto{margin-left:auto;margin-right:auto}.my-8{margin-bottom:2rem;margin-top:2rem}.my-12{margin-bottom:3rem;margin-top:3rem}.mb-2{margin-bottom:.5rem}.mb-8{margin-bottom:2rem}.mb-5{margin-bottom:1.25rem}.mb-10{margin-bottom:2.5rem}.mb-1{margin-bottom:.25rem}.mb-4{margin-bottom:1rem}.mb-3{margin-bottom:.75rem}.mr-1\.5{margin-right:.375rem}.mr-1{margin-right:.25rem}.mr-3{margin-right:.75rem}.ml-2{margin-left:.5rem}.block{display:block}.inline{display:inline}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.contents{display:contents}.hidden{display:none}.min-h-\[calc\(100vh-16px\)\]{min-height:calc(100vh - 16px)}.min-h-screen{min-height:100vh}.w-full{width:100%}.w-auto{width:auto}.w-max{width:-moz-max-content;width:max-content}.grow{flex-grow:1}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.justify-between{justify-content:space-between}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(.5rem*var(--tw-space-y-reverse));margin-top:calc(.5rem*(1 - var(--tw-space-y-reverse)))}.space-x-8>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-left:calc(2rem*(1 - var(--tw-space-x-reverse)));margin-right:calc(2rem*var(--tw-space-x-reverse))}.space-x-4>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-left:calc(1rem*(1 - var(--tw-space-x-reverse)));margin-right:calc(1rem*var(--tw-space-x-reverse))}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(1rem*var(--tw-space-y-reverse));margin-top:calc(1rem*(1 - var(--tw-space-y-reverse)))}.self-center{align-self:center}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.scroll-smooth{scroll-behavior:smooth}.whitespace-nowrap{white-space:nowrap}.rounded-xl{border-radius:.75rem}.rounded{border-radius:.25rem}.border-b-2{border-bottom-width:2px}.border-green{--tw-border-opacity:1;border-color:rgb(105 255 0/var(--tw-border-opacity))}.bg-index{--tw-bg-opacity:1;background-color:rgb(21 7 25/var(--tw-bg-opacity))}.bg-blog{--tw-bg-opacity:1;background-color:rgb(255 237 254/var(--tw-bg-opacity))}.bg-green{--tw-bg-opacity:1;background-color:rgb(105 255 0/var(--tw-bg-opacity))}.bg-amber-100{--tw-bg-opacity:1;background-color:rgb(254 243 199/var(--tw-bg-opacity))}.p-40{padding:10rem}.p-2{padding:.5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.py-8{padding-bottom:2rem;padding-top:2rem}.py-10{padding-bottom:2.5rem;padding-top:2.5rem}.py-12{padding-bottom:3rem;padding-top:3rem}.px-2{padding-left:.5rem;padding-right:.5rem}.py-1\.5{padding-bottom:.375rem;padding-top:.375rem}.py-1{padding-bottom:.25rem;padding-top:.25rem}.pr-10{padding-right:2.5rem}.pb-1\.5{padding-bottom:.375rem}.pb-1{padding-bottom:.25rem}.pb-8{padding-bottom:2rem}.pt-1{padding-top:.25rem}.text-center{text-align:center}.font-body,.font-display{font-family:JetBrains Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.text-2xl{font-size:1.5rem;line-height:2rem}.text-3xl{font-size:1.875rem;line-height:2.25rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.text-base{font-size:1rem;line-height:1.5rem}.text-6xl{font-size:3.75rem;line-height:1}.text-4xl{font-size:2.25rem;line-height:2.5rem}.font-extrabold{font-weight:800}.font-bold{font-weight:700}.uppercase{text-transform:uppercase}.italic{font-style:italic}.leading-loose{line-height:2}.leading-none{line-height:1}.tracking-widest{letter-spacing:.1em}.tracking-tight{letter-spacing:-.025em}.tracking-wide{letter-spacing:.025em}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.text-green{--tw-text-opacity:1;color:rgb(105 255 0/var(--tw-text-opacity))}.text-gray-700{--tw-text-opacity:1;color:rgb(55 65 81/var(--tw-text-opacity))}.text-slate-200{--tw-text-opacity:1;color:rgb(226 232 240/var(--tw-text-opacity))}.text-slate-400{--tw-text-opacity:1;color:rgb(148 163 184/var(--tw-text-opacity))}.text-slate-900{--tw-text-opacity:1;color:rgb(15 23 42/var(--tw-text-opacity))}.text-purple{--tw-text-opacity:1;color:rgb(150 0 255/var(--tw-text-opacity))}.text-slate-800{--tw-text-opacity:1;color:rgb(30 41 59/var(--tw-text-opacity))}.no-underline{text-decoration-line:none}.antialiased{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.opacity-50{opacity:.5}.opacity-60{opacity:.6}.opacity-30{opacity:.3}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.transition{transition-duration:.15s;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1)}.footnote-definition{display:block;font-size:.875rem;line-height:1.25rem;margin-bottom:.5rem}.footnote-definition p{display:inline;padding-left:.5rem;padding-right:.5rem}.footnote-definition-label{font-weight:700}body :focus{--tw-bg-opacity:1;--tw-text-opacity:1;background-color:rgb(150 0 255/var(--tw-bg-opacity));color:rgb(255 255 255/var(--tw-text-opacity));outline:2px solid transparent;outline-offset:2px}a{text-decoration-line:underline}a:hover{text-decoration-line:none}::marker{color:#9600ff!important}.note{--tw-border-opacity:1;border-color:rgb(105 255 0/var(--tw-border-opacity));border-left-width:3px;border-style:solid;color:rgb(71 85 105/var(--tw-text-opacity));font-size:.875rem;padding-left:1.25rem}.note,.summary{--tw-text-opacity:1;line-height:1.5rem}.summary{color:rgb(100 116 139/var(--tw-text-opacity));font-size:1rem;font-style:italic;margin-bottom:2.5rem;margin-top:-2rem;text-align:center}@media (min-width:1280px){.summary{margin-left:-14rem;margin-right:-14rem}}b,strong{font-weight:800}@font-face{font-display:swap;font-family:JetBrains Mono;font-style:normal;font-weight:300;src:url(/fonts/JetBrainsMono-Light.woff2) format("woff2")}@font-face{font-display:swap;font-family:JetBrains Mono;font-style:italic;font-weight:300;src:url(/fonts/JetBrainsMono-LightItalic.woff2) format("woff2")}@font-face{font-display:swap;font-family:JetBrains Mono;font-style:normal;font-weight:400;src:url(/fonts/JetBrainsMono-Regular.woff2) format("woff2")}@font-face{font-display:swap;font-family:JetBrains Mono;font-style:italic;font-weight:400;src:url(/fonts/JetBrainsMono-Italic.woff2) format("woff2")}@font-face{font-display:swap;font-family:JetBrains Mono;font-style:normal;font-weight:500;src:url(/fonts/JetBrainsMono-SemiBold.woff2) format("woff2")}@font-face{font-display:swap;font-family:JetBrains Mono;font-style:italic;font-weight:500;src:url(/fonts/JetBrainsMono-SemiBoldItalic.woff2) format("woff2")}@font-face{font-display:swap;font-family:JetBrains Mono;font-style:normal;font-weight:600;src:url(/fonts/JetBrainsMono-Bold.woff2) format("woff2")}@font-face{font-display:swap;font-family:JetBrains Mono;font-style:italic;font-weight:600;src:url(/fonts/JetBrainsMono-BoldItalic.woff2) format("woff2")}@font-face{font-display:swap;font-family:JetBrains Mono;font-style:normal;font-weight:800;src:url(/fonts/JetBrainsMono-ExtraBold.woff2) format("woff2")}@font-face{font-display:swap;font-family:JetBrains Mono;font-style:italic;font-weight:800;src:url(/fonts/JetBrainsMono-ExtraBoldItalic.woff2) format("woff2")}.hover\:border-b-2:hover{border-bottom-width:2px}.hover\:border-green:hover{--tw-border-opacity:1;border-color:rgb(105 255 0/var(--tw-border-opacity))}.hover\:text-slate-700:hover{--tw-text-opacity:1;color:rgb(51 65 85/var(--tw-text-opacity))}.hover\:text-slate-600:hover{--tw-text-opacity:1;color:rgb(71 85 105/var(--tw-text-opacity))}.prose-headings\:w-max :is(:where(h1,h2,h3,h4,h5,h6,th):not(:where([class~=not-prose] *))){width:-moz-max-content;width:max-content}.prose-headings\:font-display :is(:where(h1,h2,h3,h4,h5,h6,th):not(:where([class~=not-prose] *))){font-family:JetBrains Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.prose-headings\:font-extrabold :is(:where(h1,h2,h3,h4,h5,h6,th):not(:where([class~=not-prose] *))){font-weight:800}.prose-headings\:text-slate-800 :is(:where(h1,h2,h3,h4,h5,h6,th):not(:where([class~=not-prose] *))){--tw-text-opacity:1;color:rgb(30 41 59/var(--tw-text-opacity))}.prose-a\:text-white :is(:where(a):not(:where([class~=not-prose] *))){--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.prose-blockquote\:border-0 :is(:where(blockquote):not(:where([class~=not-prose] *))){border-width:0}.prose-blockquote\:text-center :is(:where(blockquote):not(:where([class~=not-prose] *))){text-align:center}.prose-blockquote\:text-xl :is(:where(blockquote):not(:where([class~=not-prose] *))){font-size:1.25rem;line-height:1.75rem}.prose-blockquote\:text-current :is(:where(blockquote):not(:where([class~=not-prose] *))){color:currentColor}.prose-strong\:text-white :is(:where(strong):not(:where([class~=not-prose] *))){--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.prose-pre\:rounded-none :is(:where(pre):not(:where([class~=not-prose] *))){border-radius:0}.prose-hr\:mx-auto :is(:where(hr):not(:where([class~=not-prose] *))){margin-left:auto;margin-right:auto}.prose-hr\:my-4 :is(:where(hr):not(:where([class~=not-prose] *))){margin-bottom:1rem;margin-top:1rem}.prose-hr\:h-0\.5 :is(:where(hr):not(:where([class~=not-prose] *))){height:.125rem}.prose-hr\:h-0 :is(:where(hr):not(:where([class~=not-prose] *))){height:0}.prose-hr\:w-48 :is(:where(hr):not(:where([class~=not-prose] *))){width:12rem}.prose-hr\:rounded :is(:where(hr):not(:where([class~=not-prose] *))){border-radius:.25rem}.prose-hr\:border-0 :is(:where(hr):not(:where([class~=not-prose] *))){border-width:0}.prose-hr\:bg-black :is(:where(hr):not(:where([class~=not-prose] *))){--tw-bg-opacity:1;background-color:rgb(0 0 0/var(--tw-bg-opacity))}.prose-hr\:opacity-20 :is(:where(hr):not(:where([class~=not-prose] *))){opacity:.2}@media (prefers-color-scheme:dark){.dark\:bg-indigo-900{--tw-bg-opacity:1;background-color:rgb(49 46 129/var(--tw-bg-opacity))}.dark\:text-slate-300{--tw-text-opacity:1;color:rgb(203 213 225/var(--tw-text-opacity))}.dark\:text-slate-400{--tw-text-opacity:1;color:rgb(148 163 184/var(--tw-text-opacity))}.hover\:dark\:text-slate-300:hover{--tw-text-opacity:1;color:rgb(203 213 225/var(--tw-text-opacity))}}@media (min-width:768px){.md\:prose{color:var(--tw-prose-body);max-width:65ch}.md\:prose :where([class~=lead]):not(:where([class~=not-prose] *)){color:var(--tw-prose-lead);font-size:1.25em;line-height:1.6;margin-bottom:1.2em;margin-top:1.2em}.md\:prose :where(a):not(:where([class~=not-prose] *)){color:var(--tw-prose-links);font-weight:500;text-decoration:underline}.md\:prose :where(strong):not(:where([class~=not-prose] *)){color:var(--tw-prose-bold);font-weight:600}.md\:prose :where(a strong):not(:where([class~=not-prose] *)){color:inherit}.md\:prose :where(blockquote strong):not(:where([class~=not-prose] *)){color:inherit}.md\:prose :where(thead th strong):not(:where([class~=not-prose] *)){color:inherit}.md\:prose :where(ol):not(:where([class~=not-prose] *)){list-style-type:decimal;margin-bottom:1.25em;margin-top:1.25em;padding-left:1.625em}.md\:prose :where(ol[type=A]):not(:where([class~=not-prose] *)){list-style-type:upper-alpha}.md\:prose :where(ol[type=a]):not(:where([class~=not-prose] *)){list-style-type:lower-alpha}.md\:prose :where(ol[type=A s]):not(:where([class~=not-prose] *)){list-style-type:upper-alpha}.md\:prose :where(ol[type=a s]):not(:where([class~=not-prose] *)){list-style-type:lower-alpha}.md\:prose :where(ol[type=I]):not(:where([class~=not-prose] *)){list-style-type:upper-roman}.md\:prose :where(ol[type=i]):not(:where([class~=not-prose] *)){list-style-type:lower-roman}.md\:prose :where(ol[type=I s]):not(:where([class~=not-prose] *)){list-style-type:upper-roman}.md\:prose :where(ol[type=i s]):not(:where([class~=not-prose] *)){list-style-type:lower-roman}.md\:prose :where(ol[type="1"]):not(:where([class~=not-prose] *)){list-style-type:decimal}.md\:prose :where(ul):not(:where([class~=not-prose] *)){list-style-type:disc;margin-bottom:1.25em;margin-top:1.25em;padding-left:1.625em}.md\:prose :where(ol>li):not(:where([class~=not-prose] *))::marker{color:var(--tw-prose-counters);font-weight:400}.md\:prose :where(ul>li):not(:where([class~=not-prose] *))::marker{color:var(--tw-prose-bullets)}.md\:prose :where(hr):not(:where([class~=not-prose] *)){border-color:var(--tw-prose-hr);border-top-width:1px;margin-bottom:3em;margin-top:3em}.md\:prose :where(blockquote):not(:where([class~=not-prose] *)){border-left-color:var(--tw-prose-quote-borders);border-left-width:.25rem;color:var(--tw-prose-quotes);font-style:italic;font-weight:500;margin-bottom:1.6em;margin-top:1.6em;padding-left:1em;quotes:"\201C""\201D""\2018""\2019"}.md\:prose :where(blockquote p:first-of-type):not(:where([class~=not-prose] *)):before{content:open-quote}.md\:prose :where(blockquote p:last-of-type):not(:where([class~=not-prose] *)):after{content:close-quote}.md\:prose :where(h1):not(:where([class~=not-prose] *)){color:var(--tw-prose-headings);font-size:2.25em;font-weight:800;line-height:1.1111111;margin-bottom:.8888889em;margin-top:0}.md\:prose :where(h1 strong):not(:where([class~=not-prose] *)){color:inherit;font-weight:900}.md\:prose :where(h2):not(:where([class~=not-prose] *)){color:var(--tw-prose-headings);font-size:1.5em;font-weight:700;line-height:1.3333333;margin-bottom:1em;margin-top:2em}.md\:prose :where(h2 strong):not(:where([class~=not-prose] *)){color:inherit;font-weight:800}.md\:mb-12{margin-bottom:3rem}.md\:prose :where(h3):not(:where([class~=not-prose] *)){color:var(--tw-prose-headings);font-size:1.25em;font-weight:600;line-height:1.6;margin-bottom:.6em;margin-top:1.6em}.md\:prose :where(h3 strong):not(:where([class~=not-prose] *)){color:inherit;font-weight:700}.md\:prose :where(h4):not(:where([class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;line-height:1.5;margin-bottom:.5em;margin-top:1.5em}.md\:prose :where(h4 strong):not(:where([class~=not-prose] *)){color:inherit;font-weight:700}.md\:prose :where(img):not(:where([class~=not-prose] *)){margin-bottom:2em;margin-top:2em}.md\:inline{display:inline}.md\:prose :where(figure>*):not(:where([class~=not-prose] *)){margin-bottom:0;margin-top:0}.md\:prose :where(figcaption):not(:where([class~=not-prose] *)){color:var(--tw-prose-captions);font-size:.875em;line-height:1.4285714;margin-top:.8571429em}.md\:prose :where(code):not(:where([class~=not-prose] *)){color:var(--tw-prose-code);font-size:.875em;font-weight:600}.md\:prose :where(code):not(:where([class~=not-prose] *)):before{content:"`"}.md\:prose :where(code):not(:where([class~=not-prose] *)):after{content:"`"}.md\:prose :where(a code):not(:where([class~=not-prose] *)){color:inherit}.md\:prose :where(h1 code):not(:where([class~=not-prose] *)){color:inherit}.md\:prose :where(h2 code):not(:where([class~=not-prose] *)){color:inherit;font-size:.875em}.md\:prose :where(h3 code):not(:where([class~=not-prose] *)){color:inherit;font-size:.9em}.md\:prose :where(h4 code):not(:where([class~=not-prose] *)){color:inherit}.md\:prose :where(blockquote code):not(:where([class~=not-prose] *)){color:inherit}.md\:prose :where(thead th code):not(:where([class~=not-prose] *)){color:inherit}.md\:prose :where(pre):not(:where([class~=not-prose] *)){background-color:var(--tw-prose-pre-bg);border-radius:.375rem;color:var(--tw-prose-pre-code);font-size:.875em;font-weight:400;line-height:1.7142857;margin-bottom:1.7142857em;margin-top:1.7142857em;overflow-x:auto;padding:.8571429em 1.1428571em}.md\:prose :where(pre code):not(:where([class~=not-prose] *)){background-color:transparent;border-radius:0;border-width:0;color:inherit;font-family:inherit;font-size:inherit;font-weight:inherit;line-height:inherit;padding:0}.md\:prose :where(pre code):not(:where([class~=not-prose] *)):before{content:none}.md\:prose :where(pre code):not(:where([class~=not-prose] *)):after{content:none}.md\:prose :where(table):not(:where([class~=not-prose] *)){font-size:.875em;line-height:1.7142857;margin-bottom:2em;margin-top:2em;table-layout:auto;text-align:left;width:100%}.md\:prose :where(thead):not(:where([class~=not-prose] *)){border-bottom-color:var(--tw-prose-th-borders);border-bottom-width:1px}.md\:prose :where(thead th):not(:where([class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;padding-bottom:.5714286em;padding-left:.5714286em;padding-right:.5714286em;vertical-align:bottom}.md\:prose :where(tbody tr):not(:where([class~=not-prose] *)){border-bottom-color:var(--tw-prose-td-borders);border-bottom-width:1px}.md\:prose :where(tbody tr:last-child):not(:where([class~=not-prose] *)){border-bottom-width:0}.md\:prose :where(tbody td):not(:where([class~=not-prose] *)){vertical-align:baseline}.md\:prose :where(tfoot):not(:where([class~=not-prose] *)){border-top-color:var(--tw-prose-th-borders);border-top-width:1px}.md\:prose :where(tfoot td):not(:where([class~=not-prose] *)){vertical-align:top}.md\:prose{--tw-prose-body:#374151;--tw-prose-headings:#111827;--tw-prose-lead:#4b5563;--tw-prose-links:#111827;--tw-prose-bold:#111827;--tw-prose-counters:#6b7280;--tw-prose-bullets:#d1d5db;--tw-prose-hr:#e5e7eb;--tw-prose-quotes:#111827;--tw-prose-quote-borders:#e5e7eb;--tw-prose-captions:#6b7280;--tw-prose-code:#111827;--tw-prose-pre-code:#e5e7eb;--tw-prose-pre-bg:#1f2937;--tw-prose-th-borders:#d1d5db;--tw-prose-td-borders:#e5e7eb;--tw-prose-invert-body:#d1d5db;--tw-prose-invert-headings:#fff;--tw-prose-invert-lead:#9ca3af;--tw-prose-invert-links:#fff;--tw-prose-invert-bold:#fff;--tw-prose-invert-counters:#9ca3af;--tw-prose-invert-bullets:#4b5563;--tw-prose-invert-hr:#374151;--tw-prose-invert-quotes:#f3f4f6;--tw-prose-invert-quote-borders:#374151;--tw-prose-invert-captions:#9ca3af;--tw-prose-invert-code:#fff;--tw-prose-invert-pre-code:#d1d5db;--tw-prose-invert-pre-bg:rgba(0,0,0,.5);--tw-prose-invert-th-borders:#4b5563;--tw-prose-invert-td-borders:#374151;font-size:1rem;line-height:1.75}.md\:prose :where(p):not(:where([class~=not-prose] *)){margin-bottom:1.25em;margin-top:1.25em}.md\:prose :where(video):not(:where([class~=not-prose] *)){margin-bottom:2em;margin-top:2em}.md\:prose :where(figure):not(:where([class~=not-prose] *)){margin-bottom:2em;margin-top:2em}.md\:prose :where(li):not(:where([class~=not-prose] *)){margin-bottom:.5em;margin-top:.5em}.md\:prose :where(ol>li):not(:where([class~=not-prose] *)){padding-left:.375em}.md\:prose :where(ul>li):not(:where([class~=not-prose] *)){padding-left:.375em}.md\:prose :where(.md\:prose>ul>li p):not(:where([class~=not-prose] *)){margin-bottom:.75em;margin-top:.75em}.md\:prose :where(.md\:prose>ul>li>:first-child):not(:where([class~=not-prose] *)){margin-top:1.25em}.md\:prose :where(.md\:prose>ul>li>:last-child):not(:where([class~=not-prose] *)){margin-bottom:1.25em}.md\:prose :where(.md\:prose>ol>li>:first-child):not(:where([class~=not-prose] *)){margin-top:1.25em}.md\:prose :where(.md\:prose>ol>li>:last-child):not(:where([class~=not-prose] *)){margin-bottom:1.25em}.md\:prose :where(ul ul,ul ol,ol ul,ol ol):not(:where([class~=not-prose] *)){margin-bottom:.75em;margin-top:.75em}.md\:prose :where(hr+*):not(:where([class~=not-prose] *)){margin-top:0}.md\:prose :where(h2+*):not(:where([class~=not-prose] *)){margin-top:0}.md\:prose :where(h3+*):not(:where([class~=not-prose] *)){margin-top:0}.md\:prose :where(h4+*):not(:where([class~=not-prose] *)){margin-top:0}.md\:prose :where(thead th:first-child):not(:where([class~=not-prose] *)){padding-left:0}.md\:prose :where(thead th:last-child):not(:where([class~=not-prose] *)){padding-right:0}.md\:prose :where(tbody td,tfoot td):not(:where([class~=not-prose] *)){padding:.5714286em}.md\:prose :where(tbody td:first-child,tfoot td:first-child):not(:where([class~=not-prose] *)){padding-left:0}.md\:prose :where(tbody td:last-child,tfoot td:last-child):not(:where([class~=not-prose] *)){padding-right:0}.md\:prose :where(.md\:prose>:first-child):not(:where([class~=not-prose] *)){margin-top:0}.md\:prose :where(.md\:prose>:last-child):not(:where([class~=not-prose] *)){margin-bottom:0}.md\:flex-row{flex-direction:row}.md\:space-y-0>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(0px*var(--tw-space-y-reverse));margin-top:calc(0px*(1 - var(--tw-space-y-reverse)))}.md\:space-x-3>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-left:calc(.75rem*(1 - var(--tw-space-x-reverse)));margin-right:calc(.75rem*var(--tw-space-x-reverse))}.md\:border-\[10px\]{border-width:10px}.md\:border-solid{border-style:solid}.md\:border-purple{--tw-border-opacity:1;border-color:rgb(150 0 255/var(--tw-border-opacity))}.md\:px-8{padding-left:2rem;padding-right:2rem}.md\:px-10{padding-left:2.5rem;padding-right:2.5rem}.md\:px-1{padding-left:.25rem;padding-right:.25rem}.md\:pr-0{padding-right:0}.md\:pt-1\.5{padding-top:.375rem}.md\:pt-1{padding-top:.25rem}.md\:text-9xl{font-size:8rem;line-height:1}.md\:text-5xl{font-size:3rem;line-height:1}.md\:text-lg{font-size:1.125rem;line-height:1.75rem}.prose-hr\:md\:my-10 :is(:where(hr):not(:where([class~=not-prose] *))){margin-bottom:2.5rem;margin-top:2.5rem}}@media (min-width:1024px){.lg\:min-h-\[calc\(100vh-20px\)\]{min-height:calc(100vh - 20px)}.lg\:w-3\/5{width:60%}.lg\:prose-lg{font-size:1.125rem;line-height:1.7777778}.lg\:prose-lg :where(p):not(:where([class~=not-prose] *)){margin-bottom:1.3333333em;margin-top:1.3333333em}.lg\:prose-lg :where([class~=lead]):not(:where([class~=not-prose] *)){font-size:1.2222222em;line-height:1.4545455;margin-bottom:1.0909091em;margin-top:1.0909091em}.lg\:prose-lg :where(blockquote):not(:where([class~=not-prose] *)){margin-bottom:1.6666667em;margin-top:1.6666667em;padding-left:1em}.lg\:prose-lg :where(h1):not(:where([class~=not-prose] *)){font-size:2.6666667em;line-height:1;margin-bottom:.8333333em;margin-top:0}.lg\:prose-lg :where(h2):not(:where([class~=not-prose] *)){font-size:1.6666667em;line-height:1.3333333;margin-bottom:1.0666667em;margin-top:1.8666667em}.lg\:prose-lg :where(h3):not(:where([class~=not-prose] *)){font-size:1.3333333em;line-height:1.5;margin-bottom:.6666667em;margin-top:1.6666667em}.lg\:prose-lg :where(h4):not(:where([class~=not-prose] *)){line-height:1.5555556;margin-bottom:.4444444em;margin-top:1.7777778em}.lg\:prose-lg :where(img):not(:where([class~=not-prose] *)){margin-bottom:1.7777778em;margin-top:1.7777778em}.lg\:prose-lg :where(video):not(:where([class~=not-prose] *)){margin-bottom:1.7777778em;margin-top:1.7777778em}.lg\:prose-lg :where(figure):not(:where([class~=not-prose] *)){margin-bottom:1.7777778em;margin-top:1.7777778em}.lg\:prose-lg :where(figure>*):not(:where([class~=not-prose] *)){margin-bottom:0;margin-top:0}.lg\:prose-lg :where(figcaption):not(:where([class~=not-prose] *)){font-size:.8888889em;line-height:1.5;margin-top:1em}.lg\:prose-lg :where(code):not(:where([class~=not-prose] *)){font-size:.8888889em}.lg\:prose-lg :where(h2 code):not(:where([class~=not-prose] *)){font-size:.8666667em}.lg\:prose-lg :where(h3 code):not(:where([class~=not-prose] *)){font-size:.875em}.lg\:prose-lg :where(pre):not(:where([class~=not-prose] *)){border-radius:.375rem;font-size:.8888889em;line-height:1.75;margin-bottom:2em;margin-top:2em;padding:1em 1.5em}.lg\:prose-lg :where(ol):not(:where([class~=not-prose] *)){margin-bottom:1.3333333em;margin-top:1.3333333em;padding-left:1.5555556em}.lg\:prose-lg :where(ul):not(:where([class~=not-prose] *)){margin-bottom:1.3333333em;margin-top:1.3333333em;padding-left:1.5555556em}.lg\:prose-lg :where(li):not(:where([class~=not-prose] *)){margin-bottom:.6666667em;margin-top:.6666667em}.lg\:prose-lg :where(ol>li):not(:where([class~=not-prose] *)){padding-left:.4444444em}.lg\:prose-lg :where(ul>li):not(:where([class~=not-prose] *)){padding-left:.4444444em}.lg\:prose-lg :where(.lg\:prose-lg>ul>li p):not(:where([class~=not-prose] *)){margin-bottom:.8888889em;margin-top:.8888889em}.lg\:prose-lg :where(.lg\:prose-lg>ul>li>:first-child):not(:where([class~=not-prose] *)){margin-top:1.3333333em}.lg\:prose-lg :where(.lg\:prose-lg>ul>li>:last-child):not(:where([class~=not-prose] *)){margin-bottom:1.3333333em}.lg\:prose-lg :where(.lg\:prose-lg>ol>li>:first-child):not(:where([class~=not-prose] *)){margin-top:1.3333333em}.lg\:prose-lg :where(.lg\:prose-lg>ol>li>:last-child):not(:where([class~=not-prose] *)){margin-bottom:1.3333333em}.lg\:prose-lg :where(ul ul,ul ol,ol ul,ol ol):not(:where([class~=not-prose] *)){margin-bottom:.8888889em;margin-top:.8888889em}.lg\:prose-lg :where(hr):not(:where([class~=not-prose] *)){margin-bottom:3.1111111em;margin-top:3.1111111em}.lg\:prose-lg :where(hr+*):not(:where([class~=not-prose] *)){margin-top:0}.lg\:prose-lg :where(h2+*):not(:where([class~=not-prose] *)){margin-top:0}.lg\:prose-lg :where(h3+*):not(:where([class~=not-prose] *)){margin-top:0}.lg\:prose-lg :where(h4+*):not(:where([class~=not-prose] *)){margin-top:0}.lg\:prose-lg :where(table):not(:where([class~=not-prose] *)){font-size:.8888889em;line-height:1.5}.lg\:prose-lg :where(thead th):not(:where([class~=not-prose] *)){padding-bottom:.75em;padding-left:.75em;padding-right:.75em}.lg\:prose-lg :where(thead th:first-child):not(:where([class~=not-prose] *)){padding-left:0}.lg\:prose-lg :where(thead th:last-child):not(:where([class~=not-prose] *)){padding-right:0}.lg\:prose-lg :where(tbody td,tfoot td):not(:where([class~=not-prose] *)){padding:.75em}.lg\:prose-lg :where(tbody td:first-child,tfoot td:first-child):not(:where([class~=not-prose] *)){padding-left:0}.lg\:prose-lg :where(tbody td:last-child,tfoot td:last-child):not(:where([class~=not-prose] *)){padding-right:0}.lg\:prose-lg :where(.lg\:prose-lg>:first-child):not(:where([class~=not-prose] *)){margin-top:0}.lg\:prose-lg :where(.lg\:prose-lg>:last-child):not(:where([class~=not-prose] *)){margin-bottom:0}.lg\:px-16{padding-left:4rem;padding-right:4rem}}@media (min-width:1280px){.xl\:-mx-56{margin-left:-14rem;margin-right:-14rem}.xl\:my-4{margin-bottom:1rem;margin-top:1rem}.xl\:inline{display:inline}.xl\:w-1\/2{width:50%}.xl\:max-w-\[900px\]{max-width:900px}.xl\:py-20{padding-bottom:5rem;padding-top:5rem}.xl\:text-6xl{font-size:3.75rem;line-height:1}.xl\:text-2xl{font-size:1.5rem;line-height:2rem}.xl\:text-base{font-size:1rem;line-height:1.5rem}}@media (min-width:1536px){.\32xl\:w-\[700px\]{width:700px}.\32xl\:max-w-\[1000px\]{max-width:1000px}.\32xl\:prose-lg{font-size:1.125rem;line-height:1.7777778}.\32xl\:prose-lg :where(p):not(:where([class~=not-prose] *)){margin-bottom:1.3333333em;margin-top:1.3333333em}.\32xl\:prose-lg :where([class~=lead]):not(:where([class~=not-prose] *)){font-size:1.2222222em;line-height:1.4545455;margin-bottom:1.0909091em;margin-top:1.0909091em}.\32xl\:prose-lg :where(blockquote):not(:where([class~=not-prose] *)){margin-bottom:1.6666667em;margin-top:1.6666667em;padding-left:1em}.\32xl\:prose-lg :where(h1):not(:where([class~=not-prose] *)){font-size:2.6666667em;line-height:1;margin-bottom:.8333333em;margin-top:0}.\32xl\:prose-lg :where(h2):not(:where([class~=not-prose] *)){font-size:1.6666667em;line-height:1.3333333;margin-bottom:1.0666667em;margin-top:1.8666667em}.\32xl\:prose-lg :where(h3):not(:where([class~=not-prose] *)){font-size:1.3333333em;line-height:1.5;margin-bottom:.6666667em;margin-top:1.6666667em}.\32xl\:prose-lg :where(h4):not(:where([class~=not-prose] *)){line-height:1.5555556;margin-bottom:.4444444em;margin-top:1.7777778em}.\32xl\:prose-lg :where(img):not(:where([class~=not-prose] *)){margin-bottom:1.7777778em;margin-top:1.7777778em}.\32xl\:prose-lg :where(video):not(:where([class~=not-prose] *)){margin-bottom:1.7777778em;margin-top:1.7777778em}.\32xl\:prose-lg :where(figure):not(:where([class~=not-prose] *)){margin-bottom:1.7777778em;margin-top:1.7777778em}.\32xl\:prose-lg :where(figure>*):not(:where([class~=not-prose] *)){margin-bottom:0;margin-top:0}.\32xl\:prose-lg :where(figcaption):not(:where([class~=not-prose] *)){font-size:.8888889em;line-height:1.5;margin-top:1em}.\32xl\:prose-lg :where(code):not(:where([class~=not-prose] *)){font-size:.8888889em}.\32xl\:prose-lg :where(h2 code):not(:where([class~=not-prose] *)){font-size:.8666667em}.\32xl\:prose-lg :where(h3 code):not(:where([class~=not-prose] *)){font-size:.875em}.\32xl\:prose-lg :where(pre):not(:where([class~=not-prose] *)){border-radius:.375rem;font-size:.8888889em;line-height:1.75;margin-bottom:2em;margin-top:2em;padding:1em 1.5em}.\32xl\:prose-lg :where(ol):not(:where([class~=not-prose] *)){margin-bottom:1.3333333em;margin-top:1.3333333em;padding-left:1.5555556em}.\32xl\:prose-lg :where(ul):not(:where([class~=not-prose] *)){margin-bottom:1.3333333em;margin-top:1.3333333em;padding-left:1.5555556em}.\32xl\:prose-lg :where(li):not(:where([class~=not-prose] *)){margin-bottom:.6666667em;margin-top:.6666667em}.\32xl\:prose-lg :where(ol>li):not(:where([class~=not-prose] *)){padding-left:.4444444em}.\32xl\:prose-lg :where(ul>li):not(:where([class~=not-prose] *)){padding-left:.4444444em}.\32xl\:prose-lg :where(.\32xl\:prose-lg>ul>li p):not(:where([class~=not-prose] *)){margin-bottom:.8888889em;margin-top:.8888889em}.\32xl\:prose-lg :where(.\32xl\:prose-lg>ul>li>:first-child):not(:where([class~=not-prose] *)){margin-top:1.3333333em}.\32xl\:prose-lg :where(.\32xl\:prose-lg>ul>li>:last-child):not(:where([class~=not-prose] *)){margin-bottom:1.3333333em}.\32xl\:prose-lg :where(.\32xl\:prose-lg>ol>li>:first-child):not(:where([class~=not-prose] *)){margin-top:1.3333333em}.\32xl\:prose-lg :where(.\32xl\:prose-lg>ol>li>:last-child):not(:where([class~=not-prose] *)){margin-bottom:1.3333333em}.\32xl\:prose-lg :where(ul ul,ul ol,ol ul,ol ol):not(:where([class~=not-prose] *)){margin-bottom:.8888889em;margin-top:.8888889em}.\32xl\:prose-lg :where(hr):not(:where([class~=not-prose] *)){margin-bottom:3.1111111em;margin-top:3.1111111em}.\32xl\:prose-lg :where(hr+*):not(:where([class~=not-prose] *)){margin-top:0}.\32xl\:prose-lg :where(h2+*):not(:where([class~=not-prose] *)){margin-top:0}.\32xl\:prose-lg :where(h3+*):not(:where([class~=not-prose] *)){margin-top:0}.\32xl\:prose-lg :where(h4+*):not(:where([class~=not-prose] *)){margin-top:0}.\32xl\:prose-lg :where(table):not(:where([class~=not-prose] *)){font-size:.8888889em;line-height:1.5}.\32xl\:prose-lg :where(thead th):not(:where([class~=not-prose] *)){padding-bottom:.75em;padding-left:.75em;padding-right:.75em}.\32xl\:prose-lg :where(thead th:first-child):not(:where([class~=not-prose] *)){padding-left:0}.\32xl\:prose-lg :where(thead th:last-child):not(:where([class~=not-prose] *)){padding-right:0}.\32xl\:prose-lg :where(tbody td,tfoot td):not(:where([class~=not-prose] *)){padding:.75em}.\32xl\:prose-lg :where(tbody td:first-child,tfoot td:first-child):not(:where([class~=not-prose] *)){padding-left:0}.\32xl\:prose-lg :where(tbody td:last-child,tfoot td:last-child):not(:where([class~=not-prose] *)){padding-right:0}.\32xl\:prose-lg :where(.\32xl\:prose-lg>:first-child):not(:where([class~=not-prose] *)){margin-top:0}.\32xl\:prose-lg :where(.\32xl\:prose-lg>:last-child):not(:where([class~=not-prose] *)){margin-bottom:0}.\32xl\:px-32{padding-left:8rem;padding-right:8rem}} \ No newline at end of file diff --git a/favicon.ico b/favicon.ico new file mode 100644 index 0000000..84555a3 Binary files /dev/null and b/favicon.ico differ diff --git a/fonts/JetBrainsMono-Bold.woff2 b/fonts/JetBrainsMono-Bold.woff2 new file mode 100644 index 0000000..4917f43 Binary files /dev/null and b/fonts/JetBrainsMono-Bold.woff2 differ diff --git a/fonts/JetBrainsMono-BoldItalic.woff2 b/fonts/JetBrainsMono-BoldItalic.woff2 new file mode 100644 index 0000000..536d3f7 Binary files /dev/null and b/fonts/JetBrainsMono-BoldItalic.woff2 differ diff --git a/fonts/JetBrainsMono-ExtraBold.woff2 b/fonts/JetBrainsMono-ExtraBold.woff2 new file mode 100644 index 0000000..8f88c54 Binary files /dev/null and b/fonts/JetBrainsMono-ExtraBold.woff2 differ diff --git a/fonts/JetBrainsMono-ExtraBoldItalic.woff2 b/fonts/JetBrainsMono-ExtraBoldItalic.woff2 new file mode 100644 index 0000000..d1478ba Binary files /dev/null and b/fonts/JetBrainsMono-ExtraBoldItalic.woff2 differ diff --git a/fonts/JetBrainsMono-Italic.woff2 b/fonts/JetBrainsMono-Italic.woff2 new file mode 100644 index 0000000..d60c270 Binary files /dev/null and b/fonts/JetBrainsMono-Italic.woff2 differ diff --git a/fonts/JetBrainsMono-Light.woff2 b/fonts/JetBrainsMono-Light.woff2 new file mode 100644 index 0000000..6538498 Binary files /dev/null and b/fonts/JetBrainsMono-Light.woff2 differ diff --git a/fonts/JetBrainsMono-LightItalic.woff2 b/fonts/JetBrainsMono-LightItalic.woff2 new file mode 100644 index 0000000..66ca3d2 Binary files /dev/null and b/fonts/JetBrainsMono-LightItalic.woff2 differ diff --git a/fonts/JetBrainsMono-Medium.woff2 b/fonts/JetBrainsMono-Medium.woff2 new file mode 100644 index 0000000..669d04c Binary files /dev/null and b/fonts/JetBrainsMono-Medium.woff2 differ diff --git a/fonts/JetBrainsMono-MediumItalic.woff2 b/fonts/JetBrainsMono-MediumItalic.woff2 new file mode 100644 index 0000000..80cfd15 Binary files /dev/null and b/fonts/JetBrainsMono-MediumItalic.woff2 differ diff --git a/fonts/JetBrainsMono-Regular.woff2 b/fonts/JetBrainsMono-Regular.woff2 new file mode 100644 index 0000000..40da427 Binary files /dev/null and b/fonts/JetBrainsMono-Regular.woff2 differ diff --git a/fonts/JetBrainsMono-SemiBold.woff2 b/fonts/JetBrainsMono-SemiBold.woff2 new file mode 100644 index 0000000..5ead7b0 Binary files /dev/null and b/fonts/JetBrainsMono-SemiBold.woff2 differ diff --git a/fonts/JetBrainsMono-SemiBoldItalic.woff2 b/fonts/JetBrainsMono-SemiBoldItalic.woff2 new file mode 100644 index 0000000..c5dd294 Binary files /dev/null and b/fonts/JetBrainsMono-SemiBoldItalic.woff2 differ diff --git a/footnotes.js b/footnotes.js new file mode 100644 index 0000000..343e663 --- /dev/null +++ b/footnotes.js @@ -0,0 +1,20 @@ +// Workaround to support footnotes within the Markdown parser +// Ref: github.com/raphlinus/pulldown-cmark/issues/142 + +const references = document.getElementsByClassName("footnote-reference") + +for (const reference of references) { + const link = reference.firstChild + const id = link.getAttribute("href").slice(1) // skip the '#' + link.setAttribute("id", `${id}_ref`) +} + +const footnotes = document.getElementsByClassName("footnote-definition") + +for (const footnote of footnotes) { + const id = footnote.getAttribute("id") + const backReference = document.createElement("a") + backReference.setAttribute("href", `#${id}_ref`) + backReference.textContent = "ā†©" + footnote.append(backReference) +} diff --git a/humans.txt b/humans.txt new file mode 100644 index 0000000..8d5c5a5 --- /dev/null +++ b/humans.txt @@ -0,0 +1,47 @@ +heyo, nice to meet you! + +this website is powered by Zola (getzola.org), Tailwind (tailwindcss.com) and Markdown. + +name: DiĆ©ssica Gurskas +email: hey at this domain +twitter: @diessicode +location: Berlin, DE +humans.txt last updated: 01-07-2023 + +tschĆ¼ĆŸ! +š””š”¦š”¢š”°š”° + + + ..^~7JGPP#########&&&#################&&&&&&&&&&G7:.......:::::::::::::::^^ + .:~??JPBB######BBBB####BBBBBBBBGGGBB###&&&&&&&&&&G7:......:::::::::::::::^^ + ::!JP#B###BBBGGGPPPGGGGGP5555555PPPPGB##&&&&&&&&&&G?!^:..::::::::::::::::^^ + ^!!7P###GP55YYYJJYYYYYYYJJJ????JJJYY5PGB##&&&&&&&&BJ?7~^:::::::::::::::::^^ + .^J5J!JBBPYJJJJJJJJ????????????????7777?JYPGB&&&&&&&GJJ7~7^::::::::::::::::^^ +:.. .~YPGPYJPPYJJJJJJJJJ????????7?????????7777??YPB#&&&&#GGJ?^!~::::::::::::::^^^^ +7!^:.. ..^7YGBGGGBGY?JJJJJJJJ???????777????????7777777JPB#&&&&BG5J!~~:::::::::^^^^^^^^^ +7!^::. ....^7JPGGBB#BY???JJJJJJ?????????77777777777777777?YG#&&&&&##PJ7~:::::::^^^^^^^^^^~ +!~^:. .~?JY5GBBBP!!?????????????7???77777777777777777?JPB&&&&#BB5J7^:::::::::^^^^^^~~~ +~~::. ...:::^!???JPGGPJ^:!?JJJJJJJ?????????????JJJJJYYYYJ???JPB#&&#BG5J?!^^::::^^^:::^^^^^^^ +~^::. ~?JJJJJJJJ?????JJ??7~~!?J5PPPP5YYJJJ???JJY5PGBBBBBGP55YJY5GB#&#BG57!~!?YJ?7!JJ?7!7~^^^^^^ +~^:.. !555YYYJJJJJJYYJJJJ??????YPGBGGGPY?!7?JJJ5PGBBGGGBBBPPPPPPPPG##BBG?!^^^~?Y5555YYJJJJ7!~^^^ +~^:.. .!YYYYYYYYYYYYYYYYYYY5YJJ5PGB###BBBBP5PGGGBB###BBBBBBBBB##&&&#BGP55J!^::::::~J5PPP55YYJJJ?7! +~^:. !Y55YY555YYYYYJ?7!~755Y!JGG5GB########GPY5GB&&&&&&&&&&&&&&&&&GPJ?!^~~^^::::~!!~~7J5PPP55PP5Y +~^:. .~Y55555P555YYJ!:...::~YJ!!5B###########B5JJ5G#&##&&&&&&&&&&&&GYJ!^::^^^^...:^:....:^!JYPGGGPP +~^:. .~J555555555Y!:. .:..~?7^?PB#########BPJ?7?5G#&&&&&&&&&#&&#BY7!^:::::::.......:::::::^~?5PGG +^::. :J55YY55555Y!. .. .~7?5G########BPYJ?777YPB#&&&&&&&&&BP?7~^^^^::::::::::::^:::::::::^!J5 +^:...?55YYYYY555J~. .:^~!?JYPGBBBBGP55YJ??7777JY5PGBBBBGPY?7~~~^::::::::::::^::::::::::::::^~ +^:..:Y5YYYYYYYYYYY?~. ..^~7????77777??JJJJJJJJ?777777?JJJJJJJ?77!!~^:^::::::::::::::::::::::^^~7?Y5 +~::.^55YYYJJJYYYYYJJ?777???????7!!~^:~7????JJJJJ??77???JJJJJJ??7!!~^:::::::::::::::::^^::::^^~J5PGPP +~::.75YYJJJJJYYJJJJ???????77??JYJJY7^:!???JJJJYYJJJ??????JJJ??77!~:::::::::::::::::::^^^^^^~?5PPPGPP +^:.:?YYJJJJJJJJJ????777777J5GGB####J7^:!JJJYYYYYYJJJJJJJYYYJJ?7~:::::::::::::::::::::~^^^^75PPPP5YJY +^:.~JYJ??????JJ??7777777JPB#BB#####G77!^!YYY55PPP55P5555Y55YJ777^:...:::::::::::::::.^!~~JPGPP5Y?JPG +^::7YYJ????????77777777JB#BBBB######G?77!7JYYY5555555YYJJJJJ7~7##G?7~:.:::::::::::::..~?5PPP5YY5PGPP +^:^JYJJ????????7!!!!775BBBBBBBBBBB###BY???7?JJJJJJJJJJJ????7!!P&&&&&&P7^::::::::::::.:?GGGG55PGGPP5Y +^^?YJJJ????777777777JGBBBBBBBBBBBBBB###GY??7??JJJJJJJJJJ??7!7G&&&&&&&&&B5J!~^^::::::::!YPYPPGP5J?7!~ +^!JJJ??????????77?YPBBBBBBGGBBBBBBBBB####B5J?77??????????77YB&&&&&&&&&&&&&&##BGY7~:.::..7J???!^^^~~~ +7JJJJ???????????5GBBBBBBBBGBBBBBBBBBBBB#####BPYJ???????JYPB&&&&&&&&&&&&&&&&&&&&&&#G?:...:?7:^!!!!!!! +JJJJJ??????????PBGGBBBBBBBBBBBBBBBBBBBBBB####&&##BBGGBB#&&&&&&&&&&&&&&&&&&&&&&&&&@@&5^...^7777?7777! +JJJJ??????777?PBGGGGGGBBBGBBBBBBBBBBBBBBB#######&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&@@@@@&J::::!7!!!!7!!! +JJJJ??????77?5BGGGGGGGGGGGGBGBBBBBBBBBBBBBB#########&&&&&&&&&&&&&&&&&&&&&&@@@@@@@@@@&B7^~!7??!~~^~~~ +JJJ???77777?JGBBGGGGGGGGGGGGGGGGGGBBBBBBBBBBB##########&&&&&&&&&&&&&&&&&&&@@@@@@@@@&&&P~!7!?5Y?7!?J7 +JJJ???77777?5GBBBBGGGGGGGGGGGGGGGGGBBBBBBBBBBB##########&&&&&&&&&&&&&&&&&&@@@@@@@@&&@&&57J7!?5P5JJ?? \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 0000000..4eae7da --- /dev/null +++ b/index.html @@ -0,0 +1 @@ +Home | DiĆ©ssica Gurskas
diessi.caBlogMisc

I'm DiĆ©ssica Gurskas. šŸ‘‹
I immerse myself in nature, sound, cycling, and the wonders of human-computer interaction.

I'm based in ever-changing Berlin, but grew up in never-changing ViamĆ£o, a humble town in Brazil which taught me to be resourceful. Whether it was making kites out of bags and twigs, playing DIY football and cricket on muddy dirt roads, or ringing neighbors' doorbells and dashing away, I hacked whatever came my way.

That ultimately led me to unearth a fascination for computers. Back when I hacked my first game and setup a pirate server just so everything was free, I felt empowered by how computers could help solve our problems. Coming of age, I also realised how they may create new ones. šŸ˜‰

Having honed my skills, and developed a passion for audio along the way, I am nowadays a Lead Software Engineer at Native Instruments. I manage web architecture and operations for leading audio brands, including iZotope.

Raised by the internet, I wholeheartedly support and draw on open knowledge to teach myself, experiment, and have fun. I wish nothing but for everyone to empower themselves towards never-ending exploration as I do.

____
\ No newline at end of file diff --git a/keybase.txt b/keybase.txt new file mode 100644 index 0000000..6f95a96 --- /dev/null +++ b/keybase.txt @@ -0,0 +1,75 @@ +================================================================== +https://keybase.io/diessica +-------------------------------------------------------------------- + +I hereby claim: + + * I am an admin of https://diessi.ca + * I am diessica (https://keybase.io/diessica) on keybase. + * I have a public key with fingerprint 4302 C586 30C5 2251 35E4 07A4 449A A724 D631 01B2 + +To do so, I am signing this object: + +{ + "body": { + "key": { + "eldest_kid": "0120c2ee894d3a532403315abd1286e80ee3245566c9405b35f3078835f66d6bd0600a", + "fingerprint": "4302c58630c5225135e407a4449aa724d63101b2", + "host": "keybase.io", + "key_id": "449aa724d63101b2", + "kid": "01018fbb8563b64f4402fda4c9a56f78869299b72a4407dd248da57eb55d6925a35a0a", + "uid": "80c2b902f6438ee3657715451871c819", + "username": "diessica" + }, + "service": { + "hostname": "diessi.ca", + "protocol": "https:" + }, + "type": "web_service_binding", + "version": 1 + }, + "ctime": 1537532089, + "expire_in": 157680000, + "prev": "95359140301f30e8c90770914e96635bbd95cb78bbdddb134083e30667dfa6c1", + "seqno": 12, + "tag": "signature" +} + +which yields the signature: + +-----BEGIN PGP MESSAGE----- +Version: Keybase OpenPGP v2.0.77 +Comment: https://keybase.io/crypto + +yMNqAnicbVJtUFRVGF6EdFgiMTAl+oAbLtUweO7HOffeNRgto7XBicKSEKH7cRZu +wO66u4CAFMFMSfFhBKMhGiAOTskIC0RkRiwoQ9pAOSLWEA3gyqhTjhSZY2PnMvmj +mc6fc85znvd5n/d9z3Cwv8Hot7mxPXqC9vP4nR1syDfsaPulv4SS7WoRZS6hcvDS +hnNV7HJn5mgqZaYAzQCFwVgQOZWVIMtwgGVpKMkqzQgICwBjgkGIkCJyAMostLKA +FwSyI6QiWQUIAImKpayaLQs7HU7N5iayHAsYBQqIBQpkGEizEHOAlziOEyWJZzgV +sTSgZYYEZttdegQxJ0suHKfZCUYumUv2/od/zzegBassCxCxMuKsHAcYqypxiihB +ZCUGkciIoswzJCfgVZXhBFWCPJYhVMkTlFgoLfnOX5ITSBNkkUggjhVIyQjyPA05 +SAs8rQi0qBNd2GmT8jBhqxp2uTRFokpjKYIWaArWG6tX8h9GnKJncDjtbrtizyVw +ttvtcJn1MHeRQ+cVYjnzX4VMWbOppIkkogA7XZrdRplpwlTcmi5JQ5Yn4wGCGEvh +3Q7NiTM1nQF5JACy9Dy4gEiKkIUiTcYIaDIqLCgi4HlAECwixEJZVkWoyLxADqoq +0ywHBBazACFetUpIoSm9pl02O9FmiE8pi2i6tCyb5M53YqrUO5geYPAzGpbft0z/ +XQZjYMi9P7cpbeXd10xPUlOJ7M6X0ZzDKuR8MljYmTbRXhNQVPpYbfTC1FMR/ft9 +ZysivftOj8SMmR+vsFjuH2I+77llCtucimP6Vvkvjn31gKdt/Ofuvrc/rHm1abYh +4JszdsvMTOSj246FKRGtXZVtizfWRf4d5b5WL09F7blZZWru2edsWJNqA8sPxIfP +H84oX1EX/oG5bNOLp0IXa3qvzo9Om/fYZs99Gz139NKl7dcTfeGPPON/OHDhN+6L +zEVDrGHibkXr8bKxopzU4e0nSs7d7H33jfJXOioDa7s6Lkgpd0YO5K3N9VXnGoYH +G93rx4wZzbDr1MD+qihTYuSAJez1o9lx3ts7j0e4R9NMGbOr+6ON7X1bt/zUUtq4 +IyXgZPVFPHrEkpLv+DQr4dC6pqDP4v5YnVD3+3Mjbe8EN4QdrFzono6cMjXKxlFP +yY/jH3188mIzZ/1OzO59KTg5uS7/0KJ7Rdn56yL0DXWWdbzXWvy8OFn7q8t6Z/72 +KvEhYauB9Wz4emHt1Rso1DZXdWXgzxy4N967e3JXQnfY+72pz04e63ki1JN8q1O7 +4mssMBkdnrfe/EE0FCSJ4wdDQpo2/uXtbCu8Nj/ul/Rluq9mZkNxYOlkkpeq4IPM +l20PWloy1mysX7klt379GZweH1LtudySmtcaM70Q9HTMhaETxS+cfrjl+2Urj5wv +74lHe7O5bf8A+5q5NQ== +=mYMo +-----END PGP MESSAGE----- + +And finally, I am proving ownership of this host by posting or +appending to this document. + +View my publicly-auditable identity here: https://keybase.io/diessica + +================================================================== diff --git a/media/2015/knowledge-diagram.png b/media/2015/knowledge-diagram.png new file mode 100644 index 0000000..7ba8fb7 Binary files /dev/null and b/media/2015/knowledge-diagram.png differ diff --git a/media/2015/knowledge-diagram_2x.png b/media/2015/knowledge-diagram_2x.png new file mode 100644 index 0000000..a76b185 Binary files /dev/null and b/media/2015/knowledge-diagram_2x.png differ diff --git a/media/2015/moinhos-de-vento.jpg b/media/2015/moinhos-de-vento.jpg new file mode 100644 index 0000000..15746e4 Binary files /dev/null and b/media/2015/moinhos-de-vento.jpg differ diff --git a/media/2015/moinhos-de-vento_medium.jpg b/media/2015/moinhos-de-vento_medium.jpg new file mode 100644 index 0000000..0b43db5 Binary files /dev/null and b/media/2015/moinhos-de-vento_medium.jpg differ diff --git a/media/2015/moinhos-de-vento_small.jpg b/media/2015/moinhos-de-vento_small.jpg new file mode 100644 index 0000000..2f70dbd Binary files /dev/null and b/media/2015/moinhos-de-vento_small.jpg differ diff --git a/media/2016/twelfth-floor.jpg b/media/2016/twelfth-floor.jpg new file mode 100644 index 0000000..9da1a68 Binary files /dev/null and b/media/2016/twelfth-floor.jpg differ diff --git a/media/2016/twelfth-floor_medium.jpg b/media/2016/twelfth-floor_medium.jpg new file mode 100644 index 0000000..06fd4f9 Binary files /dev/null and b/media/2016/twelfth-floor_medium.jpg differ diff --git a/media/2016/twelfth-floor_small.jpg b/media/2016/twelfth-floor_small.jpg new file mode 100644 index 0000000..f891fb2 Binary files /dev/null and b/media/2016/twelfth-floor_small.jpg differ diff --git a/media/2017/catalysis-diagram.png b/media/2017/catalysis-diagram.png new file mode 100644 index 0000000..537bebc Binary files /dev/null and b/media/2017/catalysis-diagram.png differ diff --git a/media/2017/catalysis-diagram_2x.png b/media/2017/catalysis-diagram_2x.png new file mode 100644 index 0000000..cd2750f Binary files /dev/null and b/media/2017/catalysis-diagram_2x.png differ diff --git a/media/2017/dad-2005.jpg b/media/2017/dad-2005.jpg new file mode 100644 index 0000000..fe31265 Binary files /dev/null and b/media/2017/dad-2005.jpg differ diff --git a/media/2017/macos_desktop.mp4 b/media/2017/macos_desktop.mp4 new file mode 100644 index 0000000..df4d2fc Binary files /dev/null and b/media/2017/macos_desktop.mp4 differ diff --git a/media/2017/noorder-amstelkanaal.jpg b/media/2017/noorder-amstelkanaal.jpg new file mode 100644 index 0000000..ea12634 Binary files /dev/null and b/media/2017/noorder-amstelkanaal.jpg differ diff --git a/media/2017/noorder-amstelkanaal_medium.jpg b/media/2017/noorder-amstelkanaal_medium.jpg new file mode 100644 index 0000000..c0e14f0 Binary files /dev/null and b/media/2017/noorder-amstelkanaal_medium.jpg differ diff --git a/media/2017/noorder-amstelkanaal_small.jpg b/media/2017/noorder-amstelkanaal_small.jpg new file mode 100644 index 0000000..8a0114b Binary files /dev/null and b/media/2017/noorder-amstelkanaal_small.jpg differ diff --git a/media/2018/abstract-syntax-tree.png b/media/2018/abstract-syntax-tree.png new file mode 100644 index 0000000..381bd3b Binary files /dev/null and b/media/2018/abstract-syntax-tree.png differ diff --git a/media/2018/benjamin-franklin-routine.jpg b/media/2018/benjamin-franklin-routine.jpg new file mode 100644 index 0000000..3610fdf Binary files /dev/null and b/media/2018/benjamin-franklin-routine.jpg differ diff --git a/media/2018/clicker-flow.jpg b/media/2018/clicker-flow.jpg new file mode 100644 index 0000000..8341170 Binary files /dev/null and b/media/2018/clicker-flow.jpg differ diff --git a/media/2018/creativity.png b/media/2018/creativity.png new file mode 100644 index 0000000..ba0815d Binary files /dev/null and b/media/2018/creativity.png differ diff --git a/media/2018/gurskas-snow.jpg b/media/2018/gurskas-snow.jpg new file mode 100644 index 0000000..19a89c9 Binary files /dev/null and b/media/2018/gurskas-snow.jpg differ diff --git a/media/2018/mary-glass-syntax-tree.png b/media/2018/mary-glass-syntax-tree.png new file mode 100644 index 0000000..940f170 Binary files /dev/null and b/media/2018/mary-glass-syntax-tree.png differ diff --git a/media/2018/sdhv18-badge.jpg b/media/2018/sdhv18-badge.jpg new file mode 100644 index 0000000..d416306 Binary files /dev/null and b/media/2018/sdhv18-badge.jpg differ diff --git a/media/2018/sdhv18-lasers.jpg b/media/2018/sdhv18-lasers.jpg new file mode 100644 index 0000000..da50621 Binary files /dev/null and b/media/2018/sdhv18-lasers.jpg differ diff --git a/media/2018/sdhv18-n2-fire.jpg b/media/2018/sdhv18-n2-fire.jpg new file mode 100644 index 0000000..31a5eb0 Binary files /dev/null and b/media/2018/sdhv18-n2-fire.jpg differ diff --git a/media/2018/sdhv18-prize.jpg b/media/2018/sdhv18-prize.jpg new file mode 100644 index 0000000..6f61e56 Binary files /dev/null and b/media/2018/sdhv18-prize.jpg differ diff --git a/media/2018/sdhv18-spectrogram.jpg b/media/2018/sdhv18-spectrogram.jpg new file mode 100644 index 0000000..afd4eb8 Binary files /dev/null and b/media/2018/sdhv18-spectrogram.jpg differ diff --git a/media/2018/sdhv18-technarium.jpg b/media/2018/sdhv18-technarium.jpg new file mode 100644 index 0000000..c6c4241 Binary files /dev/null and b/media/2018/sdhv18-technarium.jpg differ diff --git a/media/2018/sdhv18-trophies.jpg b/media/2018/sdhv18-trophies.jpg new file mode 100644 index 0000000..1f382c2 Binary files /dev/null and b/media/2018/sdhv18-trophies.jpg differ diff --git a/media/2018/vs-code-stage-selected-changes.png b/media/2018/vs-code-stage-selected-changes.png new file mode 100644 index 0000000..e54d1bc Binary files /dev/null and b/media/2018/vs-code-stage-selected-changes.png differ diff --git a/media/2018/vs-code-writing-mode.png b/media/2018/vs-code-writing-mode.png new file mode 100644 index 0000000..7270aac Binary files /dev/null and b/media/2018/vs-code-writing-mode.png differ diff --git a/media/2018/yellow-bike-lock.jpg b/media/2018/yellow-bike-lock.jpg new file mode 100644 index 0000000..5569811 Binary files /dev/null and b/media/2018/yellow-bike-lock.jpg differ diff --git a/media/2019/guitar-rig-macos-mojave-setup/audio-midi-setup.png b/media/2019/guitar-rig-macos-mojave-setup/audio-midi-setup.png new file mode 100644 index 0000000..a0eed55 Binary files /dev/null and b/media/2019/guitar-rig-macos-mojave-setup/audio-midi-setup.png differ diff --git a/media/2019/guitar-rig-macos-mojave-setup/guitar-rig.png b/media/2019/guitar-rig-macos-mojave-setup/guitar-rig.png new file mode 100644 index 0000000..b69d4e3 Binary files /dev/null and b/media/2019/guitar-rig-macos-mojave-setup/guitar-rig.png differ diff --git a/media/2019/omg-climate/discussion.jpg b/media/2019/omg-climate/discussion.jpg new file mode 100644 index 0000000..28f3e05 Binary files /dev/null and b/media/2019/omg-climate/discussion.jpg differ diff --git a/media/2019/omg-climate/global-warming-nasa.gif b/media/2019/omg-climate/global-warming-nasa.gif new file mode 100644 index 0000000..ac7d6fb Binary files /dev/null and b/media/2019/omg-climate/global-warming-nasa.gif differ diff --git a/media/2019/omg-climate/green-mafia.jpg b/media/2019/omg-climate/green-mafia.jpg new file mode 100644 index 0000000..6402e3e Binary files /dev/null and b/media/2019/omg-climate/green-mafia.jpg differ diff --git a/media/2019/omg-climate/low-carbon.jpg b/media/2019/omg-climate/low-carbon.jpg new file mode 100644 index 0000000..0111bce Binary files /dev/null and b/media/2019/omg-climate/low-carbon.jpg differ diff --git a/media/2019/omg-climate/presentation.jpg b/media/2019/omg-climate/presentation.jpg new file mode 100644 index 0000000..7f35a23 Binary files /dev/null and b/media/2019/omg-climate/presentation.jpg differ diff --git a/media/2020/bullet-journal.jpg b/media/2020/bullet-journal.jpg new file mode 100644 index 0000000..e21f89e Binary files /dev/null and b/media/2020/bullet-journal.jpg differ diff --git a/misc/index.html b/misc/index.html new file mode 100644 index 0000000..143e1e3 --- /dev/null +++ b/misc/index.html @@ -0,0 +1 @@ +Misc(ellaneous) | DiƩssica Gurskas
September 20, 2024

Misc(ellaneous)

Open to work šŸ•Šļø

Beyond my silly online presence, Iā€™m a multidisciplinary creative partner in projects and can likely assist you from idea to launch! With over a decade of experience as a computer programmer, Iā€™ve honed my skills in web development, led engineering teams, managed projects, and even designed UI/UX. Just get in touch :-)

Get in touch

Iā€™m happy to hear from most humans on most things. Say hi!

  • Bluesky for silly stuff.
  • Plain text email: hey@diessi.ca.
  • Signal for serious stuff. ā­ Preferred as itā€™s encrypted ā­
    • Donā€™t have my Signal? Please email me with your name and your reason to contact me.

Metadata

Viewable with any browserBest viewed in hi-colors 800x600 screensThis site is certified 100% cookie-freeValid RSSTrapped inside da webGitHub

This is my independent home on the internet. On my blog, I try to share knowledge and perspectives on what I find interesting ā€“ sometimes computers. When I write, please assume IMHO/IMNHSO and openness for dialogue.

You may receive my blog updates by subscribing to my RSS Feed.

License & Attribution

Your Privacy

\ No newline at end of file diff --git a/robots.txt b/robots.txt new file mode 100644 index 0000000..3e65b64 --- /dev/null +++ b/robots.txt @@ -0,0 +1,44 @@ +User-agent: * +Allow: / + +# https://github.com/ai-robots-txt/ai.robots.txt +User-agent: GPTBot +User-agent: WellKnownBot +User-agent: The Knowledge AI +User-agent: AI2Bot +User-agent: Ai2Bot-Dolma +User-agent: Amazonbot +User-agent: Applebot +User-agent: Applebot-Extended +User-agent: Bytespider +User-agent: CCBot +User-agent: ChatGPT-User +User-agent: Claude-Web +User-agent: ClaudeBot +User-agent: Diffbot +User-agent: FacebookBot +User-agent: FriendlyCrawler +User-agent: Google-Extended +User-agent: GoogleOther +User-agent: GoogleOther-Image +User-agent: GoogleOther-Video +User-agent: ICC-Crawler +User-agent: ImagesiftBot +User-agent: Meta-ExternalAgent +User-agent: Meta-ExternalFetcher +User-agent: OAI-SearchBot +User-agent: PerplexityBot +User-agent: PetalBot +User-agent: Scrapy +User-agent: Timpibot +User-agent: VelenPublicWebCrawler +User-agent: Webzio-Extended +User-agent: YouBot +User-agent: anthropic-ai +User-agent: cohere-ai +User-agent: facebookexternalhit +User-agent: iaskspider/2.0 +User-agent: img2dataset +User-agent: omgili +User-agent: omgilibot +Disallow: / \ No newline at end of file diff --git a/sitemap.xml b/sitemap.xml new file mode 100644 index 0000000..18a8c09 --- /dev/null +++ b/sitemap.xml @@ -0,0 +1,267 @@ + + + + / + + + /blog/ + + + /blog/5-bibliotecas-essenciais-para-desenvolver-react-apps/ + 2016-03-21T23:00:00 + + + /blog/a-better-es2015-and-jsx-workflow-in-vs-code/ + 2016-10-30T00:00:00 + + + /blog/a-bit-on-random-numbers-in-javascript/ + 2016-11-15T16:50:00 + + + /blog/a-cascata-das-variaveis-do-css/ + 2016-05-30T22:00:00 + + + /blog/a-fantastica-diversidade-do-front-end/ + 2016-04-09T15:10:00 + + + /blog/a-guide-to-favicons-and-touch-icons/ + 2015-09-06T10:53:00 + + + /blog/a-minimal-workspace-on-macos/ + 2017-05-04T19:45:57 + + + /blog/archive/i-travelled-to-photographs/ + 2017-04-19T10:13:00 + + + /blog/catalysis/ + 2017-04-13T11:27:00 + + + /blog/choose-life-in-berlin/ + 2017-05-12T19:15:00 + + + /blog/como-eu-vi-a-braziljs-2015/ + 2015-08-26T02:10:32 + + + /blog/computer-and-human-languages/ + 2018-06-20T18:06:00 + + + /blog/creativity/ + 2018-02-05T21:25:00 + + + /blog/dental-health-and-habits/ + 2017-12-21T08:58:09 + + + /blog/desmitificando-seletores-complexos/ + 2013-11-28 + + + /blog/dont-blame-it-on-react-or-redux/ + 2017-03-18T13:49:00 + + + /blog/encadeamento-de-metodos-em-javascript/ + 2016-08-06T16:11:32 + + + /blog/expressive-javascript-conditionals/ + 2017-10-30 + + + /blog/fetch-npm-package-without-npm-install/ + 2024-08-25T16:30:00 + + + /blog/guitar-rig-macos-mojave-setup/ + 2019-08-18T22:19:05 + + + /blog/horizontal-and-vertical-align-anything-with-css/ + 2016-11-06T19:10:01 + + + /blog/how-i-lock-my-bike-in-berlin/ + 2018-08-30T07:00:00 + + + /blog/how-to-exclude-css-images-anything-from-unit-tests/ + 2016-11-19T09:54:29 + + + /blog/how-to-spy-on-a-prop-with-jest/ + 2019-10-31T14:15:42 + + + /blog/i-m-tired-of-beautiful-looking-interfaces/ + 2016-10-23T12:50:35 + + + /blog/isolation-tank/ + 2018-12-02T08:01:00 + + + /blog/journaling/ + 2020-04-20T00:10:15 + + + /blog/learning-vim/ + 2024-09-29T14:00:15 + + + /blog/long-time-no-see/ + 2023-06-30T11:19:00 + + + /blog/mass-deleting-files-from-slack/ + 2016-04-17T00:10:15 + + + /blog/multiline-sass-comments/ + 2015-08-17 + + + /blog/my-hacking-adventure-in-lithuania/ + 2018-02-15 + + + /blog/o-css-do-futuro/ + 2016-05-29T23:21:51 + + + /blog/o-que-ha-de-errado-com-a-cultura-jquery/ + 2015-09-20T09:56:05 + + + /blog/o-til-no-javascript/ + 2015-10-31 + + + /blog/omg-climate/ + 2019-05-30T11:39:14 + + + /blog/react-and-form-management-is-redux-form-worth-it/ + 2018-05-21T18:14:00 + + + /blog/shared-variables-between-javascript-and-css/ + 2017-01-15T15:00:00 + + + /blog/svg-images-as-react-components-with-webpack/ + 2016-08-02T22:00:00 + + + /blog/tchau/ + 2017-05-13T16:12:00 + + + /blog/the-bitter-reality-of-ebooks/ + 2023-08-16T13:55:00 + + + /blog/ttt/ + 2018-04-01T23:36:00 + + + /blog/ui-components-that-abstract-mistakes/ + 2017-10-14T18:06:00 + + + /blog/var-that-this-nah/ + 2017-03-15T09:00:00 + + + /blog/we-misunderstand-learning/ + 2024-09-19T13:13:42 + + + /blog/working-better-with-git-for-a-clear-history/ + 2018-08-04T07:00:00 + + + /blog/writing-mode-in-vs-code/ + 2018-02-28T02:30:00 + + + /misc/ + 2024-09-20T11:02:00 + + + /tags/ + + + /tags/activism/ + + + /tags/books/ + + + /tags/climate-change/ + + + /tags/css/ + + + /tags/design/ + + + /tags/digital-rights/ + + + /tags/essay/ + + + /tags/html/ + + + /tags/javascript/ + + + /tags/language/ + + + /tags/music/ + + + /tags/personal/ + + + /tags/productivity/ + + + /tags/pt-br/ + + + /tags/react/ + + + /tags/script/ + + + /tags/software/ + + + /tags/test/ + + + /tags/travel/ + + + /tags/work/ + + + /tags/workflow/ + + diff --git a/tags/activism/index.html b/tags/activism/index.html new file mode 100644 index 0000000..a215e7d --- /dev/null +++ b/tags/activism/index.html @@ -0,0 +1 @@ +
diessi.caBlogMisc
Tag: activism

OMG Climate: Reflecting Together on the Climate Catastrophe

[current_path](/tags/activism/)
\ No newline at end of file diff --git a/tags/books/index.html b/tags/books/index.html new file mode 100644 index 0000000..b4b9f63 --- /dev/null +++ b/tags/books/index.html @@ -0,0 +1 @@ +
diessi.caBlogMisc
Tag: books

The Bitter Reality of Ebooks and the Kindle Model

[current_path](/tags/books/)
\ No newline at end of file diff --git a/tags/climate-change/index.html b/tags/climate-change/index.html new file mode 100644 index 0000000..8828ba8 --- /dev/null +++ b/tags/climate-change/index.html @@ -0,0 +1 @@ +
diessi.caBlogMisc
Tag: climate change

OMG Climate: Reflecting Together on the Climate Catastrophe

[current_path](/tags/climate-change/)
\ No newline at end of file diff --git a/tags/css/index.html b/tags/css/index.html new file mode 100644 index 0000000..18fec13 --- /dev/null +++ b/tags/css/index.html @@ -0,0 +1 @@ +
diessi.caBlogMisc
Tag: css

Shared Variables Between JavaScript and CSS

Horizontal and Vertical Align Anything with CSS

A Cascata das VariƔveis do CSS

O CSS do Futuro

Multiline Sass Comments

Desmitificando Seletores Complexos

[current_path](/tags/css/)
\ No newline at end of file diff --git a/tags/design/index.html b/tags/design/index.html new file mode 100644 index 0000000..dbfe25d --- /dev/null +++ b/tags/design/index.html @@ -0,0 +1 @@ +
diessi.caBlogMisc
Tag: design

I'm Tired of Beautiful-Looking User Interfaces

[current_path](/tags/design/)
\ No newline at end of file diff --git a/tags/digital-rights/index.html b/tags/digital-rights/index.html new file mode 100644 index 0000000..ad93a49 --- /dev/null +++ b/tags/digital-rights/index.html @@ -0,0 +1 @@ +
diessi.caBlogMisc
Tag: digital rights

The Bitter Reality of Ebooks and the Kindle Model

[current_path](/tags/digital-rights/)
\ No newline at end of file diff --git a/tags/essay/index.html b/tags/essay/index.html new file mode 100644 index 0000000..00a0fcc --- /dev/null +++ b/tags/essay/index.html @@ -0,0 +1 @@ +
diessi.caBlogMisc
Tag: essay

Creativity

[current_path](/tags/essay/)
\ No newline at end of file diff --git a/tags/html/index.html b/tags/html/index.html new file mode 100644 index 0000000..4069baa --- /dev/null +++ b/tags/html/index.html @@ -0,0 +1 @@ +
diessi.caBlogMisc
Tag: html

UI Components that Abstract Mistakes

A Guide to Favicons and Touch Icons

[current_path](/tags/html/)
\ No newline at end of file diff --git a/tags/index.html b/tags/index.html new file mode 100644 index 0000000..84717fc --- /dev/null +++ b/tags/index.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/tags/javascript/index.html b/tags/javascript/index.html new file mode 100644 index 0000000..f8f753a --- /dev/null +++ b/tags/javascript/index.html @@ -0,0 +1 @@ +
diessi.caBlogMisc
Tag: javascript

React and Form Management: Is Redux Form Worth It?

Expressive JavaScript Conditionals (for Humans)

UI Components that Abstract Mistakes

Don't Blame it on React or Redux

var that = this? Nah.

Shared Variables Between JavaScript and CSS

How to Exclude CSS, Images, Anything from Unit Tests

A Bit on Random Numbers in JavaScript

Encadeamento de MĆ©todos em JavaScript

SVG Images as React Components with Webpack

5 Bibliotecas Essenciais para Desenvolver React Apps

O Til no JavaScript

O Que HĆ” de Errado com a "Cultura jQuery"

[current_path](/tags/javascript/)
\ No newline at end of file diff --git a/tags/language/index.html b/tags/language/index.html new file mode 100644 index 0000000..8a630ae --- /dev/null +++ b/tags/language/index.html @@ -0,0 +1 @@ +
diessi.caBlogMisc
Tag: language

Computer and Human Languages

[current_path](/tags/language/)
\ No newline at end of file diff --git a/tags/music/index.html b/tags/music/index.html new file mode 100644 index 0000000..21a9e7f --- /dev/null +++ b/tags/music/index.html @@ -0,0 +1 @@ +
diessi.caBlogMisc
Tag: music

Setup for Audio Interface with Guitar Rig 5 on macOS Mojave

[current_path](/tags/music/)
\ No newline at end of file diff --git a/tags/personal/index.html b/tags/personal/index.html new file mode 100644 index 0000000..86240cd --- /dev/null +++ b/tags/personal/index.html @@ -0,0 +1 @@ +
diessi.caBlogMisc
Tag: personal

Long Time No See

What I've Learned by Simply Journaling

I've Sensory-Deprived Myself In a Tank

How I Lock My Bike in Berlin

T. T. T.

My Hacking Adventure in Lithuania

Dental Health and Habits

Tchau

Choose Life šŸ‡©šŸ‡Ŗ

I Travelled to Photographs

Catalysis

I'm Tired of Beautiful-Looking User Interfaces

Como Eu Vi a BrazilJS 2015

[current_path](/tags/personal/)
\ No newline at end of file diff --git a/tags/productivity/index.html b/tags/productivity/index.html new file mode 100644 index 0000000..669b552 --- /dev/null +++ b/tags/productivity/index.html @@ -0,0 +1 @@ +
diessi.caBlogMisc
Tag: productivity

What I've Learned by Simply Journaling

A Minimal Workspace on macOS

[current_path](/tags/productivity/)
\ No newline at end of file diff --git a/tags/pt-br/index.html b/tags/pt-br/index.html new file mode 100644 index 0000000..839c25d --- /dev/null +++ b/tags/pt-br/index.html @@ -0,0 +1 @@ +
diessi.caBlogMisc
Tag: pt-BR

Tchau

Encadeamento de MĆ©todos em JavaScript

A Cascata das VariƔveis do CSS

O CSS do Futuro

A FantƔstica Diversidade do Front-end

5 Bibliotecas Essenciais para Desenvolver React Apps

O Til no JavaScript

O Que HĆ” de Errado com a "Cultura jQuery"

Como Eu Vi a BrazilJS 2015

Desmitificando Seletores Complexos

[current_path](/tags/pt-br/)
\ No newline at end of file diff --git a/tags/react/index.html b/tags/react/index.html new file mode 100644 index 0000000..a8de723 --- /dev/null +++ b/tags/react/index.html @@ -0,0 +1 @@ +
diessi.caBlogMisc
Tag: react

How to Spy on a React Prop with Jest

React and Form Management: Is Redux Form Worth It?

Don't Blame it on React or Redux

How to Exclude CSS, Images, Anything from Unit Tests

A Better ES2015+ and JSX Workflow in VS Code

SVG Images as React Components with Webpack

5 Bibliotecas Essenciais para Desenvolver React Apps

[current_path](/tags/react/)
\ No newline at end of file diff --git a/tags/script/index.html b/tags/script/index.html new file mode 100644 index 0000000..fca9408 --- /dev/null +++ b/tags/script/index.html @@ -0,0 +1 @@ +
diessi.caBlogMisc
Tag: script

Mass Deleting Files from Slack

[current_path](/tags/script/)
\ No newline at end of file diff --git a/tags/software/index.html b/tags/software/index.html new file mode 100644 index 0000000..0c1ce5d --- /dev/null +++ b/tags/software/index.html @@ -0,0 +1 @@ +
diessi.caBlogMisc
Tag: software

Working Better with Git for a Clear History

Computer and Human Languages

[current_path](/tags/software/)
\ No newline at end of file diff --git a/tags/test/index.html b/tags/test/index.html new file mode 100644 index 0000000..5d07431 --- /dev/null +++ b/tags/test/index.html @@ -0,0 +1 @@ +
diessi.caBlogMisc
Tag: test

How to Exclude CSS, Images, Anything from Unit Tests

[current_path](/tags/test/)
\ No newline at end of file diff --git a/tags/travel/index.html b/tags/travel/index.html new file mode 100644 index 0000000..f2c6483 --- /dev/null +++ b/tags/travel/index.html @@ -0,0 +1 @@ +
diessi.caBlogMisc
Tag: travel

I Travelled to Photographs

[current_path](/tags/travel/)
\ No newline at end of file diff --git a/tags/work/index.html b/tags/work/index.html new file mode 100644 index 0000000..8d5abda --- /dev/null +++ b/tags/work/index.html @@ -0,0 +1 @@ +
diessi.caBlogMisc
Tag: work

A FantƔstica Diversidade do Front-end

[current_path](/tags/work/)
\ No newline at end of file diff --git a/tags/workflow/index.html b/tags/workflow/index.html new file mode 100644 index 0000000..d7b7312 --- /dev/null +++ b/tags/workflow/index.html @@ -0,0 +1 @@ +
diessi.caBlogMisc
Tag: workflow

Writing Mode in VS Code

A Better ES2015+ and JSX Workflow in VS Code

[current_path](/tags/workflow/)
\ No newline at end of file