<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Peter Piekarczyk RSS Feed]]></title><description><![CDATA[Peter Piekarczyk - Engineer, Investor, Advisor. Building Backpack for mobile]]></description><link>https://peterp.me</link><generator>GatsbyJS</generator><lastBuildDate>Mon, 04 May 2026 23:55:40 GMT</lastBuildDate><atom:link href="https://peterp.me/rss.xml" rel="self" type="application/rss+xml"/><item><title><![CDATA[How react-native-ease runs animations with no JavaScript loop]]></title><description><![CDATA[A deep dive into how react-native-ease hands animations entirely to Core Animation on iOS and ObjectAnimator on Android, with zero per-frame JavaScript involvement.]]></description><link>https://peterp.me/articles/how-react-native-ease-runs-animations-with-no-javascript-loop/</link><guid isPermaLink="false">https://peterp.me/articles/how-react-native-ease-runs-animations-with-no-javascript-loop/</guid><dc:creator><![CDATA[Peter Piekarczyk]]></dc:creator><pubDate>Wed, 29 Apr 2026 06:00:00 GMT</pubDate><content:encoded>&lt;p&gt;The &lt;a href=&quot;https://appandflow.com/&quot;&gt;AppAndFlow&lt;/a&gt; team released an amazing animation library called &lt;a href=&quot;https://github.com/AppAndFlow/react-native-ease&quot;&gt;react-native-ease&lt;/a&gt;. Here’s a deep dive into how it works under the hood.&lt;/p&gt;
&lt;p&gt;Most React Native animation libraries work the same way under the hood: a JavaScript timer drives a value, that value crosses the bridge (or JSI) every frame, and the native view updates in response. It works, but animation fidelity is tied to the health of the JS thread. Drop a frame processing a list, and your animation stutters.&lt;/p&gt;
&lt;p&gt;react-native-ease takes a different approach. Once you hand it a prop change, JavaScript is done. The animation runs entirely on the native side using Core Animation on iOS and ObjectAnimator and SpringAnimation on Android, with no JS involvement per frame.&lt;/p&gt;
&lt;p&gt;Here’s how it actually works.&lt;/p&gt;
&lt;h2 id=&quot;the-js-layer-does-one-thing-flatten-props&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#the-js-layer-does-one-thing-flatten-props&quot; aria-label=&quot;the js layer does one thing flatten props permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The JS layer does one thing: flatten props&lt;/h2&gt;
&lt;p&gt;The &lt;code class=&quot;language-text&quot;&gt;EaseView&lt;/code&gt; component is a pure render function. It takes structured props like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;tsx&quot;&gt;&lt;pre class=&quot;language-tsx&quot;&gt;&lt;code class=&quot;language-tsx&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;EaseView&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token attr-name&quot;&gt;animate&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; opacity&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; scale&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1.2&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token attr-name&quot;&gt;transition&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;spring&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; damping&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;15&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; stiffness&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;120&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And flattens them into individual scalar native props:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;animateOpacity=0.5
animateScaleX=1.2
animateScaleY=1.2
transitions.defaultConfig = { type:&quot;spring&quot;, damping:15, stiffness:120, ... }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;There’s no &lt;code class=&quot;language-text&quot;&gt;useEffect&lt;/code&gt;, no &lt;code class=&quot;language-text&quot;&gt;useRef&lt;/code&gt;, no animation state. It’s a prop resolver. The interesting part is the bitmask.&lt;/p&gt;
&lt;h3 id=&quot;the-bitmask&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#the-bitmask&quot; aria-label=&quot;the bitmask permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The bitmask&lt;/h3&gt;
&lt;p&gt;React Native’s codegen doesn’t support nullable primitives cleanly. You can’t send &lt;code class=&quot;language-text&quot;&gt;null&lt;/code&gt; for a &lt;code class=&quot;language-text&quot;&gt;Float&lt;/code&gt; prop. So when &lt;code class=&quot;language-text&quot;&gt;opacity&lt;/code&gt; isn’t in your &lt;code class=&quot;language-text&quot;&gt;animate&lt;/code&gt; prop, JS still has to send &lt;em&gt;something&lt;/em&gt; for &lt;code class=&quot;language-text&quot;&gt;animateOpacity&lt;/code&gt;. It sends the identity value: &lt;code class=&quot;language-text&quot;&gt;1.0&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;But now native has a problem: it can’t tell whether &lt;code class=&quot;language-text&quot;&gt;animateOpacity: 1.0&lt;/code&gt; means “the user animated opacity to 1” or “the user didn’t animate opacity at all and this is just the default.” Both look identical.&lt;/p&gt;
&lt;p&gt;The solution is a single extra &lt;code class=&quot;language-text&quot;&gt;Int32&lt;/code&gt; prop called &lt;code class=&quot;language-text&quot;&gt;animatedProperties&lt;/code&gt;, where each bit flags one property:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;bit 0 = opacity
bit 1 = translateX
bit 2 = translateY
bit 3 = scaleX
...&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If opacity is in your &lt;code class=&quot;language-text&quot;&gt;animate&lt;/code&gt; prop, bit 0 is set. Native checks &lt;code class=&quot;language-text&quot;&gt;mask &amp;amp; kMaskOpacity&lt;/code&gt; before touching opacity at all. If the bit is off, native ignores the value completely and lets React Native’s normal style system handle it. This lets both systems coexist on the same view without conflict.&lt;/p&gt;
&lt;h2 id=&quot;ios-core-animation-key-path-animations&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#ios-core-animation-key-path-animations&quot; aria-label=&quot;ios core animation key path animations permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;iOS: Core Animation key-path animations&lt;/h2&gt;
&lt;p&gt;The iOS native view (&lt;code class=&quot;language-text&quot;&gt;EaseView.mm&lt;/code&gt;) is a Fabric &lt;code class=&quot;language-text&quot;&gt;RCTViewComponentView&lt;/code&gt;. The main entry point is &lt;code class=&quot;language-text&quot;&gt;updateProps:oldProps:&lt;/code&gt;, which Fabric calls every time JS sends new props.&lt;/p&gt;
&lt;h3 id=&quot;model-layer-vs-presentation-layer&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#model-layer-vs-presentation-layer&quot; aria-label=&quot;model layer vs presentation layer permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Model layer vs. presentation layer&lt;/h3&gt;
&lt;p&gt;Core Animation maintains two parallel copies of every layer. The &lt;em&gt;model layer&lt;/em&gt; is what your code sets and always holds the final target value. The &lt;em&gt;presentation layer&lt;/em&gt; is what’s actually visible on screen during an animation. They’re separate objects.&lt;/p&gt;
&lt;p&gt;This distinction is critical for smooth interruption. If the user triggers a new animation while one is already running, the code reads the current visual position from the presentation layer:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;objc&quot;&gt;&lt;pre class=&quot;language-objc&quot;&gt;&lt;code class=&quot;language-objc&quot;&gt;fromValue&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;self&lt;/span&gt; presentationValueForKeyPath&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;@&quot;opacity&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If it read from the model layer instead, the interrupted animation would snap to the final value and restart from there. Reading from the presentation layer means the new animation starts from exactly wherever the view currently appears, making interruptions seamless.&lt;/p&gt;
&lt;h3 id=&quot;why-transforms-use-individual-key-paths&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#why-transforms-use-individual-key-paths&quot; aria-label=&quot;why transforms use individual key paths permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Why transforms use individual key-paths&lt;/h3&gt;
&lt;p&gt;All transform properties (scale, rotation, translation) could theoretically be combined into a single &lt;code class=&quot;language-text&quot;&gt;CATransform3D&lt;/code&gt; matrix and animated as one. The code explicitly does not do this, and for a good reason.&lt;/p&gt;
&lt;p&gt;Core Animation interpolates matrices by decomposing them back into components. This decomposition is ambiguous in certain cases. A rotation from 0° to 360° produces the same matrix at both endpoints, so Core Animation sees no change and does nothing. A combined scale+rotation can decompose differently depending on the order of operations, producing unexpected visual results.&lt;/p&gt;
&lt;p&gt;By animating individual key-paths like &lt;code class=&quot;language-text&quot;&gt;&quot;transform.rotation.z&quot;&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;&quot;transform.scale.x&quot;&lt;/code&gt;, and &lt;code class=&quot;language-text&quot;&gt;&quot;transform.translation.x&quot;&lt;/code&gt;, each component is interpolated as a plain scalar. 0 to 6.28 radians is unambiguous. The animations compose correctly on the layer without any matrix decomposition.&lt;/p&gt;
&lt;h3 id=&quot;the-first-mount-problem&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#the-first-mount-problem&quot; aria-label=&quot;the first mount problem permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The first mount problem&lt;/h3&gt;
&lt;p&gt;Enter animations (where &lt;code class=&quot;language-text&quot;&gt;initialAnimate&lt;/code&gt; differs from &lt;code class=&quot;language-text&quot;&gt;animate&lt;/code&gt;) can’t fire immediately when &lt;code class=&quot;language-text&quot;&gt;updateProps:&lt;/code&gt; is called on first mount. At that point, Fabric hasn’t finished laying out the view and its frame isn’t set yet. Animating before layout is settled means animating from wrong coordinates.&lt;/p&gt;
&lt;p&gt;So the code defers. It sets a flag in &lt;code class=&quot;language-text&quot;&gt;updateProps:&lt;/code&gt; and waits for &lt;code class=&quot;language-text&quot;&gt;finalizeUpdates:&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;didMoveToWindow&lt;/code&gt;, both of which fire after the view is fully laid out and attached to the window, before applying the enter animation.&lt;/p&gt;
&lt;h3 id=&quot;reading-the-room-overriding-invalidatelayer&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#reading-the-room-overriding-invalidatelayer&quot; aria-label=&quot;reading the room overriding invalidatelayer permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Reading the room: overriding invalidateLayer&lt;/h3&gt;
&lt;p&gt;Fabric has a method on &lt;code class=&quot;language-text&quot;&gt;RCTViewComponentView&lt;/code&gt; called &lt;code class=&quot;language-text&quot;&gt;invalidateLayer&lt;/code&gt;. It’s called internally whenever Fabric needs to re-sync style props back onto the &lt;code class=&quot;language-text&quot;&gt;CALayer&lt;/code&gt;, things like &lt;code class=&quot;language-text&quot;&gt;opacity&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;backgroundColor&lt;/code&gt;, and &lt;code class=&quot;language-text&quot;&gt;cornerRadius&lt;/code&gt; after a layout pass. It’s a reliable, consistent hook that fires exactly when you need it.&lt;/p&gt;
&lt;p&gt;The challenge is that sync clobbers whatever the animation system put there. A background color mid-transition gets reset to the style value.&lt;/p&gt;
&lt;p&gt;Rather than fighting the system, &lt;code class=&quot;language-text&quot;&gt;EaseView&lt;/code&gt; joins it. It overrides &lt;code class=&quot;language-text&quot;&gt;invalidateLayer&lt;/code&gt;, lets super do its job, then re-stamps the animated values:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;objc&quot;&gt;&lt;pre class=&quot;language-objc&quot;&gt;&lt;code class=&quot;language-objc&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;invalidateLayer &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;super&lt;/span&gt; invalidateLayer&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// re-apply our animated values on top&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Fabric tells you when the layer needs updating, so use that signal. It’s a clean handshake between two systems that both want to own the same properties, and it works because the override respects the contract rather than trying to prevent Fabric from running at all.&lt;/p&gt;
&lt;h2 id=&quot;android-objectanimator-springanimation-and-some-physics&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#android-objectanimator-springanimation-and-some-physics&quot; aria-label=&quot;android objectanimator springanimation and some physics permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Android: ObjectAnimator, SpringAnimation, and some physics&lt;/h2&gt;
&lt;p&gt;The Android side uses &lt;code class=&quot;language-text&quot;&gt;ObjectAnimator&lt;/code&gt; for timing-based animations and &lt;code class=&quot;language-text&quot;&gt;androidx.dynamicanimation.SpringAnimation&lt;/code&gt; for physics springs. Getting them to match iOS behavior requires a few non-obvious steps.&lt;/p&gt;
&lt;h3 id=&quot;props-are-batched-not-applied-immediately&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#props-are-batched-not-applied-immediately&quot; aria-label=&quot;props are batched not applied immediately permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Props are batched, not applied immediately&lt;/h3&gt;
&lt;p&gt;On Android, &lt;code class=&quot;language-text&quot;&gt;@ReactProp&lt;/code&gt; setters in &lt;code class=&quot;language-text&quot;&gt;EaseViewManager&lt;/code&gt; don’t trigger animations directly. They write to &lt;code class=&quot;language-text&quot;&gt;pending*&lt;/code&gt; fields on the view. Then &lt;code class=&quot;language-text&quot;&gt;onAfterUpdateTransaction&lt;/code&gt; flushes them all at once via &lt;code class=&quot;language-text&quot;&gt;applyPendingAnimateValues()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This batching is essential. A single React render might change opacity, scale, and translateX simultaneously. Without batching, each &lt;code class=&quot;language-text&quot;&gt;@ReactProp&lt;/code&gt; setter would fire a separate animation decision. With batching, all three changes are seen together, just like how &lt;code class=&quot;language-text&quot;&gt;updateProps:oldProps:&lt;/code&gt; on iOS receives the full old and new props as a pair.&lt;/p&gt;
&lt;h3 id=&quot;deriving-the-spring-damping-ratio&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#deriving-the-spring-damping-ratio&quot; aria-label=&quot;deriving the spring damping ratio permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Deriving the spring damping ratio&lt;/h3&gt;
&lt;p&gt;iOS’s &lt;code class=&quot;language-text&quot;&gt;CASpringAnimation&lt;/code&gt; takes raw physical parameters: &lt;code class=&quot;language-text&quot;&gt;damping&lt;/code&gt; (friction coefficient), &lt;code class=&quot;language-text&quot;&gt;stiffness&lt;/code&gt;, and &lt;code class=&quot;language-text&quot;&gt;mass&lt;/code&gt;. Android’s &lt;code class=&quot;language-text&quot;&gt;SpringForce&lt;/code&gt; takes a &lt;code class=&quot;language-text&quot;&gt;dampingRatio&lt;/code&gt;, a dimensionless 0-1 value where 1.0 means critically damped.&lt;/p&gt;
&lt;p&gt;They’re different quantities, but they describe the same physics. The conversion is:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;kotlin&quot;&gt;&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;dampingRatio &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; damping &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sqrt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;stiffness &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; mass&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is the formula from classical harmonic oscillator mechanics. It means the same &lt;code class=&quot;language-text&quot;&gt;damping&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;stiffness&lt;/code&gt;, and &lt;code class=&quot;language-text&quot;&gt;mass&lt;/code&gt; values produce visually identical springs on both platforms even though the underlying APIs accept different inputs.&lt;/p&gt;
&lt;h3 id=&quot;border-radius-via-viewoutlineprovider&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#border-radius-via-viewoutlineprovider&quot; aria-label=&quot;border radius via viewoutlineprovider permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Border radius via ViewOutlineProvider&lt;/h3&gt;
&lt;p&gt;Android has no direct equivalent of &lt;code class=&quot;language-text&quot;&gt;CALayer.cornerRadius&lt;/code&gt;. Instead, the library uses &lt;code class=&quot;language-text&quot;&gt;ViewOutlineProvider&lt;/code&gt;, a system API where you supply an outline shape, set &lt;code class=&quot;language-text&quot;&gt;clipToOutline = true&lt;/code&gt;, and the render system uses that outline for clipping and shadow rendering.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;kotlin&quot;&gt;&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; animatedOutlineProvider &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;object&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ViewOutlineProvider&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getOutline&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;view&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; View&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; outline&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Outline&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        outline&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setRoundRect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; view&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;width&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; view&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;height&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; _borderRadius&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The outline provider reads &lt;code class=&quot;language-text&quot;&gt;_borderRadius&lt;/code&gt; dynamically and is invalidated every frame during animation. The library switches back to &lt;code class=&quot;language-text&quot;&gt;ViewOutlineProvider.BACKGROUND&lt;/code&gt; when border radius isn’t being animated, so normal style-driven border radius still works when you’re not touching it from &lt;code class=&quot;language-text&quot;&gt;animate&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;camera-distance-normalization&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#camera-distance-normalization&quot; aria-label=&quot;camera distance normalization permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Camera distance normalization&lt;/h3&gt;
&lt;p&gt;For 3D rotations (&lt;code class=&quot;language-text&quot;&gt;rotateX&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;rotateY&lt;/code&gt;), Android’s API takes a &lt;code class=&quot;language-text&quot;&gt;cameraDistance&lt;/code&gt; value that controls perspective. The conversion from the CSS &lt;code class=&quot;language-text&quot;&gt;perspective&lt;/code&gt; prop isn’t a direct pass-through:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;kotlin&quot;&gt;&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;cameraDistance &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; density &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; density &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; perspective &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sqrt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code class=&quot;language-text&quot;&gt;sqrt(5)&lt;/code&gt; factor matches a specific normalization React Native applies internally to make CSS perspective values visually consistent across screen densities. Without it, a &lt;code class=&quot;language-text&quot;&gt;rotateY&lt;/code&gt; on this view would look different from a &lt;code class=&quot;language-text&quot;&gt;rotateY&lt;/code&gt; on a standard React Native view at the same perspective value.&lt;/p&gt;
&lt;h2 id=&quot;the-result&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#the-result&quot; aria-label=&quot;the result permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The result&lt;/h2&gt;
&lt;p&gt;No JS animation loop. No worklets. No C++ runtime. When a prop change arrives at native, one of two things happens: a &lt;code class=&quot;language-text&quot;&gt;CAAnimation&lt;/code&gt; gets added to a &lt;code class=&quot;language-text&quot;&gt;CALayer&lt;/code&gt;, or an &lt;code class=&quot;language-text&quot;&gt;ObjectAnimator&lt;/code&gt; starts running. From that point, the render thread handles everything. The JS thread can be completely blocked and the animation continues uninterrupted.&lt;/p&gt;
&lt;p&gt;The tradeoff is that the animatable property set is fixed. You can only animate what the native layer understands natively. But for the properties that matter most (opacity, transform, color, border radius), it’s about as low-level as you can get in React Native without writing a custom renderer.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[What's actually happening inside Legend List]]></title><description><![CDATA[An interactive simulator showing how Legend List decides what to render, how many containers to create, and where the scroll buffer zones land.]]></description><link>https://peterp.me/articles/legend-list-engine-simulator/</link><guid isPermaLink="false">https://peterp.me/articles/legend-list-engine-simulator/</guid><dc:creator><![CDATA[Peter Piekarczyk]]></dc:creator><pubDate>Tue, 29 Apr 2025 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I’ve been working on &lt;a href=&quot;https://github.com/LegendApp/legend-list&quot;&gt;Legend List&lt;/a&gt; and kept running into the same questions. How many containers does it actually create? Why does fast scrolling sometimes show blank space? Where exactly does it stop rendering items?&lt;/p&gt;
&lt;p&gt;The answers are all in a small set of formulas that run on every scroll event. So I built a simulator that lets you poke at them directly.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/legend-list-simulator/&quot;&gt;Open the Legend List Engine Simulator&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;the-three-props-worth-understanding&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#the-three-props-worth-understanding&quot; aria-label=&quot;the three props worth understanding permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The three props worth understanding&lt;/h2&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;estimatedItemSize&lt;/code&gt; is your best guess at the average item height. It feeds directly into how many containers get allocated at startup. Get it too low and you’ll create more containers than you need. Get it way off and you’ll see blank flashes during fast scrolls.&lt;/p&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;drawDistance&lt;/code&gt; is how far outside the visible viewport Legend List pre-renders items. The engine doesn’t split that budget evenly though. It allocates 1.5x in the direction you’re scrolling and only 0.5x behind you. Flip the scroll direction in the simulator and you can watch the buffer zones shift sides in real time.&lt;/p&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;initialContainerPoolRatio&lt;/code&gt; is a multiplier on top of that. Those extra containers sit idle but they’re pre-created React components, ready to activate the moment something scrolls into range without triggering a new render. That’s what the container pool column in the simulator is showing you.&lt;/p&gt;
&lt;h2 id=&quot;the-formula&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#the-formula&quot; aria-label=&quot;the formula permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The formula&lt;/h2&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;numContainers = ceil(
  ((viewportHeight - headerSize + drawDistance × 2) / avgItemSize) × numColumns
)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Drag &lt;code class=&quot;language-text&quot;&gt;drawDistance&lt;/code&gt; up and watch &lt;code class=&quot;language-text&quot;&gt;numContainers&lt;/code&gt; climb. Add columns and it multiplies. Increase &lt;code class=&quot;language-text&quot;&gt;estimatedItemSize&lt;/code&gt; and it drops. Everything in the simulator feeds into this.&lt;/p&gt;
&lt;p&gt;There’s also a &lt;code class=&quot;language-text&quot;&gt;maxVisibleArea&lt;/code&gt; cutoff, which sits 1000px past the bottom buffer. Items beyond that aren’t positioned at all. That’s what keeps things fast on long lists.&lt;/p&gt;
&lt;p&gt;The formulas in the simulator match the real source in &lt;a href=&quot;https://github.com/LegendApp/legend-list/blob/main/src/core/doInitialAllocateContainers.ts&quot;&gt;doInitialAllocateContainers.ts&lt;/a&gt; and &lt;a href=&quot;https://github.com/LegendApp/legend-list/blob/main/src/core/calculateItemsInView.ts&quot;&gt;calculateItemsInView.ts&lt;/a&gt;.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[It will take much longer than you think to build a company]]></title><description><![CDATA[An honest look at how founders consistently underestimate timelines — from landing the first customer to building something truly sustainable.]]></description><link>https://peterp.me/articles/it-will-take-longer-than-you-think/</link><guid isPermaLink="false">https://peterp.me/articles/it-will-take-longer-than-you-think/</guid><dc:creator><![CDATA[Peter Piekarczyk]]></dc:creator><pubDate>Wed, 09 Aug 2023 05:00:00 GMT</pubDate><content:encoded>&lt;p&gt;One of the most overlooked parts of building a business is time. From the time it takes to close your first customer to the time it takes to build something sustainable.&lt;/p&gt;
&lt;p&gt;Chances are, you’re going to underestimate your timelines.&lt;/p&gt;
&lt;p&gt;If you think you’re going to build a successful business overnight, your first year or even your third, especially if you’ve never done it before, you’re setting yourself up for failure.&lt;/p&gt;
&lt;p&gt;I’m sure you’ve seen the Youtube videos or Twitter posts about some 16yo marketing guru making $1m after a couple of months.&lt;/p&gt;
&lt;p&gt;That is not real.&lt;/p&gt;
&lt;p&gt;Even if there are folks getting to the point of making $1m, it’s taken them &lt;em&gt;years&lt;/em&gt; of trial and error to get there and plenty of failure.&lt;/p&gt;
&lt;p&gt;The beautiful part is, like we constantly see in this community, is that folks figure it out eventually. It can take as few as 4 years or as much as 10 for a business to take off.&lt;/p&gt;
&lt;p&gt;Some folks get a bit of headwind and manage to pull it off earlier. Others win the lottery.&lt;/p&gt;
&lt;p&gt;When you’re in your 2nd year struggling to make any money and you see a friend in the community crushing it, it can suck the wind out of you. The temptation to give up gets real.&lt;/p&gt;
&lt;p&gt;The most important thing you can do in that situation is to keep your eyes on the prize.&lt;/p&gt;
&lt;p&gt;Your time will come, it just won’t come when you expect it to.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[None of it matters until you try]]></title><description><![CDATA[Why the only real way to learn if your business idea works is to stop planning and start trying — even when you feel unprepared.]]></description><link>https://peterp.me/articles/none-of-it-matters-until-you-try/</link><guid isPermaLink="false">https://peterp.me/articles/none-of-it-matters-until-you-try/</guid><dc:creator><![CDATA[Peter Piekarczyk]]></dc:creator><pubDate>Wed, 09 Aug 2023 05:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Building a business is very hard. It’s quite frankly one of the hardest paths to take when it comes to making money. That’s a fact.&lt;/p&gt;
&lt;p&gt;For most of us here, we weren’t trained to become business people. School doesn’t typically set you up for anything like it. Neither do most things in your life.&lt;/p&gt;
&lt;p&gt;Chances are your parents and relatives aren’t successful business owners either.&lt;/p&gt;
&lt;p&gt;No matter where you’re from in the world or what you’ve been through, there will be challenges.&lt;/p&gt;
&lt;p&gt;I believe there’s a mutual respect amongst business owners that went through those challenges on their own. I’ve never met anybody more successful than me who wasn’t willing to help or looked down upon me for even trying.&lt;/p&gt;
&lt;p&gt;That’s because understanding the game and getting a piece of that pie is like reaching the final boss of your favorite video game. Success or not, it comes with respect.&lt;/p&gt;
&lt;p&gt;You might not get it from your friends &amp;#x26; family, but you’ll sure as hell get it from me and anybody else that has made something of themselves.&lt;/p&gt;
&lt;p&gt;As much as your friends &amp;#x26; family will be there to support you, they won’t understand why you’re taking such a big risk when that cushy, high paying job is available.&lt;/p&gt;
&lt;p&gt;Guess what? That cushy job will be there for the rest of your life. Everybody wants to hire an entrepreneur.&lt;/p&gt;
&lt;p&gt;So why not go out and try? Stop thinking about it. Go do it.&lt;/p&gt;
&lt;p&gt;Chances are you’ll fail your first time around but you’ll learn a lot. You’ll learn even more the second time around, but you’ll probably fail too. Your 3rd, 4th, 5th time, however could play another tune.&lt;/p&gt;
&lt;p&gt;But none of that matters unless you go out and try.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[The Power of patience in software]]></title><description><![CDATA[The underrated skill that separates good engineers from great ones: slowing down to fully understand a problem before jumping to a solution.]]></description><link>https://peterp.me/articles/patience-in-software/</link><guid isPermaLink="false">https://peterp.me/articles/patience-in-software/</guid><dc:creator><![CDATA[Peter Piekarczyk]]></dc:creator><pubDate>Fri, 04 Aug 2023 19:19:12 GMT</pubDate><content:encoded>&lt;p&gt;I think the secret to becoming a great software engineer is actually really easy, but often overlooked.&lt;/p&gt;
&lt;p&gt;When your lawnmower stops working, you wouldn’t just throw it away would you?&lt;/p&gt;
&lt;p&gt;You’d start some initial troubleshooting: is it out of gas? Is the spark plug dead? Are the blades spinning?&lt;/p&gt;
&lt;p&gt;Throwing it all away and starting over every time would be a waste of money and not practical.&lt;/p&gt;
&lt;p&gt;Software engineering is a bit different. Here, instead of money, it’s all about time.&lt;/p&gt;
&lt;p&gt;Despite making bank, many software engineers often struggle to value their time.&lt;/p&gt;
&lt;p&gt;Instead of taking a step back to understand what’s going on, you might start ripping it all apart and rewriting it.&lt;/p&gt;
&lt;p&gt;Been there, done that? I know I have.&lt;/p&gt;
&lt;p&gt;Maybe it’s because you think the code is too messy or hard to understand.&lt;/p&gt;
&lt;p&gt;Or maybe you just want to feel productive and think fingers to keyboard will get you there.&lt;/p&gt;
&lt;p&gt;So there you are, 2 days into your rewrite. The bug’s still there, even though the feels neater to you.&lt;/p&gt;
&lt;p&gt;Sometimes, you get lucky and just happen to replace the bug. Other times, not so much 😬&lt;/p&gt;
&lt;p&gt;Instead of understanding what was already there, you decided to replace it! Why?&lt;/p&gt;
&lt;p&gt;Learning how to read &amp;#x26; understand code effectively is one of the most widely overlooked skills by schools and bootcamps because it’s assumed that by writing it, you can read it too!&lt;/p&gt;
&lt;p&gt;In the real world however, most of your time is spent reading it, so without the proper foundation, you act out of desperation until it gets figured out.&lt;/p&gt;
&lt;p&gt;Abraham Lincoln once said, “Give me six hours to chop down a tree and I will spend the first four sharpening the axe.”&lt;/p&gt;
&lt;p&gt;This quote is very relevant when it comes to software. Spending time understanding the problem isn’t a waste—it’s necessary. It helps us come up with better solutions.&lt;/p&gt;
&lt;p&gt;So the question burning inside of you is, how do I do that?&lt;/p&gt;
&lt;p&gt;Well, it’s easy and hard at the same time. Start by reading each line of code.&lt;/p&gt;
&lt;p&gt;Don’t just skim it! The million dollar bugs are usually because of just one misplaced character.&lt;/p&gt;
&lt;p&gt;Log everything. I can’t stress this enough.&lt;/p&gt;
&lt;p&gt;Programs have all sorts of side effects (unfortunately) so even when the code reads linearly, you may uncover a glacier of complexity.&lt;/p&gt;
&lt;p&gt;Lastly, run that debugger and walk through each step. For the same reason logs are important, you never know where you’ll end up.&lt;/p&gt;
&lt;p&gt;So, if you want to be a great software engineer, start valuing the time you spend understanding problems.&lt;/p&gt;
&lt;p&gt;Take a step back, figure out how it works first and then decide how to fix it.&lt;/p&gt;
&lt;p&gt;It’s not just about coding, but also understanding.&lt;/p&gt;
&lt;p&gt;In software patience isn’t just a good thing—it’s a must-have.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[What it means to want it badly enough]]></title><description><![CDATA[What 'wanting it badly enough' actually means in practice for founders and builders — turning abstract motivation into concrete, consistent action.]]></description><link>https://peterp.me/articles/what-it-means-to-want-it-badly-enough/</link><guid isPermaLink="false">https://peterp.me/articles/what-it-means-to-want-it-badly-enough/</guid><dc:creator><![CDATA[Peter Piekarczyk]]></dc:creator><pubDate>Wed, 26 Jul 2023 05:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I was recently asked what it means to “want it badly enough” in a sub-comment on Reddit and I thought I’d share my response with everyone here as a post.&lt;/p&gt;
&lt;p&gt;A little about me:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I started a consulting business when I was 12 selling logos and websites on eBay&lt;/li&gt;
&lt;li&gt;I ran an agency that generated 40k/mo before I took the plunge into SaaS&lt;/li&gt;
&lt;li&gt;I founded a YC-backed startup called Draftbit that made it easy for folks to build mobile apps visually&lt;/li&gt;
&lt;li&gt;Now I’m working on a new mobile app called Backpack&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I’m 33. I’m the oldest son of Polish immigrants that escaped communism in the late 70s that found their way to Chicago. My mom worked hard at home, my dad worked hard in a factory.&lt;/p&gt;
&lt;p&gt;Like many of you, I’ve had to learn “the hard way” what it means to be an an entrepreneur and quite frankly, I still don’t know if I really know what I’m doing, but I know I want it badly enough to keep going.&lt;/p&gt;
&lt;p&gt;My parents have been here for 40 years, barely know English yet are remarkably successful for starting with nothing. Their real estate investments will allow them to retire and gave us kids a shot at 10x the life they fought hard for.&lt;/p&gt;
&lt;p&gt;When folks say the US is “the land of opportunity” I’ve realized that phrase speaks to the men &amp;#x26; women with the fundamental skills that build great enterprises. They were either born with it, were lucky enough to be mentored or wanted it badly enough they got there by sheer determination.&lt;/p&gt;
&lt;p&gt;Naval makes the point that you could drop him into any foreign country and he’d be successful again 5-10 years later. I believe this and I also believe that it is a skill you can learn. It might be the hardest skill of all, however.&lt;/p&gt;
&lt;p&gt;My friend’s dad taught him everything he knew about building a real estate empire.&lt;/p&gt;
&lt;p&gt;Paul Graham taught Alexis Ohanian and the Collison brothers how to build internet companies.&lt;/p&gt;
&lt;p&gt;That leaves all the rest of us who don’t have parental connections or mentors.&lt;/p&gt;
&lt;p&gt;Whether you come home at 5, 8 or 10pm. Whether you just put your kids to sleep or had a shitty day at work, you’re probably beat. Fatigue is a feeling we all get and all feel in some way or another.&lt;/p&gt;
&lt;p&gt;I know folks that get home at 5pm making 400k/yr+ yet still complain about how unfair life is and spend their night playing Call of Duty.&lt;/p&gt;
&lt;p&gt;I also know immigrants who barely know English delivering groceries to the complainers during the day, then put their kids to sleep and spend the next 2 hours working on getting their construction business off the ground.&lt;/p&gt;
&lt;p&gt;Whether you get thirty minutes or four hours each night, what you do with the time that you have for yourself will define who you’ll become in the future.&lt;/p&gt;
&lt;p&gt;The future you want to build could take 2 years, or realistically 10, but as long as you work at it every day, you’ll get there.&lt;/p&gt;
&lt;p&gt;That defining moment is up to you: “Do I want to figure out how to live the life of my dreams OR do I want to watch Netflix again tonight?”&lt;/p&gt;
&lt;p&gt;Now don’t get me wrong, the chances of an immigrant going from delivering groceries to billions is extremely small, but going from $15/hr and turning that into a 250k/yr construction company is living the dream.&lt;/p&gt;
&lt;p&gt;Becoming an entrepreneur is really hard, but not impossible. It’s especially hard if it’s your first time, you don’t have anyone to learn from, you don’t have a lot of time, you’ve got a family to take care of, the list goes on.&lt;/p&gt;
&lt;p&gt;The first couple of years will be painful. You will fail 100 times over but you will learn from your mistakes and keep going.&lt;/p&gt;
&lt;p&gt;I’ve had friends who were piss broke at 35 that retired at 40. I know someone who started a new company with 3 kids and are on track to hit $1M ARR.&lt;/p&gt;
&lt;p&gt;Some folks figure it out early. Some folks figure it out faster. Some folks get a head start. That’s life. It’s not always fair.&lt;/p&gt;
&lt;p&gt;So what does “wanting it badly enough” mean?&lt;/p&gt;
&lt;p&gt;Wanting it badly enough means instead of watching Netflix tonight, watch a “how to” Youtube video.&lt;/p&gt;
&lt;p&gt;Wanting it badly enough means instead of going to the bar, going to bed early and getting a head start on your day tomorrow.&lt;/p&gt;
&lt;p&gt;Wanting it badly enough means looking past the uphill battles and life’s inevitable unfairness.&lt;/p&gt;
&lt;p&gt;Wanting it badly enough means not feeling sorry for yourself and being resentful at the world for the easy choices that YOU’RE choosing to make.&lt;/p&gt;
&lt;p&gt;Wanting it badly enough means putting in the work every single day.&lt;/p&gt;
&lt;p&gt;I still haven’t figured it out, but I’m working hard to get there making sure every day counts.&lt;/p&gt;
&lt;p&gt;I wrote this out for myself because I too need to be reminded. This is a life long battle and not something that will happen over night. I know through hard work I will get there and I know you will too.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Some thoughts about Practical AI Tooling]]></title><description><![CDATA[Early ideas on what practical AI tooling infrastructure might look like — model hosting, evaluation pipelines, and the product gaps that still exist.]]></description><link>https://peterp.me/articles/practical-ai-tooling/</link><guid isPermaLink="false">https://peterp.me/articles/practical-ai-tooling/</guid><dc:creator><![CDATA[Peter Piekarczyk]]></dc:creator><pubDate>Thu, 06 Jul 2023 00:54:35 GMT</pubDate><content:encoded>&lt;p&gt;I think I have a couple of ideas for what some of the tooling, infrastructure or products around AI might look like in the future. This could already exist but nothing that I’ve heard of quite yet.&lt;/p&gt;
&lt;h2 id=&quot;model-hosting&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#model-hosting&quot; aria-label=&quot;model hosting permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Model Hosting&lt;/h2&gt;
&lt;p&gt;The ability for a user to own their own model. Many of the services you see ask you to upload the same 15-20 photos over &amp;#x26; over and they all share the same model and most likely train it the same way.&lt;/p&gt;
&lt;p&gt;What if we could save ourselves a ton of time &amp;#x26; space and just point to the same model? The “secret sauce” required by these products still exist: they have their own seed phrase, etc but now instead of taking 60-120 minutes training, you just go straight into generating.&lt;/p&gt;
&lt;h2 id=&quot;indexing-service&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#indexing-service&quot; aria-label=&quot;indexing service permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Indexing Service&lt;/h2&gt;
&lt;p&gt;Langchain has made it much easier to build conversational chat bots. There are so many ways of splitting different files, texts, etc that you might spend a lot of time trying to optimize it. If there was one great way to split a markdown file, we’d all use it, but alas, we have 10 different types of text splitters with their own variables, etc.&lt;/p&gt;
&lt;h2 id=&quot;gpu-cloud-services&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#gpu-cloud-services&quot; aria-label=&quot;gpu cloud services permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;GPU Cloud Services&lt;/h2&gt;
&lt;p&gt;You can rent a $35,000 GPU for 50 cents an hour: an incredible achievement. What folks still struggle with is how to train the data you want. There are so many different techniques for training a lora, or checkpoints, etc.&lt;/p&gt;
&lt;p&gt;Instead of having to rent your own GPU, upload your own photos, why don’t you give us all of that and we’ll figure out the most optimal way to do it?&lt;/p&gt;
&lt;h2 id=&quot;pull-request-indexing&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#pull-request-indexing&quot; aria-label=&quot;pull request indexing permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Pull Request Indexing&lt;/h2&gt;
&lt;p&gt;I think it’s fair to say that even Google, the indexing giant, would have a hard time indexing all of your data immediately for consumption. Also, if your knowledge or codebase is private, then nearly impossible to index it at all.&lt;/p&gt;
&lt;p&gt;That means, you will need to create some form of a pipeline to keep your conversational bot up to date. I can imagine creating flows for indexing services to run on pull requests or commits, so the info stays relevant. I can also see a future where we set different markers in our documnetation so these indexing services have a better idea of how to chunk it, etc.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Working with an array of refs in React]]></title><description><![CDATA[How to manage an array of React refs for a dynamic list of inputs, including a pattern for forwarding focus to the next TextInput.]]></description><link>https://peterp.me/articles/react-array-of-refs/</link><guid isPermaLink="false">https://peterp.me/articles/react-array-of-refs/</guid><dc:creator><![CDATA[Peter Piekarczyk]]></dc:creator><pubDate>Sun, 11 Jun 2023 06:00:00 GMT</pubDate><content:encoded>&lt;p&gt;This is how you’d tap “next” to select the next TextInput when you have an arbitrary amount of inputs&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Container&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; items &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; inputRef &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; useRef&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;TextInput&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;View&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;items&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;item&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; index&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;TextInput
          key&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;item&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
          ref&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;node&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;node&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
              inputRef&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;current&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;index&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; node&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
          onSubmitEditing&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; next &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; inputRef&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;current&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;index &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;next&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
              next&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;focus&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;View&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Say that you create a custom TextInput called MyCustomTextInput, you’ll have to forward the ref:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; CustomTextInput &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;forwardRef&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;props&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ref&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;TextInput ref&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;ref&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;props&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Container&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; items &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; inputRef &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; useRef&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;TextInput&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;View&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;items&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;item&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; index&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;CustomTextInput
          key&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;item&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
          ref&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;node&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;node&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
              inputRef&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;current&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;index&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; node&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
          onSubmitEditing&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; next &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; inputRef&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;current&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;index &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;next&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
              next&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;focus&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;View&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That should do it!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Troubleshooting Type Error Load Failed in React Native]]></title><description><![CDATA[How I tracked down and fixed the cryptic TypeError: Load Failed error in a React Native app — what causes it and how to resolve it.]]></description><link>https://peterp.me/articles/react-native-type-error-load-failed/</link><guid isPermaLink="false">https://peterp.me/articles/react-native-type-error-load-failed/</guid><dc:creator><![CDATA[Peter Piekarczyk]]></dc:creator><pubDate>Mon, 13 Feb 2023 06:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I recently struggled with fixing an cryptic error message: &lt;code class=&quot;language-text&quot;&gt;TypeError: Load Failed&lt;/code&gt; in my React Native app.&lt;/p&gt;
&lt;p&gt;I’m running a service worker within a WebView. On iOS, that service worker runs in Safari. Safari has various issues and this is one of them.&lt;/p&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;TypeError: Load Failed&lt;/code&gt; might end up being a different issue for you, but for me it was a CORS related issue.&lt;/p&gt;
&lt;p&gt;Here’s how I figured that out:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Opened Simulator running my app&lt;/li&gt;
&lt;li&gt;Opened Safari&lt;/li&gt;
&lt;li&gt;Top bar: Develop Menu&lt;/li&gt;
&lt;li&gt;Select Simulator&lt;/li&gt;
&lt;li&gt;Select localhost&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 500px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/7636516786e599cf837b711746053524/a331c/type-error-load-failed-safari-develop-menu.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 37.6%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAICAYAAAD5nd/tAAAACXBIWXMAABYlAAAWJQFJUiTwAAACPUlEQVR42gXB20tTAQDA4fOPRPQWQS89BSI9iEQWiM3oMkdIanRDVGS1hqRZubmb287cTd2m23Lajmc3z9xmXoh5SZ0250QqkMJAH+v51/cJWqeeTmMPmt5HtPS2o+ltp7mzBVWXGlX3A+50q1FrW7nxpIlL6qvUPbtPY4eG+ocqbrU0U6Nq4Pmgnq4P/byymhFGCyLO5DD+jIeAMsWEMkVgIYA358WTc+NTXEwsetEGdZy7e4HLbde5pmnifM0Vam82cLGuFpWuj9m1Xb5UviOY5H7G8gaiSx7cCRfWGRvm+DCWOQMjcyZcaSuOrA1T3MQb8TVq/T0ev31Km64bs28ESZlDbzYRysyzdVRFcM4PMKYYGE87sMUsDIWHMMwMYpHeM5q0MV7wIObsjM4HCK8sEVosEF4uIm3ss3r4m62fZ6xVT8hsHrF99APBU7Aynnfiz7gRJRGnZMO34CCyHkQuSST3EsTWJrEm4wzMlemPl9FOHzCYOMainGBVTjAmf/FePmZCXkSwpy04Exbss2ZMESNu2UwgLxLZjDC9IxEryYSKHwlm/Ui5AFIuytJ6ntL+FpXqHqX9DYpflymVi8zkZQRrysRoyoEo23HFnQQzPqS1aaa3JcK7EtGyzFRJxqa4aetrRGtvp/jtM2d/T1k8WCK9q7ByWETZSNHh1SBY0zZcKRFfykckGyW9miK3nWN2J02o9IlYJU68mkGuJHkx2Un9ywaGYu/o8eu4PdKKsWDnz79TsiWZcN7Hf8ewxKV7/FWVAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source
              srcset=&quot;/static/7636516786e599cf837b711746053524/ecc44/type-error-load-failed-safari-develop-menu.webp 125w,
/static/7636516786e599cf837b711746053524/0e2a5/type-error-load-failed-safari-develop-menu.webp 250w,
/static/7636516786e599cf837b711746053524/10636/type-error-load-failed-safari-develop-menu.webp 500w,
/static/7636516786e599cf837b711746053524/db9b4/type-error-load-failed-safari-develop-menu.webp 750w,
/static/7636516786e599cf837b711746053524/8d2ea/type-error-load-failed-safari-develop-menu.webp 800w&quot;
              sizes=&quot;(max-width: 500px) 100vw, 500px&quot;
              type=&quot;image/webp&quot;
            /&gt;
          &lt;source
            srcset=&quot;/static/7636516786e599cf837b711746053524/57f79/type-error-load-failed-safari-develop-menu.png 125w,
/static/7636516786e599cf837b711746053524/3e256/type-error-load-failed-safari-develop-menu.png 250w,
/static/7636516786e599cf837b711746053524/b30f8/type-error-load-failed-safari-develop-menu.png 500w,
/static/7636516786e599cf837b711746053524/b13e1/type-error-load-failed-safari-develop-menu.png 750w,
/static/7636516786e599cf837b711746053524/a331c/type-error-load-failed-safari-develop-menu.png 800w&quot;
            sizes=&quot;(max-width: 500px) 100vw, 500px&quot;
            type=&quot;image/png&quot;
          /&gt;
          &lt;img
            class=&quot;gatsby-resp-image-image&quot;
            src=&quot;/static/7636516786e599cf837b711746053524/b30f8/type-error-load-failed-safari-develop-menu.png&quot;
            alt=&quot;safari develop menu&quot;
            title=&quot;&quot;
            loading=&quot;lazy&quot;
            decoding=&quot;async&quot;
            style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
          /&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;You might see some console.log’s here. I also took the request I was running and copied it directly into Safari’s console to see if I could recreate it.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 500px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/df69d6dfb51f6e070ab12985daf09a99/8dd4b/type-error-load-failed-safari-console.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 31.2%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAGCAYAAADDl76dAAAACXBIWXMAABYlAAAWJQFJUiTwAAABCUlEQVR42o2R207CUBBF+/9fxpOCUNqCaC2kR1oQeno5d5ZpSTRGH5xkZc9MdvbDTGSd4/91wxqN0QqtFUprtNYMSuFDmBzR5SI5d4GPznOUHtEEjnKcA1UbOLWe84h01G1ANI5KWmppMdrgrJ0I3nMLgaiZzVDpBrVcMSyXdPMF/SpGxWv6xRP9wyPDas2wijGvOe5Q4vYHfCmgrqGqvrWqiK5xTLPZ0KYJKtuhsx0uS1GLOX2yRm23uH2BK4q77gtsnuOFgLbl1jTcpPwi6jYZ17IkTxLqlzfen3NElmKEuJu7Dn7RT2E0DUj5g+gkarwxDF2HGQZU3099GJ813sW531j79945PgGHR8t6u+fePQAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source
              srcset=&quot;/static/df69d6dfb51f6e070ab12985daf09a99/ecc44/type-error-load-failed-safari-console.webp 125w,
/static/df69d6dfb51f6e070ab12985daf09a99/0e2a5/type-error-load-failed-safari-console.webp 250w,
/static/df69d6dfb51f6e070ab12985daf09a99/10636/type-error-load-failed-safari-console.webp 500w,
/static/df69d6dfb51f6e070ab12985daf09a99/db9b4/type-error-load-failed-safari-console.webp 750w,
/static/df69d6dfb51f6e070ab12985daf09a99/e00f7/type-error-load-failed-safari-console.webp 1000w,
/static/df69d6dfb51f6e070ab12985daf09a99/c2ad5/type-error-load-failed-safari-console.webp 1152w&quot;
              sizes=&quot;(max-width: 500px) 100vw, 500px&quot;
              type=&quot;image/webp&quot;
            /&gt;
          &lt;source
            srcset=&quot;/static/df69d6dfb51f6e070ab12985daf09a99/57f79/type-error-load-failed-safari-console.png 125w,
/static/df69d6dfb51f6e070ab12985daf09a99/3e256/type-error-load-failed-safari-console.png 250w,
/static/df69d6dfb51f6e070ab12985daf09a99/b30f8/type-error-load-failed-safari-console.png 500w,
/static/df69d6dfb51f6e070ab12985daf09a99/b13e1/type-error-load-failed-safari-console.png 750w,
/static/df69d6dfb51f6e070ab12985daf09a99/332ff/type-error-load-failed-safari-console.png 1000w,
/static/df69d6dfb51f6e070ab12985daf09a99/8dd4b/type-error-load-failed-safari-console.png 1152w&quot;
            sizes=&quot;(max-width: 500px) 100vw, 500px&quot;
            type=&quot;image/png&quot;
          /&gt;
          &lt;img
            class=&quot;gatsby-resp-image-image&quot;
            src=&quot;/static/df69d6dfb51f6e070ab12985daf09a99/b30f8/type-error-load-failed-safari-console.png&quot;
            alt=&quot;safari console&quot;
            title=&quot;&quot;
            loading=&quot;lazy&quot;
            decoding=&quot;async&quot;
            style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
          /&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Sure enough, I had a much better CORS-related error message.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Simple Script for Expo's Eas Build Notifications in Slack]]></title><description><![CDATA[Expo doesn't currently have a way to send updates when a build succeeds or fails. I created this simple script for Cloudflare Workers.]]></description><link>https://peterp.me/articles/expo-build-slack-cloudflare-worker/</link><guid isPermaLink="false">https://peterp.me/articles/expo-build-slack-cloudflare-worker/</guid><dc:creator><![CDATA[Peter Piekarczyk]]></dc:creator><pubDate>Thu, 09 Feb 2023 20:11:04 GMT</pubDate><content:encoded>&lt;p&gt;Expo doesn’t currently have a way to send Slack updates when a build succeeds or fails. If you’re open to using &lt;a href=&quot;https://workers.cloudflare.com&quot;&gt;Cloudflare workers&lt;/a&gt; then you’re in luck!&lt;/p&gt;
&lt;p&gt;That being said, if you’d like to use this on any other service, that’s easy too! The most important part is the &lt;code class=&quot;language-text&quot;&gt;handleExpoStatus&lt;/code&gt; code block.
This is just a plain javascript object that creates the right Slack message body for the webhook.&lt;/p&gt;
&lt;p&gt;Note: Expo recommends you check that the endpoint is correctly secured so you can’t call it outside of your organizations context.
I’m not using the &lt;code class=&quot;language-text&quot;&gt;SECRET_WEBHOOK_KEY&lt;/code&gt; in this example. According to &lt;a href=&quot;https://docs.expo.dev/eas/webhooks/#webhook-server&quot;&gt;Expo’s docs&lt;/a&gt;,
you should be checking against a &lt;code class=&quot;language-text&quot;&gt;SECRET_WEBHOOK_KEY&lt;/code&gt; variable.&lt;/p&gt;
&lt;p&gt;If your URL isn’t public, then you should be ok. I added a dumb check to make sure the object includes my team’s metadata.
That being said, if somebody discovers this URL, you’ll quickly wake up to spam and change it :)&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// replace this&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;SLACK_WEBHOOK_URL&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://hooks.slack.com/services/XXX/YYY/ZZZZ&quot;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sendSlackRequest&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; text&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; blocks &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; postToSlack &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;SLACK_WEBHOOK_URL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; text&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; blocks &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;POST&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;headers&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token string-property property&quot;&gt;&quot;Content-Type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;application/json&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;request&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; env&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;request&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;method &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;POST&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; body &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; request&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

      &lt;span class=&quot;token comment&quot;&gt;// dumb check to make sure the endpoint is correct&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;body&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;accountName &lt;span class=&quot;token operator&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;My Team&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Response&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;heh&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

      &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; slackPayload &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;handleExpoStatus&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;body&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sendSlackRequest&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;slackPayload&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Response&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;ok&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Response&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;ok&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;handleExpoStatus&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;body&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;platform &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;ios&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; body&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;status &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;finished&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; url &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;itms-services://?action=download-manifest;url=https://exp.host/--/api/v2/projects/&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;body&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;appId&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;/builds/&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;body&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;/manifest.plist&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token literal-property property&quot;&gt;blocks&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;token literal-property property&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;header&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token literal-property property&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token literal-property property&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;plain_text&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token literal-property property&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;:apple-logo: Build completed successfully for iOS :ship_it_parrot:&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token literal-property property&quot;&gt;emoji&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;token literal-property property&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;section&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token literal-property property&quot;&gt;fields&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
              &lt;span class=&quot;token literal-property property&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;mrkdwn&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
              &lt;span class=&quot;token literal-property property&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;*Build Profile*: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;body&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;metadata&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;buildProfile&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;\n*Version:* &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;body&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;metadata&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;appVersion&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;\n*Build*: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;body&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;metadata&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;appBuildVersion&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;token literal-property property&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;actions&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token literal-property property&quot;&gt;elements&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
              &lt;span class=&quot;token literal-property property&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;button&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
              &lt;span class=&quot;token literal-property property&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;token literal-property property&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;plain_text&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;token literal-property property&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Download IPA&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
              &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
              &lt;span class=&quot;token literal-property property&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; body&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;artifacts&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;buildUrl&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
              &lt;span class=&quot;token literal-property property&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;button&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
              &lt;span class=&quot;token literal-property property&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;token literal-property property&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;plain_text&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;token literal-property property&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Open Build Details Page&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
              &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
              &lt;span class=&quot;token literal-property property&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; body&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;buildDetailsPageUrl&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;token literal-property property&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;image&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token literal-property property&quot;&gt;image_url&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;https://api.qrserver.com/v1/create-qr-code/?data=&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;encodeURIComponent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
            url
          &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&amp;amp;size=250x250&amp;amp;qzone=2&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token literal-property property&quot;&gt;alt_text&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;qr&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;body&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;platform &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;android&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; body&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;status &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;finished&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token literal-property property&quot;&gt;blocks&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;token literal-property property&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;header&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token literal-property property&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token literal-property property&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;plain_text&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token literal-property property&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;:android-logo: Build completed successfully for Android :ship_it_parrot:&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token literal-property property&quot;&gt;emoji&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;token literal-property property&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;section&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token literal-property property&quot;&gt;fields&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
              &lt;span class=&quot;token literal-property property&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;mrkdwn&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
              &lt;span class=&quot;token literal-property property&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;*Build Profile*: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;body&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;metadata&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;buildProfile&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;\n*Version:* &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;body&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;metadata&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;appVersion&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;\n*Build*: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;body&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;metadata&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;appBuildVersion&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;token literal-property property&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;actions&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token literal-property property&quot;&gt;elements&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
              &lt;span class=&quot;token literal-property property&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;button&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
              &lt;span class=&quot;token literal-property property&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;token literal-property property&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;plain_text&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;token literal-property property&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Download APK&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
              &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
              &lt;span class=&quot;token literal-property property&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; body&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;artifacts&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;buildUrl&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
              &lt;span class=&quot;token literal-property property&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;button&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
              &lt;span class=&quot;token literal-property property&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;token literal-property property&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;plain_text&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;token literal-property property&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Open Build Details Page&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
              &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
              &lt;span class=&quot;token literal-property property&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; body&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;buildDetailsPageUrl&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;token literal-property property&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;image&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token literal-property property&quot;&gt;image_url&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;https://api.qrserver.com/v1/create-qr-code/?data=&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;encodeURIComponent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
            body&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;artifacts&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;buildUrl
          &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&amp;amp;size=250x250&amp;amp;qzone=2&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token literal-property property&quot;&gt;alt_text&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;qr&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;body&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;platform &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;ios&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; body&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;status &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;errored&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token literal-property property&quot;&gt;blocks&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;token literal-property property&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;header&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token literal-property property&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token literal-property property&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;plain_text&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token literal-property property&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;:apple-logo: Build failed for iOS :sob:&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token literal-property property&quot;&gt;emoji&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;token literal-property property&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;section&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token literal-property property&quot;&gt;fields&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
              &lt;span class=&quot;token literal-property property&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;mrkdwn&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
              &lt;span class=&quot;token literal-property property&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;*Build Profile*: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;body&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;metadata&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;buildProfile&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;\n*Version:* &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;body&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;metadata&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;appVersion&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;\n*Build*: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;body&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;metadata&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;appBuildVersion&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;token literal-property property&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;actions&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token literal-property property&quot;&gt;elements&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
              &lt;span class=&quot;token literal-property property&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;button&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
              &lt;span class=&quot;token literal-property property&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;token literal-property property&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;plain_text&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;token literal-property property&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Open Build Details Page&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
              &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
              &lt;span class=&quot;token literal-property property&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; body&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;buildDetailsPageUrl&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;body&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;platform &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;android&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; body&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;status &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;errored&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token literal-property property&quot;&gt;blocks&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;token literal-property property&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;header&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token literal-property property&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token literal-property property&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;plain_text&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token literal-property property&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;:android-logo: Build failed for Android :sob:&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token literal-property property&quot;&gt;emoji&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;token literal-property property&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;section&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token literal-property property&quot;&gt;fields&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
              &lt;span class=&quot;token literal-property property&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;mrkdwn&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
              &lt;span class=&quot;token literal-property property&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;*Build Profile*: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;body&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;metadata&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;buildProfile&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;\n*Version:* &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;body&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;metadata&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;appVersion&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;\n*Build*: N/A&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;token literal-property property&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;actions&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token literal-property property&quot;&gt;elements&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
              &lt;span class=&quot;token literal-property property&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;button&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
              &lt;span class=&quot;token literal-property property&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;token literal-property property&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;plain_text&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;token literal-property property&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Open Build Details Page&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
              &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
              &lt;span class=&quot;token literal-property property&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; body&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;buildDetailsPageUrl&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content:encoded></item><item><title><![CDATA[Time is becoming more precious]]></title><description><![CDATA[How do I make sure that I'm focusing on what's most important?]]></description><link>https://peterp.me/articles/time-is-precious/</link><guid isPermaLink="false">https://peterp.me/articles/time-is-precious/</guid><dc:creator><![CDATA[Peter Piekarczyk]]></dc:creator><pubDate>Mon, 30 Jan 2023 20:11:04 GMT</pubDate><content:encoded>&lt;p&gt;The older I get the more I start to understand how valuable time really is.&lt;/p&gt;
&lt;p&gt;Years ago I heard a quote that went something like, “When you’re young, you exchange money for time. When you’re old, you exchange time for money.”&lt;/p&gt;
&lt;p&gt;Maybe I’m just getting impatient as I age, but I think I’m starting to understand what that means now. I used to think that I had all the time in the world.&lt;/p&gt;
&lt;p&gt;Now that family life, weddings, friendships and eventually kids are starting to show up in my daily life, I’m starting to see that I’ve got much less time than I used to!&lt;/p&gt;
&lt;p&gt;I spent my Sunday night upgrading the framework for this blog. It took me about 3 hours to do and at the end of it, my blog looks exactly the same. You might think to yourself, “4 hours isn’t that much!” and you’re right, it’s not. But when you’ve got other things going on and features to build, you start to pay attention to that time spent.&lt;/p&gt;
&lt;p&gt;I asked myself, “was it worth it?” Should I have just paid $9/mo for Ghost and moved on? Maybe. Probably. Why didn’t I do it then? Is it because I like to own my own data? Is it because I’m worried Ghost will go out of business and I’m stuck exporting files from within some walled garden? That is something that came up too.&lt;/p&gt;
&lt;p&gt;I could have spent that Sunday night writing up a new article or spending some more quality time with Lauren.&lt;/p&gt;
&lt;p&gt;Maybe I’m being overly critical of myself, maybe I worry too much about optimization at the edge. Maybe I’m just looking for a reason to write something.&lt;/p&gt;
&lt;p&gt;The point is, I’m realizing my time is becoming precious. I should get used to that sooner rather than later.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[My Thoughts on Messari's 2023 Thesis]]></title><description><![CDATA[My personal reflections and reactions to Messari's 2023 crypto thesis, covering the macro trends and bets I agree and disagree with.]]></description><link>https://peterp.me/articles/messari-2023-thesis-thoughts-reflection/</link><guid isPermaLink="false">https://peterp.me/articles/messari-2023-thesis-thoughts-reflection/</guid><dc:creator><![CDATA[Peter Piekarczyk]]></dc:creator><pubDate>Thu, 29 Dec 2022 06:00:00 GMT</pubDate><content:encoded>&lt;h3 id=&quot;some-opening-thoughts&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#some-opening-thoughts&quot; aria-label=&quot;some opening thoughts permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Some opening thoughts&lt;/h3&gt;
&lt;p&gt;I’ve been a fan of Messari’s Theses since 2018. Ryan can be annoying on Twitter, but I think we’d actually be friends in real life.&lt;/p&gt;
&lt;p&gt;For starters and most importantly, I love how he ends his 160+ page thesis with a grounding point: buy a house in the burbs &amp;#x26; start a family.&lt;/p&gt;
&lt;p&gt;While that may not be everyone’s goal, it resonates with me. We take our jobs so seriously, nothing beats the feeling of coming home to a 4 year old excited to see you (I’m not there yet, but I’m looking forward to it).&lt;/p&gt;
&lt;p&gt;I also appreciate his philosophy around writing. His section “why you must write” is a great reminder around how important it is. To think clearly, you must write well. To write well, you must read well. I’m not sure who said it but I believe in the idea.&lt;/p&gt;
&lt;p&gt;I’m writing these thoughts out for myself, but hope that others may find them useful.&lt;/p&gt;
&lt;h3 id=&quot;my-thoughts&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#my-thoughts&quot; aria-label=&quot;my thoughts permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;My Thoughts&lt;/h3&gt;
&lt;p&gt;I’m excited about the bear market. I think it filters out a lot of the noise: the scammers, ponzies and pump and dumps. It’s hard to get into crypto as a developer because you must know where to look to learn how it all works. Bear markets are a great opportunity. Bear markets are for builders.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Ethereum will face pressure with T-bill rates so high&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I think this is an interesting point. A guaranteed, non-taxable federal reserve rate of 4.6% is great. ETH Staking offers 5-7% on an asset that goes up and down in price. That might be worth it if I’ve been holding eth for years. If I’m thinking about buying eth now, I think I would rather wait for the new year and see what happens.&lt;/p&gt;
&lt;p&gt;Ethereum’s revenues are shrinking. Apple’s P/E is 23. Ethereum’s “P/E” is 195. If you’re looking at financials alone, ethereum is overvalued. I was playing around with &lt;a href=&quot;https://ultrasound.money/&quot;&gt;ultrasound.money&lt;/a&gt; and it seems like the current price should be around $600. That being said, after checking it this morning, something was fixed on the site and pegged it’s P/E to 30 and locked in a price of 1.2K USD. /shrug&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Validator decentralization&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;70% of hosted nodes for both ETH and SOL are on AWS, Hetzner and OVH&lt;/li&gt;
&lt;li&gt;50% of Solana validators are located either in Germany or the US&lt;/li&gt;
&lt;li&gt;60% of Ethereum validators are located in either Germany or the US&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I’m not sure if this worries me as much as it offers an interesting fact on what’s going on. I think this might be a cause for concern long term but it also is an awesome opportunity to spin up validators in different countries.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Things I learned&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Account Abstraction: streamlines user management of accounts and assets. I think I saw an example of Lens do this recently. It brings a UX experience most of us are used to in web2. Instead of having to sign every mundane transaction, you delegate permission to a smart contract that takes care of that for you. Similar to scopes in OAuth. For lens this works great for posting content.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Proposer Builder Separation: Delegates computationally intensive work to specialized block proposers. I’m still struggling to figure out what this does but it seems like it would make it easier for anybody to run their own ethereum node.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Light Clients: light clients use a new process to validate parts of the tree (I think). This opens up the opportunity to run nodes on laptops and phones rather than through third-party hosted nodes or centralized RPC providers.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Stablecoins. Terra UST took place earlier this year. I liked UST and used it myself. That being said, I was looking the other way when I should have been staring at the red flags. It was considered a decentralized stablecoin, something we need. Something that clearly didn’t work. Ethereum has its own algo stablecoin called FRAX. It’s partially algorithmic, otherwise backed by collateral. Whether it’ll work or not is TBD. I think it will be awhile before algo stablecoins become popular again, even if FRAX is great.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Rollups. There’s a new concept called soverign rollups. They’re a mix and match blockchain that shares consensus or data availability. There’s a thesis that appchains on Cosmos will be part of the next bull run as folks start building specific chains for their own applications (hence app chains). Think of having a specific a e-commerce based chain that can roll up its security to Ethereum, etc.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Shanghai upgrade is supposed to happen around March 2023. This will allow folks to finally unlock their staked ETH. This also changes the duration to 27 hours. You could argue that folks staking their eth have been chomping at the bits to sell. But since they’ll be able to unlock almost every day, the risk to unlock falls dramatically. One could argue that this will increase the amount of ETH staked and increase the price.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;JP Morgan proejcted staking could be a $40B/yr industry by 2025. That would have to grow to $40B. In that case, that would be $1.6B/yr in annual revenue for Lido. A massive money maker! Wow.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;I learned that Goldfinch has been growing steadily despite crypto volatility. Goldfinch’s offers off-chain loans. Their risks are the fintech sector and higher developing economies&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Zerion, Zapper &amp;#x26; Nansen make it easier to track specific wallets in real time. They also allow you to manage full, complex portfolios from a single dashboard&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Final Thoughts&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Although this year has been filled with a lot of uncertainty around crypto, I’m generally excited. I think everyone is looking for the opportunity to buy more. I’m not sure what that will look like long term. I’m not sure if I want to start buying crypto today or sometime in the new year. Things seem pretty stable right now. The feeling of “am I going to miss the next bull run” is always in the back of my mind. Maybe I will, maybe I won’t. Most importantly, I have to remember to keep building.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[React Native SectionList Expand & Collapse Guide]]></title><description><![CDATA[Getting a SectionList working with expand/collapse using the extraData prop and a Set data structure.]]></description><link>https://peterp.me/articles/react-native-sectionlist-expand-collapse/</link><guid isPermaLink="false">https://peterp.me/articles/react-native-sectionlist-expand-collapse/</guid><dc:creator><![CDATA[Peter Piekarczyk]]></dc:creator><pubDate>Fri, 16 Dec 2022 18:01:28 GMT</pubDate><content:encoded>&lt;p&gt;React Native has a component called &lt;code class=&quot;language-text&quot;&gt;SectionList&lt;/code&gt; that will render things in sections. Think favorite foods:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Deserts: ice cream, cheesecake&lt;/li&gt;
&lt;li&gt;Drinks: water, coke, beer&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 500px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/3a3b4d0593bac68f0fc1a463ef761599/d217e/sectionlist-example.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 122.39999999999999%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAYCAIAAAB1KUohAAAACXBIWXMAAAsTAAALEwEAmpwYAAACYUlEQVR42pXTyW/aQBQG8Pn/D5EqVa2qqD00hyhtRXuIwu4lEEyoYhKWsBUHOxiPFzBgwNieea8K7aWHAB39NLdvRvrmDXFdt9PpDAYDz/N0XR8Oh5qmGYYRxzEeWoRSWiqVZFnudruKokiSVCqVRFH0fR8RAWBfeDKZVKtVRVFUVV2v1wcD/4Qd27m7U1vNVrvVDsMtAHDGOd+dsB8i0Q39uixXqjeZbLrb7/7fzavpxuktFqOXfToMQgpHsYBHSGKK3ZRb/6I3v5nj/MYRwRb4QTTPoymQiOL9xXP2w634sa6l59412jJzZL6fLfJoBiSeQ6hBYmA8wvUvWA4gOEYf2BpJ5OJYWpmllaPE0xo/klfl8QJIaKJ6Zvw4kTNvb60co3l+DCvDIw9IPMPZfTJrxn4jmbfgSH4DkgBJNIWgBWEPg0fwm3x+HP+BJwGQyMLCO/X7iaCe666AVj6hRW7vJ3Ca2z1V4uG4uOqnnYm8WdTQr4J3w93yAc41j30gU3c21qy5s5zRuaXb5oiGy5hvkYUHAEei63pRLAhSUZCL2XymWlMc1z5ywkk05X4jCTps093V1mZBh296uGjBHvO/bVv48/Mw+76We1+TTu9vz/qXb8rS6QMtsMOFbSk+F9eDnNu+NHtXdFRc9NK0n3HcCvMq/DVueVdYvITQADZBZr1ITIzGuDVw9QR7BBqwDZLQwseU3UyZrdTk4auhXjw9pQNXRltitsRfQ4Xdr9paWD83Kmed+oUuf2oIp6p2tXBlpAKzRf4aWvgzJGvYWpA4GFNkNiYOhhZszEPGwLb4G3OsIBYnbfAAAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source
              srcset=&quot;/static/3a3b4d0593bac68f0fc1a463ef761599/ecc44/sectionlist-example.webp 125w,
/static/3a3b4d0593bac68f0fc1a463ef761599/0e2a5/sectionlist-example.webp 250w,
/static/3a3b4d0593bac68f0fc1a463ef761599/10636/sectionlist-example.webp 500w,
/static/3a3b4d0593bac68f0fc1a463ef761599/c85e8/sectionlist-example.webp 646w&quot;
              sizes=&quot;(max-width: 500px) 100vw, 500px&quot;
              type=&quot;image/webp&quot;
            /&gt;
          &lt;source
            srcset=&quot;/static/3a3b4d0593bac68f0fc1a463ef761599/57f79/sectionlist-example.png 125w,
/static/3a3b4d0593bac68f0fc1a463ef761599/3e256/sectionlist-example.png 250w,
/static/3a3b4d0593bac68f0fc1a463ef761599/b30f8/sectionlist-example.png 500w,
/static/3a3b4d0593bac68f0fc1a463ef761599/d217e/sectionlist-example.png 646w&quot;
            sizes=&quot;(max-width: 500px) 100vw, 500px&quot;
            type=&quot;image/png&quot;
          /&gt;
          &lt;img
            class=&quot;gatsby-resp-image-image&quot;
            src=&quot;/static/3a3b4d0593bac68f0fc1a463ef761599/b30f8/sectionlist-example.png&quot;
            alt=&quot;sectionlist-example&quot;
            title=&quot;&quot;
            loading=&quot;lazy&quot;
            decoding=&quot;async&quot;
            style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
          /&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;The not-so-obvious part is how you can create a collapsible version of this. By collapsible I mean, being able to hide the individual items upon tapping the header:&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 500px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/224129fdd1f009591a37bda4b083e344/8179f/sectionlist-collapsed.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 73.6%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAPCAIAAABr+ngCAAAACXBIWXMAAAsTAAALEwEAmpwYAAABlklEQVR42pWS3WubYBSH/f+vtosx2EYuu1HGOiKBjGjt9HVtsa2VRMvGbOJHfI0fMdr6EeN5TyFXHaRJd3g4dw+/wzmHK4qCUprnedM0eZ5nWVYURVmWAICHiptOp8PhkOd5wzBEURwMBoIg9Pv9NE0RkTG2Tw6CwDRNwzBs266qCgC6rmPbOpzs+74sy4QQTdOqqjqY9o/seR4hxLIsRVEcx/k/OYoi0zRdx51MJq7rbTYbBgwZHma7sHtREn5dqOo5UVT5TJGiOHplPveQVOHdavE7p+Yy/rNK7eLRbyDFmrJ9BAwa5NYBjo/n+vFs/NW3vofmSXB1ZN98mUUSW5zCbiQIR9DEyNU+6keu3BuP3mtyb3zzeXb6QT/7dPui+VxuV1g7rJ0jBLiZY+ttu4+P92wPD39ZVyJXU0Z/NpTUc7kMSUOVeqGuk/MuuYAXuYRYhfUSucZH5aP1490l6Vn8W8K/Ue6+xbGEdNSFAuxGBDrcjt1EmGpdct1mOsTaOrlqlzpkOtvHLVtes3aF3K77vfbDngALOT+PQC1jGwAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source
              srcset=&quot;/static/224129fdd1f009591a37bda4b083e344/ecc44/sectionlist-collapsed.webp 125w,
/static/224129fdd1f009591a37bda4b083e344/0e2a5/sectionlist-collapsed.webp 250w,
/static/224129fdd1f009591a37bda4b083e344/10636/sectionlist-collapsed.webp 500w,
/static/224129fdd1f009591a37bda4b083e344/d2bae/sectionlist-collapsed.webp 654w&quot;
              sizes=&quot;(max-width: 500px) 100vw, 500px&quot;
              type=&quot;image/webp&quot;
            /&gt;
          &lt;source
            srcset=&quot;/static/224129fdd1f009591a37bda4b083e344/57f79/sectionlist-collapsed.png 125w,
/static/224129fdd1f009591a37bda4b083e344/3e256/sectionlist-collapsed.png 250w,
/static/224129fdd1f009591a37bda4b083e344/b30f8/sectionlist-collapsed.png 500w,
/static/224129fdd1f009591a37bda4b083e344/8179f/sectionlist-collapsed.png 654w&quot;
            sizes=&quot;(max-width: 500px) 100vw, 500px&quot;
            type=&quot;image/png&quot;
          /&gt;
          &lt;img
            class=&quot;gatsby-resp-image-image&quot;
            src=&quot;/static/224129fdd1f009591a37bda4b083e344/b30f8/sectionlist-collapsed.png&quot;
            alt=&quot;sectionlist-collapsed&quot;
            title=&quot;&quot;
            loading=&quot;lazy&quot;
            decoding=&quot;async&quot;
            style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
          /&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Luckily for you, getting it working is straight forward. The key is using the &lt;code class=&quot;language-text&quot;&gt;extraData&lt;/code&gt; prop for a SectionList.&lt;/p&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;extraData&lt;/code&gt; just re-renders the list when you have to pass in new data somewhere (like changing the expand/collapse toggle state.&lt;/p&gt;
&lt;p&gt;Then you can use &lt;code class=&quot;language-text&quot;&gt;useState&lt;/code&gt; and an array or a set to get it working. I use a &lt;code class=&quot;language-text&quot;&gt;Set&lt;/code&gt; here b/c it’s easy, but in its purest form, here’s all you need to know:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;SectionList
    sections&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;DATA&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    extraData&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;expandedSections&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// extraData is required to re-render the list when expandedSections changes&lt;/span&gt;
    keyExtractor&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;item&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; index&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; item &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; index&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    renderItem&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;section&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; title &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; item &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token comment&quot;&gt;// check to see if the section is expanded&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; isExpanded &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; expandedSections&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;has&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;title&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

      &lt;span class=&quot;token comment&quot;&gt;//return null if it is&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;isExpanded&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

      &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Item title&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;item&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    renderSectionHeader&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;section&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; title &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Pressable onPress&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;handleToggle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;title&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Text style&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;styles&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;header&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;title&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;Text&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;Pressable&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To see a working version of this, check out this &lt;a href=&quot;https://snack.expo.dev/@peterpme/sectionlist-expand-and-collapse-example&quot;&gt;Snack&lt;/a&gt;.
In the event the Snack stops working, here’s a &lt;a href=&quot;https://gist.github.com/peterpme/b818eca2b7faf0e06f2466ab3e84db62&quot;&gt;gist&lt;/a&gt; you can copy/paste somewhere with the same code.&lt;/p&gt;
&lt;div data-snack-id=&quot;@peterpme/sectionlist-expand-and-collapse-example&quot; data-snack-platform=&quot;web&quot; data-snack-preview=&quot;true&quot; data-snack-theme=&quot;dark&quot; style=&quot;overflow:hidden;background:#212121;border:1px solid var(--color-border);border-radius:4px;height:505px;width:100%&quot;&gt;&lt;/div&gt;
&lt;script async src=&quot;https://snack.expo.dev/embed.js&quot;&gt;&lt;/script&gt;</content:encoded></item><item><title><![CDATA[Getting Cairo, Starkware's Language Up and Running on an M1 Mac]]></title><description><![CDATA[A practical guide to getting StarkWare's Cairo language installed and running on an Apple M1 Mac, filling in the gaps the official docs leave out.]]></description><link>https://peterp.me/articles/starkware-cairo-up-and-running/</link><guid isPermaLink="false">https://peterp.me/articles/starkware-cairo-up-and-running/</guid><dc:creator><![CDATA[Peter Piekarczyk]]></dc:creator><pubDate>Wed, 14 Dec 2022 22:11:04 GMT</pubDate><content:encoded>&lt;p&gt;Cairo is a powerful language. Their developer docs could use some work 😅
I was going to PR this until I realized their docs aren’t public, so here we are!&lt;/p&gt;
&lt;p&gt;There are two repos:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/starkware-libs/cairo-lang&quot;&gt;Cairo Lang&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/starkware-libs/cairo&quot;&gt;Cairo&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Cairo Lang&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The original python implementation. I’ve heard it doesn’t scale well and it seems like it’s deprecated in favor of Cairo.&lt;/p&gt;
&lt;p&gt;This hasn’t happened yet so you might still have to get it working.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Cairo&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The new Rust implementation. Seems way easier to use, built in rust. The new path forward!&lt;/p&gt;
&lt;p&gt;Despite having both of these options, you might still need to get Python up and running.&lt;/p&gt;
&lt;p&gt;Here’s how I did it:&lt;/p&gt;
&lt;p&gt;The first few steps are easy. You’re installing a specific version of python via brew and following &lt;a href=&quot;https://www.cairo-lang.org/docs/quickstart.html&quot;&gt;their docs&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;sh&quot;&gt;&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;brew &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; python@3.9
python3.9 &lt;span class=&quot;token parameter variable&quot;&gt;-m&lt;/span&gt; venv ~/cairo_venv
&lt;span class=&quot;token builtin class-name&quot;&gt;source&lt;/span&gt; ~/cairo_venv/bin/activate&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is where it gets interesting. I had to install this &lt;code class=&quot;language-text&quot;&gt;arch -arm64&lt;/code&gt; version of gmp first.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;sh&quot;&gt;&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;arch &lt;span class=&quot;token parameter variable&quot;&gt;-arm64&lt;/span&gt; brew &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; gmp
brew &lt;span class=&quot;token parameter variable&quot;&gt;--prefix&lt;/span&gt; gmp&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Once you’ve confirmed it works and you’re running this within your python3 environment, you need to set these flags.&lt;/p&gt;
&lt;p&gt;What do these flags do? Just make sure that pip is installed with the correct version of &lt;code class=&quot;language-text&quot;&gt;gmp&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;sh&quot;&gt;&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token assign-left variable&quot;&gt;CFLAGS&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;-I&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;`&lt;/span&gt;brew &lt;span class=&quot;token parameter variable&quot;&gt;--prefix&lt;/span&gt; gmp&lt;span class=&quot;token variable&quot;&gt;`&lt;/span&gt;&lt;/span&gt;/include &lt;span class=&quot;token assign-left variable&quot;&gt;LDFLAGS&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;-L&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;`&lt;/span&gt;brew &lt;span class=&quot;token parameter variable&quot;&gt;--prefix&lt;/span&gt; gmp&lt;span class=&quot;token variable&quot;&gt;`&lt;/span&gt;&lt;/span&gt;/lib pip &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; ecdsa fastecdsa sympy
pip3 &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; cairo-lang&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Once you’ve done that, this should run!&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;sh&quot;&gt;&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;cairo-compile test.cairo &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; test_compiled.json&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content:encoded></item><item><title><![CDATA[Creating Fun Selfies with Stable Diffusion]]></title><description><![CDATA[How I used Stable Diffusion to generate creative selfie-style images, including the prompts and settings that produced the best results.]]></description><link>https://peterp.me/articles/creating-fun-selfies-with-stable-diffusion/</link><guid isPermaLink="false">https://peterp.me/articles/creating-fun-selfies-with-stable-diffusion/</guid><dc:creator><![CDATA[Peter Piekarczyk]]></dc:creator><pubDate>Wed, 14 Dec 2022 06:00:00 GMT</pubDate><content:encoded>&lt;p&gt;It’s been fascinating to watch all the big updates coming to Stable Diffusion v1 and v2. I’ve created a Notion doc where I’ve been tracking my prompts &amp;#x26; results.&lt;/p&gt;
&lt;p&gt;There are also some steps in there to get yourself started too. &lt;a href=&quot;https://www.notion.so/AI-Generative-Art-27a0811bff3a4b9585e3d93bd21f373d&quot;&gt;Learn more here&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Joining Backpack]]></title><description><![CDATA[Announcing that I've joined Backpack to lead mobile engineering and build the future of crypto on mobile.]]></description><link>https://peterp.me/articles/backpack-announcement/</link><guid isPermaLink="false">https://peterp.me/articles/backpack-announcement/</guid><dc:creator><![CDATA[Peter Piekarczyk]]></dc:creator><pubDate>Mon, 05 Dec 2022 05:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I’m thrilled to announce that I’ve joined Backpack to lead mobile engineering 🎉&lt;/p&gt;
&lt;p&gt;I recently stepped down as Draftbit’s CTO and have been taking a break exploring what my journey will look like. Today, I’m excited &amp;#x26; humbled by the opportunity I’ve been given to work with a world-class team on Backpack.&lt;/p&gt;
&lt;p&gt;For those who may not be familiar, Backpack is a portal into web3: one-stop shop for all your DeFi apps, NFTs, games and much more.&lt;/p&gt;
&lt;p&gt;It’s no secret that the crypto world today is ridden with landmines. DeFi projects are constantly getting hacked or fake phishing sites are put up to confuse people. It can make sleeping at night quite difficult. I’ve been watching the space since 2014. It was about time to get involved. I knew that whatever I was going to work on, I needed to make sure it made life better for the every day person, not worse.&lt;/p&gt;
&lt;p&gt;That’s where Backpack comes in. The driving feature behind Backpack is an xNFT. So, wtf is an xNFT?&lt;/p&gt;
&lt;h3 id=&quot;whats-an-xnft&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#whats-an-xnft&quot; aria-label=&quot;whats an xnft permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What’s an xNFT?&lt;/h3&gt;
&lt;p&gt;According to Armani, the creator, X stands for eXecutable: tokenized code representing ownership rights over its execution. In layman’s terms: instead of pointing a regular old NFT at a jpeg on S3, you can point it at some javascript and create an entirely new world.&lt;/p&gt;
&lt;p&gt;xNFTs will create an ecosystem of decentralized apps using protocol-agnostic frameworks that work across your all favorite chains including Ethereum, Solana &amp;#x26; many more. The interface for all this is Backpack. Today, you can think of Backpack as a wallet but tomorrow, it will be so much more than that.&lt;/p&gt;
&lt;p&gt;Backpack is launching with an app store that includes anything from games like Flappy Bird to NFT marketplaces &amp;#x26; even developer tooling. These apps are all verified on chain. On-chain verification means the code you ship is the code your users will see. There’s no way nefarious actors will be able to bait &amp;#x26; switch code or create fake URLs that look like a real project. This is one of the many efforts to create a safe and fun way to interact with a web3 world.&lt;/p&gt;
&lt;h3 id=&quot;we-already-have-some-incredible-xnfts-in-our-ecosystem&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#we-already-have-some-incredible-xnfts-in-our-ecosystem&quot; aria-label=&quot;we already have some incredible xnfts in our ecosystem permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;We already have some incredible xNFTs in our ecosystem:&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://www.xnft.gg/app/9AmGmRkSQYSYAupbdKmr2et8nQkSg5bo8NAG1nmXgY6g&quot;&gt;Double Diffusion&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Double Diffusion is Stable Diffusion powered by Solana. You have the ability to generate and mint anything and pay a low fee of 0.0025 (about 3 cents) per query. This gives the power back to the creator.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://www.xnft.gg/app/7A3av8PDbqpGRfLzSujr9Dprw4SVgFbMCfJ5DXL4azRP&quot;&gt;2048&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;An engineer’s favorite, you slide numbered tiles on a grid to combine them to create the number 2048. A fun &amp;#x26; free game.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://www.xnft.gg/app/De4UnwDoaRnPFpy4NXXZCvh4W7JrX5JNcxc6u9iZfZzp&quot;&gt;Releap&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Releap is a music NFT platform. This allows you to listen to your music NFTs anytime, anywhere&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://www.xnft.gg/app/Hs78vTKzgK53qeRcYr6UFALzKB9SPNRfV79X5FtVgbKq&quot;&gt;Solend&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Solend is a DeFi protocol for lending and borrowing on the Solana blockchain. Think Aave or Compound on Solana. Solend allows anyone with an internet connection to earn interest by lending their crypto assets, and allows them to use their deposits as collateral for borrowing.&lt;/p&gt;
&lt;h3 id=&quot;building-a-better-ecosystem-for-the-every-day-person&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#building-a-better-ecosystem-for-the-every-day-person&quot; aria-label=&quot;building a better ecosystem for the every day person permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Building a better ecosystem for the every day person&lt;/h3&gt;
&lt;p&gt;Today, blockchain is something you need to understand to use correctly. Tomorrow, users won’t have to worry about which chain they’re using, how they need to transfer funds and whether the site they’re using is real. You don’t need to know how the internet works to use Facebook or Netflix. With Backpack, we’ll bring that same level of harmony to web3.&lt;/p&gt;
&lt;p&gt;Backpack is built by a world-class team. I’ve quickly realized I’m working with some of the most talented &amp;#x26; smartest people in the world. Quite frankly, I’ve had a bit of imposter syndrome. I’m excited to learn, contribute to making Backpack the best portal and ecosystem in the world.&lt;/p&gt;
&lt;p&gt;Lastly, why am I so excited about mobile? You’re probably reading this on your phone. Expect to interact with web3, blockchains &amp;#x26; crypto the same way. I’m bullish on a safe &amp;#x26; secure mobile wallet experience.&lt;/p&gt;
&lt;p&gt;I’m grateful for the opportunity to work with such a talented and smart team at Backpack. I can’t wait to learn from them and contribute to building the best portal and ecosystem for web3. And as a mobile enthusiast, I’m especially excited to help create a safe and secure mobile wallet experience for our users.&lt;/p&gt;
&lt;p&gt;There’s a lot of work to be done, but I’m ready for the journey ahead!&lt;/p&gt;
&lt;p&gt;WAO, Peter
P.S. WAO = We Are One&lt;/p&gt;
&lt;p&gt;Check us out:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://backpack.app&quot;&gt;Backpack.app&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.xnft.gg&quot;&gt;xNFT App Store&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title><![CDATA[Setting up Ikea Fyrtur Blinds in HomeAssistant without a Gateway]]></title><description><![CDATA[How to connect IKEA Fyrtur smart blinds to Home Assistant without the IKEA gateway, keeping your existing remote and repeater setup intact.]]></description><link>https://peterp.me/articles/setting-up-ikea-fyrtur-blinds-homeassistant-without-gateway/</link><guid isPermaLink="false">https://peterp.me/articles/setting-up-ikea-fyrtur-blinds-homeassistant-without-gateway/</guid><dc:creator><![CDATA[Peter Piekarczyk]]></dc:creator><pubDate>Fri, 27 Nov 2020 16:06:23 GMT</pubDate><content:encoded>&lt;p&gt;Setting up IKEA’s Fyrtur blinds with Home Assistant is easy. No gateway required.&lt;/p&gt;
&lt;p&gt;My blinds were previously controlled with the remote control and repeater, aka a “working state”. I was able to switch over to Home Assistant just fine, without having to reset anything.&lt;/p&gt;
&lt;h2 id=&quot;steps&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#steps&quot; aria-label=&quot;steps permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Steps&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Make sure to charge your blind battery to 100%. This helps with pairing.&lt;/li&gt;
&lt;li&gt;Press and hold the top and bottom buttons on the blinds for a couple seconds until they start breathing/flashing.&lt;/li&gt;
&lt;li&gt;Go over to your Zigbee setup in Home Assistant and press “Add Device”.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In about a couple seconds you should have a green box pop up that says “Pairing Successful”. You no longer need to use the repeater. The remote will not work anymore either.&lt;/p&gt;
&lt;p&gt;That being said, you could probably find a way to connect the remote directly to Home Assistant but I haven’t done that.&lt;/p&gt;
&lt;p&gt;I’ve noticed that &lt;code class=&quot;language-text&quot;&gt;cover.set_position&lt;/code&gt; works much better than &lt;code class=&quot;language-text&quot;&gt;open&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;close&lt;/code&gt;. This is running version &lt;code class=&quot;language-text&quot;&gt;2020.12.7&lt;/code&gt;. Maybe it’ll be fixed by the time you’re reading this.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Quickly delete old git branches with fzf and zsh]]></title><description><![CDATA[A short zsh function using fzf that lets you interactively select and delete old Git branches without hunting through git branch output.]]></description><link>https://peterp.me/articles/cli-tips-interactive-branch-delete/</link><guid isPermaLink="false">https://peterp.me/articles/cli-tips-interactive-branch-delete/</guid><dc:creator><![CDATA[Peter Piekarczyk]]></dc:creator><pubDate>Sat, 01 Aug 2020 05:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Do you fall victim to having a million branches when typing in &lt;code class=&quot;language-text&quot;&gt;git branch&lt;/code&gt;? It’s a pain. I wrote this quick helper that lets me select the branch I want and deletes the rest:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/e3c5277a83c2b0081df2d524503cf6ef/fzf-delete-branch.gif&quot; alt=&quot;interactive branch delete&quot;&gt;&lt;/p&gt;
&lt;p&gt;You need &lt;code class=&quot;language-text&quot;&gt;fzf&lt;/code&gt; for this to work: &lt;code class=&quot;language-text&quot;&gt;brew install fzf&lt;/code&gt;. Fzf is one of the sickest tools of our generation so do your own research and start incorporating it into your every day flow!&lt;/p&gt;
&lt;p&gt;Place this in your &lt;code class=&quot;language-text&quot;&gt;/.zshrc&lt;/code&gt; file and re-open your terminal. Viola.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;zsh&quot;&gt;&lt;pre class=&quot;language-zsh&quot;&gt;&lt;code class=&quot;language-zsh&quot;&gt;# fbd - delete git branch (including remote branches)
fbd() {
  local branches branch
  branches=$(git for-each-ref --count=30 --sort=-committerdate refs/heads/ --format=&amp;quot;%(refname:short)&amp;quot;) &amp;amp;&amp;amp;
  branch=$(echo &amp;quot;$branches&amp;quot; | fzf --multi ) &amp;amp;&amp;amp;
  git branch -D $(echo &amp;quot;$branch&amp;quot; | sed &amp;quot;s/.* //&amp;quot; | sed &amp;quot;s#remotes/[^/]*/##&amp;quot;)
}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Thanks to &lt;a href=&quot;https://www.reddit.com/r/commandline/comments/i2229p/quickly_delete_old_git_branches_interactively/g02d8sn/&quot;&gt;pgrepo on reddit&lt;/a&gt; for pointing out that for this to work with remote branches that you need to add &lt;code class=&quot;language-text&quot;&gt;[fetch] prune = true&lt;/code&gt; into your &lt;code class=&quot;language-text&quot;&gt;.gitconfig&lt;/code&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Installing Home Assistant on Ubuntu, The New Way]]></title><description><![CDATA[How to correctly install Home Assistant Supervised on Ubuntu after the documentation changed and the Supervisor panel went missing from Docker installs.]]></description><link>https://peterp.me/articles/installing-home-assistant-supervisored-on-ubuntu/</link><guid isPermaLink="false">https://peterp.me/articles/installing-home-assistant-supervisored-on-ubuntu/</guid><dc:creator><![CDATA[Peter Piekarczyk]]></dc:creator><pubDate>Fri, 31 Jul 2020 03:39:01 GMT</pubDate><content:encoded>&lt;p&gt;Have you recently tried installing Home Assistant on a new Ubuntu box? The installation docs are different and the thing that you’re looking for is nowhere to be seen. Finally, you find the Docker installation and run the appropriate scripts only to realize the “Supervisor” sidebar went missing.&lt;/p&gt;
&lt;p&gt;If you’ve been scratching your head to figure out what happened, this (slightly salty) article is for you.&lt;/p&gt;
&lt;h2 id=&quot;what-happened&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#what-happened&quot; aria-label=&quot;what happened permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What Happened?&lt;/h2&gt;
&lt;p&gt;The Home Assistant team recently &lt;a href=&quot;https://www.home-assistant.io/blog/2020/05/09/deprecating-home-assistant-supervised-on-generic-linux/&quot;&gt;decided to deprecate the installations&lt;/a&gt; for generic Linux machines on May 9th.&lt;/p&gt;
&lt;p&gt;For better or for worse, the team doesn’t collect any telemetry data so a week later they &lt;a href=&quot;https://www.home-assistant.io/blog/2020/05/26/installation-methods-and-community-guides-wiki/&quot;&gt;undo that decision&lt;/a&gt; (after what must have been a stressful series of “wtfs” in the community).&lt;/p&gt;
&lt;h2 id=&quot;i-still-love-home-assistant&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#i-still-love-home-assistant&quot; aria-label=&quot;i still love home assistant permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;I Still Love Home Assistant&lt;/h2&gt;
&lt;p&gt;As frustrating as this is, it’s hard to get upset at a group of folks who work so hard to release this amazing platform, in the open, for free. I’m sure they’ve learned a lot when it comes to managing an open source project and managing a business.&lt;/p&gt;
&lt;h2 id=&quot;the-new-problem&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#the-new-problem&quot; aria-label=&quot;the new problem permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The New Problem&lt;/h2&gt;
&lt;p&gt;Supervisor is actually completely separate than Home Assistant. Who knew!? Nobody.&lt;/p&gt;
&lt;p&gt;I’m sure, like me you spent the afternoon Googling wondering why “Supervisor” doesn’t show up (the thing with all the add-ons) when you went through the &lt;a href=&quot;https://www.home-assistant.io/docs/installation/docker/&quot;&gt;installation docs&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The funny thing about all this is that Home Assistant still offically supports Debian but who the fk uses Debian!?&lt;/p&gt;
&lt;h2 id=&quot;getting-started&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#getting-started&quot; aria-label=&quot;getting started permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Getting started&lt;/h2&gt;
&lt;p&gt;Home Assistant’s top &lt;a href=&quot;https://community.home-assistant.io/t/installing-home-assistant-supervised-on-ubuntu-18-04-4/200020&quot;&gt;post&lt;/a&gt; on their forums is Installing on Ubuntu. They no longer “officially support” Ubuntu but “support it in other ways”.&lt;/p&gt;
&lt;p&gt;The process is pretty straight forward. The difference is that this awesome person Jason (Kanga-Who) forked the script and has been maintaining it. The reality of it is there isn’t really that much maintenance to be done. Once you have this running you’ll be able to use and upgrade Home Assistant the same way you’ve always been able to!&lt;/p&gt;
&lt;p&gt;I won’t walk you through the process of setting up a USB stick to install Ubuntu. You can read about that &lt;a href=&quot;https://community.home-assistant.io/t/installing-home-assistant-supervised-on-ubuntu-18-04-4/200020&quot;&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;sh&quot;&gt;&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-i&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;apt-get&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-y&lt;/span&gt; software-properties-common apparmor-utils apt-transport-https avahi-daemon ca-certificates &lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; dbus jq network-manager socat

systemctl disable ModemManager

systemctl stop ModemManager

&lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-fsSL&lt;/span&gt; get.docker.com &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sh&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-sL&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://raw.githubusercontent.com/Kanga-Who/home-assistant/master/supervised-installer.sh&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;bash&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-s&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;config-folder-path&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#config-folder-path&quot; aria-label=&quot;config folder path permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Config folder path&lt;/h2&gt;
&lt;p&gt;Protected more closely than Ft. Knox, the config path on the installation instructions has always been hard to find. Using this installation step, it’s located here:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;/usr/share/hassio/homeassistant&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Yes, its easy to lose it when all you see is &lt;code class=&quot;language-text&quot;&gt;YOUR_CONFIG_PATH_HERE:/config&lt;/code&gt; with literally 0 clues on where it should go or where it lives.&lt;/p&gt;
&lt;p&gt;The backup/snapshot directory on the other hand is located here:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;/usr/share/hassio/backup&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;exposing-usb-devices&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#exposing-usb-devices&quot; aria-label=&quot;exposing usb devices permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Exposing USB Devices&lt;/h2&gt;
&lt;p&gt;In my experience all my devices started showing up properly and there was nothing else I needed to do! If you follow this same installation method, you’ll totally be in the clear.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Easily Deleting Deeply Nested Files with fd]]></title><description><![CDATA[How to use fd, the modern find replacement, to quickly locate and delete deeply nested files across a project without complex glob syntax.]]></description><link>https://peterp.me/articles/quickly-deleting-nested-files-with-fd/</link><guid isPermaLink="false">https://peterp.me/articles/quickly-deleting-nested-files-with-fd/</guid><dc:creator><![CDATA[Peter Piekarczyk]]></dc:creator><pubDate>Fri, 05 Jun 2020 16:06:23 GMT</pubDate><content:encoded>&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;fd&lt;/code&gt; is a modern replacement to the unix util called &lt;code class=&quot;language-text&quot;&gt;find&lt;/code&gt;. MacOS has all of these installed by default but they’re really out of date. You can upgrade them via homebrew but then you’re forced to prefix them with &lt;code class=&quot;language-text&quot;&gt;g&lt;/code&gt; or something else. Instead of having to worry about that, I’d rather just install &lt;code class=&quot;language-text&quot;&gt;fd&lt;/code&gt; via homebrew and never have to worry about compatibility.&lt;/p&gt;
&lt;p&gt;Deleting files in a nested repo is so tiring, especially with git, so this is what I do:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;sh&quot;&gt;&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;fd MyFile.js &lt;span class=&quot;token parameter variable&quot;&gt;-x&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;rm&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-rf&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It doesn’t matter where &lt;code class=&quot;language-text&quot;&gt;MyFile.js&lt;/code&gt; lives, it can live &lt;code class=&quot;language-text&quot;&gt;src/my/project/here/MyFile.js&lt;/code&gt; and it’ll find it and instantly delete it!&lt;/p&gt;
&lt;p&gt;Install it using brew: &lt;code class=&quot;language-text&quot;&gt;brew install fd&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Learn more about fd &lt;a href=&quot;https://github.com/sharkdp/fd&quot;&gt;here&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Using async / await with reduce in Javascript]]></title><description><![CDATA[A quick, practical example showing how to correctly use async/await inside JavaScript's Array reduce function without losing resolved values.]]></description><link>https://peterp.me/articles/async-await-reduce-function/</link><guid isPermaLink="false">https://peterp.me/articles/async-await-reduce-function/</guid><dc:creator><![CDATA[Peter Piekarczyk]]></dc:creator><pubDate>Thu, 04 Jun 2020 00:54:35 GMT</pubDate><content:encoded>&lt;p&gt;I got stumped trying to figure out how to use async / await. Here’s how you do it:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;buildObject&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;items&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  
  &lt;span class=&quot;token comment&quot;&gt;// promise here is technically the accumulator so we await to get it&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; items&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reduce&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;promise&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; item&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; obj &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; promise&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    obj&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;item&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getItem&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    
    &lt;span class=&quot;token comment&quot;&gt;// return the object as usual&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; obj
    
    &lt;span class=&quot;token comment&quot;&gt;// resolve an empty object (the thing we want)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Promise&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Pretty sick huh&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Using Global Node Modules The Right Way]]></title><description><![CDATA[Stop re-installing the same global node modules for every version of Node]]></description><link>https://peterp.me/articles/global-node-modules-the-right-way/</link><guid isPermaLink="false">https://peterp.me/articles/global-node-modules-the-right-way/</guid><dc:creator><![CDATA[Peter Piekarczyk]]></dc:creator><pubDate>Sat, 23 May 2020 17:43:23 GMT</pubDate><content:encoded>&lt;p&gt;When using tools like &lt;code class=&quot;language-text&quot;&gt;nvm&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;n&lt;/code&gt; or even &lt;code class=&quot;language-text&quot;&gt;homebrew&lt;/code&gt; you can end up installing multiple verisons of Node. This could mean that when you run &lt;code class=&quot;language-text&quot;&gt;npm install -g&lt;/code&gt; over time you’ll have the same executible installed in a bunch of different places. See for yourself:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;type -a expo-cli&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Do multiple versions come up?&lt;/p&gt;
&lt;h2 id=&quot;a-global-npmbin&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#a-global-npmbin&quot; aria-label=&quot;a global npmbin permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;A Global npmbin&lt;/h2&gt;
&lt;p&gt;Create a global &lt;code class=&quot;language-text&quot;&gt;npmbin&lt;/code&gt;: one place to store all of your global dependencies without having to call them with the global flag! This folder will have its own &lt;code class=&quot;language-text&quot;&gt;package.json&lt;/code&gt; and specific node version. No more node_module bloat, no more linking, &lt;em&gt;it just works&lt;/em&gt;.&lt;/p&gt;
&lt;h2 id=&quot;creating-your-bin&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#creating-your-bin&quot; aria-label=&quot;creating your bin permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Creating your bin&lt;/h2&gt;
&lt;p&gt;Create a new directory under home and cd into it:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;sh&quot;&gt;&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token function&quot;&gt;mkdir&lt;/span&gt; ~/npmbin/ &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$_&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Init with package.json. None of the fields really matter, its all local.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;sh&quot;&gt;&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token function&quot;&gt;yarn&lt;/span&gt; init &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;or &lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; init&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Add &lt;code class=&quot;language-text&quot;&gt;~/npmbin&lt;/code&gt; to your path. Open your &lt;code class=&quot;language-text&quot;&gt;~/.bashrc&lt;/code&gt; or &lt;code class=&quot;language-text&quot;&gt;~/.zshrc&lt;/code&gt; and on a new line:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;export PATH=&quot;$HOME/npmbin:$PATH&quot;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;What this does is makes &lt;code class=&quot;language-text&quot;&gt;~/npmbin&lt;/code&gt; available to use everywhere. Save &amp;#x26; restart your terminal window.&lt;/p&gt;
&lt;p&gt;Then navigate back to your &lt;code class=&quot;language-text&quot;&gt;~/npmbin&lt;/code&gt; directory and install a module you’d typically use globally (&lt;code class=&quot;language-text&quot;&gt;expo-cli&lt;/code&gt; or &lt;code class=&quot;language-text&quot;&gt;gatsby-cli&lt;/code&gt; are two I use a lot):&lt;/p&gt;
&lt;p&gt;Don’t use &lt;code class=&quot;language-text&quot;&gt;--global&lt;/code&gt; or &lt;code class=&quot;language-text&quot;&gt;-g&lt;/code&gt;! You don’t need to anymore :smile:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;sh&quot;&gt;&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;`&lt;/span&gt;expo-cli&lt;span class=&quot;token variable&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;conveniently-installing-modules&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#conveniently-installing-modules&quot; aria-label=&quot;conveniently installing modules permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Conveniently Installing Modules&lt;/h2&gt;
&lt;p&gt;You might think its annoying to have to cd into &lt;code class=&quot;language-text&quot;&gt;~/npmbin&lt;/code&gt; every time you want to install something globally. Although it doesn’t happen alot, I still did. I created a simple alias function to make it easier:&lt;/p&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;yg expo-cli&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Think &lt;code class=&quot;language-text&quot;&gt;yarn global&lt;/code&gt; but call it whatever you’d like!&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;sh&quot;&gt;&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token function-name function&quot;&gt;yg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; &lt;span class=&quot;token environment constant&quot;&gt;$HOME&lt;/span&gt;/dotfiles/npmbin
  &lt;span class=&quot;token function&quot;&gt;yarn&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$@&lt;/span&gt;
  &lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; -
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Cd into &lt;code class=&quot;language-text&quot;&gt;npmbin&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;add the file that was passed in as an argument&lt;/li&gt;
&lt;li&gt;cd back to wherever you were&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Place this inside your &lt;code class=&quot;language-text&quot;&gt;~/.zshrc&lt;/code&gt; or &lt;code class=&quot;language-text&quot;&gt;~/.bashrc&lt;/code&gt; file and restart your terminal. Give it a go.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Git Checkout Tricks You've Never Heard Of]]></title><description><![CDATA[Lesser-known git checkout tricks for cleanly removing committed files and cherrypicking changes without the hassle of revert or cherry-pick.]]></description><link>https://peterp.me/articles/git-checkout-tricks-youve-never-heard-of/</link><guid isPermaLink="false">https://peterp.me/articles/git-checkout-tricks-youve-never-heard-of/</guid><dc:creator><![CDATA[Peter Piekarczyk]]></dc:creator><pubDate>Wed, 20 May 2020 01:00:53 GMT</pubDate><content:encoded>&lt;p&gt;Want to know one of my favorite git secrets? It has to do with &lt;code class=&quot;language-text&quot;&gt;git checkout&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Sometimes you’ve made and committed files that shouldn’t be there. Stuff like &lt;code class=&quot;language-text&quot;&gt;prettier&lt;/code&gt; or &lt;code class=&quot;language-text&quot;&gt;console.logs&lt;/code&gt; you forgot to remove. You can mess around with &lt;code class=&quot;language-text&quot;&gt;git cherry-pick&lt;/code&gt; or &lt;code class=&quot;language-text&quot;&gt;git revert&lt;/code&gt; but that can be a hassle sometimes.&lt;/p&gt;
&lt;p&gt;If you have a file called &lt;code class=&quot;language-text&quot;&gt;screens/MyScreen.js&lt;/code&gt; that you want to completely reset based off &lt;code class=&quot;language-text&quot;&gt;master&lt;/code&gt;, run this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;sh&quot;&gt;&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; checkout origin/master -- my/file/whatever.js&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This works with other branches or folders, just replace &lt;code class=&quot;language-text&quot;&gt;master&lt;/code&gt; with &lt;code class=&quot;language-text&quot;&gt;any-branch-name&lt;/code&gt; and the file with the folder name:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;sh&quot;&gt;&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; checkout origin/any-branch-name -- folderName&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Running this will completely reset the file and get you back on track to merge your PR in!&lt;/p&gt;
&lt;p&gt;Have your own tricks? Let me know.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Filing for Blog Bankruptcy]]></title><description><![CDATA[I am *so* fed up of trying to get my blog l00kin' right]]></description><link>https://peterp.me/articles/filing-for-blog-bankruptcy/</link><guid isPermaLink="false">https://peterp.me/articles/filing-for-blog-bankruptcy/</guid><dc:creator><![CDATA[Peter Piekarczyk]]></dc:creator><pubDate>Sun, 17 May 2020 18:01:28 GMT</pubDate><content:encoded>&lt;p&gt;You want to know the worst part about blogging? It’s the part where you don’t actually get to writing anything.&lt;/p&gt;
&lt;p&gt;You spend days, weeks, maybe even months tirelessly trying to get your Gatsby theme to look like Kent C. Dodd’s and by the time you get there, you’re totally over it!&lt;/p&gt;
&lt;p&gt;Then you wait another 3 months before that &lt;em&gt;need&lt;/em&gt; to do great things comes over you. You’ve completely forgotten about how complicated Gatsby setup can be so you start over. Rinse &amp;#x26; Repeat.&lt;/p&gt;
&lt;p&gt;Don’t get me wrong, Gatsby is great (at least marketing has told me this). I’m tired of setting things up from scratch.&lt;/p&gt;
&lt;p&gt;I generated this new starter blog with minimal effort. I added disqus. I’m adding a home page. I’m calling it a day.&lt;/p&gt;
&lt;p&gt;Welcome to my new blog, powered by Gatsby.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Installing & Securing dd-wrt]]></title><description><![CDATA[I recently upgraded my TP-Link Archer c9 version 1 router to use dd-wrt. It’s powerful as it is but the additional settings I can add are…]]></description><link>https://peterp.me/articles/installing-securing-dd-wrt/installing-securing-dd-wrt/</link><guid isPermaLink="false">https://peterp.me/articles/installing-securing-dd-wrt/installing-securing-dd-wrt/</guid><dc:creator><![CDATA[Peter Piekarczyk]]></dc:creator><pubDate>Fri, 01 May 2020 05:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I recently upgraded my TP-Link Archer c9 version 1 router to use dd-wrt. It’s powerful as it is but the additional settings I can add are fantastic.&lt;/p&gt;
&lt;p&gt;Navigate to your router default homepage
&lt;a href=&quot;http://192.168.1.1/&quot;&gt;http://192.168.1.1/&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Change Password&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;setup-tab&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#setup-tab&quot; aria-label=&quot;setup tab permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Setup Tab&lt;/h2&gt;
&lt;p&gt;Assume if a field isn’t listed, you don’t have to change it!&lt;/p&gt;
&lt;h3 id=&quot;optional-settings&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#optional-settings&quot; aria-label=&quot;optional settings permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Optional Settings&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Router Name
&lt;ul&gt;
&lt;li&gt;Change to whatever you’d like&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 500px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/976d7a0444b336a920dcb02bc6639144/3ddc5/router-name.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 64.8%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAANCAYAAACpUE5eAAAACXBIWXMAAAsTAAALEwEAmpwYAAABe0lEQVR42pWSCW7CQAxFuf+legVUECGQPZmkJTvZ11/ZdCAIqIolK+NJ/Ob7T1b9MGJvRNCdBKaXQtFDHO0EddNjnidM03u56voebnCGfypwiisEYQlLZGja58C+71/mOI5YtW0Ly9ThCxfa8YA8S/AqCDgMw1Nlcn9F5DhJkKYp8jznk+Z5fkgJJAFd1z0k7bNCKmzbhq7riOOYGyVAxhJITVQv1VFN+1eFWZahKAp+lmV5hUjQ2wodx4FlWdA0DUKIP4HkFdXSM/mOagY2TQPP8+7GlB8uGySYvCZrSJHv+zAMA+v1GmEY8jc8Ml0GNb8KVvu7JlgURbymyRzHhaIofBADSSFdiGmaPLKqqthsNrzebrfs623sGR8qoGgC6l7BPHZI4hC73Y5FMZA8DIIABJbm1nXNWVUV+7IEZuWA4OuE70DAOE2wggyuY6EsqwuQAK7rPvwqr0bHPMETArap49OdoFgxtMMe+fl8AUrvSMl/8xbj3WF00z+prPGB1yWCcwAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source
              srcset=&quot;/static/976d7a0444b336a920dcb02bc6639144/ecc44/router-name.webp 125w,
/static/976d7a0444b336a920dcb02bc6639144/0e2a5/router-name.webp 250w,
/static/976d7a0444b336a920dcb02bc6639144/10636/router-name.webp 500w,
/static/976d7a0444b336a920dcb02bc6639144/55e37/router-name.webp 732w&quot;
              sizes=&quot;(max-width: 500px) 100vw, 500px&quot;
              type=&quot;image/webp&quot;
            /&gt;
          &lt;source
            srcset=&quot;/static/976d7a0444b336a920dcb02bc6639144/57f79/router-name.png 125w,
/static/976d7a0444b336a920dcb02bc6639144/3e256/router-name.png 250w,
/static/976d7a0444b336a920dcb02bc6639144/b30f8/router-name.png 500w,
/static/976d7a0444b336a920dcb02bc6639144/3ddc5/router-name.png 732w&quot;
            sizes=&quot;(max-width: 500px) 100vw, 500px&quot;
            type=&quot;image/png&quot;
          /&gt;
          &lt;img
            class=&quot;gatsby-resp-image-image&quot;
            src=&quot;/static/976d7a0444b336a920dcb02bc6639144/b30f8/router-name.png&quot;
            alt=&quot;./router-name.png&quot;
            title=&quot;&quot;
            loading=&quot;lazy&quot;
            decoding=&quot;async&quot;
            style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
          /&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;router-ip&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#router-ip&quot; aria-label=&quot;router ip permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Router IP&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Local IP Address: Change this! This’ll help prevent malware from spreading:
&lt;ul&gt;
&lt;li&gt;192.168.7.4 or 192.168.3.6 - just don’t keep it the default 192.168.1.1&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 500px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/349669a55ef201e5499305ac9907adc8/fb9ca/router-ip.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 48.800000000000004%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAYAAAC0VX7mAAAACXBIWXMAABYlAAAWJQFJUiTwAAABG0lEQVR42o1SSY6DQAzkf9xz5H0oD8iVX3BBMyLQLIE0NDthq5E9IiIkjMZSCbcpV1db1r6EwndQwItLPIYRy7IcYp7nl3wfVNMi2ULcKkjVcZHI0zR9BDWsOUXXdWiaBkmSwPM8rmnJLYLwr/CuLmzbhpTyKbyPMAyRpiniOEZZltB1HYZh4HQ6cc6CeZ4jVwpSZkwax/EpuGI9F0WBuq6Z1/c9TNOEZVm4XC44n8+/gr7v882O4yDLsjd3W9Eoiphzv9/Z6TAMfMHLDOmJ9HPr7OhLzTSzFeSUUFUVgwWDIIDrumjb9uPstoLUREIk/AnE0ZRSIFEhxNvs9jP8tyDNhaz/FUSmV9CqHIEFtw6O9m+/h9t9pHx7/gGI7ADrmCtS4wAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source
              srcset=&quot;/static/349669a55ef201e5499305ac9907adc8/ecc44/router-ip.webp 125w,
/static/349669a55ef201e5499305ac9907adc8/0e2a5/router-ip.webp 250w,
/static/349669a55ef201e5499305ac9907adc8/10636/router-ip.webp 500w,
/static/349669a55ef201e5499305ac9907adc8/db9b4/router-ip.webp 750w,
/static/349669a55ef201e5499305ac9907adc8/e4025/router-ip.webp 758w&quot;
              sizes=&quot;(max-width: 500px) 100vw, 500px&quot;
              type=&quot;image/webp&quot;
            /&gt;
          &lt;source
            srcset=&quot;/static/349669a55ef201e5499305ac9907adc8/57f79/router-ip.png 125w,
/static/349669a55ef201e5499305ac9907adc8/3e256/router-ip.png 250w,
/static/349669a55ef201e5499305ac9907adc8/b30f8/router-ip.png 500w,
/static/349669a55ef201e5499305ac9907adc8/b13e1/router-ip.png 750w,
/static/349669a55ef201e5499305ac9907adc8/fb9ca/router-ip.png 758w&quot;
            sizes=&quot;(max-width: 500px) 100vw, 500px&quot;
            type=&quot;image/png&quot;
          /&gt;
          &lt;img
            class=&quot;gatsby-resp-image-image&quot;
            src=&quot;/static/349669a55ef201e5499305ac9907adc8/b30f8/router-ip.png&quot;
            alt=&quot;./router-ip.png&quot;
            title=&quot;&quot;
            loading=&quot;lazy&quot;
            decoding=&quot;async&quot;
            style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
          /&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;network-settings&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#network-settings&quot; aria-label=&quot;network settings permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Network Settings&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Make sure DNSMasq for DNS and DHCP-Authoritive are checked&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 500px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/22537b9ac2ea5a5a13c3c80eae7cb390/778aa/network-settings.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 105.60000000000001%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAVCAYAAABG1c6oAAAACXBIWXMAAAsTAAALEwEAmpwYAAACSklEQVR42n1Uia7aMBDk/7+uUqkK5RGO3CGH49zkmGrMc3BC2pVGG4Iznj13edFif3rAcgSOlwQ//4Q42xl+n2NYdob9KcKvrwdO1wQ/DiG8qACmCcMwKIzjqKB/7+q6hRemCKMMcVpAyBaybMGLyqqDkA0SUb98ViEVBdq2Rd/3Ck3TKNCmacKuqir4vgvHsZGmCf5nXSMR+A6CIMDtdsPz+VRkvu+/CfkijmOFLMswThOm7z81xlG9wTEYcbgliAIXVVVDSonr9Yo0Td+EZVnCcRzc73dYloWu62YizMTqCW4OXD0B17krZYWU6ps8z5ch27at1PE2EmszSWlx6MGyvlCEISBzDEaK9BkVMnOSJAmiKMLj8VDgRTBCp9V1AyFy9M/nosrmxbu6rlXIJCMxwSQXRfFByEsYydrMfCtCkoRhCM/zFFhBMy9vha+zLIYQYrMTVMj8mJVi2HymCrO3tNcdQUL6VweMM+YqXy4XpUr30zoUbVTIVDB0gsQUQE98hMxirIlMzwnheSrV3gRVKkIqI0j6L0Ka6r1vhYzM9MTchyyE67qLEdpSSMI10Qchw2AxWAhWzmyBpUIStijLSoVLAtMTc1EOh4Maua3+ej8DfVejKqVSxdDXflbISukcsloszrKxX6RuOkCUPaaxn9eXBqdmziHzdz6f1aAzn5xn9tk6n8dgQlLqBGzbvBwIvXH0eGmi8dvv3QmRfK0yM9eL0dMKOc8kZYNz62z1ZNP16IfxI78fo6c3DKEXhKlyrvhqs2wR/gXpR1rub9LRuAAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source
              srcset=&quot;/static/22537b9ac2ea5a5a13c3c80eae7cb390/ecc44/network-settings.webp 125w,
/static/22537b9ac2ea5a5a13c3c80eae7cb390/0e2a5/network-settings.webp 250w,
/static/22537b9ac2ea5a5a13c3c80eae7cb390/10636/network-settings.webp 500w,
/static/22537b9ac2ea5a5a13c3c80eae7cb390/db9b4/network-settings.webp 750w,
/static/22537b9ac2ea5a5a13c3c80eae7cb390/cd067/network-settings.webp 768w&quot;
              sizes=&quot;(max-width: 500px) 100vw, 500px&quot;
              type=&quot;image/webp&quot;
            /&gt;
          &lt;source
            srcset=&quot;/static/22537b9ac2ea5a5a13c3c80eae7cb390/57f79/network-settings.png 125w,
/static/22537b9ac2ea5a5a13c3c80eae7cb390/3e256/network-settings.png 250w,
/static/22537b9ac2ea5a5a13c3c80eae7cb390/b30f8/network-settings.png 500w,
/static/22537b9ac2ea5a5a13c3c80eae7cb390/b13e1/network-settings.png 750w,
/static/22537b9ac2ea5a5a13c3c80eae7cb390/778aa/network-settings.png 768w&quot;
            sizes=&quot;(max-width: 500px) 100vw, 500px&quot;
            type=&quot;image/png&quot;
          /&gt;
          &lt;img
            class=&quot;gatsby-resp-image-image&quot;
            src=&quot;/static/22537b9ac2ea5a5a13c3c80eae7cb390/b30f8/network-settings.png&quot;
            alt=&quot;./network-settings.png&quot;
            title=&quot;&quot;
            loading=&quot;lazy&quot;
            decoding=&quot;async&quot;
            style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
          /&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;time-settings&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#time-settings&quot; aria-label=&quot;time settings permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Time Settings&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Time zone - check the right timezone&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Click Save, then Apply Settings&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Open up your computer’s Network Settings (System Prefs → Network)&lt;/li&gt;
&lt;li&gt;Ethernet / WiFi click “Advanced”&lt;/li&gt;
&lt;li&gt;Click RENEW DHCP Lease&lt;/li&gt;
&lt;li&gt;You can also toggle your WiFI on/off or unplug your ethernet cable back in&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Go back to&lt;/p&gt;
&lt;h1 id=&quot;basic-wireless-settings&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#basic-wireless-settings&quot; aria-label=&quot;basic wireless settings permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Basic Wireless Settings&lt;/h1&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 500px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/01a3c40cf2736f882b5003409ae09e3e/7108d/wireless-settings.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 176.8%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAjCAYAAACU9ioYAAAACXBIWXMAAAsTAAALEwEAmpwYAAAD8klEQVR42pVW2XLaSBTV///AVF5ix2WDqdjGK15SyfzA7JmKl4yxAKEFSWxaQcCZOheaaWMcM7fqVqu61afveroN1++j2Q5gOSGGUQZghtlshtFohOFwiCiK5HsymaAoChnTNMV0OpX/OOpqhIEP17URhj5msymUxHGMMAzR7/cxGAyWmznyIH6vEyMIAjSbTTiOizzPZQOVlvV6PZkjuG6R8mLVOrGQbiRJIm5MVk6NkwTj8Rj/R4yfv3zGzfWV6PX1FS4uznBZu5jrZQ1XlzVcnJ/h06cbnJ6eoLS3i3K5hHJ5b60atw8mfvnjAb/++YC/vtXx+9fvMBsWPM+F49gLdeB5HlzHgW230W63YVnWWjUYK6/TkVjpQldV4BmSjV1mJm3bhuu68H1/CcKDOEfLWDYqKawElbh1anS7XQHkRqVcKIp53RGM1nKOoo8/BGT5qJ8peZYhDAOEYRf8h+A60Ksus9YYdBavLr1BgiDsYjadiIWquHUr1wLSxXq9vtQkSWXB7hYwGy343Rj1+tPmFtLVVqsl3cKksMApxXgE33Nx187QaLUxWyRLB1sbQ4I0Gg0BZGaVZPkYrmPjzkpRN5uYTicvkrLWQgI+PT1JHBWrUKywgNlsYxjF4oGa111e7WexkGxCUF3nZVPM6Uprb901CUtRCBspRuKhBkvGNE1xW890no/QbDzhW2OAr/cmsjRZGzddxMIsy6S1yHH81iVNYsTpCOFwjFGebdZ6pfO/8a7yG04/36LfC6TdSAKq7UgSge/B9zvoeO583XVeVePk7BKVgxMcHZ/h5uYKhwcfsV8uobJfxv7+fNzd28PW9i62PuyiVCqhUinL/Do1yL7AVJRBVbFh1hTh3tZ7+OnjPd4d3MFyhzL3H1ms1GGtVkO1WsXR0RGOj49xeHiI42oV1eqR6PnZqYyVSgVbW++xvf0eOzvb2PmwXg2z5eH2u4WHuoOWHeLRdBGEfSRxLIUeL8Y0SWQcDgdSDapcVlXqkAysd4lkOE2XWSeB/Kh/n2WZ1MQucRaZZbcolmafk2lIwnp8NyLYTqcjG1WnqHYikGLst6jrmYUcV+8Uus27hi4rFtqYYBlL3YIkjpahSBYJ2Yhg6aa6S7hR/dqPMvh+gF6vv+zxt6xbMjbpi8pYqv/vnQkeTQt5Gsnaa/T1Iik6Y5MglAySsbhruikaTetFUl4lWAKSvmgpE6DeMk6vgO14iOJUHlI6oA6qeJO6vAL4hFBXKbPNhTTnTTdEPp7IlbpAeAbIMDC+6h0pBEtAR94strSZXjaea+MfO8Zjw1ny4ZtJ4QmqoPWHJV3ohgGCXoSWFyEa9F99E+rvw38B1VZmDr8poPMAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source
              srcset=&quot;/static/01a3c40cf2736f882b5003409ae09e3e/ecc44/wireless-settings.webp 125w,
/static/01a3c40cf2736f882b5003409ae09e3e/0e2a5/wireless-settings.webp 250w,
/static/01a3c40cf2736f882b5003409ae09e3e/10636/wireless-settings.webp 500w,
/static/01a3c40cf2736f882b5003409ae09e3e/db9b4/wireless-settings.webp 750w,
/static/01a3c40cf2736f882b5003409ae09e3e/e00f7/wireless-settings.webp 1000w,
/static/01a3c40cf2736f882b5003409ae09e3e/10483/wireless-settings.webp 1336w&quot;
              sizes=&quot;(max-width: 500px) 100vw, 500px&quot;
              type=&quot;image/webp&quot;
            /&gt;
          &lt;source
            srcset=&quot;/static/01a3c40cf2736f882b5003409ae09e3e/57f79/wireless-settings.png 125w,
/static/01a3c40cf2736f882b5003409ae09e3e/3e256/wireless-settings.png 250w,
/static/01a3c40cf2736f882b5003409ae09e3e/b30f8/wireless-settings.png 500w,
/static/01a3c40cf2736f882b5003409ae09e3e/b13e1/wireless-settings.png 750w,
/static/01a3c40cf2736f882b5003409ae09e3e/332ff/wireless-settings.png 1000w,
/static/01a3c40cf2736f882b5003409ae09e3e/7108d/wireless-settings.png 1336w&quot;
            sizes=&quot;(max-width: 500px) 100vw, 500px&quot;
            type=&quot;image/png&quot;
          /&gt;
          &lt;img
            class=&quot;gatsby-resp-image-image&quot;
            src=&quot;/static/01a3c40cf2736f882b5003409ae09e3e/b30f8/wireless-settings.png&quot;
            alt=&quot;./wireless-settings.png&quot;
            title=&quot;&quot;
            loading=&quot;lazy&quot;
            decoding=&quot;async&quot;
            style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
          /&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;h2 id=&quot;wireless-security&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#wireless-security&quot; aria-label=&quot;wireless security permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Wireless Security&lt;/h2&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 500px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/55e7f6c554d1bb2cad9ae354f3124507/37165/wireless-security.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 84.8%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAARCAYAAADdRIy+AAAACXBIWXMAABYlAAAWJQFJUiTwAAACkklEQVR42o1T/U/aUBTt///DlMW5uSj4y/wWBc1cFpfMLLpsga3qomUmWqDlo4UW2gJKKWc5F5+S6ZK95PR+9L777n33PO3T4UfsZreQz+3cyyyy2xvYyW4ik1lCemnxEel7TOvpRWTSS3i78AYLC6+h/boo4cvXIk6+6/h8XMDJtx84Oi7iw+ERcrld5PM57O/tCajnczns5fMC6vRls9soFgvQ9Z/Qwv4Q1WaIeitCwxvAD0fwogSNVohms4lGowHTLKNcLqNWq4nPsizRHdeF4ziiq6X5vgfbqsC2qojC4N49fggYjUaSlBvjOBZft9tFr9fD9EqSRKCFYYim48gmBo7HYyREkoh+d3cnVbXbbVSrVZG0mVwlYdxUhT4qlYrAdV38vW5vb6Ul/hsMBmKzOiYk2AEPrdfriKJoUiHbabVaAtr8wWq5gUk8zxM5XRUTKcTxUOJ5mMYPN3iej06n8wAml9scj8X+36XZtg3TNGWKpnkjunlzI3qpVEKpZODq6jcM4xKGYaBkGCKnQd/l5YVAOzh4j/XVFWxurGFtdQXbW+tYXXmH5eUMUqmZCWZfIDU7g5epR6Sm9dkZzL+aw/z8HLRWZ4Crig+zFsAwPVxbPq7tLvQLE7qu4+zsDOfn54LT01PxUdKvZKFQkMHwejS/00G5YqNi1eB3AsQJMIwTxKPJ5XMYnDKnSJ0+MkNRTA2GuiQMwwCu6wh6UfSE2JwsKeN5bRkOh8iBMfmzQ2EQOchhcKM6iZUoHvI/ycxKyQgmVJUpGg2HQ7G1IAiEh0z2HD14N2yRceqJPfJvQmweylfEGEnI++HTo1Q6q+KpbI02N9JWz0x18qRlVtDv9wXqaVHSVkmoq6emWvwX/gBOouJDrEQfWQAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source
              srcset=&quot;/static/55e7f6c554d1bb2cad9ae354f3124507/ecc44/wireless-security.webp 125w,
/static/55e7f6c554d1bb2cad9ae354f3124507/0e2a5/wireless-security.webp 250w,
/static/55e7f6c554d1bb2cad9ae354f3124507/10636/wireless-security.webp 500w,
/static/55e7f6c554d1bb2cad9ae354f3124507/db9b4/wireless-security.webp 750w,
/static/55e7f6c554d1bb2cad9ae354f3124507/e00f7/wireless-security.webp 1000w,
/static/55e7f6c554d1bb2cad9ae354f3124507/9d46e/wireless-security.webp 1002w&quot;
              sizes=&quot;(max-width: 500px) 100vw, 500px&quot;
              type=&quot;image/webp&quot;
            /&gt;
          &lt;source
            srcset=&quot;/static/55e7f6c554d1bb2cad9ae354f3124507/57f79/wireless-security.png 125w,
/static/55e7f6c554d1bb2cad9ae354f3124507/3e256/wireless-security.png 250w,
/static/55e7f6c554d1bb2cad9ae354f3124507/b30f8/wireless-security.png 500w,
/static/55e7f6c554d1bb2cad9ae354f3124507/b13e1/wireless-security.png 750w,
/static/55e7f6c554d1bb2cad9ae354f3124507/332ff/wireless-security.png 1000w,
/static/55e7f6c554d1bb2cad9ae354f3124507/37165/wireless-security.png 1002w&quot;
            sizes=&quot;(max-width: 500px) 100vw, 500px&quot;
            type=&quot;image/png&quot;
          /&gt;
          &lt;img
            class=&quot;gatsby-resp-image-image&quot;
            src=&quot;/static/55e7f6c554d1bb2cad9ae354f3124507/b30f8/wireless-security.png&quot;
            alt=&quot;./wireless-security.png&quot;
            title=&quot;&quot;
            loading=&quot;lazy&quot;
            decoding=&quot;async&quot;
            style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
          /&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;h2 id=&quot;security&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#security&quot; aria-label=&quot;security permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Security&lt;/h2&gt;
&lt;p&gt;** I have WAN requests ping enabled for line quality tests on dsl reports&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 500px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/bd5e439b132c38c147f1be6aa994286e/f778e/security.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 95.19999999999999%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAATCAYAAACQjC21AAAACXBIWXMAAAsTAAALEwEAmpwYAAAC4ElEQVR42n1U204TURTtm4kmFXqZmXOdSzvT6fSKkpRepEWagAgJAjEYUUh81vDiK4m8+O4n+An+hJ+1zD50hl7Ah51zZubMOmuvvfbOCelB+S0ovw3lN6GCLpTXmD23TEgvgaR3tAoBKSWEEA9GTrgxZLQLGU0hqttQ9beQ4QQqfgNdm5pQ4TZ0NIEMx3AcxwTnApzzlch5rkIcBWgmITqtOuLIR7tVR1R14VjrYE4Rjl2E4GW8GvZweHiIwWCAm5sbnJ6eIp/PG2aMMRM5rTWCoGIiDCN4ng+tXSilZyzoMIeUCv3BENPpFN1uF8fHx9ja2kKpVDKA9ww9D81mE1EUoVarIQgClMtlWJZlbqRDtNJPOzs72NvbM/u1tTVzLv2eARLDarVqAMMwzPZxHBvx01QIZDgcYjweQymVFWEeLAMkVgRCkQIS22XA0WiEyWRiAJeBVlKu1xMkSWKYUbRaLdBl84D9ft+kPQ+Yfs+KIqWAFAxScGjFoZSE0tqAzYtNe7qQLiLm6bsVhmRsSV50axBuAi40+CPppB58CCgDNEAhmXoCnRxB+h1wZkOI1W4gMKr+vANWOsXzXLSaMZqNGFoxOI69oE26pzRJv5OTE7Pe3t7i4ODA2GfB2KSh77nwfc/oyJgNzpyFNNKidDod9Ho9tNttnJ2dYXNz03hxwdikodA1cBXOtIwhlA8h+KMp27aNQqFgnpVyIZWGmA2MHBVC1vZM8+v6PnT9DaS/Ac4d8AXxCZDN0r9rR6tcRLnwDKX1p2BOOdVQI6lHYMwyL00w2/ywrOFw0DeDoVKp4urzR3z9/hPvrv/g6sdfdPpHsIrP7zqlUqnM2AiwjBFb0lBisL2Lfn+AoFLBp4sPuPhyjf3LX3j/7TcaL1/DKhfuO4UMS1OEuuRu3s0qbVYHQmqEo0skjTZebHRxfn6ORhKjVlVYzz+BbZUMoZyYm8C0/m8ay6Uz1IJZUWa+/Qc2VBWrw9+qbgAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source
              srcset=&quot;/static/bd5e439b132c38c147f1be6aa994286e/ecc44/security.webp 125w,
/static/bd5e439b132c38c147f1be6aa994286e/0e2a5/security.webp 250w,
/static/bd5e439b132c38c147f1be6aa994286e/10636/security.webp 500w,
/static/bd5e439b132c38c147f1be6aa994286e/db9b4/security.webp 750w,
/static/bd5e439b132c38c147f1be6aa994286e/2b36d/security.webp 788w&quot;
              sizes=&quot;(max-width: 500px) 100vw, 500px&quot;
              type=&quot;image/webp&quot;
            /&gt;
          &lt;source
            srcset=&quot;/static/bd5e439b132c38c147f1be6aa994286e/57f79/security.png 125w,
/static/bd5e439b132c38c147f1be6aa994286e/3e256/security.png 250w,
/static/bd5e439b132c38c147f1be6aa994286e/b30f8/security.png 500w,
/static/bd5e439b132c38c147f1be6aa994286e/b13e1/security.png 750w,
/static/bd5e439b132c38c147f1be6aa994286e/f778e/security.png 788w&quot;
            sizes=&quot;(max-width: 500px) 100vw, 500px&quot;
            type=&quot;image/png&quot;
          /&gt;
          &lt;img
            class=&quot;gatsby-resp-image-image&quot;
            src=&quot;/static/bd5e439b132c38c147f1be6aa994286e/b30f8/security.png&quot;
            alt=&quot;./security.png&quot;
            title=&quot;&quot;
            loading=&quot;lazy&quot;
            decoding=&quot;async&quot;
            style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
          /&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;h2 id=&quot;adminstration-keep-alive&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#adminstration-keep-alive&quot; aria-label=&quot;adminstration keep alive permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Adminstration Keep Alive&lt;/h2&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 500px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/9028995744e6746ae4f11f5fc26907cd/e56b9/admin-1.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 72%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAOCAYAAAAvxDzwAAAACXBIWXMAAAsTAAALEwEAmpwYAAACd0lEQVR42m2SS2/kRBSF/RdQP+x62G6/H+207Wl30tNRBiYQ0iwmkXjMGiSSRrDIFiRgsgj87Q9VOQxkMotPvi5XHZ97bjlvv/uGv/+658/ff+XdH7/xy8833P74PYcbww8cbm/46TBi6sPhf9w+x6mbF2xefsmwvWB98gX95pz++IL1ds+LzWv6rmW1WnF01NC1Le2qoW1XtG1L13XPcKSfotMdOj5Gp6f46UtUfIKIdnjhmul0QhAEpGmK8DxkmKN0gBSC2XzO/AOcKApo6pSqiKmKiKbOqMoU6U1Qcs5sNmMYBi4vL8mzlPz4iqY/oSpzpJQopZ7gKB2iggzlp6ggR+r48aN+RCGExPPEuC49KyQ/EPpPMKzR+Tk6fYXOXuOnu/HAe4yIQArXis7nLq7rju0/2TfiLBYL6rqiKguWywrf13iPm4XBnaCzgXz4iipPePPmiu12S1EUHxeMooimaaiqirquLVprhBC2rdlsylHbc7w9RSlJlmV2SOanxqnB1CZrUzthGNoJGuI4trwXlMpuPFq1DJsT68q4M2c2m40VN+dMl33fU5bl2HKe5/bFiNl8hBiRCuFOUdmapLvg26+veHd/z9nZGQ8PD+z3e66vr9ntdtzd3dnaMS5sVtaRsJM1rVoeczFrxnXg+8RxYmsTlXn+izFmonBUuEQXF6jkFJW+ws8/I8g/Jaz2+PEaraR1PZ1Mxtymn+C6c+au+2QYoyE7lIS66aiWLc1qIEoKhAzG+6gXzKZTuq7n/PxzsjQhW+9ZrgbKIrP389mUg8C0ERFFC9IkJgx8pPDG9qWw7ky+JvQwDFiUG5KsJFqEH702/wAgRZxNSKOnOgAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source
              srcset=&quot;/static/9028995744e6746ae4f11f5fc26907cd/ecc44/admin-1.webp 125w,
/static/9028995744e6746ae4f11f5fc26907cd/0e2a5/admin-1.webp 250w,
/static/9028995744e6746ae4f11f5fc26907cd/10636/admin-1.webp 500w,
/static/9028995744e6746ae4f11f5fc26907cd/db9b4/admin-1.webp 750w,
/static/9028995744e6746ae4f11f5fc26907cd/294ed/admin-1.webp 902w&quot;
              sizes=&quot;(max-width: 500px) 100vw, 500px&quot;
              type=&quot;image/webp&quot;
            /&gt;
          &lt;source
            srcset=&quot;/static/9028995744e6746ae4f11f5fc26907cd/57f79/admin-1.png 125w,
/static/9028995744e6746ae4f11f5fc26907cd/3e256/admin-1.png 250w,
/static/9028995744e6746ae4f11f5fc26907cd/b30f8/admin-1.png 500w,
/static/9028995744e6746ae4f11f5fc26907cd/b13e1/admin-1.png 750w,
/static/9028995744e6746ae4f11f5fc26907cd/e56b9/admin-1.png 902w&quot;
            sizes=&quot;(max-width: 500px) 100vw, 500px&quot;
            type=&quot;image/png&quot;
          /&gt;
          &lt;img
            class=&quot;gatsby-resp-image-image&quot;
            src=&quot;/static/9028995744e6746ae4f11f5fc26907cd/b30f8/admin-1.png&quot;
            alt=&quot;./admin-1.png&quot;
            title=&quot;&quot;
            loading=&quot;lazy&quot;
            decoding=&quot;async&quot;
            style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
          /&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 500px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/1d784f3b388fa1491088966e3e686ac7/69ebe/admin-2.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 41.6%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAICAYAAAD5nd/tAAAACXBIWXMAAAsTAAALEwEAmpwYAAABQ0lEQVR42m2S3VLDIBCF8wzaQhMCSZpAQn5b+2PVduJ4550dO51eOM74/g9xHIipsfWC4Sy7fBwWHELG4PEaXO7A5RZctfCYgOe58Dzverj0rCeTCVz3b51DKUEQNxDJPfxoBn86B2McjJkCNijutJhq+FxYrVSKIAitZqzLO4QQ6Ewh1xJkfANKbkEpBaXd6f3wfuZ4+4VqtoLOUnx+nLDbPqGuawghrGMLNCdlmT7PeZ5DKWULhtcxwONhj6ZpkMoY4XKPtFqjLIxrbvMWmKYGlCFJEmitrY7j+Ko/Jn55PaBu5kiVxOr5DfV8jaoswLn4BUopUVWVhRVFgTAMYdZ7yBAYbT6gyw54Or7j8WFj9/Chw96R6d2lo0u9vJuhbVtE0RSj0fj80n3eMRDTUN/3/wVcxmVZYbFYIAiCqy9lHH4DaCHdneDFSVMAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source
              srcset=&quot;/static/1d784f3b388fa1491088966e3e686ac7/ecc44/admin-2.webp 125w,
/static/1d784f3b388fa1491088966e3e686ac7/0e2a5/admin-2.webp 250w,
/static/1d784f3b388fa1491088966e3e686ac7/10636/admin-2.webp 500w,
/static/1d784f3b388fa1491088966e3e686ac7/db9b4/admin-2.webp 750w,
/static/1d784f3b388fa1491088966e3e686ac7/66767/admin-2.webp 754w&quot;
              sizes=&quot;(max-width: 500px) 100vw, 500px&quot;
              type=&quot;image/webp&quot;
            /&gt;
          &lt;source
            srcset=&quot;/static/1d784f3b388fa1491088966e3e686ac7/57f79/admin-2.png 125w,
/static/1d784f3b388fa1491088966e3e686ac7/3e256/admin-2.png 250w,
/static/1d784f3b388fa1491088966e3e686ac7/b30f8/admin-2.png 500w,
/static/1d784f3b388fa1491088966e3e686ac7/b13e1/admin-2.png 750w,
/static/1d784f3b388fa1491088966e3e686ac7/69ebe/admin-2.png 754w&quot;
            sizes=&quot;(max-width: 500px) 100vw, 500px&quot;
            type=&quot;image/png&quot;
          /&gt;
          &lt;img
            class=&quot;gatsby-resp-image-image&quot;
            src=&quot;/static/1d784f3b388fa1491088966e3e686ac7/b30f8/admin-2.png&quot;
            alt=&quot;./admin-2.png&quot;
            title=&quot;&quot;
            loading=&quot;lazy&quot;
            decoding=&quot;async&quot;
            style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
          /&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 500px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/8ff6f5e1a061fd7cad084241a79658d7/8a01d/admin-3.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 73.6%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAPCAYAAADkmO9VAAAACXBIWXMAAAsTAAALEwEAmpwYAAACLUlEQVR42m2US4/aMBSF+QVdUJ5JSEpI4lcS3lI1oiO1HVGkSggxBbqoNN2M1E3V/7861XFwBphZXNlG9udzjm9oeH6EUHxBJL8iTFfw/QE8z4Pn+efxdfks37flXcxZDT8I4Q/n8D4s7GjX501vwngwGKDf76Hf7yMIKgG9Xs+OjSAIkBuJydggS2O02210u716Aw/Z4rzTRKBWkJ+fMc4lirLEv79/MJ/PMZ1OEUURGrxRCAmlFJTSSNMUo9EIw+HQgi7VdTpt5MUED9++I00SZEKiXD1CKgNjNMIwrBRWMIWiKDCZTJDnOaSUtUpXrVYLi8Uchx+PyLIUQmkkd7+g8zHKIq+AVJhlmQUSwkOV7W5t+Rq4wOF4tAqF1JD3T1CmRJGbF4UEEai1tnYHg8GVMgflRbPZDLvdrrIsFbK7n5C6QG5ugITRalmWNlwqZL2l8Hg8IktTm5349PTaMmFCCAukfWOMVUw4L3RZXgL5eLRMYGX5AsjDBHJTwmzOc/7O1yaU+2iZ7bHdbjEaxUgzieTjCULlMFrZqKxlKqSq8Xhcq3OP5H7nutlsYrlc4nQ6QYgMUhuI+9+V5bJAGEYvQLaMy5EgVw5MhfUrHw5IklFl+QwsXIYE0h4Pufw4ck3rBHLtLDPX9XoNrXmRRjx5QCYUtLqwzFycXSrlnMUmr76QTv29xnGMzWaD/X5vc2y/f2e7gXvYEY2r7/WNuu1HthQvZjy02L/58/gPxRmtqgVNQ5YAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source
              srcset=&quot;/static/8ff6f5e1a061fd7cad084241a79658d7/ecc44/admin-3.webp 125w,
/static/8ff6f5e1a061fd7cad084241a79658d7/0e2a5/admin-3.webp 250w,
/static/8ff6f5e1a061fd7cad084241a79658d7/10636/admin-3.webp 500w,
/static/8ff6f5e1a061fd7cad084241a79658d7/a45d9/admin-3.webp 708w&quot;
              sizes=&quot;(max-width: 500px) 100vw, 500px&quot;
              type=&quot;image/webp&quot;
            /&gt;
          &lt;source
            srcset=&quot;/static/8ff6f5e1a061fd7cad084241a79658d7/57f79/admin-3.png 125w,
/static/8ff6f5e1a061fd7cad084241a79658d7/3e256/admin-3.png 250w,
/static/8ff6f5e1a061fd7cad084241a79658d7/b30f8/admin-3.png 500w,
/static/8ff6f5e1a061fd7cad084241a79658d7/8a01d/admin-3.png 708w&quot;
            sizes=&quot;(max-width: 500px) 100vw, 500px&quot;
            type=&quot;image/png&quot;
          /&gt;
          &lt;img
            class=&quot;gatsby-resp-image-image&quot;
            src=&quot;/static/8ff6f5e1a061fd7cad084241a79658d7/b30f8/admin-3.png&quot;
            alt=&quot;./admin-3.png&quot;
            title=&quot;&quot;
            loading=&quot;lazy&quot;
            decoding=&quot;async&quot;
            style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
          /&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;h2 id=&quot;commands&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#commands&quot; aria-label=&quot;commands permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Commands&lt;/h2&gt;
&lt;p&gt;In startup script, I have these 3 settings. This is the “Transmit Queue Length”. I have a very small length set from the traditional 1500 to help improve ping times.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;ifconfig eth0 txqueuelen 2
ifconfig eth1 txqueuelen 2
sleep 10&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;pi-hole-settings&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#pi-hole-settings&quot; aria-label=&quot;pi hole settings permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Pi-hole settings&lt;/h2&gt;
&lt;p&gt;Pi-hole is a network adblocker that runs on the raspberry pi:&lt;/p&gt;
&lt;p&gt;These settings live under Services &gt; DNSMasq.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;sh&quot;&gt;&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;dhcp-option&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;6,192&lt;/span&gt;.168.XXX.XXX
domain-needed
bogus-priv
no-resolv
&lt;span class=&quot;token assign-left variable&quot;&gt;server&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;192.168&lt;/span&gt;.XXX.XXX
expand-hosts&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;resources&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#resources&quot; aria-label=&quot;resources permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;ftp://ftp.dd-wrt.com/betas/2020/&quot;&gt;ftp://ftp.dd-wrt.com/betas/2020/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://wiki.dd-wrt.com/wiki/index.php/Installation&quot;&gt;https://wiki.dd-wrt.com/wiki/index.php/Installation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dfarq.homeip.net/recommended-dd-wrt-settings/&quot;&gt;https://dfarq.homeip.net/recommended-dd-wrt-settings/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://wiki.dd-wrt.com/wiki/index.php/Basic_Wireless_Settings&quot;&gt;https://wiki.dd-wrt.com/wiki/index.php/Basic_Wireless_Settings&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.reddit.com/r/DestinyTheGame/comments/5zxaw0/reduce_lag_in_pvpimprove_your_connection_indepth/&quot;&gt;https://www.reddit.com/r/DestinyTheGame/comments/5zxaw0/reduce_lag_in_pvpimprove_your_connection_indepth/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.reddit.com/r/pihole/comments/er1opk/pihole_ddwrt_dns_redirection_issues/&quot;&gt;https://www.reddit.com/r/pihole/comments/er1opk/pihole_ddwrt_dns_redirection_issues/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Archer C9v1 dd-wrt beta &lt;a href=&quot;ftp://ftp.dd-wrt.com/betas/2020/04-15-2020-r42910/tplink_archer-c9v1/&quot;&gt;ftp://ftp.dd-wrt.com/betas/2020/04-15-2020-r42910/tplink_archer-c9v1/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title><![CDATA[Protect your Home & Mobile Network with NextDNS]]></title><description><![CDATA[NextDNS is the privacy-enabled tool you’ve been waiting for. It’s like Pi-hole but runs in the cloud. Right now it’s free, but once they…]]></description><link>https://peterp.me/articles/protect-your-home-network-with-nextdns/protect-your-home-network-with-nextdns/</link><guid isPermaLink="false">https://peterp.me/articles/protect-your-home-network-with-nextdns/protect-your-home-network-with-nextdns/</guid><dc:creator><![CDATA[Peter Piekarczyk]]></dc:creator><pubDate>Mon, 27 Apr 2020 05:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;https://nextdns.io&quot;&gt;NextDNS&lt;/a&gt; is the privacy-enabled tool you’ve been waiting for. It’s like Pi-hole but runs in the cloud.&lt;/p&gt;
&lt;p&gt;Right now it’s free, but once they leave beta they plan to charge a couple bucks a month. &lt;strong&gt;Worth. every. penny.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;NextDNS will encrypt your DNS, block ads, bypass censorship, protect your privacy and offer parental controls.&lt;/p&gt;
&lt;p&gt;NextDNS will also protect you from everything like Cryptojacking, threat intelligence, crazy algorithms, NSA spying, wide spectrum trackers (like wtf!) and much more&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Finally&lt;/em&gt; you can use NextDNS like a Pi-hole in the cloud and block any list of websites, including lists like &lt;a href=&quot;https://github.com/StevenBlack/hosts&quot;&gt;Steven Black’s Host Files&lt;/a&gt;.&lt;/p&gt;
&lt;h1 id=&quot;running-nextdns-via-apps&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#running-nextdns-via-apps&quot; aria-label=&quot;running nextdns via apps permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Running NextDNS via Apps&lt;/h1&gt;
&lt;p&gt;You can run NextDNS on every device individually. Download the specific app, enter your configuration id, done!&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://play.google.com/store/apps/details?id=io.nextdns.NextDNS&quot;&gt;Google Play Store&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://apps.apple.com/app/nextdns/id1463342498&quot;&gt;iOS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://nextdns.io/download/windows/stable&quot;&gt;Windows&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://apps.apple.com/app/nextdns/id1464122853&quot;&gt;Mac App Store&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/nextdns/nextdns/wiki&quot;&gt;Linux&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://chrome.google.com/webstore/detail/nextdns/pkdcfcnohogmdmhllilgaheobbjadggl&quot;&gt;Chrome OS&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Make sure you’re running an up to date DD-WRT version. Most routers support the latest updates.&lt;/p&gt;
&lt;h1 id=&quot;running-nextdns-directly-on-your-router&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#running-nextdns-directly-on-your-router&quot; aria-label=&quot;running nextdns directly on your router permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Running NextDNS directly on your Router&lt;/h1&gt;
&lt;p&gt;The nice part about this is that you don’t have to install any apps. The tricky part is, depending on the router/software you have, this can turn into a shitshow.&lt;/p&gt;
&lt;p&gt;You can see if your router supports one-click install &lt;a href=&quot;https://github.com/nextdns/nextdns/wiki&quot;&gt;here&lt;/a&gt;.
A lot of your favorite routers are supported:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;OpenWRT&lt;/li&gt;
&lt;li&gt;Merlin (Asus)&lt;/li&gt;
&lt;li&gt;Ubiquiti EdgeOS / USG&lt;/li&gt;
&lt;li&gt;Synology&lt;/li&gt;
&lt;li&gt;VyOS&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Since I run dd-wrt, it’s a bit more complex:&lt;/p&gt;
&lt;h1 id=&quot;warning---this-shit-is-complex-and-you-might-brick-your-router&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#warning---this-shit-is-complex-and-you-might-brick-your-router&quot; aria-label=&quot;warning   this shit is complex and you might brick your router permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Warning - This Shit Is Complex And You Might Brick Your Router&lt;/h1&gt;
&lt;p&gt;Don’t blame me for it, every router config is different. YMMV, etc. Make sure you back it up and whatever.&lt;/p&gt;
&lt;h2 id=&quot;enabling-jffs-if-you-dont-have-it-enabled&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#enabling-jffs-if-you-dont-have-it-enabled&quot; aria-label=&quot;enabling jffs if you dont have it enabled permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Enabling JFFS if you don’t have it enabled&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://wiki.dd-wrt.com/wiki/index.php/JFFS#Enable_JFFS:_Create_.2Fjffs&quot;&gt;https://wiki.dd-wrt.com/wiki/index.php/JFFS#Enable_JFFS:&lt;em&gt;Create&lt;/em&gt;.2Fjffs&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Click Administration Tab&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Scroll down to JFFS2 Support. It’s probably disabled. Click Enable&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 500px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/f380e661e0ae05a1b74c2242c3287960/685e1/jffs-disabled.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 22.400000000000002%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAECAYAAACOXx+WAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAtklEQVR42mWPSwrDMAwFc4MsG0uyTRpDWufjUOgFSqGrQrLKEXr/E7xihWTRLgY90NiSCrZn+G6Bu7zg4lthH0HmBGb+o6oqhYhBZNQjIiX3CxEHV0fFhxt8k2BdDRE+xJ38UQgBTdNAmGF9DVe3sCKw1qpT5JDSgHHoMPRXDH3ElBKmadKJxhgl57Issa4r5nlBbAPi/Yn4+OCWeoxjUq/YThGIiNY950G/5+YNNo+PSsfbzfkCuoZuwdncvv8AAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source
              srcset=&quot;/static/f380e661e0ae05a1b74c2242c3287960/ecc44/jffs-disabled.webp 125w,
/static/f380e661e0ae05a1b74c2242c3287960/0e2a5/jffs-disabled.webp 250w,
/static/f380e661e0ae05a1b74c2242c3287960/10636/jffs-disabled.webp 500w,
/static/f380e661e0ae05a1b74c2242c3287960/52234/jffs-disabled.webp 706w&quot;
              sizes=&quot;(max-width: 500px) 100vw, 500px&quot;
              type=&quot;image/webp&quot;
            /&gt;
          &lt;source
            srcset=&quot;/static/f380e661e0ae05a1b74c2242c3287960/57f79/jffs-disabled.png 125w,
/static/f380e661e0ae05a1b74c2242c3287960/3e256/jffs-disabled.png 250w,
/static/f380e661e0ae05a1b74c2242c3287960/b30f8/jffs-disabled.png 500w,
/static/f380e661e0ae05a1b74c2242c3287960/685e1/jffs-disabled.png 706w&quot;
            sizes=&quot;(max-width: 500px) 100vw, 500px&quot;
            type=&quot;image/png&quot;
          /&gt;
          &lt;img
            class=&quot;gatsby-resp-image-image&quot;
            src=&quot;/static/f380e661e0ae05a1b74c2242c3287960/b30f8/jffs-disabled.png&quot;
            alt=&quot;./jffs-disabled.png&quot;
            title=&quot;&quot;
            loading=&quot;lazy&quot;
            decoding=&quot;async&quot;
            style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
          /&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Save. Wait a few seconds. Then, click Apply Settings.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Go back to JFFS2 Support. Click “Enable” on Clean Internal Flash Storage. Don’t click Save, just Apply Settings.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 500px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/83b95781354d2fee37d736560bd1354b/517d9/jffs-enabled.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 38.4%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAICAYAAAD5nd/tAAAACXBIWXMAAAsTAAALEwEAmpwYAAABR0lEQVR42nVSyU7DMBTsJyCqNovTLHXseEmTkJZSFlEhDoUeuCAhOHJGXJD4/kHPUSIocBjNk/08nnn2KJZbzPLzDnyFKDFgYYjwP7AIjDFXE0dRNNTEI5ZvwfgFZmqPSO0Rpg08bzo0HSKYHsH3PQRBgMlkguPx2NW+77v9kTUCRgtYzVGaHEZLVFWFNE1dEwnTAYeQQd2+oaxXkFLg/m6Hl+cnSCmxWCw6h1IWIPBcQMgCQggYY5AkCTzPG6KSYBgyVFePKHQJPk+xOrvE9c0OnM+dqBOs69oJENMt5I7Qti02mw3iOB4cUqTPj3ecrteorES2fIDavmLZWDQnbSdYFAU45yAmZFn2a+C9Q1orlHYpyJFSCkmS/nwUckWb5JJqaqbZDXNzUTtBcluWJbTWsNa6VN9n7QT7w8R9/dfr9jjsP/wNX7q13/HshutOAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source
              srcset=&quot;/static/83b95781354d2fee37d736560bd1354b/ecc44/jffs-enabled.webp 125w,
/static/83b95781354d2fee37d736560bd1354b/0e2a5/jffs-enabled.webp 250w,
/static/83b95781354d2fee37d736560bd1354b/10636/jffs-enabled.webp 500w,
/static/83b95781354d2fee37d736560bd1354b/2aac6/jffs-enabled.webp 694w&quot;
              sizes=&quot;(max-width: 500px) 100vw, 500px&quot;
              type=&quot;image/webp&quot;
            /&gt;
          &lt;source
            srcset=&quot;/static/83b95781354d2fee37d736560bd1354b/57f79/jffs-enabled.png 125w,
/static/83b95781354d2fee37d736560bd1354b/3e256/jffs-enabled.png 250w,
/static/83b95781354d2fee37d736560bd1354b/b30f8/jffs-enabled.png 500w,
/static/83b95781354d2fee37d736560bd1354b/517d9/jffs-enabled.png 694w&quot;
            sizes=&quot;(max-width: 500px) 100vw, 500px&quot;
            type=&quot;image/png&quot;
          /&gt;
          &lt;img
            class=&quot;gatsby-resp-image-image&quot;
            src=&quot;/static/83b95781354d2fee37d736560bd1354b/b30f8/jffs-enabled.png&quot;
            alt=&quot;./jffs-enabled.png&quot;
            title=&quot;&quot;
            loading=&quot;lazy&quot;
            decoding=&quot;async&quot;
            style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
          /&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Once the settings are applied, turn off Clean Internal Flash Storage and Click Save&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 500px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/83b95781354d2fee37d736560bd1354b/517d9/jffs-enabled.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 38.4%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAICAYAAAD5nd/tAAAACXBIWXMAAAsTAAALEwEAmpwYAAABR0lEQVR42nVSyU7DMBTsJyCqNovTLHXseEmTkJZSFlEhDoUeuCAhOHJGXJD4/kHPUSIocBjNk/08nnn2KJZbzPLzDnyFKDFgYYjwP7AIjDFXE0dRNNTEI5ZvwfgFZmqPSO0Rpg08bzo0HSKYHsH3PQRBgMlkguPx2NW+77v9kTUCRgtYzVGaHEZLVFWFNE1dEwnTAYeQQd2+oaxXkFLg/m6Hl+cnSCmxWCw6h1IWIPBcQMgCQggYY5AkCTzPG6KSYBgyVFePKHQJPk+xOrvE9c0OnM+dqBOs69oJENMt5I7Qti02mw3iOB4cUqTPj3ecrteorES2fIDavmLZWDQnbSdYFAU45yAmZFn2a+C9Q1orlHYpyJFSCkmS/nwUckWb5JJqaqbZDXNzUTtBcluWJbTWsNa6VN9n7QT7w8R9/dfr9jjsP/wNX7q13/HshutOAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source
              srcset=&quot;/static/83b95781354d2fee37d736560bd1354b/ecc44/jffs-enabled.webp 125w,
/static/83b95781354d2fee37d736560bd1354b/0e2a5/jffs-enabled.webp 250w,
/static/83b95781354d2fee37d736560bd1354b/10636/jffs-enabled.webp 500w,
/static/83b95781354d2fee37d736560bd1354b/2aac6/jffs-enabled.webp 694w&quot;
              sizes=&quot;(max-width: 500px) 100vw, 500px&quot;
              type=&quot;image/webp&quot;
            /&gt;
          &lt;source
            srcset=&quot;/static/83b95781354d2fee37d736560bd1354b/57f79/jffs-enabled.png 125w,
/static/83b95781354d2fee37d736560bd1354b/3e256/jffs-enabled.png 250w,
/static/83b95781354d2fee37d736560bd1354b/b30f8/jffs-enabled.png 500w,
/static/83b95781354d2fee37d736560bd1354b/517d9/jffs-enabled.png 694w&quot;
            sizes=&quot;(max-width: 500px) 100vw, 500px&quot;
            type=&quot;image/png&quot;
          /&gt;
          &lt;img
            class=&quot;gatsby-resp-image-image&quot;
            src=&quot;/static/83b95781354d2fee37d736560bd1354b/b30f8/jffs-enabled.png&quot;
            alt=&quot;./jffs-enabled.png&quot;
            title=&quot;&quot;
            loading=&quot;lazy&quot;
            decoding=&quot;async&quot;
            style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
          /&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Reboot your router!&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;installing-entware-on-dd-wrt&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#installing-entware-on-dd-wrt&quot; aria-label=&quot;installing entware on dd wrt permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Installing Entware on DD-WRT&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://wiki.dd-wrt.com/wiki/index.php/Installing_Entware&quot;&gt;https://wiki.dd-wrt.com/wiki/index.php/Installing_Entware&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;It sounds like a PITA but it really isn’t bad. You need a USB stick.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You need e2fsprogs to convert to e2f fiesystem that’s supported by your router:&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;brew install e2fsprogs&lt;/code&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;sudo $(brew --prefix e2fsprogs)/sbin/mkfs.ext2 -L opt /dev/disk2s1&lt;/code&gt; Run diskutil list to see the right disk&lt;/li&gt;
&lt;li&gt;mkfs.ext2 for USB dis, mkfs.ext3 for hard drive&lt;/li&gt;
&lt;li&gt;If you get a “resource busy” command then run &lt;code class=&quot;language-text&quot;&gt;diskutil unmount disk3&lt;/code&gt; (again, find disk with diskutil list)&lt;/li&gt;
&lt;li&gt;Once that’s done, plug it into your router&lt;/li&gt;
&lt;li&gt;Go to DD-WRT Admin, find Services USB and turn on: Core USB Support, USB Storage and Automatic Drive Mount are all enabled&lt;/li&gt;
&lt;li&gt;Reboot your router&lt;/li&gt;
&lt;li&gt;Download Entware&lt;/li&gt;
&lt;li&gt;Go here and under “Installation” figure out your router type. It’s probably ARM7 but make sure !!! &lt;a href=&quot;https://wiki.dd-wrt.com/wiki/index.php/Installing_Entware&quot;&gt;https://wiki.dd-wrt.com/wiki/index.php/Installing_Entware&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;mkdir&lt;/span&gt; /opt/jffs
&lt;span class=&quot;token function&quot;&gt;mount&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-n&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--bind&lt;/span&gt; /opt/jffs /jffs&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;cd into &lt;code class=&quot;language-text&quot;&gt;/opt/jffs&lt;/code&gt;&lt;/p&gt;
&lt;h2 id=&quot;install-nextdns&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#install-nextdns&quot; aria-label=&quot;install nextdns permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Install NextDNS&lt;/h2&gt;
&lt;p&gt;Whew, we’re finally here!&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sh&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-c&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;printf&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;GET /install HTTP/1.0&lt;span class=&quot;token entity&quot; title=&quot;\n&quot;&gt;\n&lt;/span&gt;Host: nextdns.io&lt;span class=&quot;token entity&quot; title=&quot;\n&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;token entity&quot; title=&quot;\n&quot;&gt;\n&lt;/span&gt;&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt;
    openssl s_client &lt;span class=&quot;token parameter variable&quot;&gt;-quiet&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-connect&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;nextdns.io:443&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&lt;span class=&quot;token file-descriptor important&quot;&gt;2&lt;/span&gt;&gt;&lt;/span&gt;/dev/null &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;sed&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-n&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;/^\r/,$p&apos;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sed&lt;/span&gt; 1d&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;restart-your-router&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#restart-your-router&quot; aria-label=&quot;restart your router permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Restart your Router&lt;/h2&gt;
&lt;h1 id=&quot;closing-thoughts&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#closing-thoughts&quot; aria-label=&quot;closing thoughts permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Closing Thoughts&lt;/h1&gt;
&lt;p&gt;DD-WRT support is finnicky right now, but the NextDNS team is actively working on making it a one-click installation.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[FNM: The Fastest Node Version Manager Ever]]></title><description><![CDATA[Why fnm (Fast Node Manager) is the best replacement for nvm and n — written in Rust, it switches Node versions nearly instantly.]]></description><link>https://peterp.me/articles/fnm-fastest-node-version-manager-ever/</link><guid isPermaLink="false">https://peterp.me/articles/fnm-fastest-node-version-manager-ever/</guid><dc:creator><![CDATA[Peter Piekarczyk]]></dc:creator><pubDate>Sun, 22 Mar 2020 05:00:00 GMT</pubDate><content:encoded>&lt;p&gt;We’ve been using &lt;code class=&quot;language-text&quot;&gt;nvm&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;n&lt;/code&gt; and maybe even &lt;code class=&quot;language-text&quot;&gt;homebrew&lt;/code&gt; for years to manage our Node.js version. They have been &lt;em&gt;good enough&lt;/em&gt; until now. &lt;a href=&quot;https://github.com/Schniz/fnm&quot;&gt;fnm&lt;/a&gt; stands for “Fast Node Manager”.&lt;/p&gt;
&lt;p&gt;It’s written in &lt;a href=&quot;https://reasonml.org&quot;&gt;ReasonML&lt;/a&gt; and has literally instant startup times:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/480f91e3f4e27be6ed55c266186314e5/fnm.gif&quot; alt=&quot;fnm instant startup speed&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;features&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#features&quot; aria-label=&quot;features permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Features:&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Single file, easy installation, instant startup&lt;/li&gt;
&lt;li&gt;Built with speed in mind (seriously)&lt;/li&gt;
&lt;li&gt;Works with &lt;code class=&quot;language-text&quot;&gt;.nvmrc&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;.node-version&lt;/code&gt; files (compatible with your current tooling)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;installation&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#installation&quot; aria-label=&quot;installation permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Installation:&lt;/h2&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;zsh&quot;&gt;&lt;pre class=&quot;language-zsh&quot;&gt;&lt;code class=&quot;language-zsh&quot;&gt;brew install Schniz/tap/fnm&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;configuration&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#configuration&quot; aria-label=&quot;configuration permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Configuration:&lt;/h2&gt;
&lt;p&gt;After you’ve installed it, you have to add &lt;code class=&quot;language-text&quot;&gt;fnm&lt;/code&gt; to your path. I use &lt;code class=&quot;language-text&quot;&gt;zsh&lt;/code&gt; so this is what I have in my &lt;code class=&quot;language-text&quot;&gt;.zshrc&lt;/code&gt; file:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;zsh&quot;&gt;&lt;pre class=&quot;language-zsh&quot;&gt;&lt;code class=&quot;language-zsh&quot;&gt;eval &amp;quot;$(fnm env --multi --use-on-cd)&amp;quot;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id=&quot;breakdown&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#breakdown&quot; aria-label=&quot;breakdown permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Breakdown&lt;/h3&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;--multi&lt;/code&gt; - will allow you to use a different Node version per shell. This means if you open a new terminal window and change the version number, it won’t be linked to the old one (this is what you want!)&lt;/p&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;--use-on-cd&lt;/code&gt; - will automatically switch the node version based on your &lt;code class=&quot;language-text&quot;&gt;.nvmrc&lt;/code&gt; file. You might have had this off if you’ve used &lt;code class=&quot;language-text&quot;&gt;nvm&lt;/code&gt; in the past, but its blazing :fire: fast, it’s worth keeping it on by default&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/Schniz/fnm&quot;&gt;Learn more on Github&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Adding Spotify to Home Assistant]]></title><description><![CDATA[Step-by-step guide to integrating Spotify with Home Assistant after the configuration change introduced in version 106 and later.]]></description><link>https://peterp.me/articles/adding-spotify-to-home-assistant/</link><guid isPermaLink="false">https://peterp.me/articles/adding-spotify-to-home-assistant/</guid><dc:creator><![CDATA[Peter Piekarczyk]]></dc:creator><pubDate>Mon, 02 Mar 2020 06:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Home Assistant recently changed the way Spotify’s configured so I wrote up a guide. This works with most versions of HomeAssistant but I used it with 106 &amp;#x26; up.&lt;/p&gt;
&lt;h1 id=&quot;steps&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#steps&quot; aria-label=&quot;steps permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Steps&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;Login to the &lt;strong&gt;&lt;a href=&quot;https://developer.spotify.com/dashboard&quot;&gt;Spotify Developers Console&lt;/a&gt;&lt;/strong&gt; with your Spotify username and password.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Create a Client ID&lt;/strong&gt; in the top right corner. A popup should appear.&lt;/li&gt;
&lt;li&gt;Enter &lt;strong&gt;Home Assistant (or whatever)&lt;/strong&gt; for the app name. Description doesn’t matter. Put “Automation” in the description. A new pop up appears.&lt;/li&gt;
&lt;li&gt;Click the &lt;strong&gt;Non Commercial&lt;/strong&gt; button on the right hand side.&lt;/li&gt;
&lt;li&gt;Checkmark &lt;strong&gt;Website&lt;/strong&gt; and then press Next. Next popup.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;all 3 checkboxes&lt;/strong&gt; and then click &lt;strong&gt;Submit.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;You’ll see a new page with your newly created app.&lt;/li&gt;
&lt;li&gt;In the top right corner, click the green button that says &lt;strong&gt;Edit Settings.&lt;/strong&gt; A popup appears. We need to add &lt;strong&gt;Redirect URI’s&lt;/strong&gt; and nothing else.&lt;/li&gt;
&lt;li&gt;Create two redirect URIs. One that goes to your lovelace UI and the other to the appropriate URL. **Even if you have Nabu Casa or DuckDNS set up, just use your local http:// URL.
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://192.168.0.1:8123/lovelace/lovelace_default_view&quot;&gt;http://192.168.0.1:8123/lovelace/lovelace_default_view&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://192.168.0.1:8123/auth/external/callback&quot;&gt;http://192.168.0.1:8123/auth/external/callback&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Show Client Secret.&lt;/strong&gt; Open up &lt;strong&gt;Configuration.yaml&lt;/strong&gt; and paste the keys directly or use secrets.yaml (like I have below)&lt;/li&gt;
&lt;li&gt;Create a &lt;code class=&quot;language-text&quot;&gt;spotify&lt;/code&gt; key in your &lt;code class=&quot;language-text&quot;&gt;configuration.yaml&lt;/code&gt; file as shown below. I use the &lt;a href=&quot;https://www.home-assistant.io/docs/configuration/secrets/&quot;&gt;secrets.yaml&lt;/a&gt; file which is why you see &lt;code class=&quot;language-text&quot;&gt;!secret&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yaml&quot;&gt;&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;spotify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;client_id&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token tag&quot;&gt;!secret&lt;/span&gt; spotify_id (OR &quot;clientidxyz&quot;)
  &lt;span class=&quot;token key atrule&quot;&gt;client_secret&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token tag&quot;&gt;!secret&lt;/span&gt; spotify_secret (OR &quot;clientsecretxyz&quot;)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Restart Home Assistant by going to &lt;strong&gt;Configuration&lt;/strong&gt; and clicking &lt;strong&gt;Server Controls,&lt;/strong&gt; then &lt;strong&gt;Restart&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;You’ll see a new notification in the bottom left corner for &lt;strong&gt;New Devices Discovered.&lt;/strong&gt; Click &lt;strong&gt;Check it out,&lt;/strong&gt; then click &lt;strong&gt;Configure&lt;/strong&gt; under Spotify. Everything should happen automatically.&lt;/li&gt;
&lt;li&gt;Once that pos up, you should see a pop up that says Success. Just click &lt;strong&gt;Finish.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;If you have any other Spotify integrations, just click &lt;strong&gt;Ignore.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;You’re Done!&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;add-spotify-to-your-lovelace-dashboard&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#add-spotify-to-your-lovelace-dashboard&quot; aria-label=&quot;add spotify to your lovelace dashboard permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Add Spotify to your Lovelace Dashboard&lt;/h1&gt;
&lt;p&gt;If you want to add Spotify to your LoveLace Dashboard. Click Spotify under &lt;strong&gt;Configured&lt;/strong&gt;, then click it again.&lt;/p&gt;
&lt;p&gt;You’ll now see a page with Automations, Scenes, etc. Just click &lt;strong&gt;Add To LoveLace at the top.&lt;/strong&gt; **This seems to be broken in 106, but if you check your dashboard it might just show up so who knows!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[GraphQL Getting Past Step 3]]></title><description><![CDATA[Practical patterns for moving beyond the GraphQL basics: cache updates, optimistic responses, and structuring queries in a real production app.]]></description><link>https://peterp.me/articles/graphql-getting-past-step-3/</link><guid isPermaLink="false">https://peterp.me/articles/graphql-getting-past-step-3/</guid><dc:creator><![CDATA[Peter Piekarczyk]]></dc:creator><pubDate>Wed, 19 Feb 2020 06:00:00 GMT</pubDate><content:encoded>&lt;p&gt;GraphQL is becoming one of the most popular data query libraries in the world. This is a talk that I’ve converted into an article. Enjoy!&lt;/p&gt;
&lt;h1 id=&quot;first-version-of-draftbit&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#first-version-of-draftbit&quot; aria-label=&quot;first version of draftbit permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;First Version of Draftbit&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;Node&lt;/li&gt;
&lt;li&gt;React&lt;/li&gt;
&lt;li&gt;Postgres&lt;/li&gt;
&lt;li&gt;Raw SQL Queries &amp;#x26; knex (for the most part)&lt;/li&gt;
&lt;li&gt;GraphQL&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;https://media.giphy.com/media/mIvrv5Qe0kHlu/giphy.mp4&quot;&gt;https://media.giphy.com/media/mIvrv5Qe0kHlu/giphy.mp4&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Throwing stuff at the wall and hoping it sticks (it didn’t)&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;We quickly realized we weren’t doing things the right way so we started rewriting new features&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;em&gt;Draftbit 1.1&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ReasonML on the client ✅&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;Draftbit 1.2&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;TypeORM ✅&lt;/li&gt;
&lt;li&gt;TypeScript on the Server ✅&lt;/li&gt;
&lt;li&gt;Prisma ✅&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;Draftbit 1.3&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Dataloader ✅&lt;/li&gt;
&lt;li&gt;Thinking about structuring our GraphQL queries more efficiently ✅✅✅&lt;/li&gt;
&lt;li&gt;Writing Tests ✅✅✅&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;good-but-not-great&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#good-but-not-great&quot; aria-label=&quot;good but not great permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Good but not great&lt;/h3&gt;
&lt;p&gt;GraphQL field resolvers aren’t being used correctly. The SQL is fast but because of how we’re handling this in a nested data structure, its not necessarily taking full advantage of GraphQL.&lt;/p&gt;
&lt;p&gt;This also meant that we were writing custom queries for every type of request we wanted, instead of being able to traverse the tree.&lt;/p&gt;
&lt;p&gt;There are pros &amp;#x26; cons to this (but mainly cons).&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;jsx&quot;&gt;&lt;pre class=&quot;language-jsx&quot;&gt;&lt;code class=&quot;language-jsx&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;getAppById&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;token parameter&quot;&gt;_&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; uuid &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; db&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;uuid&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; userId &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  info&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; app&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; db&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;raw&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
        SELECT a.*,
        (
          SELECT COUNT(*)
          FROM app_screens a_s
          INNER JOIN screens s
          ON a_s.screen_id = s.id
          WHERE app_id = a.id
          AND s.is_deleted IS FALSE
        ) as num_screens
        FROM apps a
        WHERE a.uuid = ? AND a.is_deleted IS FALSE
      &lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;uuid&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;much-better&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#much-better&quot; aria-label=&quot;much better permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Much better&lt;/h2&gt;
&lt;p&gt;We’re utilizing GraphQL’s field resolver pattern correctly. Instead of having to re-write the same query, we were able to utilize &lt;code class=&quot;language-text&quot;&gt;Dataloader&lt;/code&gt; to fetch the id from cache on every tick&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;jsx&quot;&gt;&lt;pre class=&quot;language-jsx&quot;&gt;&lt;code class=&quot;language-jsx&quot;&gt;t&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;list&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;app&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; AppType&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token function-variable function&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; uuid &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; _&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; loaders &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; loaders&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;appsByWorkspaceUuid&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;load&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;uuid&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h1 id=&quot;dataloader&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#dataloader&quot; aria-label=&quot;dataloader permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Dataloader&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/graphql/dataloader&quot;&gt;https://github.com/graphql/dataloader&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;DataLoader is a generic utility to be used as part of your application’s data fetching layer to provide a simplified and consistent API over various remote data sources such as databases or web services via batching and caching.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;*Dataloader works by taking an array of ids and returning an array of promises that fulfill that data&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;jsx&quot;&gt;&lt;pre class=&quot;language-jsx&quot;&gt;&lt;code class=&quot;language-jsx&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getComponents&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;arrayOfIds&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; components &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getComponentsById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;arrayofIds&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; components
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; componentLoader &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;DataLoader&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;getComponents&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

componentLoader&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;load&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;xyz-abc&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
componentloader&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;loadMany&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I struggled getting this right for awhile and avoided dataloader. That was partially because we weren’t using field resolvers correctly so I wasn’t thinking about using it the right way.&lt;/p&gt;
&lt;h1 id=&quot;graphql-nexus&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#graphql-nexus&quot; aria-label=&quot;graphql nexus permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;GraphQL Nexus&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/prisma-labs/nexus&quot;&gt;https://github.com/prisma-labs/nexus&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Declarative, code-first and strongly typed GraphQL schema construction for TypeScript &amp;#x26; JavaScript&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;GraphQL Nexus helps you write your graphql schema with typescript by generating definitions alongside of your code. It’s allowed us to identify errors in the way that we return data very easily.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;jsx&quot;&gt;&lt;pre class=&quot;language-jsx&quot;&gt;&lt;code class=&quot;language-jsx&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; queryType&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; stringArg&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; makeSchema &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;nexus&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; GraphQLServer &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;graphql-yoga&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; Query &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;queryType&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;definition&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    t&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;hello&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token literal-property property&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;stringArg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;nullable&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token function-variable function&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;parent&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; name &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;Hello &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;name &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;World&quot;&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; schema &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;makeSchema&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;types&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;Query&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;outputs&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;schema&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; __dirname &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;/generated/schema.graphql&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;typegen&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; __dirname &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;/generated/typings.ts&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; server &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;GraphQLServer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  schema&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

server&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;start&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;Server is running on http://localhost:4000&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;GraphQL Nexus doesn’t do anything else besides constructing your graphql schema (code-first), which means that you don’t have to use their stack or servers or whatever. All it will do is generate a &lt;code class=&quot;language-text&quot;&gt;schema.graphql&lt;/code&gt; file that you can include.&lt;/p&gt;
&lt;h1 id=&quot;typeorm&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#typeorm&quot; aria-label=&quot;typeorm permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;TypeORM&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/typeorm/typeorm&quot;&gt;https://github.com/typeorm/typeorm&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;ORM for TypeScript and JavaScript (ES7, ES6, ES5). Supports MySQL, PostgreSQL, MariaDB, SQLite, MS SQL Server, Oracle, SAP Hana, WebSQL databases. Works in NodeJS, Browser, Ionic, Cordova and Electron platforms. &lt;a href=&quot;http://typeorm.io/&quot;&gt;http://typeorm.io&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;TypeORM is the ORM we use with our Postgres database. Instead of writing raw sql queries we’re able to build and join entities easily that are typed.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;jsx&quot;&gt;&lt;pre class=&quot;language-jsx&quot;&gt;&lt;code class=&quot;language-jsx&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;Entity&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; PrimaryGeneratedColumn&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Column&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; BaseEntity&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;typeorm&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

@&lt;span class=&quot;token function&quot;&gt;Entity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;User&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;BaseEntity&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;

    @&lt;span class=&quot;token function&quot;&gt;PrimaryGeneratedColumn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; number&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    @&lt;span class=&quot;token function&quot;&gt;Column&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;firstName&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; string&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    @&lt;span class=&quot;token function&quot;&gt;Column&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;lastName&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; string&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    @&lt;span class=&quot;token function&quot;&gt;Column&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;age&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; number&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You create an entity file like this. It supports any type of database schema that you’ve got. Then all you have to do is write functions like:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;jsx&quot;&gt;&lt;pre class=&quot;language-jsx&quot;&gt;&lt;code class=&quot;language-jsx&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; allUsers &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; User&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; firstUser &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; User&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;findOne&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; peter &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; User&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;findOne&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;firstName&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Peter&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;lastName&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;P&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h1 id=&quot;caching&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#caching&quot; aria-label=&quot;caching permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Caching&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;Database level&lt;/li&gt;
&lt;li&gt;ORM level&lt;/li&gt;
&lt;li&gt;Apollo Server level&lt;/li&gt;
&lt;li&gt;Apollo Client level&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It’s easy to forget about all the caching solutions we’ve had in the past that have been working great. At least I’ve forgotten about lower level tools that used to be a lot more popular: Nginx, HA Proxy, etc.&lt;/p&gt;
&lt;p&gt;These days there are modern solutions for caching that let you handle it through your application rather than outside of it.&lt;/p&gt;
&lt;h2 id=&quot;caching-in-typeorm&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#caching-in-typeorm&quot; aria-label=&quot;caching in typeorm permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Caching in TypeORM&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://typeorm.io/#/caching&quot;&gt;https://typeorm.io/#/caching&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Once you set &lt;code class=&quot;language-text&quot;&gt;cache:true&lt;/code&gt; in your ormconfig, it will generate a &lt;code class=&quot;language-text&quot;&gt;query-results-cache&lt;/code&gt; table in your databae that’ll cache operations for 1 second by default.&lt;/p&gt;
&lt;p&gt;Caching is controlled by individual queries:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;jsx&quot;&gt;&lt;pre class=&quot;language-jsx&quot;&gt;&lt;code class=&quot;language-jsx&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; users &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; connection
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createQueryBuilder&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;User&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;user&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;where&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;user.isAdmin = :isAdmin&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;isAdmin&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;cache&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getMany&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If you want to change the amount of time spent caching you can also do &lt;code class=&quot;language-text&quot;&gt;cache(5000)&lt;/code&gt; or some arbitrary number to make that happen.&lt;/p&gt;
&lt;p&gt;If you’re using a multi database setup then you can also cache using a cluster or redis.&lt;/p&gt;
&lt;h2 id=&quot;caching-in-apollo&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#caching-in-apollo&quot; aria-label=&quot;caching in apollo permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Caching in Apollo&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.apollographql.com/docs/apollo-server/performance/caching/&quot;&gt;https://www.apollographql.com/docs/apollo-server/performance/caching/&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;cache-hints&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#cache-hints&quot; aria-label=&quot;cache hints permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Cache Hints&lt;/h3&gt;
&lt;p&gt;Cache hints are convenient to Apollo but apparently don’t conform to the GraphQL spec. Use at your own risk (we decided against it)&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;jsx&quot;&gt;&lt;pre class=&quot;language-jsx&quot;&gt;&lt;code class=&quot;language-jsx&quot;&gt;type Comment @&lt;span class=&quot;token function&quot;&gt;cacheControl&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token literal-property property&quot;&gt;maxAge&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;post&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Post&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id=&quot;full-response-cache&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#full-response-cache&quot; aria-label=&quot;full response cache permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Full Response Cache&lt;/h3&gt;
&lt;p&gt;It uses memory LRU cache by default so if you’re using multiple server instances (like Kubernetes or some crazier shit) it might make sense to use Redis (again)&lt;/p&gt;
&lt;p&gt;You can utilize this to save your session headers instead of constantly trying to unravel on every request.&lt;/p&gt;
&lt;h3 id=&quot;redis-or-memcached-response-caching&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#redis-or-memcached-response-caching&quot; aria-label=&quot;redis or memcached response caching permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Redis or MemCached Response Caching&lt;/h3&gt;
&lt;p&gt;If you’d prefer to save your cache in Redis (which is what we do) Apollo also offers caching using MemCached or Redis and its really simple to setup:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;jsx&quot;&gt;&lt;pre class=&quot;language-jsx&quot;&gt;&lt;code class=&quot;language-jsx&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; RedisCache &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;apollo-server-cache-redis&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; server &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ApolloServer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  typeDefs&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  resolvers&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;cache&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;RedisCache&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;host&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;redis-server&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;persisted-queries&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#persisted-queries&quot; aria-label=&quot;persisted queries permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Persisted Queries&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.apollographql.com/docs/apollo-server/performance/apq/&quot;&gt;https://www.apollographql.com/docs/apollo-server/performance/apq/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Persisted queries work by reducing the size of your query to a hash, saving bandwidth and improving network performance.&lt;/p&gt;
&lt;p&gt;*You need to switch away from Apollo Boost for this to work. There is no server setup required&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;jsx&quot;&gt;&lt;pre class=&quot;language-jsx&quot;&gt;&lt;code class=&quot;language-jsx&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; createPersistedQueryLink &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;apollo-link-persisted-queries&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; createHttpLink &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;apollo-link-http&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; InMemoryCache &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;apollo-cache-inmemory&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; ApolloClient &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;apollo-client&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; link &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createPersistedQueryLink&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;concat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createHttpLink&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;uri&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;/graphql&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; client &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ApolloClient&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;cache&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;InMemoryCache&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;link&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; link&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;using-get-requests-for-graphql&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#using-get-requests-for-graphql&quot; aria-label=&quot;using get requests for graphql permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Using GET requests for GraphQL&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.apollographql.com/docs/apollo-server/performance/apq/#using-get-requests-with-apq-on-a-cdn&quot;&gt;https://www.apollographql.com/docs/apollo-server/performance/apq/#using-get-requests-with-apq-on-a-cdn&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;GraphQL queries are usually too long for a GET request which is why we use POST, but if you use APQ you can change that and have the request cached at the CDN level.&lt;/p&gt;
&lt;p&gt;*This doesn’t work with batching&lt;/p&gt;
&lt;h1 id=&quot;flyio&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#flyio&quot; aria-label=&quot;flyio permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Fly.io&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://fly.io/&quot;&gt;https://fly.io/&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Fly makes Heroku apps 50-80% faster. It’s like a CDN but for server processes &amp;#x26; app data&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Fly sets our servers up at the edge so they load a lot faster. I don’t necessarily understand all the specifics, but working with Kurt to make this a reality at Draftbit has been a great experience.&lt;/p&gt;
&lt;p&gt;Fly also includes a redis for every server you deploy and that’s exciting on its own&lt;/p&gt;
&lt;h1 id=&quot;graphql-cost-analysis&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#graphql-cost-analysis&quot; aria-label=&quot;graphql cost analysis permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;GraphQL Cost Analysis&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/pa-bru/graphql-cost-analysis&quot;&gt;https://github.com/pa-bru/graphql-cost-analysis&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This can be used to protect your GraphQL servers against DoS attacks, compute the data consumption per user and limit it.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It’s very easy to set up and add it into your middleware. It’s supported by everything from &lt;code class=&quot;language-text&quot;&gt;express-graphql&lt;/code&gt; to &lt;code class=&quot;language-text&quot;&gt;apollo-server&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;jsx&quot;&gt;&lt;pre class=&quot;language-jsx&quot;&gt;&lt;code class=&quot;language-jsx&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; costAnalysis &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;graphql-cost-analysis&apos;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; costAnalyzer &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;costAnalysis&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;maximumCost&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You can customize different costs for different queries so you understand what the data consumption is per user or per request.&lt;/p&gt;
&lt;p&gt;It’s easy to track down situations where somebody is hijacking your GraphQL server and trying to access information that maybe they shouldn’t be.&lt;/p&gt;
&lt;h1 id=&quot;graphql-depth-limit&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#graphql-depth-limit&quot; aria-label=&quot;graphql depth limit permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;GraphQL Depth Limit&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/stems/graphql-depth-limit&quot;&gt;https://github.com/stems/graphql-depth-limit&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Dead-simple defense against unbounded GraphQL queries. Limit the complexity of the queries solely by their depth.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Since GraphQL can recursively build a tree of your data, it’s really simple to write a query that breaks your server. By setting the depth limit you limit the risk of someone being able to do something like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;graphql&quot;&gt;&lt;pre class=&quot;language-graphql&quot;&gt;&lt;code class=&quot;language-graphql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;query&lt;/span&gt; &lt;span class=&quot;token definition-query function&quot;&gt;BreakTheServer&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token object&quot;&gt;users&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token object&quot;&gt;apps&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token object&quot;&gt;users&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token object&quot;&gt;apps&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;token object&quot;&gt;users&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token object&quot;&gt;apps&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
             &lt;span class=&quot;token object&quot;&gt;users&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
               &lt;span class=&quot;token object&quot;&gt;apps&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
               &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
             &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
           &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h1 id=&quot;graphql-rate-limit&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#graphql-rate-limit&quot; aria-label=&quot;graphql rate limit permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;GraphQL Rate Limit&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/teamplanes/graphql-rate-limit&quot;&gt;https://github.com/teamplanes/graphql-rate-limit&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A GraphQL Rate Limiter to add basic but granular rate limiting to your Queries or Mutations.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;You can rate limit the amount of requests that are happening on the GraphQL level to prevent from random shit from hitting the fan 😅&lt;/p&gt;
&lt;p&gt;We already use GraphQL Shield at Draftbit so this pattern is really easy to setup:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;jsx&quot;&gt;&lt;pre class=&quot;language-jsx&quot;&gt;&lt;code class=&quot;language-jsx&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; createRateLimitRule &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;graphql-rate-limit&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; rateLimitRule &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createRateLimitRule&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;identifyContext&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; permissions &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;shield&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;Query&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// Step 2: Apply the rate limit rule instance to the field with config&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;getItems&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;rateLimitRule&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;window&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;1s&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The nice part about this is that everything lives inside the Javascript world and not the GraphQL world. It makes it easy for us to fine tune it (and it can be type-checked).&lt;/p&gt;
&lt;h1 id=&quot;other-useful-tools&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#other-useful-tools&quot; aria-label=&quot;other useful tools permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Other Useful Tools&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;toobusy-js&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/STRML/node-toobusy&quot;&gt;https://github.com/STRML/node-toobusy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Stay responsive under extreme load&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;rate-limiter&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/microlinkhq/async-ratelimiter&quot;&gt;https://github.com/microlinkhq/async-ratelimiter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;limit the number of calls that are taking place, backed by redis&lt;/li&gt;
&lt;li&gt;A tip is to use your user’s session variables but if that’s not available, you can limit it by the ip using the additional &lt;code class=&quot;language-text&quot;&gt;request-ip&lt;/code&gt; package&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;reason&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://reasonml.github.io/&quot;&gt;https://reasonml.github.io/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;OneGraph&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://onegraph.io&quot;&gt;https://onegraph.io&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;token refresh&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/newsiberian/apollo-link-token-refresh&quot;&gt;https://github.com/newsiberian/apollo-link-token-refresh&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;thanks&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#thanks&quot; aria-label=&quot;thanks permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Thanks!&lt;/h1&gt;
&lt;p&gt;Thanks to Tracy, Ann, Pato and This Dot Labs for hosting. It’s been an honor speaking alongside of Shawn too who is a very well known figure in the community.&lt;/p&gt;
&lt;h1 id=&quot;questions--answers&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#questions--answers&quot; aria-label=&quot;questions  answers permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Questions / Answers&lt;/h1&gt;</content:encoded></item><item><title><![CDATA[Reason Apollo Cache Update Patterns]]></title><description><![CDATA[Practical patterns for managing Apollo cache updates in ReasonML — optimistic responses, refetchQueries, and manually updating lists after mutations.]]></description><link>https://peterp.me/articles/reason-apollo-cache-update-patterns/</link><guid isPermaLink="false">https://peterp.me/articles/reason-apollo-cache-update-patterns/</guid><dc:creator><![CDATA[Peter Piekarczyk]]></dc:creator><pubDate>Sat, 15 Feb 2020 06:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;refetchQueries&lt;/code&gt; are great when you need to refetch data that’s not easy to handle with cache updates. Updating the cache using an optimistic response reduces the amount of requests and lets you handle the whole operation on the client and updating / removing from a list of resources.&lt;/p&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;optimisticResponse&lt;/code&gt; will immediately return back a fake object that mimics the response the server would return on success. The update function therefore is called twice. Once for the optimisticResponse (instant) and the second time when the server responds successfully.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Relevant reading:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.apollographql.com/docs/react/performance/optimistic-ui/&quot;&gt;https://www.apollographql.com/docs/react/performance/optimistic-ui/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;update&lt;/code&gt; will allow you to access the cached update on the client and add or remove items from a list. This automatically happens with &lt;code class=&quot;language-text&quot;&gt;update&lt;/code&gt; requests but you do need to update the cache manually for creating and deleting requests.&lt;/p&gt;
&lt;p&gt;You should model your optimistic response exactly the same, except for the &lt;code class=&quot;language-text&quot;&gt;uuid&lt;/code&gt; we should include something random and temporarily. If we had the &lt;code class=&quot;language-text&quot;&gt;id&lt;/code&gt; value we’d use -1 but since &lt;code class=&quot;language-text&quot;&gt;uuid&lt;/code&gt; is a string you can use &lt;code class=&quot;language-text&quot;&gt;xyz123&lt;/code&gt;. The value is arbitrary and is immediately replaced.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;More Relevant reading:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.apollographql.com/docs/react/caching/cache-interaction/&quot;&gt;https://www.apollographql.com/docs/react/caching/cache-interaction/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is an example of what an optimistic response looks like:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;reason&quot;&gt;&lt;pre class=&quot;language-reason&quot;&gt;&lt;code class=&quot;language-reason&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;token constructor&quot;&gt;OptimisticRemove&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; t &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;__typename&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; string&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;removeAsset&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; string&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;external&lt;/span&gt; cast&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; t &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Js&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Json&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;t &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;%identity&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; make &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;~&lt;/span&gt;uuid&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;__typename&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Mutation&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;removeAsset&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; uuid&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;cast&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;token constructor&quot;&gt;RemoveAsset&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;%graphql
  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt;
    mutation &lt;span class=&quot;token constructor&quot;&gt;RemoveAsset&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;$uuid&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constructor&quot;&gt;ID&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      removeAsset&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;uuid&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; $uuid&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id=&quot;-note-youll-need-to-add-code-classlanguage-text__typename-stringcode-to-your-graphql-response-type&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#-note-youll-need-to-add-code-classlanguage-text__typename-stringcode-to-your-graphql-response-type&quot; aria-label=&quot; note youll need to add code classlanguage text__typename stringcode to your graphql response type permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;** Note: You’ll need to add &lt;code class=&quot;language-text&quot;&gt;__typename: string&lt;/code&gt; to your GraphQL response type!&lt;/h3&gt;
&lt;p&gt;This is how we call the creation of the optimistic response. We pass in a uuid because its what we pass into the real request. In this case its &lt;code class=&quot;language-text&quot;&gt;uuid&lt;/code&gt; but it could be &lt;code class=&quot;language-text&quot;&gt;asset&lt;/code&gt; or &lt;code class=&quot;language-text&quot;&gt;screen&lt;/code&gt; or any other resource.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;reason&quot;&gt;&lt;pre class=&quot;language-reason&quot;&gt;&lt;code class=&quot;language-reason&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; variables &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;AssetQueries&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;RemoveAsset&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;makeVariables&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;~&lt;/span&gt;uuid&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    removeAssetMutation&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;~&lt;/span&gt;variables&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;/* --- */&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;~&lt;/span&gt;optimisticResponse&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;AssetQueries&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;OptimisticRemove&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;make&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;~&lt;/span&gt;uuid&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;/* --- */&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;|&gt;&lt;/span&gt; ignore&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You can now use optimisticResponse with an update which immediately removes an item from the list (same instructions for adding):&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;reason&quot;&gt;&lt;pre class=&quot;language-reason&quot;&gt;&lt;code class=&quot;language-reason&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;mutateRemoveAsset&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; _&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; _&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;token class-name&quot;&gt;ApolloHooks&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;useMutation&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;token class-name&quot;&gt;AssetQueries&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;RemoveAsset&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;definition&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;~&lt;/span&gt;update&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;AssetQueries&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;removeFromCache&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;appUuid&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; assetType&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;removeFromCache&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;reason&quot;&gt;&lt;pre class=&quot;language-reason&quot;&gt;&lt;code class=&quot;language-reason&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; removeFromCache &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;appUuid&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; assetType&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; client&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; mutationResult&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token comment&quot;&gt;/* mutationResult gives you access to the result of the fake and real mutation*/&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;switch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;mutationResult&lt;span class=&quot;token operator&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;#&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token constructor&quot;&gt;None&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token constructor&quot;&gt;Some&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; assetUuid &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; data&lt;span class=&quot;token operator&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;#&lt;/span&gt;removeAsset&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	  
	  &lt;span class=&quot;token comment&quot;&gt;/* build the query the same way you would in your request */&lt;/span&gt;
	  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; query &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
	    &lt;span class=&quot;token class-name&quot;&gt;AssetQueries&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;GetAssets&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;make&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
	      &lt;span class=&quot;token operator&quot;&gt;~&lt;/span&gt;filter&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;appUuid&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; appUuid&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;fileType&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constructor&quot;&gt;Some&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;assetType&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
	      &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
	    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; readQueryOptions &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; toReadQueryOptions&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;query&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	  &lt;span class=&quot;token comment&quot;&gt;/* read the query and get the local, cached data */&lt;/span&gt;
	  &lt;span class=&quot;token keyword&quot;&gt;switch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;AssetReadQuery&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;readQuery&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;client&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; readQueryOptions&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	  &lt;span class=&quot;token comment&quot;&gt;/* if there is no cached data, apollo throws so this just catches the throw */&lt;/span&gt;
	  &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;exception&lt;/span&gt; _ &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
	  &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; cachedResponse &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt;
	    &lt;span class=&quot;token keyword&quot;&gt;switch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cachedResponse &lt;span class=&quot;token operator&quot;&gt;|&gt;&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Js&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Nullable&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;toOption&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	    &lt;span class=&quot;token comment&quot;&gt;/* if there is no cached data because its nullable, just move on */&lt;/span&gt;
	    &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token constructor&quot;&gt;None&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
	    &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token constructor&quot;&gt;Some&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cachedAssets&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt;
	      &lt;span class=&quot;token comment&quot;&gt;/* BS7 feature that wraps Json and gives you record access */&lt;/span&gt;
	      &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; cachedData &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; cast&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cachedAssets&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	      &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; data &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	        &lt;span class=&quot;token string&quot;&gt;&quot;assets&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
	          &lt;span class=&quot;token comment&quot;&gt;/* for a remove, filter out the assetUuid from the list * /
	          Belt.Array.keep(cachedData##assets, asset =&gt; {
	            asset.uuid !== assetUuid
	          }),
	      };

	      /* write the query back to cache. You&apos;re done! */&lt;/span&gt;
	      &lt;span class=&quot;token class-name&quot;&gt;AssetWriteQuery&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;make&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;~&lt;/span&gt;client&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;~&lt;/span&gt;variables&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;query&lt;span class=&quot;token operator&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;#&lt;/span&gt;variables&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;~&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;There are three lines you need to add to the top of the file to access the cache requests.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;reason&quot;&gt;&lt;pre class=&quot;language-reason&quot;&gt;&lt;code class=&quot;language-reason&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;external&lt;/span&gt; cast&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Js&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Json&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;t &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;AssetQueries&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;GetAssets&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;t &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;%identity&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;token constructor&quot;&gt;AssetReadQuery&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ApolloClient&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constructor&quot;&gt;ReadQuery&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;AssetQueries&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constructor&quot;&gt;GetAssets&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;token constructor&quot;&gt;AssetWriteQuery&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ApolloClient&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constructor&quot;&gt;WriteQuery&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;AssetQueries&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constructor&quot;&gt;GetAssets&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href=&quot;https://bucklescript.github.io/docs/en/intro-to-external#special-identity-external&quot;&gt;External cast&lt;/a&gt; is bs7’s way of handling casting the raw array of objects as a record:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;reason&quot;&gt;&lt;pre class=&quot;language-reason&quot;&gt;&lt;code class=&quot;language-reason&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;external&lt;/span&gt; cast&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Js&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Json&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;t &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;AssetQueries&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;GetAssets&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;t &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;%identity&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Full file:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;reason&quot;&gt;&lt;pre class=&quot;language-reason&quot;&gt;&lt;code class=&quot;language-reason&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;token constructor&quot;&gt;GetAssets&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;%graphql
  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt;
    query &lt;span class=&quot;token constructor&quot;&gt;GetAssets&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;$filter&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constructor&quot;&gt;AssetFilter&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      assets&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;filter&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; $filter&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; @bsRecord &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        __typename
        uuid
        fileName
        fileType
        mimeType
        url
        slug
        snackUrl
     &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;external&lt;/span&gt; cast&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Js&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Json&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;t &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;GetAssets&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;t &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;%identity&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;token constructor&quot;&gt;AssetReadQuery&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ApolloClient&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constructor&quot;&gt;ReadQuery&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constructor&quot;&gt;GetAssets&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;token constructor&quot;&gt;AssetWriteQuery&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ApolloClient&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constructor&quot;&gt;WriteQuery&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constructor&quot;&gt;GetAssets&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;token constructor&quot;&gt;OptimisticCreate&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; t &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;__typename&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; string&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;createAsset&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;
      &lt;span class=&quot;token string&quot;&gt;&quot;__typename&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; string&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token string&quot;&gt;&quot;uuid&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; string&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token string&quot;&gt;&quot;fileName&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; string&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token string&quot;&gt;&quot;fileType&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; string&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token string&quot;&gt;&quot;mimeType&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; string&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token string&quot;&gt;&quot;url&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; string&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token string&quot;&gt;&quot;slug&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; string&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token string&quot;&gt;&quot;snackUrl&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; option&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;string&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;external&lt;/span&gt; cast&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; t &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Js&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Json&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;t &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;%identity&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; make &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;~&lt;/span&gt;asset&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token string&quot;&gt;&quot;__typename&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Mutation&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token string&quot;&gt;&quot;createAsset&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token string&quot;&gt;&quot;__typename&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; asset&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;__typename&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token string&quot;&gt;&quot;uuid&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; asset&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;uuid&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token string&quot;&gt;&quot;fileName&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; asset&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;fileName&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token string&quot;&gt;&quot;fileType&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; asset&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;fileType&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token string&quot;&gt;&quot;mimeType&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; asset&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mimeType&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token string&quot;&gt;&quot;url&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; asset&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;url&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token string&quot;&gt;&quot;slug&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; asset&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;slug&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token string&quot;&gt;&quot;snackUrl&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; asset&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;snackUrl&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;cast&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;token constructor&quot;&gt;CreateAsset&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;%graphql
  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt;
    mutation &lt;span class=&quot;token constructor&quot;&gt;CreateAsset&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;$input&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constructor&quot;&gt;CreateAssetInput&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      createAsset&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;input&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; $input&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        uuid
        fileName
        fileType
        mimeType
        url
        slug
        snackUrl
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;token constructor&quot;&gt;OptimisticRemove&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; t &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;__typename&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; string&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;removeAsset&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; string&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;external&lt;/span&gt; cast&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; t &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Js&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Json&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;t &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;%identity&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; make &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;~&lt;/span&gt;uuid&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;__typename&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Mutation&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;removeAsset&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; uuid&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;cast&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;token constructor&quot;&gt;RemoveAsset&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;%graphql
  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt;
    mutation &lt;span class=&quot;token constructor&quot;&gt;RemoveAsset&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;$uuid&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constructor&quot;&gt;ID&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      removeAsset&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;uuid&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; $uuid&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; removeFromCache &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;appUuid&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; assetType&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; client&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; mutationResult&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;switch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;mutationResult&lt;span class=&quot;token operator&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;#&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token constructor&quot;&gt;None&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token constructor&quot;&gt;Some&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; assetUuid &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; data&lt;span class=&quot;token operator&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;#&lt;/span&gt;removeAsset&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; query &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
      &lt;span class=&quot;token class-name&quot;&gt;GetAssets&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;make&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;~&lt;/span&gt;filter&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;appUuid&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; appUuid&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;fileType&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constructor&quot;&gt;Some&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;assetType&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; readQueryOptions &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; toReadQueryOptions&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;query&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;switch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;AssetReadQuery&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;readQuery&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;client&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; readQueryOptions&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;exception&lt;/span&gt; _ &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; cachedResponse &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;switch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cachedResponse &lt;span class=&quot;token operator&quot;&gt;|&gt;&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Js&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Nullable&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;toOption&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token constructor&quot;&gt;None&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token constructor&quot;&gt;Some&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cachedAssets&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; cachedData &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; cast&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cachedAssets&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; data &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;token string&quot;&gt;&quot;assets&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;token class-name&quot;&gt;Belt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;keep&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cachedData&lt;span class=&quot;token operator&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;#&lt;/span&gt;assets&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; asset &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
              asset&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;uuid &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; assetUuid
            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;token class-name&quot;&gt;AssetWriteQuery&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;make&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;~&lt;/span&gt;client&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;~&lt;/span&gt;variables&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;query&lt;span class=&quot;token operator&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;#&lt;/span&gt;variables&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;~&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;other&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#other&quot; aria-label=&quot;other permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Other&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Interesting GH issue: &lt;a href=&quot;https://github.com/Astrocoders/reason-apollo-hooks/issues/61&quot;&gt;https://github.com/Astrocoders/reason-apollo-hooks/issues/61&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title><![CDATA[Learning Higher-Order Components in React]]></title><description><![CDATA[We're building a general purpose loading screen]]></description><link>https://peterp.me/articles/higher-order-components-in-react/</link><guid isPermaLink="false">https://peterp.me/articles/higher-order-components-in-react/</guid><dc:creator><![CDATA[Peter Piekarczyk]]></dc:creator><pubDate>Tue, 24 Apr 2018 12:01:01 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;https://cdn-images-1.medium.com/max/1200/1*WqA5KCPtu44P14_6NgX3Bw.jpeg&quot; alt=&quot;A higher-order component in the wild by Gamze Bozkaya on Unsplash&quot;&gt;
A higher-order component in the wild by &lt;a href=&quot;https://unsplash.com/photos/kxGHHEjUP7Q?utm_source=unsplash&amp;#x26;utm_medium=referral&amp;#x26;utm_content=creditCopyText&quot;&gt;Gamze Bozkaya&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/search/photos/higher-order?utm_source=unsplash&amp;#x26;utm_medium=referral&amp;#x26;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Let me share a secret: no matter how long you’ve been doing something, you’re bound to have to relearn some part of it. I haven’t built my own higher-order component in a long time and made a lot of mistakes. Real mistakes.&lt;/p&gt;
&lt;h3 id=&quot;why&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#why&quot; aria-label=&quot;why permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Why?&lt;/h3&gt;
&lt;p&gt;The other day I was adding a simple loading indicator to screens in my new app. You’ve probably used this pattern before:&lt;/p&gt;
&lt;p&gt;An InfoScreen that renders Hi when loading is false in React Native&lt;/p&gt;
&lt;p&gt;This is great. It’s simple and convenient for one screen. If you’re not used to React Native, &lt;code class=&quot;language-text&quot;&gt;ActivityIndicator&lt;/code&gt; is one of the beautiful parts of app development — a component that &lt;em&gt;exists&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;When you find yourself repeating this same pattern often, its nice to see what we can do to rid ourselves from the tedious task of Copy &amp;#x26; Paste.&lt;/p&gt;
&lt;h3 id=&quot;what-do-iknow&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#what-do-iknow&quot; aria-label=&quot;what do iknow permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What do I know?&lt;/h3&gt;
&lt;p&gt;I know that I’ll have a &lt;code class=&quot;language-text&quot;&gt;loading&lt;/code&gt; prop FOR SURE.&lt;/p&gt;
&lt;p&gt;What am I apprehensive about? The strategy I will use to genuinely make my life easier (instead of harder — sometimes we need a friendly reminder).&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn-images-1.medium.com/max/2560/1*KHFk4TZZQlAscHgktarR4w.jpeg&quot; alt=&quot;Highly Organized Fruit by Alex Block on Unsplash&quot;&gt;
Highly Organized Fruit by &lt;a href=&quot;https://unsplash.com/photos/vWI1kTcMcDI?utm_source=unsplash&amp;#x26;utm_medium=referral&amp;#x26;utm_content=creditCopyText&quot;&gt;Alex Block&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/search/photos/order?utm_source=unsplash&amp;#x26;utm_medium=referral&amp;#x26;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;first-pass&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#first-pass&quot; aria-label=&quot;first pass permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;First Pass&lt;/h3&gt;
&lt;p&gt;First pass at a loading indicator higher-order component&lt;/p&gt;
&lt;p&gt;Besides the function wrapping &lt;code class=&quot;language-text&quot;&gt;React.PureComponent&lt;/code&gt; everything should look familiar. If you want to skip ahead and use this as-is, just paste this into our &lt;code class=&quot;language-text&quot;&gt;InfoScreen&lt;/code&gt; file and wrap the export:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;withLoadingScreen&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;InfoScreen&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This pattern may look familiar if you’ve used Apollo or Redux before:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;connect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  mapStateToProps&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  mapActionCreators
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;InfoScreen&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id=&quot;compose&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#compose&quot; aria-label=&quot;compose permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Compose&lt;/h3&gt;
&lt;p&gt;If you’re wondering how to use both &lt;code class=&quot;language-text&quot;&gt;connect&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;withLoadingScreen&lt;/code&gt; you can wrap the components individually or use a &lt;code class=&quot;language-text&quot;&gt;compose&lt;/code&gt; function. Writing a compose function by hand is cool, but importing the one from one of the libraries you’re already using is cooler. Both &lt;code class=&quot;language-text&quot;&gt;redux&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;react-apollo&lt;/code&gt; come bundled with their own:&lt;/p&gt;
&lt;p&gt;various compose imports from redux / react-apollo&lt;/p&gt;
&lt;h3 id=&quot;does-itwork&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#does-itwork&quot; aria-label=&quot;does itwork permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Does it work?&lt;/h3&gt;
&lt;p&gt;Depending on what your setup looks like, it might work perfectly or it might not work at all! 😃 🙃&lt;/p&gt;
&lt;p&gt;I’m using &lt;code class=&quot;language-text&quot;&gt;react-navigation&lt;/code&gt; which supports a static method called &lt;a href=&quot;https://reactnavigation.org/docs/stack-navigator.html#navigationoptions-used-by-stacknavigator&quot;&gt;navigationOptions&lt;/a&gt; to override header title and styles.&lt;/p&gt;
&lt;p&gt;The loading screen works as intended, but the header styles are gone! What happened? &lt;a href=&quot;https://reactjs.org/docs/higher-order-components.html&quot;&gt;Static methods aren’t copied over!&lt;/a&gt; It’s super easy to overlook but also super easy to fix.&lt;/p&gt;
&lt;p&gt;There’s a library called &lt;a href=&quot;https://github.com/mridgway/hoist-non-react-statics&quot;&gt;hoist-non-react-statics&lt;/a&gt; that will automatically copy over static variables like &lt;code class=&quot;language-text&quot;&gt;navigationOptions&lt;/code&gt; , &lt;code class=&quot;language-text&quot;&gt;defaultProps&lt;/code&gt;and &lt;code class=&quot;language-text&quot;&gt;propTypes&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;second-pass-hoisting-static-variables&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#second-pass-hoisting-static-variables&quot; aria-label=&quot;second pass hoisting static variables permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Second Pass: Hoisting Static Variables&lt;/h3&gt;
&lt;p&gt;Second pass at LoadingScreen higher-order component&lt;/p&gt;
&lt;p&gt;Instead of returning the class immediately, we return it only after calling &lt;code class=&quot;language-text&quot;&gt;hoistNonReactStatics&lt;/code&gt; . The header is rendering correctly again. Woo!&lt;/p&gt;
&lt;h3 id=&quot;third-pass-passing-inoptions&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#third-pass-passing-inoptions&quot; aria-label=&quot;third pass passing inoptions permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Third Pass: Passing in Options&lt;/h3&gt;
&lt;p&gt;Now that the loading screen itself functions correctly, I want to pass in a different loading indicator size for different screens.&lt;/p&gt;
&lt;p&gt;Sometimes the default loading indicator is too big or the wrong color so I’d like to be able to adjust when I need to.&lt;/p&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;connect&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;graphql&lt;/code&gt; both give you options:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;connect(mapStateToProps, mapActionCreators)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;graphql(MyQuery, { options })&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We can do the same by adding another function call:&lt;/p&gt;
&lt;p&gt;withNavigationOptions Higher Order Component with additional options&lt;/p&gt;
&lt;p&gt;In this case I wanted to control the size of the &lt;code class=&quot;language-text&quot;&gt;ActivityIndicator&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token function&quot;&gt;withLoadingScreen&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;large&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;InfoScreen&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// or using compose:&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;compose&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;withLoadingScreen&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;large&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;compose&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    mapStateToProps&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    mapActionCreators
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;InfoScreen&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id=&quot;bonus-round-naming-your-components&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#bonus-round-naming-your-components&quot; aria-label=&quot;bonus round naming your components permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Bonus Round: Naming Your Components&lt;/h3&gt;
&lt;p&gt;You’re bound to run into issues. Sometimes the component name doesn’t show up or doesn’t match the component in question. We can fix this easily by writing a simple function called &lt;code class=&quot;language-text&quot;&gt;getDisplayName&lt;/code&gt; :&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getDisplayName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;WrappedComponent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    WrappedComponent&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;displayName &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; WrappedComponent&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;LoadingScreen&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;A higher-order component with a display name&lt;/p&gt;
&lt;h3 id=&quot;conclusion&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#conclusion&quot; aria-label=&quot;conclusion permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;Higher-order components have a few weird things about them that you can fix easily. Code responsibly.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Your first ReasonML PR into an existing React Native Codebase]]></title><description><![CDATA[Type-safe, fast with a similar syntax to javascript makes it an obvious choice.]]></description><link>https://peterp.me/articles/getting-started-with-reasonml-in-react-native/</link><guid isPermaLink="false">https://peterp.me/articles/getting-started-with-reasonml-in-react-native/</guid><dc:creator><![CDATA[Peter Piekarczyk]]></dc:creator><pubDate>Sat, 03 Mar 2018 19:19:08 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;https://cdn-images-1.medium.com/max/1200/1*SaPK2OLdX_BeFp7yxRvbcg.jpeg&quot; alt=&quot;A delightful plate of Reason. Take a bite! by Amy Treasure on Unsplash&quot;&gt;&lt;/p&gt;
&lt;p&gt;ReasonML is becoming a popular way of building React apps. It’s based on the OCaml programming language with syntax very similar to JavaScript but with a compiler that warns you early on, instead of when your app is live!&lt;/p&gt;
&lt;p&gt;If you’ve been sold on ReasonML and you’re ready to incorporate your first component into a personal or better yet — company project!, this article is for you!&lt;/p&gt;
&lt;h3 id=&quot;read-thisfirst&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#read-thisfirst&quot; aria-label=&quot;read thisfirst permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Read This First&lt;/h3&gt;
&lt;p&gt;My goal is for you to get your first PR out the door. I’m skipping over a lot of the “why” and jumping right into “this is how”.&lt;/p&gt;
&lt;p&gt;Learning something new is never easy. Making time for learning is already a struggle given how much bosses are piling onto our plates these days. I want to make this as stress-free and simple for you as possible.&lt;/p&gt;
&lt;p&gt;If you find that it’s not, just &lt;a href=&quot;https://twitter.com/peterpme&quot;&gt;let me know.&lt;/a&gt; Until then sit back, relax, stretch your copy-and-paste fingers and follow along. Welcome to Reason.&lt;/p&gt;
&lt;h3 id=&quot;installing-reason&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#installing-reason&quot; aria-label=&quot;installing reason permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Installing Reason&lt;/h3&gt;
&lt;p&gt;A huge convenience of Reason is being able to install everything through npm. That makes it super easy to get started. &lt;a href=&quot;https://github.com/reasonml-community/bs-react-native&quot;&gt;Read more about it here.&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;sh&quot;&gt;&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token function&quot;&gt;yarn&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--dev&lt;/span&gt; bs-platform &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;yarn&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt; reason-react bs-react-native&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h4 id=&quot;create-a-bsconfigjson&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#create-a-bsconfigjson&quot; aria-label=&quot;create a bsconfigjson permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Create a bsconfig.json&lt;/h4&gt;
&lt;p&gt;bsconfig.json is a file that supports settings for &lt;a href=&quot;https://bucklescript.github.io/&quot;&gt;bucklescript&lt;/a&gt;. After looking at a bunch of these, I’ve concluded that they’re usually exactly the same.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Altos is the name of my app. You should replace that 😃&lt;/strong&gt;&lt;/p&gt;
&lt;h4 id=&quot;add-scripts&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#add-scripts&quot; aria-label=&quot;add scripts permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Add Scripts&lt;/h4&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;json&quot;&gt;&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token property&quot;&gt;&quot;scripts&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
 &lt;span class=&quot;token property&quot;&gt;&quot;build&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;bsb -make-world -clean-world&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
 &lt;span class=&quot;token property&quot;&gt;&quot;watch&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;bsb -make-world -clean-world -w&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h4 id=&quot;project-structure&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#project-structure&quot; aria-label=&quot;project structure permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Project Structure&lt;/h4&gt;
&lt;p&gt;Create a &lt;code class=&quot;language-text&quot;&gt;re&lt;/code&gt; folder next to package.json This is where all of your components will live. In our &lt;code class=&quot;language-text&quot;&gt;bsconfig.json&lt;/code&gt; file we have &lt;code class=&quot;language-text&quot;&gt;sources&lt;/code&gt; that already include &lt;code class=&quot;language-text&quot;&gt;re&lt;/code&gt; . &lt;a href=&quot;https://reasonml.github.io/docs/en/project-structure.html#publishing&quot;&gt;Here are some other great guidelines&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;All your components will need to be capitalized:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Typography.re&lt;/li&gt;
&lt;li&gt;Label.re&lt;/li&gt;
&lt;li&gt;Add the following to your &lt;code class=&quot;language-text&quot;&gt;.gitignore:&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;sh&quot;&gt;&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;.merlin
.bsb.lock
lib&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h4 id=&quot;bsjs-files&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#bsjs-files&quot; aria-label=&quot;bsjs files permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;.bs.js files&lt;/h4&gt;
&lt;p&gt;If you want to sneak Reason into your codebase without forcing your teammates to install &lt;code class=&quot;language-text&quot;&gt;bs-platform&lt;/code&gt; you’re welcome to add the generated &lt;code class=&quot;language-text&quot;&gt;*.bs.js&lt;/code&gt; files. That being said, you might face merge conflicts down the road.&lt;/p&gt;
&lt;p&gt;If your teammates are all cool with Reason, place &lt;code class=&quot;language-text&quot;&gt;*.bs.js&lt;/code&gt; inside your &lt;code class=&quot;language-text&quot;&gt;.gitignore&lt;/code&gt; and have them install &lt;code class=&quot;language-text&quot;&gt;bs-platform.&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Every team is different so I leave this decision up to you. Chances are you can get away with including them and &lt;a href=&quot;https://reasonml.chat/t/should-i-include-or-exclude-bs-js-files-in-git/60&quot;&gt;figure it out later.&lt;/a&gt;&lt;/p&gt;
&lt;h4 id=&quot;press-play&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#press-play&quot; aria-label=&quot;press play permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Press Play&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;Open up a terminal window and run &lt;code class=&quot;language-text&quot;&gt;yarn watch or npm run watch&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Start your React Native Project &lt;code class=&quot;language-text&quot;&gt;react-native run-ios&lt;/code&gt; or &lt;code class=&quot;language-text&quot;&gt;expo start&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If nothing broke, you have succeeded in getting your project ready for Reason! Pat yourself on the back — you have taken an enormous step forward to your first Reason pull request!&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn-images-1.medium.com/max/2560/1*0Q7LTDXRR0b89ByL9nbrpg.jpeg&quot; alt=&quot;Delicious bite-size chunks of Reason by Rose Elena on Unsplash&quot;&gt;
Delicious bite-size chunks of Reason by &lt;a href=&quot;https://unsplash.com/photos/llWdsvyRxYA?utm_source=unsplash&amp;#x26;utm_medium=referral&amp;#x26;utm_content=creditCopyText&quot;&gt;Rose Elena&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/search/photos/treats?utm_source=unsplash&amp;#x26;utm_medium=referral&amp;#x26;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;your-first-component&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#your-first-component&quot; aria-label=&quot;your first component permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Your First Component&lt;/h3&gt;
&lt;p&gt;Creating your first component can be really easy or really hard. If you’re going to try and convert something with a lot of external modules, you’re going to have a bad time.&lt;/p&gt;
&lt;p&gt;The first component I introduced into our project was a simple Label:&lt;/p&gt;
&lt;p&gt;Label component in ReactJS&lt;/p&gt;
&lt;p&gt;The label consumes a prop &lt;code class=&quot;language-text&quot;&gt;label&lt;/code&gt; and sets the background color to gray. The only components I’m using are &lt;code class=&quot;language-text&quot;&gt;View, Text, StyleSheet&lt;/code&gt; because the bindings are supported by &lt;a href=&quot;https://github.com/reasonml-community/bs-react-native&quot;&gt;bs-react-native&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Bindings let ReasonML know the type of your code from Javascript so it can save you from making silly mistakes later.&lt;/p&gt;
&lt;h4 id=&quot;converting-toreason&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#converting-toreason&quot; aria-label=&quot;converting toreason permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Converting to Reason&lt;/h4&gt;
&lt;p&gt;At first glance, a lot of things are the same, but a lot are different. &lt;strong&gt;ReasonML requires semicolons!&lt;/strong&gt; The compiler will delightfully let you know.&lt;/p&gt;
&lt;p&gt;The Label component converted to ReactReason.&lt;/p&gt;
&lt;h4 id=&quot;imports&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#imports&quot; aria-label=&quot;imports permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Imports&lt;/h4&gt;
&lt;p&gt;In ReactJS and Javascript, you’d import something via &lt;code class=&quot;language-text&quot;&gt;import React from &apos;react&apos;&lt;/code&gt; or &lt;code class=&quot;language-text&quot;&gt;const React = require(&apos;react&apos;).&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Reason will import the libraries you have installed automatically. We added them in &lt;code class=&quot;language-text&quot;&gt;bsconfig.json.&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;When you see &lt;code class=&quot;language-text&quot;&gt;open BsReactNative&lt;/code&gt; you’re doing something similar to &lt;code class=&quot;language-text&quot;&gt;import { Component } from &apos;react&apos;.&lt;/code&gt; You can &lt;code class=&quot;language-text&quot;&gt;import React from &apos;react&apos;&lt;/code&gt; and then call React.Component, or import the Component directly and save yourself some text.&lt;/p&gt;
&lt;p&gt;So, instead of writing &lt;code class=&quot;language-text&quot;&gt;BsReactNative.StyleSheet, BsReactNative.View&lt;/code&gt; I can &lt;code class=&quot;language-text&quot;&gt;open BsReactNative&lt;/code&gt; and write &lt;code class=&quot;language-text&quot;&gt;StyleSheet, View&lt;/code&gt; instead.&lt;/p&gt;
&lt;h4 id=&quot;local-opens&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#local-opens&quot; aria-label=&quot;local opens permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Local Opens&lt;/h4&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;re&quot;&gt;&lt;pre class=&quot;language-re&quot;&gt;&lt;code class=&quot;language-re&quot;&gt;Style.(&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;A dot with nothing after it in this case is called a “local open”. Its the same as calling &lt;code class=&quot;language-text&quot;&gt;import Style&lt;/code&gt; but only for this function. This helps us avoid conflicts across the whole file.&lt;/p&gt;
&lt;p&gt;See how within the function we’re calling &lt;code class=&quot;language-text&quot;&gt;borderRadius&lt;/code&gt; ? We could also do something like this instead:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;re&quot;&gt;&lt;pre class=&quot;language-re&quot;&gt;&lt;code class=&quot;language-re&quot;&gt;style=(
 Style.style([
 Style.borderRadius(4.)
]);&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;em&gt;(thanks to&lt;/em&gt; &lt;a href=&quot;https://medium.com/u/ddb95b022776&quot;&gt;&lt;em&gt;Sean Grove&lt;/em&gt;&lt;/a&gt; &lt;em&gt;for pointing this out!)&lt;/em&gt;&lt;/p&gt;
&lt;h4 id=&quot;styling--stylesheets&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#styling--stylesheets&quot; aria-label=&quot;styling  stylesheets permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Styling / StyleSheets&lt;/h4&gt;
&lt;p&gt;Styling is tricky at first but gets easier over time. Let me save you a lot of time and effort by linking you to &lt;a href=&quot;https://github.com/reasonml-community/bs-react-native/blob/master/src/style.rei&quot;&gt;all the style types supported by bs-react-native&lt;/a&gt;. I’d highly recommend keep this open until you get the hang of it!&lt;/p&gt;
&lt;p&gt;Why is styling tricky? Because you’re not used to typing things a certain way. Here’s a great example:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;re&quot;&gt;&lt;pre class=&quot;language-re&quot;&gt;&lt;code class=&quot;language-re&quot;&gt;borderRadius(4.)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;vs&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;re&quot;&gt;&lt;pre class=&quot;language-re&quot;&gt;&lt;code class=&quot;language-re&quot;&gt;paddingHorizontal(Pt(10.))&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In ReactJS, &lt;code class=&quot;language-text&quot;&gt;borderRadius&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;paddingHorizontal&lt;/code&gt; are the same type (number). but in ReactReason, they’re different:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;borderRadius&lt;/code&gt; is a &lt;a href=&quot;https://github.com/reasonml-community/bs-react-native/blob/master/src/style.rei#L278&quot;&gt;float&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;paddingHorizontal&lt;/code&gt; is a &lt;a href=&quot;https://github.com/reasonml-community/bs-react-native/blob/master/src/style.rei#L156&quot;&gt;pt_pct&lt;/a&gt;. &lt;code class=&quot;language-text&quot;&gt;pt_pct&lt;/code&gt; isn’t a Reason thing. It’s a type within the bs-react-native library that means:&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;This can either be a float wrapped by point (pt) or a float wrapped by a percentage (pct)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4 id=&quot;components&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#components&quot; aria-label=&quot;components permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Components&lt;/h4&gt;
&lt;p&gt;A stateless function component in ReactJs will be represented by a function:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;Label&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; label &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Text&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;label&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;Text&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In Reason React:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;re&quot;&gt;&lt;pre class=&quot;language-re&quot;&gt;&lt;code class=&quot;language-re&quot;&gt;*/ Label.re */

[@react.component]
let make = (~label) =&amp;gt; &amp;lt;Text&amp;gt; {React.string(label)} &amp;lt;/Text&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;[@react.component]&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;You put this above every component. Think of this like a decorator in Javascript. It knows to convert the sugar to React calls.&lt;/p&gt;
&lt;p&gt;The arguments:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Optional components look like this: &lt;code class=&quot;language-text&quot;&gt;~label=?&lt;/code&gt; with an &lt;code class=&quot;language-text&quot;&gt;=?&lt;/code&gt; at th
e end&lt;/li&gt;
&lt;li&gt;Default arguments should look familiar: &lt;code class=&quot;language-text&quot;&gt;label=&quot;Network&quot;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;stringtoelement&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#stringtoelement&quot; aria-label=&quot;stringtoelement permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;stringToElement&lt;/h4&gt;
&lt;p&gt;If you try to display your label the same way you would in ReactJS, you’ll be greeted with a compiler error. That’s because you have to convert the string to an React element: &lt;code class=&quot;language-text&quot;&gt;ReasonReact.stringToElement(label).&lt;/code&gt; Why do we do this? Because &lt;a href=&quot;https://reasonml.github.io/reason-react/docs/en/render.html#docsNav&quot;&gt;Reason’s type system restricts you from passing arbitrary data&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;You’ll also notice a space between &lt;code class=&quot;language-text&quot;&gt;&amp;lt;Text&gt; &amp;lt;/Text&gt;&lt;/code&gt;. That’s intentional!&lt;/p&gt;
&lt;p&gt;There’s a good chance you’re going to display a number in your first component. That would look like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;re&quot;&gt;&lt;pre class=&quot;language-re&quot;&gt;&lt;code class=&quot;language-re&quot;&gt;&amp;lt;Text&amp;gt; {ReasonReact.stringToElement(string_of_int(10)} &amp;lt;/Text&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;There’s a &lt;a href=&quot;https://reasonml.github.io/reason-react/docs/en/render.html#docsNav&quot;&gt;couple of different&lt;/a&gt; special element types you might need, but I would strongly suggest you focus on a simple component first.&lt;/p&gt;
&lt;h4 id=&quot;exporting-your-component-to-jsland&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#exporting-your-component-to-jsland&quot; aria-label=&quot;exporting your component to jsland permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Exporting your component to JS land&lt;/h4&gt;
&lt;p&gt;In ReactJS, you’d write &lt;code class=&quot;language-text&quot;&gt;export default&lt;/code&gt; or &lt;code class=&quot;language-text&quot;&gt;export const&lt;/code&gt; and consume your component the way you would with anything else.&lt;/p&gt;
&lt;p&gt;In ReasonReact, there’s an extra step you have to take via &lt;code class=&quot;language-text&quot;&gt;wrapReasonForJs&lt;/code&gt; .&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;re&quot;&gt;&lt;pre class=&quot;language-re&quot;&gt;&lt;code class=&quot;language-re&quot;&gt;let default =
  ReasonReact.wrapReasonForJs(~component, jsProps =&amp;gt;
    make(~label=jsProps##label, [||])
  );&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Basically the pattern is to take your props (in this case we only have label) and pass them in as: &lt;code class=&quot;language-text&quot;&gt;~label=jsProps##label&lt;/code&gt; . Children will look like: &lt;code class=&quot;language-text&quot;&gt;[||]&lt;/code&gt; .&lt;/p&gt;
&lt;h4 id=&quot;use-it&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#use-it&quot; aria-label=&quot;use it permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Use it!&lt;/h4&gt;
&lt;p&gt;You’ve done such a great job putting together your first component, it’s time for you to use it. Just import it with the &lt;code class=&quot;language-text&quot;&gt;bs&lt;/code&gt; extension:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;re&quot;&gt;&lt;pre class=&quot;language-re&quot;&gt;&lt;code class=&quot;language-re&quot;&gt;import Label from &amp;quot;./re/Label.bs.js&amp;quot;

&amp;lt;Label label=&amp;quot;REACT NATIVE&amp;quot; /&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id=&quot;push-it-up--let-meknow&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#push-it-up--let-meknow&quot; aria-label=&quot;push it up  let meknow permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Push it up &amp;#x26; let me know!&lt;/h3&gt;
&lt;p&gt;I challenge you to create one small, tiny Reason component and introduce it into your company’s React Native app. If you do, please &lt;a href=&quot;https://twitter.com/peterpme&quot;&gt;let me know!!&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Otherwise, until you’re ready &lt;a href=&quot;https://twitter.com/peterpme&quot;&gt;follow me on Twitter&lt;/a&gt;. You’ll see a lot of Reason-related stuff.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/peterpme/reason-react-native-example&quot;&gt;I created a base repo of this &amp;#x26; expo as a reference.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Thanks to&lt;/em&gt; &lt;a href=&quot;https://khoanguyen.me/&quot;&gt;&lt;em&gt;thangngoc89&lt;/em&gt;&lt;/a&gt; &lt;em&gt;and&lt;/em&gt; &lt;a href=&quot;http://www.riseos.com/&quot;&gt;&lt;em&gt;sgrove&lt;/em&gt;&lt;/a&gt; &lt;em&gt;for peer-reviewing this.&lt;/em&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Taming React Native’s ScrollView with flex]]></title><description><![CDATA[Is it flex? Is it the ScrollView?]]></description><link>https://peterp.me/articles/taming-react-native-scrollview-with-flex/</link><guid isPermaLink="false">https://peterp.me/articles/taming-react-native-scrollview-with-flex/</guid><dc:creator><![CDATA[Peter Piekarczyk]]></dc:creator><pubDate>Mon, 05 Feb 2018 14:01:01 GMT</pubDate><content:encoded>&lt;p&gt;Time and time again I find myself fighting a ScrollView to get it to work the way I want it to. Is it flex? Is it the ScrollView? It was time I wrote an article.&lt;/p&gt;
&lt;p&gt;My favorite scenario, the one that inspired this article, the one that I &lt;em&gt;always&lt;/em&gt; forget about, the one I recently encountered for &lt;a href=&quot;https://www.orchard.ai&quot;&gt;Orchard&lt;/a&gt;, (what a build-up) is one where I’d like the screen to scroll normally when things don’t fit and &lt;code class=&quot;language-text&quot;&gt;justify-content: space-between&lt;/code&gt; when there’s room.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 500px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/789516c909bdbe9c3a48594aeca5834f/a331c/iphone-scrolling-large.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 99.2%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAIAAAAC64paAAAACXBIWXMAAAsTAAALEwEAmpwYAAAEEUlEQVR42o3Te0xTVxgA8M5s4DKXOASnEqRUWikvYVZx2YuRuBgzBEJ8ABZkMKG2vIXBLONRC/Rxe9vyWoC+pUABAaFVnlscMsK6iJCBjGDJyHD9g9LSm8tovfcutKVu/+377yTnd77vnPN9OAzDEASxWq0QBMEwbLVazWazzWbD9sJisUAQZDabt7a2IAiyWCybm5smkwlFURyGYQaDYXp6empqSq/Xj42NzczMrKysbG9vO7HJZHo8+dMvev3kkyezs7PP5uZGxkbX1tYwDMMhCLKxsWGz2WAYhiDIZrPZ7XYYhnd2dtzJUQTFUOx1oK7Fbubl5WUOj8sDAL4A4AH8uzVsrU63ex0UwTBsfX29QiK+XcUszisozi8ouVNWXM95Ov/MhdNvpONwuHc93t6/76133vT0wL3hd8z3L6PReXxrh2q/IOk9AdW7LOFQaaIXKwXHSaGDLEfZO/aknK/x5UmEmrRTnJsnqtOO16QHJV8wLC07sVDeckx6K2Sk+tQwO/RRDVnLPiwrymnkOPD2zpUSGrGvNGq87pMx4NxDXtg4QMi9svDrrBNzWxsIUsaXEw3Rg7zPB4HY4SaSkpnJr9zFdvjv+LyvAtuLPtNyz/XXftrHpQwBAdmJv+mfOnFts/Bw882wByxyd0WQpjJYwzoiKb3OKsPsr3bx5aKs95X5QferQrqrSepKvx42iZG8urjkxLyWBt/W3NNaXmhvTXA3mzIA+kqZNJDteDA7ksosiNCw4n+Qne4HYh+1nZ9QEukphoXnTtzYLg9RlVN/7rww3EIZAHOmH5DvcRj1XAd+haYyC8M6WZcmZGf6hbE6ScyoksSgunGzWoFvK6FohZF9QMR9AaW/PkDKyhHv4TRmUaCqMmqwPqIH/EAjihxsCaKnuXGTWk6WlSf+qIoeagrvFlwb7wxSculuTL1TeLaLf3mi40xv48UheexETyAtdXXRjRVECfP8iOTD/oZwjfALnZwgraWL3GV/W0SUVH3c1xyuBilqcURvKykrzbDoLlvpLc4ndLDxChZezsYr6nwavmOIeE6M3Cgv8W6rOKEBA9oFfnIgUtselpf9YmHxNRYVBKpr8fK7flK2v6yO1MbNFQOu9qTeyvK6FBNwPcE/OeH41TgC9SoxJtqw7Oqw7ztUPsLC4A7eSQWHJOOSFeBBQTlDtIcZdLonbt9Rr0P+R476evsc8PAMJZPXX750fZVSdhC8TeoCT7aDpHsiokp8AKzM5te58Nz8fGNzU/E3JXHx8RmZmQAo0D3U2W121DF6jycnP8rNiCqmEa/F+SdcPJtPi6BlyLs6Xdi5CYZho9FoNpux/waKIMY/1laXfh8d0g5oulcWnv/5wmBzTLsLIwjyr1FHURTF/kf8A4jVHcepz1KqAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source
              srcset=&quot;/static/789516c909bdbe9c3a48594aeca5834f/ecc44/iphone-scrolling-large.webp 125w,
/static/789516c909bdbe9c3a48594aeca5834f/0e2a5/iphone-scrolling-large.webp 250w,
/static/789516c909bdbe9c3a48594aeca5834f/10636/iphone-scrolling-large.webp 500w,
/static/789516c909bdbe9c3a48594aeca5834f/db9b4/iphone-scrolling-large.webp 750w,
/static/789516c909bdbe9c3a48594aeca5834f/8d2ea/iphone-scrolling-large.webp 800w&quot;
              sizes=&quot;(max-width: 500px) 100vw, 500px&quot;
              type=&quot;image/webp&quot;
            /&gt;
          &lt;source
            srcset=&quot;/static/789516c909bdbe9c3a48594aeca5834f/57f79/iphone-scrolling-large.png 125w,
/static/789516c909bdbe9c3a48594aeca5834f/3e256/iphone-scrolling-large.png 250w,
/static/789516c909bdbe9c3a48594aeca5834f/b30f8/iphone-scrolling-large.png 500w,
/static/789516c909bdbe9c3a48594aeca5834f/b13e1/iphone-scrolling-large.png 750w,
/static/789516c909bdbe9c3a48594aeca5834f/a331c/iphone-scrolling-large.png 800w&quot;
            sizes=&quot;(max-width: 500px) 100vw, 500px&quot;
            type=&quot;image/png&quot;
          /&gt;
          &lt;img
            class=&quot;gatsby-resp-image-image&quot;
            src=&quot;/static/789516c909bdbe9c3a48594aeca5834f/b30f8/iphone-scrolling-large.png&quot;
            alt=&quot;iPhone 5s. vs iPhone X Scrolling&quot;
            title=&quot;&quot;
            loading=&quot;lazy&quot;
            decoding=&quot;async&quot;
            style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
          /&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;h4 id=&quot;a-couple-of-different-solutions-came-to-mind-atfirst&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#a-couple-of-different-solutions-came-to-mind-atfirst&quot; aria-label=&quot;a couple of different solutions came to mind atfirst permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;A couple of different solutions came to mind at first:&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Use either &lt;code class=&quot;language-text&quot;&gt;View&lt;/code&gt; or &lt;code class=&quot;language-text&quot;&gt;ScrollView&lt;/code&gt; depending on the device height (meh)&lt;/li&gt;
&lt;li&gt;Decrease the text size until everything fit (meh)&lt;/li&gt;
&lt;li&gt;Place the “Privacy Policy” outside of the &lt;code class=&quot;language-text&quot;&gt;ScrollView&lt;/code&gt; making it sticky, but it felt weird to scroll over and still see the privacy policy.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I felt like these options would either make my life miserable or even worse: the user’s life miserable. I went to the docs for &lt;code class=&quot;language-text&quot;&gt;ScrollView&lt;/code&gt; and read over &lt;a href=&quot;https://facebook.github.io/react-native/docs/scrollview.html#contentcontainerstyle&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;contentContainerStyle&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;These styles will be applied to the scroll view content container which wraps all of the child views&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;contentContainerStyle is a step in the right direction. It will apply styles to the content container as if there were a &lt;code class=&quot;language-text&quot;&gt;View&lt;/code&gt; wrapping your children.&lt;/p&gt;
&lt;p&gt;It worked great on the iPhone X. There was enough room so everything was justified vertically. But what happens when you try this on a smaller device like the iPhone 5s? It sticks! Why?&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/da3f29896c383dde0c9bf6f1ac9a7038/iphone5s-broken-scroll.gif&quot; alt=&quot;iPhone 5s with a ScrollView that doesn’t scroll&quot;&gt;&lt;/p&gt;
&lt;h4 id=&quot;react-native-flex-vs-cssflex&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#react-native-flex-vs-cssflex&quot; aria-label=&quot;react native flex vs cssflex permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;React Native Flex vs. CSS Flex&lt;/h4&gt;
&lt;p&gt;It turns out that &lt;code class=&quot;language-text&quot;&gt;flex&lt;/code&gt; &lt;a href=&quot;https://facebook.github.io/react-native/docs/layout-props.html#flex&quot;&gt;functions a bit differently&lt;/a&gt; in React Native than it does in CSS which is why setting &lt;code class=&quot;language-text&quot;&gt;flex: 1&lt;/code&gt; didn’t work the way I thought it would.&lt;/p&gt;
&lt;p&gt;In CSS, &lt;code class=&quot;language-text&quot;&gt;flex&lt;/code&gt; is short-hand for controlling the following properties:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;flex-grow&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;flex-shrink&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;flex-basis&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Writing &lt;code class=&quot;language-text&quot;&gt;flex: 1&lt;/code&gt; in CSS is shorthand for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;flex-grow: 1&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;flex-shrink: 1&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;flex-basis: 0&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In React Native, on the other hand, &lt;code class=&quot;language-text&quot;&gt;flex&lt;/code&gt; consumes a number, not an string and it works like this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;positive number — component becomes flexible and will function proportionally to its value. A value of 2 will take up twice as much space as a sibling that has a value of 1.&lt;/li&gt;
&lt;li&gt;0 — the component isn’t flexible and is sized by &lt;code class=&quot;language-text&quot;&gt;width&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;height&lt;/code&gt; .&lt;/li&gt;
&lt;li&gt;-1 — the component is sized by its &lt;code class=&quot;language-text&quot;&gt;width&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;height&lt;/code&gt; but if there’s not enough space, it will shrink to satisfy &lt;code class=&quot;language-text&quot;&gt;minWidth&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;minHeight&lt;/code&gt; .&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;flex-grow&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#flex-grow&quot; aria-label=&quot;flex grow permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Flex Grow&lt;/h4&gt;
&lt;p&gt;Writing &lt;code class=&quot;language-text&quot;&gt;flex-grow: 1&lt;/code&gt; in CSS is shorthand for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;flex-grow: 1&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;flex-shrink: 1&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;flex-basis: auto&lt;/code&gt; (this is different!)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;flex-grow&lt;/code&gt; distributes &lt;strong&gt;free space&lt;/strong&gt; to &lt;code class=&quot;language-text&quot;&gt;flex&lt;/code&gt; items. When there is no free space, &lt;code class=&quot;language-text&quot;&gt;flex-grow&lt;/code&gt; does nothing and &lt;code class=&quot;language-text&quot;&gt;flex-shrink&lt;/code&gt; takes over to determine how much items will shrink relative to its siblings (instead of grow).&lt;/p&gt;
&lt;h4 id=&quot;why-does-thismatter&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#why-does-thismatter&quot; aria-label=&quot;why does thismatter permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Why does this matter?&lt;/h4&gt;
&lt;p&gt;The solution has to do with the implementation differences of &lt;code class=&quot;language-text&quot;&gt;flex&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;flexGrow&lt;/code&gt; in React Native.&lt;/p&gt;
&lt;p&gt;Since &lt;code class=&quot;language-text&quot;&gt;flexGrow&lt;/code&gt; functions the same way, we can easily solve this problem by updating our &lt;code class=&quot;language-text&quot;&gt;contentContainerStyle&lt;/code&gt; to &lt;code class=&quot;language-text&quot;&gt;flexGrow: 1&lt;/code&gt; instead:&lt;/p&gt;
&lt;p&gt;Using &lt;code class=&quot;language-text&quot;&gt;flexGrow&lt;/code&gt; vs. &lt;code class=&quot;language-text&quot;&gt;flex&lt;/code&gt; in &lt;code class=&quot;language-text&quot;&gt;contentContainerStyle&lt;/code&gt; prop&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/533983cef37218d3ed481ad3ded9972f/iphone5s-fixed-scrolling.gif&quot; alt=&quot;iPhone 5s with a ScrollView that scrolls correctly&quot;&gt;&lt;/p&gt;
&lt;p&gt;Hopefully neither of us will have to struggle with a &lt;code class=&quot;language-text&quot;&gt;ScrollView&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;flex&lt;/code&gt; again!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Shaving 2 Minutes Off Our Graphcool Deployment Times]]></title><description><![CDATA[In as little as 1 minute]]></description><link>https://peterp.me/articles/shaving-2-minutes-off-our-graphql-deployment-times/</link><guid isPermaLink="false">https://peterp.me/articles/shaving-2-minutes-off-our-graphql-deployment-times/</guid><dc:creator><![CDATA[Peter Piekarczyk]]></dc:creator><pubDate>Sat, 06 Jan 2018 19:43:23 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;https://cdn-images-1.medium.com/max/800/1*emGM4P2MpMFkQ2pIT1Cifg.jpeg&quot; alt=&quot;Photo by Erik Eastman on Unsplash&quot;&gt;
Photo by &lt;a href=&quot;https://unsplash.com/photos/yiptq3TFiX8?utm_source=unsplash&amp;#x26;utm_medium=referral&amp;#x26;utm_content=creditCopyText&quot;&gt;Erik Eastman&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=unsplash&amp;#x26;utm_medium=referral&amp;#x26;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://graph.cool&quot;&gt;Graphcool&lt;/a&gt; is an awesome GraphQL-powered backend we use at &lt;a href=&quot;https://www.orchard.ai&quot;&gt;Orchard&lt;/a&gt;. One of the features they offer is custom functions (resolvers) a la AWS Lambda.&lt;/p&gt;
&lt;p&gt;The thing is, deploying to any environment includes both prod AND dev dependencies inside your node_modules folder. That means eslint and anything else you have in that directory.&lt;/p&gt;
&lt;p&gt;I’m sure this will change soon enough, but for now there’s a few simple steps we can follow to minimize our bundle size &amp;#x26; time spent deploying:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Remove any files &amp;#x26; folders that aren’t related to Graphcool. That goes for any scripts, utilities, functions, etc that don’t need to live here.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;/src only includes the functions we require. Nothing else.&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;tree&quot;&gt;&lt;pre class=&quot;language-tree&quot;&gt;&lt;code class=&quot;language-tree&quot;&gt;├── README.md
├── graphcool.yml
├── node_modules
├── package.json
├── src
├── types.graphql
└── yarn.lock&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Create npm commands in your package.json that will delete node_modules and only install packages required for production. Now you’ll know for sure that none of your eslint stuff will be bundled and deployed.&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;json&quot;&gt;&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token property&quot;&gt;&quot;deploy:dev&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;rm -rf node_modules &amp;amp;&amp;amp; yarn --prod &amp;amp;&amp;amp; graphcool deploy -t dev &amp;amp;&amp;amp; yarn&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Lastly, &lt;strong&gt;YMMV&lt;/strong&gt; but yarn includes a &lt;code class=&quot;language-text&quot;&gt;—-flat&lt;/code&gt;flag you can use to only install one version of a package across ALL your dependencies. We didn’t run into any issues using this, but you might so give it a go on dev first:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;json&quot;&gt;&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token property&quot;&gt;&quot;deploy:dev&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;rm -rf node_modules &amp;amp;&amp;amp; yarn --prod --flat &amp;amp;&amp;amp; graphcool deploy -t dev &amp;amp;&amp;amp; yarn&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We were going to go as far as removing lodash and installing only the modules we use (lodash.chunk, lodash.get) but after running — flat, we discovered some of our node modules already require lodash and saved ourselves the hassle by just forcing that version. Our yarn.lock file is like 100x smaller!&lt;/p&gt;
&lt;h4 id=&quot;we-went-from-120s-deployments-down-to191s&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#we-went-from-120s-deployments-down-to191s&quot; aria-label=&quot;we went from 120s deployments down to191s permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;We went from 120s deployments down to 19.1s!&lt;/h4&gt;
&lt;p&gt;So it was worth writing about :)&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Environment Variables in Expo using Release Channels]]></title><description><![CDATA[Makes it easy to release to multiple environments]]></description><link>https://peterp.me/articles/environment-variables-in-expo-using-release-channels/</link><guid isPermaLink="false">https://peterp.me/articles/environment-variables-in-expo-using-release-channels/</guid><dc:creator><![CDATA[Peter Piekarczyk]]></dc:creator><pubDate>Tue, 02 Jan 2018 17:31:06 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;https://cdn-images-1.medium.com/max/800/1*lBI5jG-D0rBhO3OnSgm6Ag.jpeg&quot; alt=&quot;Photo by Sergii Bozhko on Unsplash&quot;&gt;
Photo by &lt;a href=&quot;https://unsplash.com/photos/_56sISeZzLc?utm_source=unsplash&amp;#x26;utm_medium=referral&amp;#x26;utm_content=creditCopyText&quot;&gt;Sergii Bozhko&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=unsplash&amp;#x26;utm_medium=referral&amp;#x26;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Expo has recently released &lt;a href=&quot;https://docs.expo.io/versions/latest/guides/release-channels.html&quot;&gt;Release Channels&lt;/a&gt; that allow you to deploy, rollback and test your app with different users by just adding the &lt;code class=&quot;language-text&quot;&gt;--release-channel&lt;/code&gt; flag on the publish command.&lt;/p&gt;
&lt;p&gt;One of my favorite things about Release Channels is the ability to define pseudo environment variables so I can easily switch between dev, staging &amp;#x26; prod.&lt;/p&gt;
&lt;p&gt;Here’s how I do it:&lt;/p&gt;
&lt;p&gt;An example of handling environment variables in Expo using Release Channels&lt;/p&gt;
&lt;p&gt;The reason why I use indexOf is because I’ll release new versions of my app based on the package.json version. That way I keep things sync’d up across the entire Orchard ecosystem:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;sh&quot;&gt;&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;exp publish --release-channel staging-1.20.1
exp publish --release-channel staging-1.21.0

exp publish --release-channel prod-2.0.0&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h4 id=&quot;notes&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#notes&quot; aria-label=&quot;notes permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Notes:&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;In the current release of &lt;strong&gt;Expo v24&lt;/strong&gt;, the releaseChannel key DOES NOT show up in dev mode.&lt;/li&gt;
&lt;li&gt;In future releases, the releaseChannel key may show up as &lt;strong&gt;undefined&lt;/strong&gt;. DO NOT quote me on this, its just speculation.&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title><![CDATA[Command Line Tip: Lowercase all file names in a given directory]]></title><description><![CDATA[If I didn't write about it, I'd forget it.]]></description><link>https://peterp.me/articles/cli-tips-lowercase-all-filenames-in-directory/</link><guid isPermaLink="false">https://peterp.me/articles/cli-tips-lowercase-all-filenames-in-directory/</guid><dc:creator><![CDATA[Peter Piekarczyk]]></dc:creator><pubDate>Thu, 28 Dec 2017 19:19:12 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;https://cdn-images-1.medium.com/max/800/1*sS6KcsjhHDEI1T0ka164Wg.jpeg&quot; alt=&quot;Photo by Franz Harvin Aceituna on Unsplash&quot;&gt;&lt;/p&gt;
&lt;p&gt;Here’s a one-liner you can use to change all the filenames that include uppercase letters to lowercase. If I didn’t write about it, I’d forget how it works, so here we go!&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;sh&quot;&gt;&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token for-or-select variable&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; *&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;mv&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$f&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; $f &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;tr&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;[:upper:]&apos;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;[:lower:&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;done&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Break down:&lt;/p&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;for file in *&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;For every file (variable). You could also do &lt;code class=&quot;language-text&quot;&gt;in *.pdf&lt;/code&gt; and that would only select PDF’s for example&lt;/p&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;do echo $f&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;do is part of the for loop syntax, &lt;code class=&quot;language-text&quot;&gt;echo&lt;/code&gt; the variable &lt;code class=&quot;language-text&quot;&gt;f&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;mv $f $(echo $f | tr &apos;[:upper:]&apos; &apos;[:lower:&apos;])&lt;/code&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Run &lt;code class=&quot;language-text&quot;&gt;translate characters (tr)&lt;/code&gt; command to translate upper case characters to lower case characters&lt;/li&gt;
&lt;li&gt;Then move the original file name to the one outputted by the &lt;code class=&quot;language-text&quot;&gt;tr&lt;/code&gt; command&lt;/li&gt;
&lt;li&gt;You’re done! Celebrate&lt;/li&gt;
&lt;/ol&gt;</content:encoded></item><item><title><![CDATA[Thoughts on Structuring your Apollo Queries & Mutations]]></title><description><![CDATA[After using Apollo for the last few months, I've picked up some great patterns]]></description><link>https://peterp.me/articles/thoughts-on-structuring-apollo-queries-mutations/</link><guid isPermaLink="false">https://peterp.me/articles/thoughts-on-structuring-apollo-queries-mutations/</guid><dc:creator><![CDATA[Peter Piekarczyk]]></dc:creator><pubDate>Fri, 20 Oct 2017 14:56:48 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;https://cdn-images-1.medium.com/max/800/1*X3AZL38e8zWBeXpZXxW0lQ.jpeg&quot; alt=&quot;Photo by Patryk Grądys on Unsplash&quot;&gt;
Photo by &lt;a href=&quot;https://unsplash.com/photos/4pPzKfd6BEg?utm_source=unsplash&amp;#x26;utm_medium=referral&amp;#x26;utm_content=creditCopyText&quot;&gt;Patryk Grądys&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=unsplash&amp;#x26;utm_medium=referral&amp;#x26;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://open.spotify.com/track/3Dfy5u28HChURIwcCL4Rto&quot;&gt;Rezz - Synthesia on Spotify&lt;/a&gt;:
This is what I listen to when I code. I wrote this article while listening to the entire album. Listen at your own risk &lt;em&gt;😃&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;After using Apollo for the last few months, I’ve picked up some great patterns we’ve adopted at &lt;a href=&quot;https://www.orchard.ai&quot;&gt;Orchard&lt;/a&gt;, where we’ve re-implemented an experience for our beta testers just about every week&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The faster we can build something, the sooner we can get feedback from our beta testers and the better chance we have of building an amazing product.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4 id=&quot;folder-structure&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#folder-structure&quot; aria-label=&quot;folder structure permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;strong&gt;Folder Structure:&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;I don’t inline my queries. Maybe I’m cray cray, but I strongly believe in being able to search and reuse something as quickly as possible. &lt;a href=&quot;https://github.com/ggreer/the_silver_searcher&quot;&gt;ag&lt;/a&gt;, &lt;a href=&quot;https://github.com/junegunn/fzf&quot;&gt;fzf&lt;/a&gt;, &lt;a href=&quot;https://www.alfredapp.com/workflows/&quot;&gt;Alfred Workflows&lt;/a&gt; and &lt;a href=&quot;https://nuclide.io/docs/features/quick-open/#code-search&quot;&gt;Nuclide search&lt;/a&gt; are my best friends IRL. I try to be as descriptive as possible, even if that means a 40 character filename.&lt;/p&gt;
&lt;h4 id=&quot;heres-what-that-folder-structure-lookslike&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#heres-what-that-folder-structure-lookslike&quot; aria-label=&quot;heres what that folder structure lookslike permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Here’s what that folder structure looks like:&lt;/h4&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;/containers
/components
/utilities
/modals
/graphql
/queries
/mutations&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I typically like to keep my folder structure flat. I’m ok with nesting GraphQL because I’ve realized over time that I can figure out if something is a query or a mutation without appending &lt;code class=&quot;language-text&quot;&gt;mutation&lt;/code&gt; or &lt;code class=&quot;language-text&quot;&gt;query&lt;/code&gt; to the end of the file.&lt;/p&gt;
&lt;h4 id=&quot;naming-conventions&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#naming-conventions&quot; aria-label=&quot;naming conventions permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Naming Conventions:&lt;/h4&gt;
&lt;p&gt;Mutations will always start with an action:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;saveUserPushToken&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;updateOnboardingProfile&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;createUser&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Queries just describe what I’m looking for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;userProfile&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;userConnections&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;reminders&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Sometimes they’ll even look like this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;remindersWithNewFeatureOfSomeKind&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;userProfileWithUserSettings&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;userPrioritiesWithRemindersAtTheTop&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I don’t prefix them with anything because I already know they live under the &lt;code class=&quot;language-text&quot;&gt;queries&lt;/code&gt; folder no matter what I do. Besides, prefixing them with something like &lt;code class=&quot;language-text&quot;&gt;get&lt;/code&gt; may make it seem like an API action. Also, I tried it and didn’t like it.&lt;/p&gt;
&lt;h4 id=&quot;file-structure&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#file-structure&quot; aria-label=&quot;file structure permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;File Structure:&lt;/h4&gt;
&lt;p&gt;I don’t like to keep them in the same file either because I literally spend more time scrolling than I do typing! What does each file look like? The way you’d expect:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; gql &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;graphql-tag&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; updateUsername &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; gql&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
  mutation UpdateUsername($id: ID!, $username: String!) {
    updateUsername(id: $id, username: $username) {
      id
    }
  }
&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; updateUsername&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;updateUserProfile&lt;/code&gt; will have its own file too!&lt;/p&gt;
&lt;p&gt;This way no matter what, I can continue to move quickly, implement our new features from design and have an exact description of what each and every file is doing.&lt;/p&gt;
&lt;h3 id=&quot;final-thoughts&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#final-thoughts&quot; aria-label=&quot;final thoughts permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Final Thoughts&lt;/h3&gt;
&lt;p&gt;I’ve fallen in love with this setup for my queries and mutations. I’ve rewritten our mutations and queries ~50 times and haven’t like I’ve been going against the grain yet.&lt;/p&gt;
&lt;p&gt;That being said, this folder / file structure is not for everyone. Consult with your manager and co-worker and make sure that this folder structure is right for you.&lt;/p&gt;
&lt;p&gt;Side effects include yelling at me online so don’t yell at me!&lt;/p&gt;
&lt;p&gt;If you have a better way, I’m always open to new ideas: &lt;a href=&quot;https://www.twitter.com/peterpme&quot;&gt;Hit me up on Twitter&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Ciao!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Apollo Tote, Declarative Patterns and a Sneak Peek into Apollo 2.0]]></title><description><![CDATA[A guest post on the Apollo GraphQL Blog]]></description><link>https://peterp.me/articles/apollo-tote-declarative-patterns-sneak-peak-into-apollo2/</link><guid isPermaLink="false">https://peterp.me/articles/apollo-tote-declarative-patterns-sneak-peak-into-apollo2/</guid><dc:creator><![CDATA[Peter Piekarczyk]]></dc:creator><pubDate>Tue, 10 Oct 2017 18:32:18 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;https://cdn-images-1.medium.com/max/800/1*-iRwtXSSIuhyj80jS6Js_w.jpeg&quot; alt=&quot;Photo by Lee Campbell on Unsplash&quot;&gt;
Photo by &lt;a href=&quot;https://unsplash.com/photos/qNPESem_t4I?utm_source=unsplash&amp;#x26;utm_medium=referral&amp;#x26;utm_content=creditCopyText&quot;&gt;Lee Campbell&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/?utm_source=unsplash&amp;#x26;utm_medium=referral&amp;#x26;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;This is a guest post from&lt;/em&gt; &lt;a href=&quot;https://medium.com/u/cff8a83d5fc3&quot;&gt;&lt;em&gt;Peter Piekarczyk&lt;/em&gt;&lt;/a&gt;&lt;em&gt;, technical co-founder and Apollo / React Native guru at&lt;/em&gt; &lt;a href=&quot;https://www.orchard.ai/&quot;&gt;&lt;em&gt;Orchard.ai&lt;/em&gt;&lt;/a&gt;&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/peterpme/apollo-tote&quot;&gt;Apollo Tote&lt;/a&gt; is a declarative React component. Take what you’ve been doing inside your “smart” containers and apply it with JSX! It’s meant to be a simple helper library for your Apollo queries until declarative components are released in Apollo 2.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I created this because I don’t believe separate components and containers need to be applied everywhere. There are times where I’d prefer to see everything in one, succinct file.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I came up with the idea for Apollo Tote while working on &lt;a href=&quot;https://www.orchard.ai&quot;&gt;Orchard Ai&lt;/a&gt;. We’re utilizing &lt;a href=&quot;https://www.expo.io&quot;&gt;Expo&lt;/a&gt; and &lt;a href=&quot;https://apollodata.com&quot;&gt;Apollo&lt;/a&gt; to help you stay on top of your relationships &amp;#x26; network the same way you do about diet, health and fitness.&lt;/p&gt;
&lt;p&gt;At the very minimum, give it a query and a few render props:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;ApolloTote
 query&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;user { imageUrl }&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
 renderLoading&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Avatar&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Loading &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
 render&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Avatar imageUrl&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;user&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;imageUrl &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Note: Apollo Tote is not meant to be used everywhere. We only support queries for now. That being said, there are places where Apollo Tote shines!&lt;/p&gt;
&lt;h3 id=&quot;use-cases&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#use-cases&quot; aria-label=&quot;use cases permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Use Cases&lt;/h3&gt;
&lt;h4 id=&quot;logged-in--logged-out-authentication--authorization&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#logged-in--logged-out-authentication--authorization&quot; aria-label=&quot;logged in  logged out authentication  authorization permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Logged In / Logged Out (Authentication / Authorization)&lt;/h4&gt;
&lt;p&gt;Authentication &amp;#x26; Authorization have always been a drag, for whatever reason. You’ll save a user token in localStorage, but you start to realize there’s a few cases you need to handle:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A token exists but the user no longer does (this sounds so dark IRL)&lt;/li&gt;
&lt;li&gt;A token exists but has expired&lt;/li&gt;
&lt;li&gt;There is no token (this one’s easy!)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Apollo Tote Authorization &amp;#x26; Authentication Example&lt;/p&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;renderError, renderLoading, render&lt;/code&gt; are all Apollo-specific and map directly to { error, loading, data }.&lt;/p&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;test, handleFail, handlePass&lt;/code&gt; are additional helper methods you can use to test for something specific.&lt;/p&gt;
&lt;p&gt;In this case I’m testing for &lt;code class=&quot;language-text&quot;&gt;user.id&lt;/code&gt;, but you can use it for anything where you might use &lt;code class=&quot;language-text&quot;&gt;branch&lt;/code&gt; in Recompose: anything that needs to pass or fail.&lt;/p&gt;
&lt;p&gt;In this case, I’m dispatching &lt;code class=&quot;language-text&quot;&gt;LOG_IN / LOG_OUT&lt;/code&gt; with Redux, but feel free to use an event emitter or call a class method, etc.&lt;/p&gt;
&lt;h4 id=&quot;handling-loading--errorstates&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#handling-loading--errorstates&quot; aria-label=&quot;handling loading  errorstates permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Handling Loading / Error States&lt;/h4&gt;
&lt;p&gt;I like to load a different component when I’m handling error state. My favorite way of doing that is by exporting a &lt;code class=&quot;language-text&quot;&gt;Loading&lt;/code&gt; component. This way I don’t have to fk around with any of the styling to get the loading state I’d like. It just works!&lt;/p&gt;
&lt;p&gt;Apollo Tote makes that super easy for ya by giving you the &lt;code class=&quot;language-text&quot;&gt;renderLoading&lt;/code&gt; prop:&lt;/p&gt;
&lt;p&gt;Apollo Tote Loading State Example&lt;/p&gt;
&lt;h3 id=&quot;final-thoughts&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#final-thoughts&quot; aria-label=&quot;final thoughts permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Final Thoughts&lt;/h3&gt;
&lt;p&gt;Apollo Tote &amp;#x26; render props are a great option when it comes to working with a complex application structure. While Apollo Tote is around today, a version of it will appear in Apollo 2. I’ll keep the API as similar as I can so when its ready, all you’ll have to do is replace the import!&lt;/p&gt;
&lt;p&gt;This is an awesome opportunity for the community to help make Apollo 2’s declarative components an awesome experience.&lt;/p&gt;
&lt;p&gt;Shout-out to my friends &lt;a href=&quot;https://medium.com/u/93de0780c5e6&quot;&gt;Kye Hohenberger&lt;/a&gt; and &lt;a href=&quot;https://medium.com/u/e55117c5994d&quot;&gt;Kyle Shevlin&lt;/a&gt; for the feedback. It’s something I always appreciate!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Building High Performance Web Apps with Emotion and Next.js]]></title><description><![CDATA[How to use Emotion, one of the fastest CSS-in-JS libraries, with Next.js to ship performant server-rendered styles with an API similar to styled-components.]]></description><link>https://peterp.me/articles/building-high-perf-web-apps-with-emotion-and-nextjs/</link><guid isPermaLink="false">https://peterp.me/articles/building-high-perf-web-apps-with-emotion-and-nextjs/</guid><dc:creator><![CDATA[Peter Piekarczyk]]></dc:creator><pubDate>Wed, 07 Jun 2017 05:00:00 GMT</pubDate><content:encoded>&lt;p&gt;If you haven’t heard of Emotion yet, it’s one of the fastest CSS-in-JS libraries to date. Its API is similar to styled-components but delivers your stylesheets over 200x faster. If you don’t believe me, check out @tkh44’s article here or the benchmarks you can run on your own here.&lt;/p&gt;
&lt;p&gt;Under the hood, Emotion uses a babel plugin to parse your CSS and constructs style blocks from your components. It reads those blocks with PostCSS, manipulates them and writes template literals back with babel. It’s the reason why Emotion is so fast: it takes care of all the expensive operations like parsing nested rules and prefixes ahead of time.&lt;/p&gt;
&lt;p&gt;When you combine an awesome server-rendered experience like Next.js with Emotion, you get a high performant website right out of the box.&lt;/p&gt;
&lt;h4 id=&quot;installation&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#installation&quot; aria-label=&quot;installation permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Installation&lt;/h4&gt;
&lt;p&gt;The easiest way to get started is by using &lt;code class=&quot;language-text&quot;&gt;create-next-app&lt;/code&gt; to generate a brand new project.&lt;/p&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;create-next-app&lt;/code&gt; takes the same approach &lt;code class=&quot;language-text&quot;&gt;create-react-app&lt;/code&gt; does but it generates a Next.js project instead. It’ll install all the dependencies you need ahead of time and put together the base project.&lt;/p&gt;
&lt;p&gt;Run the following to get yourself started with Next.js and Emotion:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;yarn global add create-next-app&lt;/code&gt; or &lt;code class=&quot;language-text&quot;&gt;npm install -g create-next-app&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;create-next-app hackernews&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;cd hackernews&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;yarn add emotion&lt;/code&gt; or &lt;code class=&quot;language-text&quot;&gt;npm install —-save emotion&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;yarn&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#yarn&quot; aria-label=&quot;yarn permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Yarn&lt;/h4&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;yarn&lt;/code&gt; is an alternative package manager to &lt;code class=&quot;language-text&quot;&gt;npm&lt;/code&gt; that strives for high performance and security. You can read more about it at &lt;a href=&quot;%5Bhttps://yarnpkg.com%5D(https://yarnpkg.com)&quot;&gt;yarnpkg.com&lt;/a&gt; or get started with it right away by running &lt;code class=&quot;language-text&quot;&gt;brew update &amp;amp;&amp;amp; brew install yarn&lt;/code&gt; in your terminal.&lt;/p&gt;
&lt;h4 id=&quot;configuration&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#configuration&quot; aria-label=&quot;configuration permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Configuration&lt;/h4&gt;
&lt;p&gt;For Next.js and other server-rendered libraries, Emotion requires an additional step of adding an &lt;code class=&quot;language-text&quot;&gt;inline-mode&lt;/code&gt; configuration to your babelrc. If you were using &lt;code class=&quot;language-text&quot;&gt;create-react-app&lt;/code&gt; or a single page app with no server rendering, you could skip this step.&lt;/p&gt;
&lt;h4 id=&quot;extract-vs-inlinemode&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#extract-vs-inlinemode&quot; aria-label=&quot;extract vs inlinemode permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Extract vs. Inline Mode&lt;/h4&gt;
&lt;p&gt;Extract is how Emotion works out of the box. It’s the “high perf” setting if you’re not worried about IE11 or below and aren’t doing any server rendering. The reason why its faster is because it skips the prefixing step older browsers require.&lt;/p&gt;
&lt;p&gt;Inline Mode is the “safety net” setting that is just a smidge slower but supports every browser React does and supports server rendering. If you’re developing for a wide audience of people and browsers, this is the mode you want to go with.&lt;/p&gt;
&lt;h4 id=&quot;getting-started&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#getting-started&quot; aria-label=&quot;getting started permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Getting Started&lt;/h4&gt;
&lt;p&gt;Emotion supports almost every technique and API you’ve loved when it comes to CSS-in-JS libraries including raw CSS files. It makes porting your project over from virtually anything a breeze!&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; Avatar &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;styled&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;‘img’&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
 width: 100px;
 height: 100px;
&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h4 id=&quot;final-thoughts&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#final-thoughts&quot; aria-label=&quot;final thoughts permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Final Thoughts&lt;/h4&gt;
&lt;p&gt;I love Emotion because it supports a lot of the same features I was looking for when comparing different CSS-in-JSS libraries except offering incredible performance we all strive to achieve.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[9 Things I Wish I Knew When I Started Writing Code]]></title><description><![CDATA[I’ve been paying it forward for the last two years by teaching newer programmers how to craft their code. On an informal basis, I’ll guide…]]></description><link>https://peterp.me/articles/things-i-wish-i-knew-when-i-started-writing-code/</link><guid isPermaLink="false">https://peterp.me/articles/things-i-wish-i-knew-when-i-started-writing-code/</guid><dc:creator><![CDATA[Peter Piekarczyk]]></dc:creator><pubDate>Thu, 30 Mar 2017 17:49:12 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;https://cdn-images-1.medium.com/max/1200/1*YqJp40BS2gi9na6ExRrwjQ.jpeg&quot; alt=&quot;Photo by Kimon Maritz on unsplash.com&quot;&gt;
Photo by Kimon Maritz on unsplash.com&lt;/p&gt;
&lt;p&gt;I’ve been paying it forward for the last two years by teaching newer programmers how to craft their code. On an informal basis, I’ll guide a student through typical, real-world challenges: from thinking through the database structure to reading error messages.&lt;/p&gt;
&lt;p&gt;After doing this for a bit, I’ve noticed a common pattern beginners (including myself) face when they’re first starting out. Here are a few tips and tricks to help step up your game:&lt;/p&gt;
&lt;h4 id=&quot;1-read-every-line-ofcode&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#1-read-every-line-ofcode&quot; aria-label=&quot;1 read every line ofcode permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;1. Read every line of code&lt;/h4&gt;
&lt;p&gt;If you skim code the way you might skim articles (like this one), you might find yourself missing an important piece of the puzzle. You can’t play chess when you don’t see every piece. The same applies to reading code.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Every line, word and character counts!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Error messages become much less cryptic once you realize you may have misspelled a function or missed a parenthesis.&lt;/p&gt;
&lt;p&gt;Fixing that pressing bug will take less time because you’ll understand &lt;em&gt;exactly&lt;/em&gt; what is happening.&lt;/p&gt;
&lt;h4 id=&quot;2-focus-on-the-abstraction-after-you-understand-the-abstraction&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#2-focus-on-the-abstraction-after-you-understand-the-abstraction&quot; aria-label=&quot;2 focus on the abstraction after you understand the abstraction permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;2. Focus on the abstraction after you understand the abstraction&lt;/h4&gt;
&lt;p&gt;It’s easy to get ahead of yourself by abstracting out your codebase to a few functions. I suggest you hold off on any abstractions until you absolutely understand the need to.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Don’t worry about building a system that supports every use case you can think of right off the bat!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Build for one use case first. Then another, then another. The pattern will eventually stick out like a sore thumb and you’ll naturally come to the right abstraction.&lt;/p&gt;
&lt;h4 id=&quot;3-dont-repeat-yourself-doesnt-mean-you-need-to-re-use-everyfunction&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#3-dont-repeat-yourself-doesnt-mean-you-need-to-re-use-everyfunction&quot; aria-label=&quot;3 dont repeat yourself doesnt mean you need to re use everyfunction permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;3. “Don’t Repeat Yourself” doesn’t mean you need to re-use every function&lt;/h4&gt;
&lt;p&gt;Don’t Repeat Yourself is a phrase thrown around a lot in programming, but it doesn’t mean you should be throwing it around a lot in practice!&lt;/p&gt;
&lt;p&gt;DRY helps you isolate your changes and increase maintainability because you’re only editing a few things to make an impact.&lt;/p&gt;
&lt;p&gt;What I’ve noticed is that the DRY principles are being orchestrated on an entire codebase rather than a feature. So, if a site has two different tightly-coupled pages and one of the page layouts change, it also changes the layout of the first page which might not be intended.&lt;/p&gt;
&lt;p&gt;I suggest you identify the “core” (won’t change often) and “leaves” (constantly changing) and focus your DRY techniques on core.&lt;/p&gt;
&lt;p&gt;Just like with the previously mentioned abstractions, it will take some time and a few “oopsie” experiences to strike the right balance.&lt;/p&gt;
&lt;h4 id=&quot;4-if-you-dont-knowask&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#4-if-you-dont-knowask&quot; aria-label=&quot;4 if you dont knowask permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;4. If you don’t know, ask!&lt;/h4&gt;
&lt;p&gt;Ask as many questions as it takes for you to understand a problem or a piece of code. Don’t worry about feeling stupid or feeling like you should know the answer.&lt;/p&gt;
&lt;p&gt;No matter where you are in your career, you will never completely grasp an entire library, framework or function from the get-go.&lt;/p&gt;
&lt;p&gt;Take a look at open source for example. Everyone has different philosophies, coding styles and libraries they like to use. There’s an abundance of them and you’ll never &lt;em&gt;always&lt;/em&gt; know what every single piece is doing.&lt;/p&gt;
&lt;p&gt;At work, you might think you &lt;em&gt;should&lt;/em&gt; understand something so you spend an hour or two researching when you could have just tapped the engineer next to you for a quick explanation.&lt;/p&gt;
&lt;p&gt;Everyone is entitled to fully understanding the problem before coming up with a solution no matter the skill level.&lt;/p&gt;
&lt;h4 id=&quot;5-find-a-mentor-or-friend-you-can-go-to-forhelp&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#5-find-a-mentor-or-friend-you-can-go-to-forhelp&quot; aria-label=&quot;5 find a mentor or friend you can go to forhelp permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;5. Find a mentor or friend you can go to for help&lt;/h4&gt;
&lt;p&gt;I owe a lot of my skills to the folks that stuck with me over the years. I went through a lot of trial and error on my own growing up and that was a great experience. That being said, having someone throw you a bone and guiding you down a &lt;em&gt;better&lt;/em&gt; path is very valuable.&lt;/p&gt;
&lt;p&gt;Imagine trying to build something in Javascript and picking up a random set of tools. What you choose might be the right tool for the job, or it may not be. You &lt;em&gt;might&lt;/em&gt; spend months or even years working through the kinks only to realize there was a solution that fit your exact needs!&lt;/p&gt;
&lt;p&gt;A mentor can help you make those decisions up front.&lt;/p&gt;
&lt;h4 id=&quot;6-use-github-search-to-your-advantage&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#6-use-github-search-to-your-advantage&quot; aria-label=&quot;6 use github search to your advantage permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;6. Use Github Search to your advantage&lt;/h4&gt;
&lt;p&gt;My secret to writing code is spending a TON of time searching Github for the answer I’m looking for. Google and Stack Overflow are great but a lot of times the answer you’re looking for could be framework specific or out of date.&lt;/p&gt;
&lt;p&gt;For example, 90% of the answers (I made this % up) on Stack Overflow will give you a jQuery solution when you’re looking for a pure javascript one.&lt;/p&gt;
&lt;p&gt;Searching Github for “document.getElementsByClassName” for example, will give you a practical, up-to-date example. If you do your due diligence and make sure the code is being used or has been updated recently, you’ve just got a killer template to work from! Clone it, try it out on your own and see if what it’s doing matches what you’re looking for.&lt;/p&gt;
&lt;h4 id=&quot;7-boilerplates-can-be-atrap&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#7-boilerplates-can-be-atrap&quot; aria-label=&quot;7 boilerplates can be atrap permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;7. Boilerplates can be a trap!&lt;/h4&gt;
&lt;p&gt;Boilerplates have become popular over the years. They’re usually a set of utilities, patterns and opinions you can use to get started with your project.&lt;/p&gt;
&lt;p&gt;It’s easy to reach for one, but you may find yourself in a position where you’re not sure what is going on or how to fix it.&lt;/p&gt;
&lt;p&gt;Start with the basics first. Open up a scratch pad like codepen.io or jsfiddle.net and try and understand how something works. Not only will you have a better understanding of the framework, but there’s a good chance that through isolation you’ll learn fundamental parts of a language too.&lt;/p&gt;
&lt;h4 id=&quot;8-dont-worry-about-what-your-friends-aredoing&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#8-dont-worry-about-what-your-friends-aredoing&quot; aria-label=&quot;8 dont worry about what your friends aredoing permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;8. Don’t worry about what your friends are doing&lt;/h4&gt;
&lt;p&gt;Remember:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Everyone learns at their own pace&lt;/li&gt;
&lt;li&gt;Everyone has different interests in the programming realm&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Just because your friend is working on Artificial Intelligence, Machine Learning, Data Science or Web Development doesn’t mean that they’re better than you are. Those are all popular buzzwords that sound crazy but in reality are very approachable as long you just want to give it a shot!&lt;/p&gt;
&lt;p&gt;Sure, writing HTML is a lot easier than machine learning but I’d argue that Javascript and UI Development have equal non-trivial challenges.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Don’t focus on what other people are doing. Focus on yourself!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Even if they are better, you shouldn’t be discouraged. You’ve found yourself writing code because YOU like to write code. Keep it that way :)&lt;/p&gt;
&lt;h4 id=&quot;9-youre-a-gardener-not-anengineer&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#9-youre-a-gardener-not-anengineer&quot; aria-label=&quot;9 youre a gardener not anengineer permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;9. You’re a gardener, not an engineer&lt;/h4&gt;
&lt;p&gt;I don’t remember where this idea came from but I’m a huge fan of it.&lt;/p&gt;
&lt;p&gt;A civil engineer, for example will build a bridge and move on to his/her next project. There might be maintenance work that takes place every few years, but that’s most likely done by a different division.&lt;/p&gt;
&lt;p&gt;A gardener however, nurtures his/her plants over time. You water it on a weekly basis, trim leaves monthly and re-pot yearly.&lt;/p&gt;
&lt;p&gt;You can argue that growing plants outside defeats this analogy, but nurturing your plant will improve its chances of success in the wild!&lt;/p&gt;
&lt;p&gt;I call myself a gardener because I’m constantly maintaining my code. You should too :)&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn-images-1.medium.com/max/800/1*GM5_niBxMouNtsqxRgkBXg.jpeg&quot; alt=&quot;Succulents by Brooke Cagle from Unsp&quot;&gt;
Succulents by Brooke Cagle from Unsp&lt;/p&gt;</content:encoded></item><item><title><![CDATA[5 Vim Plugins I Can’t Live Without for Javascript Development]]></title><description><![CDATA[I’m constantly looking for ways I can improve my workflows and development environment.]]></description><link>https://peterp.me/articles/5-vim-plugins-i-cant-live-without-for-javascript-development/</link><guid isPermaLink="false">https://peterp.me/articles/5-vim-plugins-i-cant-live-without-for-javascript-development/</guid><dc:creator><![CDATA[Peter Piekarczyk]]></dc:creator><pubDate>Sun, 19 Mar 2017 20:11:04 GMT</pubDate><content:encoded>&lt;p&gt;I’m constantly looking for ways I can improve my workflows and development environment. Before I could even call myself a programmer, I was fascinated with making my terminal look cool, even if I didn’t exactly know how to use it yet! That’s stuck with me over the years and I’d love to share some of my recent favorites:&lt;/p&gt;
&lt;h4 id=&quot;1-prettieran-opinionated-javascript-formatter&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#1-prettieran-opinionated-javascript-formatter&quot; aria-label=&quot;1 prettieran opinionated javascript formatter permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;strong&gt;1. Prettier — An Opinionated Javascript Formatter&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;Prettier will automagically format your code so you don’t have to. Spend less time arguing styles with your peers so you can spend more time writing your app.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn-images-1.medium.com/max/800/1*vAggmzG1t1RpXK72ENQ6AA.gif&quot; alt=&quot;A random Javascript file I saved. See how it automatically formatted it for me?&quot;&gt;
A random Javascript file I saved. See how it automatically formatted it for me?&lt;/p&gt;
&lt;p&gt;Installation for NeoVim and Vim is very straight forward:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Install via npm &lt;code class=&quot;language-text&quot;&gt;npm install -g prettier&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Or Yarn (recommended) &lt;code class=&quot;language-text&quot;&gt;yarn global add prettier&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Add the following to your init.vim or vimrc file: 
&lt;code class=&quot;language-text&quot;&gt;autocmd FileType javascript set formatprg=prettier --stdin&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;If you want to format on save:
&lt;code class=&quot;language-text&quot;&gt;autocmd BufWritePre *.js :normal gggqG&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;If you want to restore cursor position on save (can be buggy): 
&lt;code class=&quot;language-text&quot;&gt;autocmd BufWritePre *.js exe &quot;normal! gggqG&amp;lt;C-o&gt;&amp;lt;C-o&gt;&quot;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;**Why I personally like this:
**I’m no longer worried about making sure I’ve got the right formatting in place. I’m getting used to letting the computer control my source code so I can optimize time spent on app-related changes instead.&lt;/p&gt;
&lt;p&gt;See more at &lt;a href=&quot;https://github.com/prettier/prettier&quot;&gt;https://github.com/prettier/prettier&lt;/a&gt;&lt;/p&gt;
&lt;h4 id=&quot;2-nrrwrgnnarrow-regionplugin&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#2-nrrwrgnnarrow-regionplugin&quot; aria-label=&quot;2 nrrwrgnnarrow regionplugin permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;strong&gt;2. NrrwRgn — Narrow Region Plugin&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;Select a part of your code and open it in a new buffer! When you’re ready to go back to the original file, just save it and your isolated changes appear instantly!&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn-images-1.medium.com/max/800/1*edlKjVNbcY8nEi6t7IYSdQ.gif&quot; alt=&quot;Someone accidently made this FRIEND instead of USER. I loaded it up with NR, made the changes I wanted to make and brought them back to the original file!&quot;&gt;
Someone accidently made this FRIEND instead of USER. I loaded it up with NR, made the changes I wanted to make and brought them back to the original file!&lt;/p&gt;
&lt;p&gt;Install using the Plugin Manager of your choice. I like Vim Plug.&lt;/p&gt;
&lt;p&gt;Plug ‘chrisbra/NrrwRgn’&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The commands I use most often:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;:NR - open selection in a new window
:NW - open current visuaul window in a new window
:NRP - mark a selection so you can open multiple parts of a file
:NRM - after using NRP, run this so you can open those parts!
&lt;a href=&quot;https://github.com/wesQ3/vim-windowswap&quot;&gt;https://github.com/wesQ3/vim-windowswap&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;**Why I personally like this:
**Sometimes I can get frustrated working with very large files. I like to focus on one part of that if I can. It’s easier on the eyes to see 5–15 lines instead of 150.&lt;/p&gt;
&lt;p&gt;See more at &lt;a href=&quot;https://github.com/chrisbra/NrrwRgn&quot;&gt;https://github.com/chrisbra/NrrwRgn&lt;/a&gt;&lt;/p&gt;
&lt;h4 id=&quot;3-windowswapeasily-swap-windowpanes&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#3-windowswapeasily-swap-windowpanes&quot; aria-label=&quot;3 windowswapeasily swap windowpanes permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;3. WindowSwap — Easily Swap Window Panes&lt;/h4&gt;
&lt;p&gt;By pressing &lt;code class=&quot;language-text&quot;&gt;&amp;lt;leader&gt;ww&lt;/code&gt; you can swap windows around your screen without having to redo your layout.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn-images-1.medium.com/max/800/1*2TA_MurarkjxmbQ3E2bXEw.gif&quot; alt=&quot;See how I swapped the two windows in this simple example?&quot;&gt;
See how I swapped the two windows in this simple example?&lt;/p&gt;
&lt;p&gt;Install using the Plugin Manager of your choice. I like Vim Plug.&lt;/p&gt;
&lt;p&gt;Plug ’&lt;a href=&quot;https://github.com/wesQ3/vim-windowswap&quot;&gt;https://github.com/wesQ3/vim-windowswap&lt;/a&gt;’&lt;/p&gt;
&lt;p&gt;**Why I personally like this:
**When my ADD is in overdrive, I’ve got like 15 panes open. Sometimes I want to move stuff around without having to close it out and re-open it. This allows me to do just that.&lt;/p&gt;
&lt;p&gt;See more at &lt;a href=&quot;https://github.com/wesQ3/vim-windowswap&quot;&gt;https://github.com/wesQ3/vim-windowswap&lt;/a&gt;&lt;/p&gt;
&lt;h4 id=&quot;4-aleasynchronous-lintengine&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#4-aleasynchronous-lintengine&quot; aria-label=&quot;4 aleasynchronous lintengine permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;4. ALE — Asynchronous Lint Engine&lt;/h4&gt;
&lt;p&gt;A linting plugin for Neovim and Vim 8. This will automatically hook into your linter’s configuration and show you errors in the gutter!&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn-images-1.medium.com/max/800/1*4MBJPbgv3IBN6zPvfZpyLw.gif&quot; alt=&quot;I took a project I did before using Prettier. Saved it. Whoah! See all that red on the left hand side? That’s Ale doing its magic! You’ll also get the rule instructions at the bottom of the window so you know exactly what to change!&quot;&gt;
I took a project I did before using Prettier. Saved it. Whoah! See all that red on the left hand side? That’s Ale doing its magic! You’ll also get the rule instructions at the bottom of the window so you know exactly what to change!&lt;/p&gt;
&lt;p&gt;Install using the Plugin Manager of your choice. I like Vim Plug.&lt;/p&gt;
&lt;p&gt;Plug ‘w0rp/ale’&lt;/p&gt;
&lt;p&gt;**Why I personally like this:
**Prettier handles your source code styling, but there’s still a lot eslint can do for you! Stuff like accessibility and removing unused modules and vars should still handled by eslint. Pair with a library like &lt;a href=&quot;https://github.com/prettier/prettier-eslint&quot;&gt;prettier-eslint&lt;/a&gt; by &lt;a href=&quot;https://medium.com/u/db72389e89d8&quot;&gt;Kent C. Dodds&lt;/a&gt; &amp;#x26; friends makes this an awesome part of your workflow!&lt;/p&gt;
&lt;p&gt;See more at &lt;a href=&quot;https://github.com/w0rp/ale&quot;&gt;https://github.com/w0rp/ale&lt;/a&gt;&lt;/p&gt;
&lt;h4 id=&quot;5-deopleteauto-completion-framework&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#5-deopleteauto-completion-framework&quot; aria-label=&quot;5 deopleteauto completion framework permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;5. Deoplete — Auto Completion Framework&lt;/h4&gt;
&lt;p&gt;This will add an autocomplete dropdown for your files. It works asynchronously. You &lt;em&gt;will&lt;/em&gt; need Neovim and Python 3 installed for this to work.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn-images-1.medium.com/max/800/1*fE_2XywJM9EcfK6eXgTT-g.gif&quot; alt=&quot;Look! Autocomplete!&quot;&gt;
Look! Autocomplete!&lt;/p&gt;
&lt;p&gt;Vim Plug Installation:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;sh&quot;&gt;&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;Plug &lt;span class=&quot;token string&quot;&gt;&apos;Shougo/deoplete.nvim&apos;&lt;/span&gt;, &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;do&apos;&lt;/span&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;:UpdateRemotePlugins&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Before continuing with the next steps, verify that you need to. Open up Neovim and run &lt;code class=&quot;language-text&quot;&gt;:echo has(&quot;python3&quot;)&lt;/code&gt; If the return value is 1, you don’t have to do anything else! Otherwise, keep following along:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;sh&quot;&gt;&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;pip3 &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; neovim
pip3 &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--upgrade&lt;/span&gt; neovim &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0.1&lt;/span&gt;.8 is required&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Add the following to your Neovim init.vim file:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;sh&quot;&gt;&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;let&lt;/span&gt; g:deoplete&lt;span class=&quot;token comment&quot;&gt;#enable_at_startup = 1&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;See more at &lt;a href=&quot;https://github.com/Shougo/deoplete.nvim&quot;&gt;https://github.com/Shougo/deoplete.nvim&lt;/a&gt;&lt;/p&gt;
&lt;h4 id=&quot;bonus-55flow-autocompletion-withdeoplete&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#bonus-55flow-autocompletion-withdeoplete&quot; aria-label=&quot;bonus 55flow autocompletion withdeoplete permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Bonus 5.5 — Flow Autocompletion with Deoplete&lt;/h4&gt;
&lt;p&gt;Love flow-type and wish you could use autocompletion? &lt;a href=&quot;https://twitter.com/wokalski&quot;&gt;Wojtek Czekalski&lt;/a&gt; &lt;em&gt;just&lt;/em&gt; created an awesome library to make it happen!&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;sh&quot;&gt;&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot; Place deoplete first, then autocomplete-flow
Plug &apos;Shougo/deoplete.nvim&apos;, { &apos;do&apos;: &apos;:UpdateRemotePlugins&apos; }
Plug &apos;wokalski/autocomplete-flow&apos;

&quot;&lt;/span&gt; You will also need the following &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; argument completion:
Plug &lt;span class=&quot;token string&quot;&gt;&apos;Shougo/neosnippet&apos;&lt;/span&gt;
Plug &lt;span class=&quot;token string&quot;&gt;&apos;Shougo/neosnippet-snippets&apos;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;See more at &lt;a href=&quot;https://github.com/wokalski/autocomplete-flow&quot;&gt;https://github.com/wokalski/autocomplete-flow&lt;/a&gt;&lt;/p&gt;
&lt;h4 id=&quot;closing-thoughts&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#closing-thoughts&quot; aria-label=&quot;closing thoughts permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Closing Thoughts&lt;/h4&gt;
&lt;p&gt;Like I said, I’m constantly looking for ways to improve my own flows. Is there something I’m missing? Would you love to learn more?&lt;/p&gt;
&lt;p&gt;Feel free to &lt;a href=&quot;https://twitter.com/peterpme&quot;&gt;tweet me&lt;/a&gt; or &lt;a href=&quot;https://github.com/peterpme/dotfiles/blob/master/config/nvim/init.vim&quot;&gt;check out ALL my Vim plugins here.&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Speeding up Git with SSH Config]]></title><description><![CDATA[A simple SSH config trick borrowed from Paul Irish's dotfiles that noticeably speeds up Git operations over SSH connections.]]></description><link>https://peterp.me/articles/speed-up-your-ssh-with-this-one-weird-trick/</link><guid isPermaLink="false">https://peterp.me/articles/speed-up-your-ssh-with-this-one-weird-trick/</guid><dc:creator><![CDATA[Peter Piekarczyk]]></dc:creator><pubDate>Fri, 11 Nov 2016 17:09:37 GMT</pubDate><content:encoded>&lt;p&gt;I’ve been snooping around &lt;a href=&quot;https://medium.com/u/6d5456230083&quot;&gt;Paul Irish&lt;/a&gt;’s dotfiles and discovered this gem.
I instantly noticed the difference and absolutely needed to share this with the rest of the world!&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;sh&quot;&gt;&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# copy to ~/.ssh/config&lt;/span&gt;

Host github.com
	ControlMaster auto
	ControlPersist &lt;span class=&quot;token number&quot;&gt;120&lt;/span&gt;

Host *
	&lt;span class=&quot;token comment&quot;&gt;# Always use SSH2.&lt;/span&gt;
	Protocol &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;

	&lt;span class=&quot;token comment&quot;&gt;# Use a shared channel for all sessions to the same host,&lt;/span&gt;
	&lt;span class=&quot;token comment&quot;&gt;# instead of always opening a new one. This leads to much&lt;/span&gt;
	&lt;span class=&quot;token comment&quot;&gt;# quicker connection times.&lt;/span&gt;
	ControlMaster auto
	ControlPath ~/.ssh/control/%r@%h:%p
	ControlPersist &lt;span class=&quot;token number&quot;&gt;1800&lt;/span&gt;

	&lt;span class=&quot;token comment&quot;&gt;# also this stuff&lt;/span&gt;
	Compression &lt;span class=&quot;token function&quot;&gt;yes&lt;/span&gt;
	TCPKeepAlive &lt;span class=&quot;token function&quot;&gt;yes&lt;/span&gt;
	ServerAliveInterval &lt;span class=&quot;token number&quot;&gt;20&lt;/span&gt;
	ServerAliveCountMax &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href=&quot;https://serversforhackers.com/video/using-the-ssh-config-file&quot; title=&quot;https://serversforhackers.com/video/using-the-ssh-config-file&quot;&gt;Learn more by watching this video on SSH&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Save 20px by Going Frameless and Getting Rid of Atom’s Title Bar]]></title><description><![CDATA[That's an extra line of code in your editor!]]></description><link>https://peterp.me/articles/going-frameless-in-atom-by-getting-rid-of-titlebar/</link><guid isPermaLink="false">https://peterp.me/articles/going-frameless-in-atom-by-getting-rid-of-titlebar/</guid><dc:creator><![CDATA[Peter Piekarczyk]]></dc:creator><pubDate>Sat, 29 Oct 2016 21:15:42 GMT</pubDate><content:encoded>&lt;p&gt;Being a fan of keyboard shortcuts, I have never been a fan of macOS’ Title Bar.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Close&lt;/li&gt;
&lt;li&gt;Minimize&lt;/li&gt;
&lt;li&gt;Full Screen&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You know the bar I’m talking about. Most of the time, it’s not worth the real estate.&lt;/p&gt;
&lt;p&gt;I scoured Github Issues and PR’s until I found exactly what I was looking for: &lt;a href=&quot;https://github.com/atom/atom/issues/4599#issuecomment-246213477&quot;&gt;A recipe&lt;/a&gt;, thanks to the man by the name of &lt;a href=&quot;https://github.com/deeperx&quot;&gt;deeperx on Github&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;sh&quot;&gt;&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# quit Atom&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-g&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; asar
asar e /Applications/Atom.app/Contents/Resources/app.asar /tmp/atomasar

&lt;span class=&quot;token comment&quot;&gt;# 1. Edit src/main-window/atom-window.js &amp;amp; add:&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;#   frame: false&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# 2. After the line&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;#   title: &apos;Atom&apos;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# 3. Save&lt;/span&gt;

asar p /tmp/atomasar /Applications/Atom.app/Contents/Resources/app.asar
&lt;span class=&quot;token function&quot;&gt;rm&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-rf&lt;/span&gt; /tmp/atomasar&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn-images-1.medium.com/max/800/1*K-bqRArMonf9nsm1jubahw.png&quot; alt=&quot;See! No Title Bar!&quot;&gt;
No Title Bar!&lt;/p&gt;
&lt;h4 id=&quot;keep-in-mind&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#keep-in-mind&quot; aria-label=&quot;keep in mind permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Keep in mind!&lt;/h4&gt;
&lt;p&gt;When you do this, moving your window around with a mouse will be virtually impossible, make sure you use some window management software!&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/atom/atom/issues/4599#issuecomment-246213477&quot;&gt;View the issue on Github&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[React Router Authentication]]></title><description><![CDATA[An easy way to route based on a logged in user]]></description><link>https://peterp.me/articles/react-router-authentication-help/</link><guid isPermaLink="false">https://peterp.me/articles/react-router-authentication-help/</guid><dc:creator><![CDATA[Peter Piekarczyk]]></dc:creator><pubDate>Thu, 28 Jul 2016 22:03:12 GMT</pubDate><content:encoded>&lt;p&gt;I was looking through the &lt;a href=&quot;https://github.com/davezuko/react-redux-starter-kit/issues/906&quot;&gt;issues of a popular boilerplate&lt;/a&gt; today and there was a question about how folks would handle authentication with this new style of creating routes (&lt;a href=&quot;https://github.com/reactjs/react-router/blob/master/docs/API.md#plainroute&quot;&gt;PlainRoute&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Here’s what you need to know:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;requireAuth&lt;/code&gt; is a &lt;a href=&quot;https://github.com/reactjs/react-router/blob/master/docs/API.md#onenternextstate-replace-callback&quot;&gt;React Router&lt;/a&gt; function. It takes 3 arguments: nextState, replace, callback&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;replace&lt;/strong&gt; is all we’re after, but you have the ability to do more if you choose to&lt;/li&gt;
&lt;li&gt;within &lt;code class=&quot;language-text&quot;&gt;requireAuth&lt;/code&gt;, invoke whatever technique you’re using to identify a user or a token&lt;/li&gt;
&lt;li&gt;If a token exists, carry on&lt;/li&gt;
&lt;li&gt;If a token does not exist, replace history with an unauthenticated route&lt;/li&gt;
&lt;li&gt;If you decide to use a callback, the transition will be blocked until &lt;code class=&quot;language-text&quot;&gt;callback&lt;/code&gt; is called (in the docs)&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;requireAuth&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;nextState&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; replace&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; callback&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; token &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; localStorage&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getItem&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;@TOKEN&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;token&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;replace&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;/&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;callback&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;createRoutes&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;store&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;/&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;childRoutes&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;// Authenticated&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token literal-property property&quot;&gt;component&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; CoreLayout&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
 &lt;span class=&quot;token operator&quot;&gt;**&lt;/span&gt;onEnter&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; requireAuth&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// add this**&lt;/span&gt;
      &lt;span class=&quot;token literal-property property&quot;&gt;indexRoute&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Dashboard&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token literal-property property&quot;&gt;childRoutes&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;ProfileRoute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;store&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        BillingRoute
      &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;// Not-authenticated&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token literal-property property&quot;&gt;component&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ModalLayout&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token literal-property property&quot;&gt;childRoutes&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
        LoginRoute
      &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;// Other Not-authenticated routes&lt;/span&gt;
    HelpRoute&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    ContactRoute
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If you have any issues, &lt;a href=&quot;http://twitter.com/peterpme&quot;&gt;hit me up&lt;/a&gt;!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Quickly Preview iTerm2 Themes Without Having to Import Them First]]></title><description><![CDATA[Faster access to themes]]></description><link>https://peterp.me/articles/quickly-preview-iterm2-themes-without-importing-them/</link><guid isPermaLink="false">https://peterp.me/articles/quickly-preview-iterm2-themes-without-importing-them/</guid><dc:creator><![CDATA[Peter Piekarczyk]]></dc:creator><pubDate>Thu, 07 Jul 2016 14:58:03 GMT</pubDate><content:encoded>&lt;p&gt;I was perusing &lt;a href=&quot;https://github.com/mbadolato/iTerm2-Color-Schemes#previewing-color-schemes&quot;&gt;https://github.com/mbadolato/iTerm2-Color-Schemes#previewing-color-schemes&lt;/a&gt; when all the way at the bottom, I noticed a simple tool that lets you preview themes without having to import them first!&lt;/p&gt;
&lt;p&gt;From within the iTerm2-Color-Schemes directory, type one of the following:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Apply AdventureTime scheme to the current session&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;sh&quot;&gt;&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;tools/preview.rb schemes/AdventureTime.itermcolors&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Apply the schemes in turn.&lt;/li&gt;
&lt;li&gt;Press any key to advance; hit CTRL-C or ESC to stop&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&quot;preview-all-the-themes-at-the-same-time&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#preview-all-the-themes-at-the-same-time&quot; aria-label=&quot;preview all the themes at the same time permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Preview all the themes at the same time:&lt;/h4&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;sh&quot;&gt;&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;tools/preview.rb schemes/*&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;img src=&quot;/994f1319d9ffe04cbfc1abd6adef0281/iterm-themes-preview.gif&quot; alt=&quot;Theme Preview 🔥&quot;&gt;
Theme Preview 🔥&lt;/p&gt;
&lt;p&gt;I’ve been using this library for years never scrolling down far enough. Hopefully I’m not the only one who hasn’t done that 😂&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Thoughts on Becoming a Better Developer]]></title><description><![CDATA[Reflections on what separates truly great engineers — deliberate practice, deep thinking before coding, and lessons from watching world-class developers work.]]></description><link>https://peterp.me/articles/thoughts-on-becoming-a-better-developer/</link><guid isPermaLink="false">https://peterp.me/articles/thoughts-on-becoming-a-better-developer/</guid><dc:creator><![CDATA[Peter Piekarczyk]]></dc:creator><pubDate>Sun, 12 Jun 2016 05:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I’ve been thinking a lot about how I can improve my productivity as a technical startup founder. “Work smart, not hard” is a constant, subconscious whisper. How often do I actually practice that idea? What does that even mean? Where do I draw the line between thinking &lt;em&gt;too&lt;/em&gt; much or &lt;em&gt;too&lt;/em&gt; little?&lt;/p&gt;
&lt;p&gt;I’ve always wanted to play ball at the same level Facebook employees do. People like &lt;a href=&quot;https://github.com/gaearon&quot;&gt;Dan Abramov&lt;/a&gt;, &lt;a href=&quot;https://github.com/acdlite&quot;&gt;Andrew Clark&lt;/a&gt; and &lt;a href=&quot;https://github.com/leebyron&quot;&gt;Lee Byron&lt;/a&gt; don’t just sit down and start writing code.&lt;/p&gt;
&lt;p&gt;They identify a problem, think through it, brainstorm a few solutions and some implementation ideas for the solutions before writing any serious code. The evidence is &lt;a href=&quot;https://code.facebook.com/posts/1691455094417024/graphql-a-data-query-language/&quot;&gt;everywhere&lt;/a&gt;. Every article starts with some form of “this was a problem and this is how we fixed it”.&lt;/p&gt;
&lt;p&gt;I see them as the professional athletes of our world. Their stadium is Github. Their playing fields are Issues &amp;#x26; Pull Requests. The bulk of the decision-making process happens right in front of you. You don’t need to wait for an announcement, just &lt;a href=&quot;https://github.com/facebook/react/pull/12237&quot;&gt;follow the pull requests&lt;/a&gt;. You can experience fumbles, touchdowns and the &lt;a href=&quot;https://github.com/facebook/react/releases/tag/v16.0.0&quot;&gt;superbowl&lt;/a&gt;. Remember &lt;a href=&quot;http://isfiberreadyyet.com/&quot;&gt;IsFiberReadyYet&lt;/a&gt;?&lt;/p&gt;
&lt;p&gt;I’ve clearly drank the Facebook Koolaid, but these athletes exist outside the Facebook ecosystem as well. They play for &lt;a href=&quot;https://github.com/STALTZ&quot;&gt;themselves&lt;/a&gt;, &lt;a href=&quot;https://github.com/developit&quot;&gt;big&lt;/a&gt; and &lt;a href=&quot;https://github.com/bahmutov&quot;&gt;small companies all over the world&lt;/a&gt;. &lt;/p&gt;
&lt;p&gt;Being able to watch the people at the highest level practice &amp;#x26; play is truly an exciting time in our lives.&lt;/p&gt;
&lt;p&gt;So now what’s stopping me from becoming a professional athlete?&lt;/p&gt;
&lt;h2 id=&quot;work-smart&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#work-smart&quot; aria-label=&quot;work smart permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Work Smart&lt;/h2&gt;
&lt;p&gt;Civil engineers don’t show up at the job site and start digging. They research, plan and review for &lt;em&gt;months&lt;/em&gt; before getting the stamp of approval to start digging. &lt;/p&gt;
&lt;p&gt;Unlike civil engineers, we’ve been equally blessed and cursed with the privilege of writing code anytime, anywhere. There’s nothing stopping us from showing up at our own job site and digging to our heart’s content.&lt;/p&gt;
&lt;p&gt;But what are we building and what are we digging up? This is where I should &lt;strong&gt;work smart:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Am I solving a problem?&lt;/li&gt;
&lt;li&gt;Is this going to actually add value to my life?&lt;/li&gt;
&lt;li&gt;I’m not actually doing this for the tweets, am I?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It’s so tempting to sit down and start writing but you may find yourself taking 3 steps back sooner than you think! How will I interact with this function?&lt;/p&gt;
&lt;p&gt;I think the best people in our industry are the ones that can think through a problem and solution before writing any code**.&lt;/p&gt;
&lt;p&gt;It’s tempting to sit down and open up Atom and jumping right in but how often do you go 3 steps back just because you didn’t spend 5 minutes thinking through the data flow?&lt;/p&gt;
&lt;h2 id=&quot;work-hard&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#work-hard&quot; aria-label=&quot;work hard permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Work Hard&lt;/h2&gt;
&lt;p&gt;Give it hell. Be the best person you can be, whatever that means for you.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[React Native Android & Custom Fonts Checklist]]></title><description><![CDATA[A checklist to make fonts easier to manage]]></description><link>https://peterp.me/articles/custom-fonts-checklist-for-react-native-android/</link><guid isPermaLink="false">https://peterp.me/articles/custom-fonts-checklist-for-react-native-android/</guid><dc:creator><![CDATA[Peter Piekarczyk]]></dc:creator><pubDate>Fri, 10 Jun 2016 23:13:58 GMT</pubDate><content:encoded>&lt;p&gt;Here are a few things to remember:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;file type needs to be &lt;code class=&quot;language-text&quot;&gt;ttf&lt;/code&gt; NOT OTF!&lt;/li&gt;
&lt;li&gt;Create &lt;code class=&quot;language-text&quot;&gt;assets/fonts&lt;/code&gt; if it doesn’t exist (mkdir -p assets/fonts)&lt;/li&gt;
&lt;li&gt;place the font files within &lt;code class=&quot;language-text&quot;&gt;./android/app/src/main/assets/fonts/FONT_NAME.ttf&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Recompile. &lt;code class=&quot;language-text&quot;&gt;react-native run-android&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;fontFamily: FONT_NAME (1:1)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Viola!&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title><![CDATA[Operator Mono & Fira Code — The Best of Both Worlds]]></title><description><![CDATA[Making your terminal editor font beautiful]]></description><link>https://peterp.me/articles/operator-mono-fira-code-the-best-of-both-worlds/</link><guid isPermaLink="false">https://peterp.me/articles/operator-mono-fira-code-the-best-of-both-worlds/</guid><dc:creator><![CDATA[Peter Piekarczyk]]></dc:creator><pubDate>Thu, 09 Jun 2016 17:50:59 GMT</pubDate><content:encoded>&lt;p&gt;If Operator Mono and Fira Code spent a lot of time together and had a baby, you’d get something that looks like this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn-images-1.medium.com/max/800/1*hE_nLB776KUDXPERE_3cXw.png&quot; alt=&quot;Ligatures &amp;#x26; italics working in harmony. See the !== and the arrow function?&quot;&gt;
Ligatures &amp;#x26; italics working in harmony. See the !== and the arrow function?&lt;/p&gt;
&lt;p&gt;Operator Mono is cool and all, but quite frankly after seeing Fira Code’s ligatures, I had a tough time choosing between the two. So I made them work together.&lt;/p&gt;
&lt;p&gt;If you’re not sure what I’m talking about, check out the graphic below. Yes, it’s frickin’ sweet.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 500px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/371c4a6e637c103318d3b926f498f5cf/70bfa/fira-code-ligatures.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 201.6%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAoCAIAAABxU02MAAAACXBIWXMAAAsTAAALEwEAmpwYAAADsklEQVR42o1V226rOhDt/39Wq6pvfaiUNEmDEy4G29gY8B0bcrQzOtlpmrZ7PSCDvZiL18w8nO7BWjtN0+l0CiF476214zh+PfZw8z5NUwiBMTYMQ9u2fd8TQjDGlNKv/L/kZVlOp5MxRkophFBKbTYbznmWZQihcRyPxyOc+USGT/MZyxVg6+YVztxabtt2GAattRACghzHEdZCCOccrDHGIQT40R8ypVQIMQwDhJplWYzxdDqN44gxds5JKfu+Z4xZayml3nuMsdb6AZI0z7OUsqoqY0xd1yEEpdQ8z+mMruuMMYyxcRzzPA8hxBjnef7rdowxhCClzPPcGEMpnaZJShlCaNtWa80Y896HEO7EfPlFSmlZFvD8eh1jvJNtwDzPfd9ba7XW0zR5751z3vuUkj3Dez8Mg1LqDjmlJIQwxgzDYIwpy1IIQSmFtdbaGNN13TAM3yrs4kXXdVrrS+R3j30iX0vCOQfOxxi999e731qGPe/9drsty3K9XgshdrvdZeunwriUB6W06zrQkxDid7evyWVZtm2LELLWEkL+NWZIWPwfoLOvAd8hg5gIIdZaKWWMUZwBqoa0f6sw55y1tmmarusYYzFGjDGsjTEgtfuW/RnQCaZp2mw2QgittVIKxDfP8x0yeFLX9fF4lFJ2Z7y9vWGMvfdSSkJIVVXQ2O5bvtxN3/d1XQ/DMI5j27bW2qIoKKU/Jezai5vkQ8Kv6/EOmRDS9/3xeARteO+bptFac86dc1VVpZS+Jed5rpRarVZKqdfXV4zx8/Mzxni73dZ1/fT0dJ3wWzJjTEpZlmWM0VqbUhrHEZ7W2vf3d2vtt2RjjHNOKeW9Z4w558qyVEoRQowxCKGfLF9kCApdlgXaY0ppnudfEga9SmudUoKWCP4rpeq6vinMO/Lsug4GQNd14zjChTdNU1WVEOIncgjBOVcURdu22+2WMYYQyrKMc26tZYz9IpK+7zebDULo5eXl4+NjtVo9Pj5yzlNKzrlfYoZ6qKqqrmt+BmOMUso53+/3MKg+TcmbWl++ALrC/cK4XA88b8btZX1bksuy1HV9OBwgnxjj9XrNOUcI5XnOOe/7HkpKSlkUxbXxh3meCSFlWRJCmqbBGGdZxhjL8xxjLKUchqGqKhiRVVVdG/9DZowBmVKKMd7tdpzzoiiqqoKSbpqGMaa1xhjfksuy3O/3xRl5nq/Xa0LIbrc7HA7gLUIIRhdC6FNJLsuilAILSimtNYxyeIXhCN+hYK7v+T8QGwWDrilSbgAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source
              srcset=&quot;/static/371c4a6e637c103318d3b926f498f5cf/ecc44/fira-code-ligatures.webp 125w,
/static/371c4a6e637c103318d3b926f498f5cf/0e2a5/fira-code-ligatures.webp 250w,
/static/371c4a6e637c103318d3b926f498f5cf/10636/fira-code-ligatures.webp 500w,
/static/371c4a6e637c103318d3b926f498f5cf/24503/fira-code-ligatures.webp 632w&quot;
              sizes=&quot;(max-width: 500px) 100vw, 500px&quot;
              type=&quot;image/webp&quot;
            /&gt;
          &lt;source
            srcset=&quot;/static/371c4a6e637c103318d3b926f498f5cf/57f79/fira-code-ligatures.png 125w,
/static/371c4a6e637c103318d3b926f498f5cf/3e256/fira-code-ligatures.png 250w,
/static/371c4a6e637c103318d3b926f498f5cf/b30f8/fira-code-ligatures.png 500w,
/static/371c4a6e637c103318d3b926f498f5cf/70bfa/fira-code-ligatures.png 632w&quot;
            sizes=&quot;(max-width: 500px) 100vw, 500px&quot;
            type=&quot;image/png&quot;
          /&gt;
          &lt;img
            class=&quot;gatsby-resp-image-image&quot;
            src=&quot;/static/371c4a6e637c103318d3b926f498f5cf/b30f8/fira-code-ligatures.png&quot;
            alt=&quot;Fira Code Ligatures&quot;
            title=&quot;&quot;
            loading=&quot;lazy&quot;
            decoding=&quot;async&quot;
            style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
          /&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;All you have to do to get this working is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/tonsky/FiraCode#download-fira-code-v1102--follow-updates--firacode&quot;&gt;Download Fira Code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.typography.com/blog/introducing-operator&quot;&gt;Purchase &amp;#x26; Download Operator Mono (get your co to buy it)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Delete the “fonts” package if you’re using it. AFAIK it’ll screw things up.&lt;/li&gt;
&lt;li&gt;Open up Atom’s stylesheet and paste below. (Atom -&gt; Stylesheet)&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title><![CDATA[Implicit imports in Webpack using ProvidePlugin]]></title><description><![CDATA[Get rid of commonly used import statements]]></description><link>https://peterp.me/articles/implicit-imports-in-webpack-with-provideplugin/</link><guid isPermaLink="false">https://peterp.me/articles/implicit-imports-in-webpack-with-provideplugin/</guid><dc:creator><![CDATA[Peter Piekarczyk]]></dc:creator><pubDate>Tue, 19 Apr 2016 18:01:28 GMT</pubDate><content:encoded>&lt;p&gt;Do you find yourself writing this in every single one of your files?&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; React from ‘react&apos;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Remember how you used the &lt;code class=&quot;language-text&quot;&gt;ProvidePlugin&lt;/code&gt; to replace &lt;code class=&quot;language-text&quot;&gt;Promise&lt;/code&gt; globally in your app?&lt;/p&gt;
&lt;p&gt;We can use that same approach for stuff we’re using everywhere else too.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// webpack.config.js&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;webpack&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ProvidePlugin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;React&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ‘react’&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;Promise&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ‘bluebird’&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;cx&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;classnames&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;get&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;lodash.get&apos;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now, I understand I use a few examples here, but I wouldn’t get too crazy. Focus on the packages you’re confident you’re going to use EVERYWHERE&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Working Through cannot find module unicode/category/So in Keystone]]></title><description><![CDATA[Fixing Keystone's unicode problem]]></description><link>https://peterp.me/articles/fixing-keystones-unicode-problem/</link><guid isPermaLink="false">https://peterp.me/articles/fixing-keystones-unicode-problem/</guid><dc:creator><![CDATA[Peter Piekarczyk]]></dc:creator><pubDate>Wed, 13 Apr 2016 19:56:30 GMT</pubDate><content:encoded>&lt;p&gt;Every once in awhile, you might encounter an error like this in KeystoneJS:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;sh&quot;&gt;&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;module.js:341
 throw err&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
 ^

Error: Cannot &lt;span class=&quot;token function&quot;&gt;find&lt;/span&gt; module ‘unicode/category/So’
 at Function.Module._resolveFilename &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;module.js:339:15&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
 at Function.Module._load &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;module.js:290:25&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
 at Module.require &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;module.js:367:17&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
 at require &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;internal/module.js:16:19&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
 at symbols &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;E:projectskeystoneappnode_modulesslugslug.js:6:16&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
 at E:projectskeystoneappnode_modulesslugslug.js:199:5
 at Object.&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;anonymous&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;E:projectskeystoneappnode_modulesslugslug.js:212
:2&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
 at Module._compile &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;module.js:413:34&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
 at Object.Module._extensions&lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;js &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;module.js:422:10&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
 at Module.load &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;module.js:357:32&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;What the heck is unicode? Why Does it keep freakin’ out on me?&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Unicode is a character encoding standard for handling text expressed in most of the world’s writing systems&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;You’ve probably heard of &lt;code class=&quot;language-text&quot;&gt;UTF-8&lt;/code&gt;, well UTF stands for: Unicode Transformation Format and the 8 means it uses 8-bit blocks to represent a character, but you can learn all about that on your own!&lt;/p&gt;
&lt;p&gt;Here’s how to fix it:&lt;/p&gt;
&lt;p&gt;Remove the npm unicode package, if it exists:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;sh&quot;&gt;&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; remove unicode&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Install unicode-data on your Ubuntu (or *nix) box:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;sh&quot;&gt;&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;apt-get&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; unicode-data&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Reinstall the npm unicode package:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;sh&quot;&gt;&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; unicode&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Sources:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://www.fileformat.info/info/unicode/utf8.htm&quot;&gt;http://www.fileformat.info/info/unicode/utf8.htm&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Unicode&quot;&gt;https://en.wikipedia.org/wiki/Unicode&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item></channel></rss>