<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Jim Frenette</title>
    <description>The latest articles on DEV Community by Jim Frenette (@jimfrenette).</description>
    <link>https://dev.to/jimfrenette</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F227382%2Fd8269f8e-22fb-4a75-8d43-8e8e09142620.jpg</url>
      <title>DEV Community: Jim Frenette</title>
      <link>https://dev.to/jimfrenette</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jimfrenette"/>
    <language>en</language>
    <item>
      <title>Cascade Select Dropdown in AEM Component Dialog</title>
      <dc:creator>Jim Frenette</dc:creator>
      <pubDate>Tue, 03 Nov 2020 05:30:32 +0000</pubDate>
      <link>https://dev.to/jimfrenette/cascade-select-dropdown-in-aem-component-dialog-3hhm</link>
      <guid>https://dev.to/jimfrenette/cascade-select-dropdown-in-aem-component-dialog-3hhm</guid>
      <description>&lt;p&gt;This tutorial demonstrates how to populate &lt;a href="https://helpx.adobe.com/experience-manager/6-5/sites/developing/using/reference-materials/coral-ui/coralui3/Coral.Select.html"&gt;CoralUI Select&lt;/a&gt; dropdowns in an AEM component dialog from a JSON data source using JavaScript. For added complexity, we're cascading the dropdowns in multiple instances within a &lt;a href="https://helpx.adobe.com/experience-manager/6-5/sites/developing/using/reference-materials/granite-ui/api/jcr_root/libs/granite/ui/components/coral/foundation/form/multifield/index.html"&gt;Multifield&lt;/a&gt; component.&lt;/p&gt;

&lt;h3&gt;
  
  
  Component Dialog
&lt;/h3&gt;

&lt;p&gt;Rather than create a new component, we're just going to modify the existing helloworld component that is included with the project.&lt;/p&gt;

&lt;p&gt;In the helloworld dialog &lt;code&gt;.content.xml&lt;/code&gt;, add the following component nodes after the existing text component node.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; Heading component (optional)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;heading&lt;/span&gt;
    &lt;span class="na"&gt;jcr:primaryType=&lt;/span&gt;&lt;span class="s"&gt;"nt:unstructured"&lt;/span&gt;
    &lt;span class="na"&gt;sling:resourceType=&lt;/span&gt;&lt;span class="s"&gt;"granite/ui/components/coral/foundation/heading"&lt;/span&gt;
    &lt;span class="na"&gt;text=&lt;/span&gt;&lt;span class="s"&gt;"Cars"&lt;/span&gt;
    &lt;span class="na"&gt;level=&lt;/span&gt;&lt;span class="s"&gt;"3"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2.&lt;/strong&gt; Composite Multifield component&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;cars&lt;/span&gt;
    &lt;span class="na"&gt;jcr:primaryType=&lt;/span&gt;&lt;span class="s"&gt;"nt:unstructured"&lt;/span&gt;
    &lt;span class="na"&gt;sling:resourceType=&lt;/span&gt;&lt;span class="s"&gt;"granite/ui/components/coral/foundation/form/multifield"&lt;/span&gt;
    &lt;span class="na"&gt;composite=&lt;/span&gt;&lt;span class="s"&gt;"{Boolean}true"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;field&lt;/span&gt;
        &lt;span class="na"&gt;jcr:primaryType=&lt;/span&gt;&lt;span class="s"&gt;"nt:unstructured"&lt;/span&gt;
        &lt;span class="na"&gt;sling:resourceType=&lt;/span&gt;&lt;span class="s"&gt;"granite/ui/components/coral/foundation/container"&lt;/span&gt;
        &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"./cars"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;items&lt;/span&gt; &lt;span class="na"&gt;jcr:primaryType=&lt;/span&gt;&lt;span class="s"&gt;"nt:unstructured"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;make&lt;/span&gt;
                &lt;span class="na"&gt;jcr:primaryType=&lt;/span&gt;&lt;span class="s"&gt;"nt:unstructured"&lt;/span&gt;
                &lt;span class="na"&gt;sling:resourceType=&lt;/span&gt;&lt;span class="s"&gt;"granite/ui/components/coral/foundation/form/select"&lt;/span&gt;
                &lt;span class="na"&gt;emptyText=&lt;/span&gt;&lt;span class="s"&gt;"Select a make"&lt;/span&gt;
                &lt;span class="na"&gt;fieldLabel=&lt;/span&gt;&lt;span class="s"&gt;"Car"&lt;/span&gt;
                &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"./make"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/make&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;model&lt;/span&gt;
                &lt;span class="na"&gt;jcr:primaryType=&lt;/span&gt;&lt;span class="s"&gt;"nt:unstructured"&lt;/span&gt;
                &lt;span class="na"&gt;sling:resourceType=&lt;/span&gt;&lt;span class="s"&gt;"granite/ui/components/coral/foundation/form/select"&lt;/span&gt;
                &lt;span class="na"&gt;emptyText=&lt;/span&gt;&lt;span class="s"&gt;"Select a model"&lt;/span&gt;
                &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"./model"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/model&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/items&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/field&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/cars&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Multifield needs to be composite to store the cars &lt;code&gt;jcr:content&lt;/code&gt; as item nodes.&lt;/p&gt;

&lt;h4&gt;
  
  
  Cars Data
&lt;/h4&gt;

&lt;p&gt;A endpoint that returns a JSON response could be used instead, but for this proof-of-concept we're just adding a static JSON file resource to the existing &lt;code&gt;clientlib-base&lt;/code&gt;. Create the folders &lt;code&gt;resources/data&lt;/code&gt; in &lt;code&gt;clientlib-base&lt;/code&gt; and add this &lt;code&gt;cars.json&lt;/code&gt; file to it. e.g.,&lt;/p&gt;

&lt;h5&gt;
  
  
  clientlib-base/resources/data/cars.json
&lt;/h5&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"cars"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="nl"&gt;"make"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Chevy"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"models"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"Camaro Z28"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Camaro ZL1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Chevelle SS 454"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s2"&gt;"Nova SS"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"make"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Dodge"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"models"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"Challenger"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Charger Daytona"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Dart 426 Hemi"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"make"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Ford"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"models"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"Fairlane Torino GT"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Mustang Boss 429"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Mustang Mach 1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Mustang Shelby GT500"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Talladega"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Torino Cobra"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Component Dialog JavaScript
&lt;/h4&gt;

&lt;p&gt;To add JavaScript that will be used by our component dialog, we're going to create a &lt;code&gt;clientlib-edit&lt;/code&gt; folder with a &lt;code&gt;jcr:primaryType&lt;/code&gt; of &lt;code&gt;cq:ClientLibraryFolder&lt;/code&gt; in our component folder. To ensure that the library is only loaded for authoring dialogs, it needs to have its category set to &lt;code&gt;cq.authoring.dialog&lt;/code&gt;. Additionally, to use the &lt;code&gt;ClientLibraryProxyServlet&lt;/code&gt; that allows us to modularize our client libraries under &lt;code&gt;/apps&lt;/code&gt;, set the &lt;code&gt;allowProxy&lt;/code&gt; property. For example,&lt;/p&gt;

&lt;h5&gt;
  
  
  helloworld/clientlib-edit/.content.xml
&lt;/h5&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;jcr:root&lt;/span&gt; &lt;span class="na"&gt;xmlns:cq=&lt;/span&gt;&lt;span class="s"&gt;"http://www.day.com/jcr/cq/1.0"&lt;/span&gt; &lt;span class="na"&gt;xmlns:jcr=&lt;/span&gt;&lt;span class="s"&gt;"http://www.jcp.org/jcr/1.0"&lt;/span&gt;
          &lt;span class="na"&gt;jcr:primaryType=&lt;/span&gt;&lt;span class="s"&gt;"cq:ClientLibraryFolder"&lt;/span&gt;
          &lt;span class="na"&gt;allowProxy=&lt;/span&gt;&lt;span class="s"&gt;"{Boolean}true"&lt;/span&gt;
          &lt;span class="na"&gt;categories=&lt;/span&gt;&lt;span class="s"&gt;"[cq.authoring.dialog]"&lt;/span&gt;
          &lt;span class="na"&gt;dependencies=&lt;/span&gt;&lt;span class="s"&gt;"[cq.jquery]"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Note the &lt;code&gt;cq.jquery&lt;/code&gt; dependency. This is for just a couple jQuery methods included in our &lt;code&gt;dialog.js&lt;/code&gt; and since it is already being loaded by AEM for its authoring environment, there is no additional overhead. Most of the script is using vanilla JS for modern browsers. As for the couple of jQuery functions, they could be refactored to vanilla JS pretty easily.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For the &lt;code&gt;dialog.js&lt;/code&gt; JavaScript that includes the Coral UI API object. Please continue to the original post at &lt;a href="https://jimfrenette.com/aem/components/dialog-coral-ui-select-cascade/"&gt;jimfrenette.com/aem/components/dialog-coral-ui-select-cascade&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/udidVJ4cn5k"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

</description>
    </item>
    <item>
      <title>WSL2 with Windows Terminal</title>
      <dc:creator>Jim Frenette</dc:creator>
      <pubDate>Sun, 05 Jul 2020 01:37:36 +0000</pubDate>
      <link>https://dev.to/jimfrenette/wsl2-with-windows-terminal-1cm5</link>
      <guid>https://dev.to/jimfrenette/wsl2-with-windows-terminal-1cm5</guid>
      <description>&lt;p&gt;Windows has finally created a developer command line experience that can compete with OS X and bare metal Linux with the release of WSL2 combined with the new Windows Terminal. For WSL2 installion and updates, refer to the official &lt;a href="https://docs.microsoft.com/en-us/windows/wsl/"&gt;Windows Subsystem for Linux Documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/q_cspAhX3rU"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Free your mind of an inferior Windows developer experience and make the jump&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The following has been tested on Windows 10 build 19041 with WSL2 enabled and set as the default version.&lt;br&gt;
Additionally,&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ubuntu from the &lt;a href="https://aka.ms/wslstore"&gt;Windows Store&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Windows Terminal from the &lt;a href="https://aka.ms/terminal"&gt;Windows Store&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Windows Terminal
&lt;/h3&gt;

&lt;p&gt;One of the things I really like about the new Windows Terminal is the cut, copy and paste keybindings. No more Ctrl+Shift needed, just use Ctrl+V to paste. For example, here are some snippets from my terminal &lt;code&gt;settings.json&lt;/code&gt;.&lt;/p&gt;
&lt;h5&gt;
  
  
  settings.json
&lt;/h5&gt;


&lt;div class="highlight"&gt;&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;If&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;enabled,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;selections&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;are&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;automatically&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;copied&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;your&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;clipboard.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"copyOnSelect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;If&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;enabled,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;formatted&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;data&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;is&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;also&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;copied&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;your&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;clipboard&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"copyFormatting"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;A&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;profile&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;specifies&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;command&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;execute&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;paired&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;with&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;information&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;about&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;how&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;it&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;should&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;look&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;feel.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Each&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;one&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;of&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;them&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;will&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;appear&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'New&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Tab'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;dropdown,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;can&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;be&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;invoked&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;commandline&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;with&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;`wt.exe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;-p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;xxx`&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;To&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;learn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;more&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;about&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;profiles,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;visit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;https://aka.ms/terminal-profile-settings&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"profiles"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"defaults"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Put&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;settings&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;here&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;that&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;you&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;want&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;apply&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;all&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;profiles.&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"fontSize"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Add&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;custom&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;keybindings&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;this&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;array.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;To&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;unbind&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;key&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;combination&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;your&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;defaults.json,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;command&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"unbound"&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;To&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;learn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;more&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;about&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;keybindings,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;visit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;https://aka.ms/terminal-keybindings&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"keybindings"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Copy&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;paste&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;are&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;bound&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Ctrl+Shift+C&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Ctrl+Shift+V&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;your&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;defaults.json.&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;These&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;two&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;lines&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;additionally&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;bind&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;them&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Ctrl+C&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Ctrl+V.&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;To&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;learn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;more&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;about&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;selection&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;visit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;https://aka.ms/terminal-selection&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"copy"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"singleLine"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"keys"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ctrl+c"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"paste"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"keys"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ctrl+v"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;

    &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Press&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Ctrl+Shift+F&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;open&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;search&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;box&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"find"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"keys"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ctrl+shift+f"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;

    &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Press&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Alt+Shift+D&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;open&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;pane.&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"split"&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"auto"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;makes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;this&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;pane&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;open&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;direction&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;that&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;provides&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;most&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;surface&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;area.&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"splitMode"&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"duplicate"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;makes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;pane&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;use&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;focused&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;pane's&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;profile.&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;To&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;learn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;more&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;about&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;panes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;visit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;https://aka.ms/terminal-panes&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"splitPane"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"split"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"auto"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"splitMode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"duplicate"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"keys"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"alt+shift+d"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Oh My Zsh
&lt;/h3&gt;

&lt;p&gt;One of the first things I do when setting up a new bash shell is install &lt;a href="http://zsh.sourceforge.net/"&gt;zsh&lt;/a&gt; and &lt;a href="https://ohmyz.sh/"&gt;Oh My Zsh&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you're an &lt;code&gt;npm&lt;/code&gt; user, I reccommend installing &lt;a href="https://github.com/nvm-sh/nvm"&gt;nvm&lt;/a&gt; as an Oh My ZSH! custom plugin by cloning &lt;code&gt;zsh-nvm&lt;/code&gt; into your custom plugins repo as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; ~/.oh-my-zsh/custom/plugins

git clone https://github.com/lukechilds/zsh-nvm
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Then load as a plugin in your &lt;code&gt;~/.zshrc&lt;/code&gt; profile. Note that plugins need to be added before &lt;code&gt;oh-my-zsh.sh&lt;/code&gt; is sourced.&lt;/p&gt;

&lt;h5&gt;
  
  
  .zshrc
&lt;/h5&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;...

&lt;span class="c"&gt;# Which plugins would you like to load?&lt;/span&gt;
&lt;span class="c"&gt;# Standard plugins can be found in $ZSH/plugins/&lt;/span&gt;
&lt;span class="c"&gt;# Custom plugins may be added to $ZSH_CUSTOM/plugins/&lt;/span&gt;
&lt;span class="c"&gt;# Example format: plugins=(rails git textmate ruby lighthouse)&lt;/span&gt;
&lt;span class="c"&gt;# Add wisely, as too many plugins slow down shell startup.&lt;/span&gt;
&lt;span class="nv"&gt;plugins&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt;
 git
 zsh-nvm
&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="nb"&gt;source&lt;/span&gt; &lt;span class="nv"&gt;$ZSH&lt;/span&gt;/oh-my-zsh.sh
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Additionally, if you're using Java and Maven, you can install and run those from WSL2 to build projects even if they exist on the mounted native Windows file system.&lt;/p&gt;

&lt;p&gt;For example, I use &lt;a href="https://sdkman.io/"&gt;SDKMAN!&lt;/a&gt; to manage mutiple JDK versions similar to how I manage multiple node versions using nvm.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--FZJicS0D--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/8yhnqmfjdv70z8319js4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--FZJicS0D--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/8yhnqmfjdv70z8319js4.png" alt="WSL windows terminal example of mvn --version"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Explorer
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4_dfsnoa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/c652v851vxr3xz1xpmmk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4_dfsnoa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/c652v851vxr3xz1xpmmk.png" alt="WSL Ubuntu Files in Windows Explorer"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Access your WSL files in Explorer by entering network path &lt;code&gt;\\wsl$&lt;/code&gt; in the address bar.&lt;/p&gt;

&lt;h4&gt;
  
  
  Resources
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://docs.docker.com/docker-for-windows/wsl/"&gt;Docker Desktop WSL 2 backend&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://github.com/robbyrussell/oh-my-zsh"&gt;github.com/robbyrussell/oh-my-zsh&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://gist.github.com/jimfrenette/21c7f19bc12c94c60628bebbf943a974"&gt;resolv.sh&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://code.visualstudio.com/docs/remote/remote-overview"&gt;VS Code Remote Development&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Originally posted at &lt;a href="https://jimfrenette.com/2020/07/wsl2-windows-terminal/"&gt;jimfrenette.com/2020/07/wsl2-windows-terminal&lt;/a&gt;&lt;/p&gt;

</description>
      <category>wsl</category>
      <category>windows</category>
    </item>
    <item>
      <title>AEM File Transfers for Developers</title>
      <dc:creator>Jim Frenette</dc:creator>
      <pubDate>Tue, 28 Jan 2020 02:33:17 +0000</pubDate>
      <link>https://dev.to/jimfrenette/aem-file-transfers-for-developers-2da8</link>
      <guid>https://dev.to/jimfrenette/aem-file-transfers-for-developers-2da8</guid>
      <description>&lt;p&gt;There are several different ways to handle file transfers between AEM and your local file system. In this post, I'm going to go over a couple command line tools to transfers files between my local file system and AEM 6.5: AEM repo tool and FileVault VLT.&lt;/p&gt;

&lt;h3&gt;
  
  
  AEM repo tool
&lt;/h3&gt;

&lt;p&gt;Follow the instructions at &lt;a href="https://github.com/Adobe-Marketing-Cloud/tools/tree/master/repo"&gt;Adobe-Marketing-Cloud / tools / repo&lt;/a&gt; to install on your system. For Linux, I used curl to install the &lt;code&gt;repo&lt;/code&gt; bash script since it is just a single file. e.g.,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl -L https://raw.githubusercontent.com/Adobe-Marketing-Cloud/tools/master/repo/repo -o $HOME/bin/repo

chmod +x $HOME/bin/repo
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Add the &lt;code&gt;repo&lt;/code&gt; script to your environment PATH as needed.&lt;/p&gt;

&lt;h4&gt;
  
  
  Config
&lt;/h4&gt;

&lt;p&gt;Defaults&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Property&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;server&lt;/td&gt;
&lt;td&gt;&lt;a href="http://localhost:4502"&gt;http://localhost:4502&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;credentials&lt;/td&gt;
&lt;td&gt;admin:admin&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If your server and/or credentials differ from the defaults, in your project folder, create a &lt;code&gt;.repo&lt;/code&gt; file with your AEM server location and credentials. e.g.,&lt;/p&gt;

&lt;h5&gt;
  
  
  .repo
&lt;/h5&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;server=http://192.168.1.10:4502
credentials=gilfoyle:secret
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h4&gt;
  
  
  Checkout
&lt;/h4&gt;

&lt;p&gt;Specify the AEM JCR path to transfer from. Unlike &lt;code&gt;vlt&lt;/code&gt;, you can only perform an action on a single path. There is not an option for a batch transfer that can use a filter.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd myproject

repo checkout /apps/weretail
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This will create a &lt;code&gt;jcr_root&lt;/code&gt; folder containing the checked out folders and files.&lt;/p&gt;

&lt;ul class="tree"&gt;
  &lt;li&gt;
&lt;i class="icon-folder-open"&gt;&lt;/i&gt; myproject
    &lt;ul&gt;
      &lt;li&gt;
&lt;i class="icon-folder-open"&gt;&lt;/i&gt; jcr_root
        &lt;ul&gt;
          &lt;li&gt;
&lt;i class="icon-folder-open"&gt;&lt;/i&gt; apps
            &lt;ul&gt;
              &lt;li&gt;
&lt;i class="icon-folder"&gt;&lt;/i&gt; weretail&lt;/li&gt;
            &lt;/ul&gt;
          &lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;.repo&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Use the &lt;code&gt;put&lt;/code&gt; command to transfer updated files into the AEM JCR.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd jcr_root/apps/weretail/components/content/heroimage

repo put heroimage.html
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Use the &lt;code&gt;-s&lt;/code&gt; option with a command to specify a different server to interact with. For example, transfer to the publish instance on port 4503.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;repo put -s http://localhost:4503 heroimage.html
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h4&gt;
  
  
  Commands
&lt;/h4&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Alias&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;checkout&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Intial checkout of server content on file system&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;diff&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Show differences, same as 'localdiff'&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;get&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Download server content to local file system&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;localdiff&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Show differences done locally compared to server&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;put&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Upload local file system content to server&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;serverdiff&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Show differences done on the server compared to local&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;status&lt;/td&gt;
&lt;td&gt;st&lt;/td&gt;
&lt;td&gt;list status of modified/added/deleted files&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;For help on a command, use &lt;code&gt;repo &amp;lt;command&amp;gt; -h&lt;/code&gt;. e.g., &lt;code&gt;repo -h get&lt;/code&gt;. For the entire help contents, &lt;code&gt;repo -h&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  IDE Integration
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/Adobe-Marketing-Cloud/tools/blob/master/repo/README.md"&gt;Adobe-Marketing-Cloud / &lt;br&gt;
tools / repo / README&lt;/a&gt; contains a good bit of information on how to integrate the commands into various IDE's including Visual Studio Code and IntelliJ. These integration methods should also work for the FileVault VLT commands.&lt;/p&gt;
&lt;h4&gt;
  
  
  VS Code
&lt;/h4&gt;

&lt;p&gt;Create a &lt;code&gt;tasks.json&lt;/code&gt; for the curent workspace. e.g., &lt;code&gt;.vscode/tasks.json&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Select Terminal &amp;gt; Configure Tasks &amp;gt; Create &lt;code&gt;tasks.json&lt;/code&gt; file from template &amp;gt; Others.&lt;/p&gt;

&lt;p&gt;Folder actions will be performed on the folder of the currently opened file.&lt;/p&gt;
&lt;h5&gt;
  
  
  tasks.json
&lt;/h5&gt;


&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;version&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2.0.0&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;tasks&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;label&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;put file&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;shell&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;command&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;repo put -f ${file}&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;problemMatcher&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;label&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;put folder&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;shell&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;command&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;repo put -f ${fileDirname}&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;problemMatcher&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;label&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;get file&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;shell&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;command&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;repo get -f ${file}&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;problemMatcher&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;label&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;get folder&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;shell&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;command&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;repo get -f ${fileDirname}&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;problemMatcher&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;For more information on Visual Studio Code integration, refer to the &lt;a href="https://code.visualstudio.com/docs/editor/tasks"&gt;VS Code Task&lt;/a&gt; documentation.&lt;/p&gt;
&lt;h3&gt;
  
  
  FileVault VLT
&lt;/h3&gt;

&lt;p&gt;The Apache Jackrabbit FileVault VLT command line tool maps the contents of an AEM Java Content Repository (JCR) to your file system.&lt;/p&gt;

&lt;p&gt;To get the latest &lt;a href="https://jackrabbit.apache.org/filevault/"&gt;FileVault&lt;/a&gt;, clone or download the &lt;a href="https://github.com/apache/jackrabbit-filevault"&gt;jackrabbit-filevault&lt;/a&gt; repo from github.&lt;/p&gt;

&lt;p&gt;In AEM versions 6.3 and earlier, you could install FileVault from its archive in the &lt;code&gt;crx-quickstart/opt/filevault/&lt;/code&gt; folder of your AEM instance. For example, AEM 6.3, includes both &lt;code&gt;filevault-3.1.38.tgz&lt;/code&gt; and &lt;code&gt;filevault-3.1.38.zip&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Next, build FileVault using Maven. e.g.,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd jackrabbit-filevault

mvn clean install
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Check the documentation for build requirements. At the time of this writing, Maven 3.3.9 (or higher) with Java 8 (or higher) required. I used openjdk version 1.8.0_232 and Maven 3.6.2 when building.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The initial build will take a few minutes, for example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary for Apache Jackrabbit FileVault (Reactor Project) 3.4.1-SNAPSHOT:
[INFO]
[INFO] Apache Jackrabbit FileVault (Parent Project) ....... SUCCESS [  9.574 s]
[INFO] Apache Jackrabbit FileVault Core Bundle ............ SUCCESS [02:31 min]
[INFO] Apache Jackrabbit FileVault Diff (Diff utilities) .. SUCCESS [  1.549 s]
[INFO] Apache Jackrabbit FileVault JCR Remoting Service ... SUCCESS [  1.658 s]
[INFO] Apache Jackrabbit FileVault RCP Server Bundle ...... SUCCESS [  1.224 s]
[INFO] Apache Jackrabbit FileVault Documentation .......... SUCCESS [  0.066 s]
[INFO] Apache Jackrabbit FileVault Sync Service ........... SUCCESS [  1.611 s]
[INFO] Apache Jackrabbit FileVault Platform Interaction ... SUCCESS [  0.947 s]
[INFO] Apache Jackrabbit FileVault Command Line Interface . SUCCESS [  2.600 s]
[INFO] Apache Jackrabbit FileVault Package Hook Example ... SUCCESS [  2.040 s]
[INFO] Apache Jackrabbit FileVault Package Hook Sling Example SUCCESS [  0.350 s]
[INFO] Apache Jackrabbit FileVault Validation ............. SUCCESS [  3.375 s]
[INFO] Apache Jackrabbit FileVault (Reactor Project) ...... SUCCESS [ 13.789 s]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  03:15 min
[INFO] Finished at: 2019-12-06T18:42:47-05:00
[INFO] ------------------------------------------------------------------------
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h4&gt;
  
  
  Installation
&lt;/h4&gt;

&lt;p&gt;Extract the archive from the &lt;code&gt;vault-cli/target&lt;/code&gt; directory in the build.&lt;/p&gt;

&lt;p&gt;For example,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd vault-cli/target

tar xfz vault-cli-3.4.1-SNAPSHOT-bin.tar.gz
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;If you like, rename the directory for the PATH so it does not contain &lt;code&gt;-SNAPSHOT&lt;/code&gt;. e.g.,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mv vault-cli-3.4.1-SNAPSHOT vault-cli-3.4.1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Add the &lt;code&gt;bin&lt;/code&gt; directory which contains &lt;code&gt;vlt&lt;/code&gt; and &lt;code&gt;vlt.bat&lt;/code&gt; to your environment PATH. For example, in Linux, this can be done in the users &lt;code&gt;.profile&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export PATH=$PATH:$HOME/aem/jackrabbit-filevault/vault-cli/target/vault-cli-3.4.1/bin
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Once you've updated your environment PATH to include the &lt;code&gt;bin&lt;/code&gt; directory, verify using the &lt;code&gt;vlt&lt;/code&gt; command (you may have to logout for your PATH changes to take effect).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;vlt --help
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h4&gt;
  
  
  Checkout
&lt;/h4&gt;

&lt;p&gt;Using &lt;code&gt;vlt co&lt;/code&gt;, you can checkout files from the AEM JCR.&lt;/p&gt;

&lt;p&gt;Note: this example will checkout all of the files. &lt;em&gt;In a default AEM 6.5 author instance, there are over 2 GB's of files.&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd jcr_root

vlt --credentials admin:admin co --force http://localhost:4502/crx
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;The credentials only need to be specified on the initial checkout and are added to &lt;code&gt;~/.vault/auth.xml&lt;/code&gt; for subsequent operations.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  Checkout Filter
&lt;/h4&gt;

&lt;p&gt;A &lt;code&gt;META-INF&lt;/code&gt; manifest folder exists alongside the &lt;code&gt;jcr_root&lt;/code&gt;. Create this folder if needed and add a &lt;code&gt;vault/filter.xml&lt;/code&gt; file. Now you can checkout just the directories you specify in this filter instead of the entire JCR.&lt;/p&gt;

&lt;ul class="tree"&gt;
  &lt;li&gt;
&lt;i class="icon-folder-open"&gt;&lt;/i&gt; myproject
    &lt;ul&gt;
      &lt;li&gt;
&lt;i class="icon-folder"&gt;&lt;/i&gt; jcr_root&lt;/li&gt;
      &lt;li&gt;
&lt;i class="icon-folder-open"&gt;&lt;/i&gt; META-INF
        &lt;ul&gt;
          &lt;li&gt;
&lt;i class="icon-folder-open"&gt;&lt;/i&gt; vault
            &lt;ul&gt;
              &lt;li&gt;filter.xml&lt;/li&gt;
            &lt;/ul&gt;
          &lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;
  
  
  filter.xml
&lt;/h5&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;workspaceFilter&lt;/span&gt; &lt;span class="na"&gt;version=&lt;/span&gt;&lt;span class="s"&gt;"1.0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;filter&lt;/span&gt; &lt;span class="na"&gt;root=&lt;/span&gt;&lt;span class="s"&gt;"/apps/weretail"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;filter&lt;/span&gt; &lt;span class="na"&gt;root=&lt;/span&gt;&lt;span class="s"&gt;"/apps/we-retail-communities"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;filter&lt;/span&gt; &lt;span class="na"&gt;root=&lt;/span&gt;&lt;span class="s"&gt;"/apps/we-retail-screens"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;filter&lt;/span&gt; &lt;span class="na"&gt;root=&lt;/span&gt;&lt;span class="s"&gt;"/content/we-retail"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/workspaceFilter&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Save the filter and run &lt;code&gt;vlt checkout&lt;/code&gt;. Use &lt;code&gt;--force&lt;/code&gt; to overwrite the previous checkout as needed. e.g.,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd jcr_root

vlt co --force http://localhost:4502/crx
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h4&gt;
  
  
  Commit
&lt;/h4&gt;

&lt;p&gt;Update and commit a file back into the AEM JCR to test the operation. For example,&lt;/p&gt;

&lt;p&gt;&lt;code&gt;apps/weretail/components/content/heroimage/heroimage.html&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;sly data-sly-use.heroImage="we.retail.core.model.HeroImage"&amp;gt;
  &amp;lt;div class="${heroImage.classList} jumbotron"
     style="background-image: url('${(properties.fileReference || properties.fileName) ? heroImage.image.src : '' @ context='uri'}');"&amp;gt;
    &amp;lt;div class="container cq-dd-image"&amp;gt;
      &amp;lt;div class="we-HeroImage-wrapper"&amp;gt;
        &amp;lt;p class="h3"&amp;gt;${properties.heading}&amp;lt;/p&amp;gt;
        &amp;lt;strong class="we-HeroImage-title h1"&amp;gt;${properties.title || currentPage.title}&amp;lt;/strong&amp;gt;

        &amp;lt;h3 style="font-weight:bold;text-shadow: 2px 2px 4px #000000;"&amp;gt;
          VLT TESTING
        &amp;lt;/h3&amp;gt;

        &amp;lt;p data-sly-test="${properties.buttonLabel &amp;amp;&amp;amp; properties.buttonLinkTo}"&amp;gt;
          &amp;lt;a class="btn btn-primary btn-action" href="${properties.buttonLinkTo @ extension = 'html'}" role="button"&amp;gt;${properties.buttonLabel}&amp;lt;/a&amp;gt;
        &amp;lt;/p&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/sly&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Commit the change with the &lt;code&gt;-v&lt;/code&gt; option (verbose output) to see what is being transferred. e.g.,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;vlt ci -v apps/weretail/components/content/heroimage/heroimage.html
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Verify the update, e.g.,&lt;/p&gt;

&lt;p&gt;View a page that has the &lt;code&gt;heroimage&lt;/code&gt; component as published, &lt;a href="http://localhost:4502/content/we-retail/us/en.html?wcmmode=disabled" rel="nofollow"&gt;&lt;/a&gt;&lt;a href="http://localhost:4502/content/we-retail/us/en.html?wcmmode=disabled"&gt;http://localhost:4502/content/we-retail/us/en.html?wcmmode=disabled&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  VLT Commands
&lt;/h4&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Alias&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;add&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Puts files and directories under version control&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;checkout&lt;/td&gt;
&lt;td&gt;co&lt;/td&gt;
&lt;td&gt;Checkout a Vault file system&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;commit&lt;/td&gt;
&lt;td&gt;ci&lt;/td&gt;
&lt;td&gt;Send changes from your working copy to the repository&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;console&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Run an interactive console&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;delete&lt;/td&gt;
&lt;td&gt;del, rm&lt;/td&gt;
&lt;td&gt;Remove files and directories from version control&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;diff&lt;/td&gt;
&lt;td&gt;di&lt;/td&gt;
&lt;td&gt;Display the differences between two paths&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;export&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Export the Vault filesystem&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;format&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Formats vault docview files&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;import&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Import a Vault filesystem&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;info&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Displays information about a local file&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;propget&lt;/td&gt;
&lt;td&gt;pg&lt;/td&gt;
&lt;td&gt;Print the value of a property on files or directories&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;proplist&lt;/td&gt;
&lt;td&gt;pl&lt;/td&gt;
&lt;td&gt;Print the properties on files or directories&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;propset&lt;/td&gt;
&lt;td&gt;ps&lt;/td&gt;
&lt;td&gt;Set the value of a property on files or directories&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;rcp&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Remote copy of repository content&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;resolved&lt;/td&gt;
&lt;td&gt;res&lt;/td&gt;
&lt;td&gt;Remove 'conflicted' state on working copy files or directories&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;revert&lt;/td&gt;
&lt;td&gt;rev&lt;/td&gt;
&lt;td&gt;Restore pristine working copy file (undo most local edits)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;status&lt;/td&gt;
&lt;td&gt;st&lt;/td&gt;
&lt;td&gt;Print the status of working copy files and directories&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;sync&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Control vault sync service&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;update&lt;/td&gt;
&lt;td&gt;up&lt;/td&gt;
&lt;td&gt;Bring changes from the repository into the working copy&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;For help on a command, use &lt;code&gt;vlt --help&lt;/code&gt; plus the name of the command. e.g., &lt;code&gt;vlt --help commit&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;Originally posted at &lt;a href="https://jimfrenette.com/2019/12/aem-developer-file-transfers/"&gt;jimfrenette.com/.../aem-developer-file-transfers&lt;/a&gt; | &lt;a href="https://jimfrenette.com/aem/"&gt;AEM Developer Resources&lt;/a&gt;&lt;/p&gt;

</description>
      <category>aem</category>
      <category>jcr</category>
    </item>
    <item>
      <title>JavaScript Document Object (DOM) Helpers</title>
      <dc:creator>Jim Frenette</dc:creator>
      <pubDate>Sun, 15 Dec 2019 14:23:28 +0000</pubDate>
      <link>https://dev.to/jimfrenette/javascript-document-object-dom-helpers-2911</link>
      <guid>https://dev.to/jimfrenette/javascript-document-object-dom-helpers-2911</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--VwLXgOiH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/hnkg7wac6xu0mfhj92zl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--VwLXgOiH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/hnkg7wac6xu0mfhj92zl.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A few DOM helpers to assist with the transition from jQuery to vanilla JavaScript.&lt;/p&gt;

&lt;h4&gt;
  
  
  indexInParent
&lt;/h4&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;indexInParent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parentNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;childNodes&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;num&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;num&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;nodeType&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;num&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h4&gt;
  
  
  indexOfParent
&lt;/h4&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;indexOfParent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[].&lt;/span&gt;&lt;span class="nx"&gt;indexOf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parentElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h4&gt;
  
  
  matches
&lt;/h4&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;matches&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;elem&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isMsMatch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;msMatchesSelector&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;elem&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;elem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;msMatchesSelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isMatchSelector&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;matchesSelector&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;elem&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;elem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;matchesSelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isMatch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;matches&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;elem&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;elem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;matches&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// Test the element to see if it matches the provided selector&lt;/span&gt;
    &lt;span class="c1"&gt;// use different methods for compatibility&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;isMsMatch&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;isMatchSelector&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;isMatch&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="c1"&gt;// Return the result of the test&lt;/span&gt;
    &lt;span class="c1"&gt;// If any of the above variables is true, the return value will be true&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h4&gt;
  
  
  closest
&lt;/h4&gt;

&lt;p&gt;For each element in the set, get the first element that matches the selector by testing the element itself and traversing up through its ancestors in the DOM tree.&lt;/p&gt;

&lt;p&gt;Depends on &lt;code&gt;matches&lt;/code&gt;;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;getClosest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;elem&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// This allows for matching based on any selector, not just a single class.&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(;&lt;/span&gt; &lt;span class="nx"&gt;elem&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;elem&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;elem&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;elem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parentNode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Traverse up the dom until document is reached&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;matches&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;elem&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// Test each element to see if it matches. If it does, return it.&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;elem&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;closest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;getClosest&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Usage for the above that's in a file set up for &lt;a href="https://developers.google.com/web/fundamentals/performance/optimizing-javascript/tree-shaking"&gt;tree shaking&lt;/a&gt;, e.g., &lt;code&gt;helpers.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { closest } from 'js/helpers';
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h4&gt;
  
  
  offset top
&lt;/h4&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;getOffsetTop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;offsetTop&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nb"&gt;isNaN&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;offsetTop&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;offsetTop&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;offsetTop&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;offsetParent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;offsetTop&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h4&gt;
  
  
  next
&lt;/h4&gt;

&lt;p&gt;Get the immediately following sibling of each element in the set of matched elements.&lt;/p&gt;

&lt;p&gt;Depends on &lt;code&gt;matches&lt;/code&gt;, &lt;code&gt;prev&lt;/code&gt;;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nextElementSibling&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;matches&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nextElementSibling&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nextElementSibling&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nextElementSibling&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h4&gt;
  
  
  prev
&lt;/h4&gt;

&lt;p&gt;Get the immediately preceding sibling of each element in the set of matched elements.&lt;/p&gt;

&lt;p&gt;Depends on &lt;code&gt;matches&lt;/code&gt;;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;previousElementSibling&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;matches&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;previousElementSibling&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;previousElementSibling&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;previousElementSibling&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h4&gt;
  
  
  siblings
&lt;/h4&gt;

&lt;p&gt;Get the siblings of each element in the set of matched elements.&lt;/p&gt;

&lt;p&gt;Depends on &lt;code&gt;matches&lt;/code&gt;;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;siblings&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prototype&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parentNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;child&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;matches&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;child&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Originally published at &lt;a href="https://jimfrenette.com/javascript/document/"&gt;jimfrenette.com/javascript/document&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
    </item>
    <item>
      <title>WSL ubuntu zsh nvm etc.</title>
      <dc:creator>Jim Frenette</dc:creator>
      <pubDate>Mon, 14 Oct 2019 15:13:36 +0000</pubDate>
      <link>https://dev.to/jimfrenette/wsl-ubuntu-zsh-nvm-etc-ba6</link>
      <guid>https://dev.to/jimfrenette/wsl-ubuntu-zsh-nvm-etc-ba6</guid>
      <description>&lt;p&gt;The Windows Subsystem for Linux (WSL) seems to be mature enough now to give it another shot. Copy and paste, and other simple annoyances that kept me away before are working better. Also, I've been reading that &lt;a href="https://github.com/creationix/nvm"&gt;nvm&lt;/a&gt; (Node Version Manager) works now, so here goes.&lt;/p&gt;

&lt;p&gt;The following has been tested on Windows 10 Professional (version 1709, build 16299.309) with WSL enabled and Ubuntu installed from the &lt;a href="https://aka.ms/wslstore"&gt;Windows Store&lt;/a&gt;. It's also working fine on the current May 2019 Update, version 1903.&lt;/p&gt;

&lt;h3&gt;
  
  
  Ubuntu Update
&lt;/h3&gt;

&lt;p&gt;If it has been a while, first thing I like to do with the Ubuntu app is update and upgrade the ubuntu Linux packages. First update the package database with &lt;code&gt;apt-get update&lt;/code&gt;, then upgrade with &lt;code&gt;apt-get upgrade&lt;/code&gt; or &lt;code&gt;apt-get dist-upgrade&lt;/code&gt;. I prefer &lt;code&gt;apt-get dist-upgrade&lt;/code&gt; since it will remove obsolete packages and add new ones as needed.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Windows update does not change the WSL Ubuntu installation. To upgrade to a new release, run &lt;code&gt;sudo do-release-upgrade&lt;/code&gt; in the Ubuntu Terminal.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Oh My Zsh
&lt;/h3&gt;

&lt;p&gt;Oh My Zsh will spruce up your Ubuntu bash and add some additional functionality. Here is a screenshot of my Ubuntu app to illustrate.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QXVc8iiS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/h3bxllvc2a2ji6csujf7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QXVc8iiS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/h3bxllvc2a2ji6csujf7.png" alt="WSL Ubuntu bash example oh-my-zsh cowsay etc."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Install Oh My Zsh just as you would on any other ubuntu system. Note that Zsh is a pre-requisite. For installation instructions and more information, visit &lt;a href="https://github.com/robbyrussell/oh-my-zsh"&gt;https://github.com/robbyrussell/oh-my-zsh&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Your going to want to change the font to fix unknown character issues. I've installed the DejaVu Sans Mono for Powerline font available &lt;a href="https://github.com/powerline/fonts"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--oXzqpWWp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/vg6pqapkwin7ee2095td.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--oXzqpWWp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/vg6pqapkwin7ee2095td.png" alt="WSL Ubuntu bash font properties"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;To set WSL Ubuntu bash with zsh as your integrated terminal in &lt;a href="https://jimfrenette.com/code-editors/visual-studio-code/"&gt;VS Code&lt;/a&gt;. Update your user settings file, e.g., &lt;code&gt;%appdata%\Code\User\settings.json&lt;/code&gt; with the following.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h5&gt;
  
  
  settings.json
&lt;/h5&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;terminal.integrated.shell.windows&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;C:&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;Windows&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;System32&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;bash.exe&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;terminal.integrated.shellArgs.windows&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;-c&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;zsh&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  ssh
&lt;/h3&gt;

&lt;p&gt;If you want to use your existing git and/or other ssh keys, copy them from their folder in Windows into a &lt;code&gt;.ssh&lt;/code&gt; folder under ubuntu. For example,&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd ~/
mkdir .ssh

# navigate to Windows .ssh folder, e.g.,
cd ../mnt/c/Users/Gilfoyle/.ssh

# copy the keys into ubuntu .ssh folder
cp id_rsa ~/.ssh/
cp id_rsa.pub ~/.ssh/

# set permissions on the private key for github
chmod 600 ~/.ssh/id_rsa
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;
  
  
  nvm
&lt;/h3&gt;

&lt;p&gt;nvm is a utility for installing and managing multiple versions of node.js.&lt;/p&gt;

&lt;p&gt;Install as an Oh My ZSH! custom plugin by cloning &lt;code&gt;zsh-nvm&lt;/code&gt; into your custom plugins repo.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd ~/.oh-my-zsh/custom/plugins

git clone https://github.com/lukechilds/zsh-nvm ~/.oh-my-zsh/custom/plugins/zsh-nvm
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Then load as a plugin in your &lt;code&gt;.zshrc&lt;/code&gt; profile. Note that plugins need to be added before &lt;code&gt;oh-my-zsh.sh&lt;/code&gt; is sourced. For example, here is a snippet from my &lt;code&gt;.zshrc&lt;/code&gt; profile.&lt;/p&gt;

&lt;h5&gt;
  
  
  .zshrc
&lt;/h5&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Which plugins would you like to load? (plugins can be found in ~/.oh-my-zsh/plugins/*)
# Custom plugins may be added to ~/.oh-my-zsh/custom/plugins/
# Example format: plugins=(rails git textmate ruby lighthouse)
# Add wisely, as too many plugins slow down shell startup.
plugins=(git)

plugins+=(zsh-nvm)

source $ZSH/oh-my-zsh.sh
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;If you want to install &lt;a href="https://yarnpkg.com"&gt;Yarn&lt;/a&gt;, use &lt;code&gt;apt-get install --no-install-recommends yarn&lt;/code&gt;. By default, Yarn installs nodejs as a system-wide dependency.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;After updating your &lt;code&gt;.zshrc&lt;/code&gt; profile to load the &lt;code&gt;nvm&lt;/code&gt; plugin, close and re-open the Ubuntu app and to install nvm when the plugin is loaded for the first time.&lt;/p&gt;

&lt;p&gt;One the install has completed, you can verify by running &lt;code&gt;nvm&lt;/code&gt; which should output the &lt;code&gt;nvm --help&lt;/code&gt; contents.&lt;/p&gt;

&lt;p&gt;Install the latest LTS version of Node.js which at the time of this writing is version 8.11.1&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# install node
nvm install 8.11.1  
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;If you want to upgrade npm, use &lt;code&gt;nvm install-latest-npm&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  etc.
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/alexanderepstein/Bash-Snippets"&gt;Bash-Snippets&lt;/a&gt; collection of bash scripts.&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apt-get install fortune

apt-get install cowsay

apt-get install htop
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h4&gt;
  
  
  Mount
&lt;/h4&gt;

&lt;p&gt;Mount a drive such as a USB flash drive formatted as FAT, ExFAT or NTFS. For example, a drive listed as &lt;code&gt;F:\&lt;/code&gt; in Windows would be mounted as follows.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir /mnt/f
mount -t drvfs f: /mnt/f
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h4&gt;
  
  
  Bind
&lt;/h4&gt;

&lt;p&gt;Bind a custom mount for any drives you want to access. For example, the &lt;code&gt;C&lt;/code&gt; drive. This is also required should you want to use Docker volume mount paths as described in &lt;a href="https://nickjanetakis.com/blog/setting-up-docker-for-windows-and-wsl-to-work-flawlessly"&gt;this post by Nick Janetakis&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Windows 10 17.09&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir /c
mount --bind /mnt/c /c

# unmount
umount /mnt/c
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;Included in Windows 10 version 1803 (April 2018 Update) is support for WSL launch configuration. The &lt;code&gt;/etc/wsl.conf&lt;/code&gt; file contains settings for drive mounting and network configuration. Read the Microsoft Developer blog post, &lt;a href="https://blogs.msdn.microsoft.com/commandline/2018/02/07/automatically-configuring-wsl/"&gt;Automatically Configuring WSL&lt;/a&gt; for more information on how to use &lt;code&gt;wsl.conf&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Windows 10 18.03 WSL Configuration File&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Create the &lt;code&gt;/etc/wsl.conf&lt;/code&gt; file and set &lt;code&gt;root = /&lt;/code&gt; so you can access drives with &lt;code&gt;/c&lt;/code&gt; or &lt;code&gt;/e&lt;/code&gt; instead of &lt;code&gt;/mnt/c&lt;/code&gt; and &lt;code&gt;/mnt/e&lt;/code&gt;.&lt;/p&gt;

&lt;h5&gt;
  
  
  wsl.conf
&lt;/h5&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[automount]
root = /
options = "metadata"
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h4&gt;
  
  
  File System
&lt;/h4&gt;

&lt;p&gt;If you want to browse the files using Windows Explorer and/or backup the root file system, the location of these files is in the hidden AppData folder. For example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;%localappdata%\Packages\CanonicalGroupLimited.UbuntuonWindows_79rhkp1fndgsc\LocalState\rootfs
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;From &lt;a href="https://blogs.msdn.microsoft.com/commandline/2016/11/17/do-not-change-linux-files-using-windows-apps-and-tools/"&gt;Rich Turners blog post&lt;/a&gt; ...&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--rCL7cJll--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/0lckj2ggmyn8v0rxw130.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rCL7cJll--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/0lckj2ggmyn8v0rxw130.png" alt="Do not change Linux files using Windows apps and tools"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;More info available at &lt;a href="https://blogs.msdn.microsoft.com/wsl/2016/06/15/wsl-file-system-support/"&gt;WSL File System Support&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Resources
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://docs.microsoft.com/en-us/windows/wsl/install-win10"&gt;docs.microsoft.com/en-us/windows/wsl/install-win10&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://github.com/robbyrussell/oh-my-zsh"&gt;github.com/robbyrussell/oh-my-zsh&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://github.com/powerline/fonts"&gt;github.com/powerline/fonts&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://github.com/creationix/nvm"&gt;github.com/creationix/nvm&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Originally published at &lt;a href="https://jimfrenette.com/2018/04/wsl-ubuntu-zsh-nvm-etc/"&gt;jimfrenette.com/2018/04/wsl-ubuntu-zsh-nvm-etc&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ubuntu</category>
      <category>bash</category>
      <category>vscode</category>
    </item>
    <item>
      <title>Node.js Koa Container</title>
      <dc:creator>Jim Frenette</dc:creator>
      <pubDate>Thu, 10 Oct 2019 13:33:42 +0000</pubDate>
      <link>https://dev.to/jimfrenette/node-js-koa-container-50hb</link>
      <guid>https://dev.to/jimfrenette/node-js-koa-container-50hb</guid>
      <description>&lt;p&gt;An example of how to create a Docker container application using &lt;a href="http://koajs.com"&gt;Koa.js&lt;/a&gt; Next generation web framework for &lt;a href="https://nodejs.com/"&gt;Node.js&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In the project root, initialize using &lt;a href="https://yarnpkg.com"&gt;Yarn&lt;/a&gt; or &lt;a href="https://www.npmjs.com/"&gt;npm&lt;/a&gt;.&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn init -y
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Install dependencies.&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn add koa
yarn add koa-body
yarn add koa-logger
yarn add koa-router
yarn add koa-views
yarn add swig
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Create an &lt;code&gt;app&lt;/code&gt; folder in the project root.&lt;/p&gt;

&lt;p&gt;In the app folder, create a folder named &lt;code&gt;lib&lt;/code&gt;. Then create this &lt;code&gt;render.js&lt;/code&gt; module in the new lib folder.&lt;/p&gt;

&lt;h5&gt;
  
  
  render.js
&lt;/h5&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
  * Module dependencies.
  */&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;views&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;koa-views&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;path&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// setup views mapping .html&lt;/span&gt;
&lt;span class="c1"&gt;// to the swig template engine&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;views&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/../views&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;map&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;html&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;swig&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In the app folder, create a folder for templates named &lt;code&gt;views&lt;/code&gt;. Then create this &lt;code&gt;index.html&lt;/code&gt; template in the new views folder.&lt;/p&gt;

&lt;h5&gt;
  
  
  index.html
&lt;/h5&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1.0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;http-equiv=&lt;/span&gt;&lt;span class="s"&gt;"X-UA-Compatible"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"ie=edge"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Document&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;{{content}}&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Using &lt;a href="https://emmet.io/"&gt;Emmet&lt;/a&gt;, which is &lt;a href="https://code.visualstudio.com/docs/editor/emmet"&gt;built into VS Code&lt;/a&gt;, you can create the index.html content by entering an exclamation mark on the first line then select the tab key.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In the app folder, create this &lt;code&gt;app.js&lt;/code&gt; application entrypoint file.&lt;/p&gt;

&lt;h5&gt;
  
  
  app.js
&lt;/h5&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;render&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./lib/render&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;logger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;koa-logger&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;router&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;koa-router&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;koaBody&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;koa-body&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Koa&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;koa&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Koa&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// middleware&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;koaBody&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

&lt;span class="c1"&gt;// route definitions&lt;/span&gt;

&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;routes&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;index&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello World&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// listen&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Project structure&lt;/p&gt;

&lt;p&gt;project&lt;br&gt;
 ┣ app&lt;br&gt;
 ┃ ┣ lib&lt;br&gt;
 ┃ ┃ ┗ render.js&lt;br&gt;
 ┃ ┣ views&lt;br&gt;
 ┃ ┃ ┗ index.html&lt;br&gt;
 ┃ ┗ app.js&lt;br&gt;
 ┗ package.json&lt;/p&gt;

&lt;p&gt;Test the application locally in a browser at &lt;a href="http://localhost:3000"&gt;http://localhost:3000&lt;/a&gt;. Use Ctrl+C to kill the app after verifying it works.&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd app
node app.js
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;
  
  
  Docker
&lt;/h3&gt;

&lt;p&gt;To containerize the application, create a &lt;code&gt;docker-compose.yml&lt;/code&gt; file in the project root as follows.&lt;/p&gt;
&lt;h5&gt;
  
  
  docker-compose.yml
&lt;/h5&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;version: '3'

services:
  app:
    image: node:alpine
    user: "node"
    working_dir: /home/node/app
    environment:
      - NODE_ENV=production
    ports:
      - "3000:3000"
    volumes:
      - ./app:/home/node/app
      - ./node_modules:/home/node/node_modules
    expose:
      - "3000"
    command: "node app.js"
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Build, (re)create and start, the container in disconnected mode. The &lt;code&gt;app&lt;/code&gt; folder is attached as a volume and mapped to the working directory, &lt;code&gt;/home/node/app&lt;/code&gt; in the container. The &lt;code&gt;node app.js&lt;/code&gt; command is executed in the containers working directory.&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker-compose up -d
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Test the application locally in a browser at &lt;a href="http://localhost:3000"&gt;http://localhost:3000&lt;/a&gt;. Use Ctrl+C to kill the app after verifying it works.&lt;/p&gt;

&lt;p&gt;Stop and remove the container and volumes created by &lt;code&gt;docker-compose up&lt;/code&gt;.&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker-compose down
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Build a Docker image for better performance and deployment once initial development is completed. Instead of mapping the local &lt;code&gt;app&lt;/code&gt; and &lt;code&gt;node_modules&lt;/code&gt; folders to the container, copy files and folders into the container, set working directories and run commands as needed.&lt;/p&gt;

&lt;p&gt;Create this Dockerfile in the project root&lt;/p&gt;

&lt;h5&gt;
  
  
  Dockerfile
&lt;/h5&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM node:alpine
WORKDIR /home/node

# using wildcard (*) to copy both package.json and package-lock.json
COPY package*.json /home/node/
RUN yarn install --production

# create and set app directory as current dir
WORKDIR /home/node/app
COPY app/ /home/node/app/
EXPOSE 3000
CMD ["node", "app.js"]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Build the image and tag it. In the project root run the following command.&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker build -t myapp-node .
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Test the new &lt;code&gt;myapp-node&lt;/code&gt; Docker image using &lt;code&gt;docker run&lt;/code&gt;. Same URL as before, &lt;a href="http://localhost:3000"&gt;http://localhost:3000&lt;/a&gt;.&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker run -u node -w /home/node/app -e NODE_ENV=production -p 3000:3000 --expose 3000 myapp-node node "app.js"
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Stop the container using &lt;code&gt;docker stop&lt;/code&gt; followed by the container ID. To get a list of all running containers, use &lt;code&gt;docker ps --filter status=running&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That's it!&lt;/p&gt;

&lt;p&gt;This post originally published at &lt;a href="https://jimfrenette.com/docker/node-js-koa-container/"&gt;jimfrenette.com/docker/node-js-koa-container&lt;/a&gt;&lt;/p&gt;

</description>
      <category>node</category>
      <category>docker</category>
    </item>
    <item>
      <title>New Webpack Development Server Plugin</title>
      <dc:creator>Jim Frenette</dc:creator>
      <pubDate>Tue, 08 Oct 2019 13:02:11 +0000</pubDate>
      <link>https://dev.to/jimfrenette/new-webpack-development-server-plugin-512f</link>
      <guid>https://dev.to/jimfrenette/new-webpack-development-server-plugin-512f</guid>
      <description>&lt;p&gt;I always thought it was odd to use the &lt;code&gt;webpack-cli&lt;/code&gt; command &lt;code&gt;webpack-dev-server&lt;/code&gt; instead of &lt;code&gt;webpack&lt;/code&gt; in my npm script for development. Lo and behold, last month, &lt;code&gt;webpack-plugin-serve&lt;/code&gt; was released, a new webpack plugin to use instead of the quirky webpack-dev-server.&lt;/p&gt;

&lt;p&gt;I'm using the fairly basic split configuration from my &lt;a href="https://github.com/jimfrenette/uiCookbook/tree/master/sidebars"&gt;uiCookbook/sidebars&lt;/a&gt; application to demonstrate how to replace &lt;a href="https://github.com/webpack/webpack-dev-server"&gt;webpack-dev-server&lt;/a&gt; with the new &lt;a href="https://github.com/shellscape/webpack-plugin-serve"&gt;webpack-plugin-serve&lt;/a&gt; plugin&lt;/p&gt;

&lt;h4&gt;
  
  
  Requirements
&lt;/h4&gt;

&lt;p&gt;Active LTS &lt;a href="https://nodejs.org"&gt;Node&lt;/a&gt; version, e.g., version 8.0.0+ or version 10.0.0+. Read the &lt;a href="https://github.com/shellscape/webpack-plugin-serve"&gt;webpack-plugin-serve&lt;/a&gt; documentation for more info.&lt;/p&gt;

&lt;h3&gt;
  
  
  Demo Application
&lt;/h3&gt;

&lt;p&gt;Start by cloning or &lt;a href="https://github.com/jimfrenette/uiCookbook/archive/2018-09-sidebars.zip"&gt;downloading&lt;/a&gt; the uiCookbook repository containing the sidebars application. The following &lt;code&gt;git clone&lt;/code&gt; command uses the &lt;code&gt;--branch&lt;/code&gt; option to specify the &lt;code&gt;2018-09-sidebars&lt;/code&gt; tag. This tag represents the checksum version of the repo that predates the change to &lt;code&gt;webpack-plugin-serve&lt;/code&gt; in the current version of the app.&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# clone 2018-09-sidebars tag in uiCookbook repo
git clone https://github.com/jimfrenette/uiCookbook.git --branch=2018-09-sidebars

# change to sidebars directory    
cd uiCookbook/sidebars
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Before making any changes, make sure the application builds for you.&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# install node_modules    
npm i

# run dev build
npm run dev
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The web browser should open with the app loaded in localhost as shown below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--57JR94fN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/wi7xna4yd0mwbmycga0c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--57JR94fN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/wi7xna4yd0mwbmycga0c.png" alt="responsive sidebars in flexbox"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After confirming that the app builds and the dev server is running on localhost, cancel the running process with Ctrl + C.&lt;/p&gt;

&lt;h4&gt;
  
  
  Replace Packages
&lt;/h4&gt;

&lt;p&gt;Let's remove and replace the &lt;a href="https://docs.npmjs.com/packages-and-modules/"&gt;npm packages and modules&lt;/a&gt; from the application as follows.&lt;/p&gt;

&lt;p&gt;Replace the webpack development server. Additionally, remove the &lt;code&gt;write-file-webpack-plugin&lt;/code&gt; since it only works with &lt;code&gt;webpack-dev-server&lt;/code&gt;.&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm uninstall webpack-dev-server
npm uninstall write-file-webpack-plugin

# install webpack-plugin-serve --save-dev
npm i webpack-plugin-serve -D
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Replace the &lt;code&gt;webpack-cli&lt;/code&gt; with &lt;code&gt;webpack-nano&lt;/code&gt;. This new Webpack CLI is the optimal solution, it's super tiny (~90% smaller than webpack-cli and webpack-command) and allows unlimited custom flags. &lt;a href="https://github.com/shellscape/webpack-nano"&gt;more info&lt;/a&gt;&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm uninstall webpack-cli

# install webpack-nano --save-dev
npm i webpack-nano -D
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h4&gt;
  
  
  &lt;a href="https://docs.npmjs.com/cli/run-script"&gt;npm-run-script&lt;/a&gt;
&lt;/h4&gt;

&lt;p&gt;In the &lt;code&gt;package.json&lt;/code&gt; file, update the &lt;code&gt;scripts.dev&lt;/code&gt; and &lt;code&gt;scripts.build&lt;/code&gt; properties for &lt;code&gt;webpack-nano&lt;/code&gt; to run the builds. All applicable options, e.g., &lt;code&gt;mode&lt;/code&gt; and &lt;code&gt;watch&lt;/code&gt; will instead be added to the respective configuration files.&lt;/p&gt;
&lt;h5&gt;
  
  
  package.json
&lt;/h5&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt; ...

  "scripts": {
    "dev": "wp --config config/dev.config.js",
    "build": "wp --config config/prod.config.js",
    "test": "echo \"Error: no test specified\" &amp;amp;&amp;amp; exit 1"
  },
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;Note that the ellipsis &lt;code&gt;...&lt;/code&gt; in the code snippet above is not a part of the actual code and is there only to denote code that is being skipped and not applicable to the example. To view the entire file, examine the &lt;a href="https://github.com/jimfrenette/uiCookbook/tree/master/sidebars"&gt;source code&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Webpack Configuration
&lt;/h3&gt;

&lt;p&gt;Since the &lt;code&gt;write-file-webpack-plugin&lt;/code&gt; was removed, be sure to remove it from the config file.&lt;/p&gt;

&lt;h5&gt;
  
  
  dev.config.js
&lt;/h5&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// delete this line:
const writeFilePlugin = require('write-file-webpack-plugin');
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The configuration is split across three files located in the &lt;code&gt;config&lt;/code&gt; folder. The &lt;code&gt;base.config.js&lt;/code&gt; contains code common to both the &lt;code&gt;dev.config.js&lt;/code&gt; and &lt;code&gt;prod.config.js&lt;/code&gt; configurations. Start by adding the &lt;code&gt;const&lt;/code&gt; object to include the &lt;code&gt;webpack-plugin-serve&lt;/code&gt; module near the top of the &lt;code&gt;dev.config.js&lt;/code&gt; file where the other constants are defined. Under that, create a new instance of Serve named serve that contains our dev server options.&lt;/p&gt;

&lt;h5&gt;
  
  
  dev.config.js
&lt;/h5&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...

const { WebpackPluginServe: Serve } = require('webpack-plugin-serve');

const serve = new Serve({
  host: 'localhost',
  static: ['./'],
  open: true,
  liveReload: true
});    
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Next, update the &lt;code&gt;module.exports&lt;/code&gt; as follows. Note that we're setting the &lt;code&gt;mode&lt;/code&gt; and &lt;code&gt;watch&lt;/code&gt; flags here instead of our npm script.&lt;/p&gt;

&lt;h5&gt;
  
  
  dev.config.js
&lt;/h5&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...

module.exports = merge(baseConfig, {
  mode: 'development',
  devtool: 'eval-source-map',
  entry: {
    app: ['webpack-plugin-serve/client']
  },
  plugins: [
    serve
  ],
  watch: true
});
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Updated &lt;a href="https://github.com/jimfrenette/uiCookbook/blob/master/sidebars/config/dev.config.js"&gt;dev.config.js&lt;/a&gt; file.&lt;/p&gt;

&lt;p&gt;Next, in the &lt;code&gt;base.config.js&lt;/code&gt;, change the &lt;code&gt;entry.app&lt;/code&gt; property value into an array so &lt;code&gt;webpack-merge&lt;/code&gt; handles it properly since we added an &lt;code&gt;entry.app&lt;/code&gt; property to the &lt;code&gt;dev.config.js&lt;/code&gt; in the previous step.&lt;/p&gt;

&lt;h5&gt;
  
  
  base.config.js
&lt;/h5&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...

  entry: {
    app: ['./js/index.js']
 },    
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In the production build config, we're only adding &lt;code&gt;mode: 'production'&lt;/code&gt; to the &lt;code&gt;module.exports&lt;/code&gt;.&lt;/p&gt;

&lt;h5&gt;
  
  
  prod.config.js
&lt;/h5&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...

module.exports = merge(baseConfig, {
  mode: 'production',    
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;That's it. Run the dev build again, this time using the updated configuration.&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm run dev
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h5&gt;
&lt;i class="icon-github"&gt;&lt;/i&gt; &lt;a href="https://github.com/jimfrenette/uiCookbook/tree/master/sidebars"&gt;Source Code&lt;/a&gt;
&lt;/h5&gt;

&lt;h4&gt;
  
  
  Additional Resources
&lt;/h4&gt;

&lt;p&gt;&lt;span class="sprite-wrapper"&gt;&lt;i class="sprite react alignleft"&gt;&lt;/i&gt;&lt;/span&gt;&lt;br&gt;
&lt;a href="https://github.com/jimfrenette/minimal-react-webpack-babel-setup/tree/plugin-serve"&gt;The minimal React, Webpack, Babel Setup: using webpack-plugin-serve&lt;/a&gt; - Looking for a barebones React Webpack configuration that uses webpack-plugin-serve? Similar to the above, this fork of &lt;a href="https://www.robinwieruch.de/"&gt;Robin Wieruch&lt;/a&gt;'s boilerplate project on GitHub has been modified slightly to also use shellscape's new &lt;a href="https://github.com/shellscape/webpack-plugin-serve"&gt;webpack-plugin-serve&lt;/a&gt; along with their &lt;a href="https://github.com/shellscape/webpack-nano"&gt;webpack-nano&lt;/a&gt; CLI replacement. &lt;a href="https://github.com/jimfrenette/minimal-react-webpack-babel-setup/tree/plugin-serve"&gt;Source Code on GitHub&lt;/a&gt;&lt;br&gt;
&lt;span class="clearfix"&gt;&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Originally published at &lt;a href="https://jimfrenette.com/2018/12/new-webpack-development-server-plugin/"&gt;jimfrenette.com/2018/12/new-webpack-development-server-plugin&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webpack</category>
      <category>javascript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Xdebug for Mac OS X PHP</title>
      <dc:creator>Jim Frenette</dc:creator>
      <pubDate>Mon, 07 Oct 2019 12:35:46 +0000</pubDate>
      <link>https://dev.to/jimfrenette/xdebug-for-mac-os-x-php-3g9</link>
      <guid>https://dev.to/jimfrenette/xdebug-for-mac-os-x-php-3g9</guid>
      <description>&lt;p&gt;Follow these instructions for PHP provided with Mac OS X to &lt;code&gt;phpize&lt;/code&gt; Xdebug source, configure, build and install the PHP Xdebug extension.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  On Mac OS X Mojave, use the Xdebug extension included with the system in &lt;code&gt;/usr/lib/php/extensions/no-debug-non-zts-20160303&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://xdebug.org/download.php"&gt;Download&lt;/a&gt; the latest version of Xdebug.&lt;/p&gt;

&lt;p&gt;Verify that PHP is installed. e.g.,&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;php -v

# output
PHP 7.1.19 (cli) (built: Aug 17 2018 20:10:18) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.1.0, Copyright (c) 1998-2018 Zend Technologies
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Extract the downloaded Xdebug tarball as described in the earlier instructions above. e.g.,&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd ~/Downloads

mkdir xdebug
mv xdebug-2.6.1.tgz xdebug/

cd xdebug
tar xzf xdebug-2.6.1.tgz
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Run &lt;code&gt;phpize&lt;/code&gt; from within the extracted Xdebug source directory. e.g.,&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd xdebug-2.6.1

phpize
grep: /usr/include/php/main/php.h: No such file or directory
grep: /usr/include/php/Zend/zend_modules.h: No such file or directory
grep: /usr/include/php/Zend/zend_extensions.h: No such file or directory
Configuring for:
PHP Api Version:
Zend Module Api No:
Zend Extension Api No:
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If the Xcode commandline tools are not installed, &lt;code&gt;phpize&lt;/code&gt; outputs missing include file messages. You can install the Xcode commandline tools using the CLI. e.g.,&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;xcode-select --install
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If the Xcode commandline tools are already installed and/or you still get the missing include files message, force a reinstall of the commandline tools header files. e.g.,&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo installer -pkg /Library/Developer/CommandLineTools/Packages/macOS_SDK_headers_for_macOS_10.14.pkg -target /
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Retry running &lt;code&gt;phpize&lt;/code&gt; from within the extracted Xdebug source directory. e.g.,&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;phpize
Configuring for:
PHP Api Version:         20160303
Zend Module Api No:      20160303
Zend Extension Api No:   320160303
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Configure Xdebug.&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;./configure
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Build Xdebug.&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;make
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Starting with OS X 10.11 El Capitan, system files and processes are protected with System Integrity Protection (SIP). Since &lt;code&gt;/usr/lib/php/extensions&lt;/code&gt; write operations are not permitted with SIP enabled, install the Xdebug extension under the &lt;code&gt;/usr/local&lt;/code&gt;. e.g.,&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo mkdir -p /usr/local/php/extensions

sudo cp modules/xdebug.so /usr/local/php/extensions/
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Update the &lt;code&gt;/private/etc/php.ini&lt;/code&gt; file to load the Xdebug extension. e.g.,&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...

;;;;;;;;;;;;;;;;;;;;;;
; Dynamic Extensions ;
;;;;;;;;;;;;;;;;;;;;;;

...

zend_extension=/usr/lib/php/extensions/no-debug-non-zts-20160303/xdebug.so
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;  If &lt;code&gt;/private/etc/php.ini&lt;/code&gt; does not exist, PHP is using the default settings. Copy the &lt;code&gt;/private/etc/php.ini.default&lt;/code&gt; sample configuration file to &lt;code&gt;/private/etc/php.ini&lt;/code&gt; and update it to customize PHP settings.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Verify&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;php -i | grep xdebug

# expected output
xdebug
xdebug support =&amp;gt; enabled
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;If you get the following error message in the output, use the Xdebug extension provided with the system in &lt;code&gt;/usr/lib/php/extensions/no-debug-non-zts-20160303&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Failed loading /usr/local/php/extensions/xdebug.so:  dlopen(/usr/local/php/extensions/xdebug.so, 0x0009): code signature in (/usr/local/php/extensions/xdebug.so) not valid for use in process: mapped file has no cdhash, completely unsigned? Code has to be at least ad-hoc signed.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Remote Debugging
&lt;/h3&gt;

&lt;p&gt;Enable remote debugging by adding the following xDebug settings at or near the bottom of the &lt;code&gt;php.ini&lt;/code&gt; file.&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...

[XDebug]
xdebug.remote_enable = 1
xdebug.remote_autostart = 1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Originally published at &lt;a href="https://jimfrenette.com/2018/12/xdebug-for-mac-os-x-php/"&gt;jimfrenette.com/2018/12/xdebug-for-mac-os-x-php&lt;/a&gt;&lt;/p&gt;

</description>
      <category>php</category>
    </item>
    <item>
      <title>Responsive Content Filter JavaScript</title>
      <dc:creator>Jim Frenette</dc:creator>
      <pubDate>Mon, 30 Sep 2019 04:05:34 +0000</pubDate>
      <link>https://dev.to/jimfrenette/responsive-content-filter-javascript-345k</link>
      <guid>https://dev.to/jimfrenette/responsive-content-filter-javascript-345k</guid>
      <description>&lt;p&gt;This code sample shows how to create a responsive list filter using plain JavaScript (no jQuery). JavaScript gets the breakpoint value from a hidden css pseudo element that uses a media query to set its value. Therefore, it is not necessary to maintain rendundant responsive breakpoint values in the script.&lt;/p&gt;

&lt;p&gt;All of the code is available to &lt;a href="https://jimfrenette.com/code-editors/sandbox/responsive-filter-js"&gt;edit and demo&lt;/a&gt; in our online sandbox.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;a href="https://jimfrenette.com/code-editors/sandbox/responsive-filter-js"&gt;Demo&lt;/a&gt;
&lt;/h4&gt;

&lt;h5&gt;
  
  
  &lt;a href="https://jimfrenette.com/javascript/responsive-filter"&gt;jQuery version&lt;/a&gt;
&lt;/h5&gt;

</description>
      <category>css</category>
      <category>javascript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Images Larger than Container CSS
 </title>
      <dc:creator>Jim Frenette</dc:creator>
      <pubDate>Tue, 24 Sep 2019 11:51:59 +0000</pubDate>
      <link>https://dev.to/jimfrenette/title-images-larger-than-container-css-1j38</link>
      <guid>https://dev.to/jimfrenette/title-images-larger-than-container-css-1j38</guid>
      <description>&lt;p&gt;This will center the image inside of a element when the elements height and/or width is smaller than the image. This works well when you have image assets of various aspect ratios that you want to display as thumbs that are the same size.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;a href="https://jimfrenette.com/code-editors/sandbox/images-larger" rel="noopener noreferrer"&gt;demo&lt;/a&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Ftex9lz7beh7beo90n4gl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Ftex9lz7beh7beo90n4gl.png" alt="Screen capture of demo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h5&gt;
  
  
  HTML
&lt;/h5&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;ul&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"thumbnails"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://via.placeholder.com/400x300/9932CC/FFFFFF"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://via.placeholder.com/500x300/7FFFD4/000000"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://via.placeholder.com/300x200/87CEFA/000000"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://via.placeholder.com/300x400/F4A460/000000"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h5&gt;
  
  
  CSS
&lt;/h5&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;ul&lt;/span&gt;&lt;span class="nc"&gt;.thumbnails&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;flex-wrap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;wrap&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;ul&lt;/span&gt;&lt;span class="nc"&gt;.thumbnails&lt;/span&gt; &lt;span class="nt"&gt;li&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;150px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;4px&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt; &lt;span class="m"&gt;#FFF&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;overflow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;hidden&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;relative&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;150px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;ul&lt;/span&gt;&lt;span class="nc"&gt;.thumbnails&lt;/span&gt; &lt;span class="nt"&gt;li&lt;/span&gt; &lt;span class="nt"&gt;img&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;absolute&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;-9999px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;bottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;-9999px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;-9999px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;right&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;-9999px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;250px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Originally published at &lt;a href="https://jimfrenette.com/css/images-larger-than-container/" rel="noopener noreferrer"&gt;jimfrenette.com/css/images-larger-than-container&lt;/a&gt;&lt;/p&gt;

</description>
      <category>css</category>
      <category>webdev</category>
    </item>
    <item>
      <title>How To Create a WordPress Shortcode for flickr Albums</title>
      <dc:creator>Jim Frenette</dc:creator>
      <pubDate>Mon, 23 Sep 2019 12:01:00 +0000</pubDate>
      <link>https://dev.to/jimfrenette/how-to-create-a-wordpress-shortcode-for-flickr-albums-4mlp</link>
      <guid>https://dev.to/jimfrenette/how-to-create-a-wordpress-shortcode-for-flickr-albums-4mlp</guid>
      <description>&lt;p&gt;How to create a WordPress custom shortcode to display photos from flickr. This post documents using the &lt;a href="https://jimfrenette.com/2017/12/slick-lazy-load-photo-grid-webpack-3/"&gt;Slick Lazy Load Photo Grid&lt;/a&gt; along with the flickr API to render photo albums in Wordpress Posts wherever the shortcode is entered. &lt;a href="https://webpack.js.org/"&gt;Webpack&lt;/a&gt; 4, &lt;a href="https://github.com/postcss/autoprefixer"&gt;autoprefixer&lt;/a&gt;, and &lt;a href="https://babeljs.io/"&gt;babel&lt;/a&gt; are included for building the JS and CSS.&lt;/p&gt;

&lt;h4&gt;
  
  
  Requirements
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://www.flickr.com/services/api/"&gt;flickr API&lt;/a&gt; key. From their API page, select the Create an App link for more information on how to request an API key.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://nodejs.org"&gt;Node.js&lt;/a&gt; with NPM&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If you're looking for a local Wordpress development environment, may I suggest giving &lt;a href="https://github.com/wodby/docker4wordpress"&gt;docker4wordpress&lt;/a&gt; a try which I have written about in my post titled, &lt;a href="https://jimfrenette.com/2018/05/wordpress-from-development-to-production-using-docker/"&gt;WordPress from Development to Production using Docker&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Shortcode
&lt;/h3&gt;

&lt;p&gt;Creating a custom shortcode is done by adding PHP code to the theme &lt;code&gt;functions.php&lt;/code&gt; file. I prefer keeping my custon WordPress functions in separate files rather than lumping them all in the existing &lt;code&gt;functions.php&lt;/code&gt; file. To do this, create a &lt;code&gt;functions&lt;/code&gt; folder and add a new &lt;code&gt;slickflickr.php&lt;/code&gt; file to it.&lt;/p&gt;

&lt;p&gt;Add the following &lt;code&gt;php&lt;/code&gt; code to the &lt;code&gt;slickflickr.php&lt;/code&gt; file to register the custom &lt;code&gt;shortcode_handler&lt;/code&gt; function. Be sure to replace the example &lt;code&gt;$api_key&lt;/code&gt; value with your &lt;a href="https://www.flickr.com/services/api/"&gt;flickr API&lt;/a&gt; key.&lt;/p&gt;

&lt;h5&gt;
  
  
  slickflickr.php
&lt;/h5&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php
/**
 * Slick Flickr Album Shortcode
 *
 * @param array [photoset_id
 * example
 * [slickflickrshortcode photoset_id=72157685387149525]
 *
 * @return string Unordered list of images for lazy loading slick photo gallery
 *
 * url format reference:
 * https://www.flickr.com/services/api/misc.urls.html
 */
function slickflickr_shortcode_handler($args) {

    $xml = slickflickr_get_photoset($args['photoset_id']);

    ob_start();
  ?&amp;gt;
  &amp;lt;ul class="photogrid"&amp;gt;
  &amp;lt;?php
    foreach($xml-&amp;gt;photoset[0]-&amp;gt;photo as $photo) {
        echo '&amp;lt;li&amp;gt;&amp;lt;img data-src="https://farm' . $photo['farm'] . '.staticflickr.com/' . $photo['server'] . '/' . $photo['id'] . '_' . $photo['secret'] . '_b.jpg" alt="' . $photo['title'] . '" /&amp;gt;&amp;lt;/li&amp;gt;';
    }
    ?&amp;gt;
    &amp;lt;/ul&amp;gt;
    &amp;lt;?php
    return ob_get_clean();
}
add_shortcode( 'slickflickrshortcode',  'slickflickr_shortcode_handler' );

function slickflickr_curl($url) {
    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_HEADER, 0);
    $data = curl_exec($ch); // response
    curl_close($ch);
    return $data;
}

function slickflickr_get_photoset($photoset_id) {
    $results = null;
    $api_key = '1234a567bc89d101ef1ghij121314klm';
    $url = 'https://api.flickr.com/services/rest/?method=flickr.photosets.getPhotos&amp;amp;api_key=' . $api_key . '&amp;amp;photoset_id=' . $photoset_id . '&amp;amp;format=rest';
    $xml = new \SimpleXmlElement(slickflickr_curl($url));
    return $xml;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Reference: &lt;a href="https://codex.wordpress.org/Shortcode_API"&gt;WordPress Shortcode API&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At or near the bottom of the &lt;code&gt;functions.php&lt;/code&gt;, add this &lt;a href="http://php.net/manual/en/function.require.php"&gt;require&lt;/a&gt; statement to include the custom shortcode handler in the theme.&lt;/p&gt;

&lt;h5&gt;
  
  
  functions.php
&lt;/h5&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...

/**
* Slick flickr Shortcode Handler
*/
require get_parent_theme_file_path( '/functions/slickflickr.php' );
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;Note that the ellipsis &lt;code&gt;...&lt;/code&gt; in the code snippets throught this tutorial are not a part of the actual code and is there only to denote code that is being skipped and not applicable to the example.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Test the custom shortcode by entering the shortcode text in a post. For example, &lt;code&gt;[slickflickrshortcode photoset_id=72157685387149525]&lt;/code&gt;. When you &lt;code&gt;view-source&lt;/code&gt; for that post, you should see an unordered list with &lt;code&gt;img&lt;/code&gt; elements. The flickr album image URL's are added to the &lt;code&gt;img&lt;/code&gt; element &lt;code&gt;data-src&lt;/code&gt; attribute for lazy-loading. The styling and image lazy-loading is handled by CSS and JavaScript code that we will add to the WordPress theme in a subsequent section.&lt;/p&gt;




&lt;h3&gt;
  
  
  Theme
&lt;/h3&gt;

&lt;p&gt;For the front end, we need to bring the UI build process for the JavaScript and CSS into a WordPress theme. In this tutorial, I'm going to use a copy of the TwentySeventeen Theme that comes with WordPress along with my &lt;a href="https://github.com/jimfrenette/twentyseventeen-sass"&gt;TwentySeventeen Theme Sass&lt;/a&gt;. If you want a completely blank slate instead, you could use the _s theme I've written about &lt;a href="https://jimfrenette.com/2018/08/completely-blank-no-css-_s-wordpress-starter-theme"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Download or clone the &lt;a href="https://github.com/jimfrenette/twentyseventeen-sass"&gt;TwentySeventeen Theme Sass&lt;/a&gt; into the &lt;code&gt;mytwentyseventeen&lt;/code&gt; folder. If you have an existing theme, download the zip file from github instead, extract, and copy the &lt;code&gt;src&lt;/code&gt; folder into your theme.&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd wp-content/themes

git clone https://github.com/jimfrenette/twentyseventeen-sass.git mytwentyseventeen
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Copy all of the &lt;code&gt;twentyseventeen&lt;/code&gt; theme folders and files into the new &lt;code&gt;mytwentyseventeen&lt;/code&gt; theme.&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd wp-content/themes

cp -r twentyseventeen/ mytwentyseventeen/
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;On Windows? I have written about some Unix like command line interfaces for it including &lt;a href="https://jimfrenette.com/2018/04/wsl-ubuntu-zsh-nvm-etc/"&gt;WSL ubuntu zsh nvm etc.&lt;/a&gt;, and &lt;a href="https://jimfrenette.com/2017/02/cygwin-oh-my-zsh-recipe/"&gt;Cygwin Oh My ZSH Recipe&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  UI Build
&lt;/h3&gt;

&lt;p&gt;Since we're not using Gulp, delete &lt;code&gt;gulpfile.js&lt;/code&gt; and &lt;code&gt;package.json&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Create these files in the the new theme. We will edit them later. For example,&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd wp-content/themes/mytwentyseventeen

# create the .babelrc file
touch .babelrc

# create a new package.json file using npm
npm init

# create the postcss config
touch postcss.config.js
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h4&gt;
  
  
  NPM Packages
&lt;/h4&gt;

&lt;p&gt;Install NPM packages to transpile the Javascript and Sass using Webpack 4.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd wp-content/themes/mytwentyseventeen

npm i webpack webpack-cli webpack-merge --save-dev

npm i autoprefixer --save-dev

npm i babel-loader @babel/core @babel/preset-env --save-dev

npm i css-loader style-loader --save-dev

npm i mini-css-extract-plugin --save-dev

npm i node-sass sass-loader --save-dev

npm i optimize-css-assets-webpack-plugin --save-dev

npm i postcss-loader --save-dev

npm i resolve-url-loader url-loader --save-dev

npm i uglifyjs-webpack-plugin --save-dev
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h4&gt;
  
  
  Webpack 4 Configuration
&lt;/h4&gt;

&lt;p&gt;Create a webpack folder with three &lt;code&gt;config.js&lt;/code&gt; files.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd wp-content/themes/mytwentyseventeen

mkdir webpack

cd webpack

touch base.config.js

touch dev.config.js

touch prod.config.js
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;base.config.js&lt;/code&gt; file contains a configuration that is common to both dev and prod.&lt;/p&gt;

&lt;h5&gt;
  
  
  base.config.js
&lt;/h5&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const path = require('path');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");

module.exports = {
  context: path.resolve(__dirname, '../src'),
  entry: {
    app: './js/index.js'
  },
  output: {
    path: path.resolve(__dirname, '../dist')
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: "../style.css",
    })
  ],
  externals: {
    // require("jquery") is external and available
    // on the global var jQuery
    "jquery": "jQuery"
  },
  module: {
    rules: [
      {
        test: /\.(css|scss)$/,
        use: [
          MiniCssExtractPlugin.loader,
          'css-loader',
          {
            loader: 'postcss-loader' },
          {
            /* for ~slick-carousel/slick/slick-theme.scss */
            loader: 'resolve-url-loader' },
          {
            /* for resolve-url-loader:
                source maps must be enabled on any preceding loader */
            loader: 'sass-loader?sourceMap' }
        ]
      },
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: 'babel-loader'
      },
      { /* for ~slick-carousel/slick/slick-theme.scss */
        test: /\.(eot|woff|woff2|ttf|svg|png|jpg|gif)$/,
        loader: 'url-loader?limit=30000&amp;amp;name=[name]-[hash].[ext]'
      }
    ]
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;dev.config.js&lt;/code&gt; file contains only configuration settings specifically for development. The configuration settings in the &lt;code&gt;base.config.js&lt;/code&gt; file are combined with this dev configuration by &lt;code&gt;webpack-merge&lt;/code&gt;.&lt;/p&gt;

&lt;h5&gt;
  
  
  dev.config.js
&lt;/h5&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const merge = require('webpack-merge');
const baseConfig = require('./base.config.js');

module.exports = merge(baseConfig, {
  devtool: 'eval-source-map',
});
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;prod.config.js&lt;/code&gt; file contains only configuration settings specifically for the production build. The configuration settings in the &lt;code&gt;base.config.js&lt;/code&gt; file are also combined with this configuration by &lt;code&gt;webpack-merge&lt;/code&gt;.&lt;/p&gt;

&lt;h5&gt;
  
  
  prod.config.js
&lt;/h5&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const merge = require('webpack-merge');
const baseConfig = require('./base.config.js');
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");
const UglifyJsPlugin = require("uglifyjs-webpack-plugin");

module.exports = merge(baseConfig, {
  optimization: {
    minimizer: [
      new OptimizeCSSAssetsPlugin({})
    ]
  },
  plugins: [
    new UglifyJsPlugin({
      uglifyOptions: { output: { comments: false } }
    })
  ]
});
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Add the &lt;code&gt;presets&lt;/code&gt; property to the &lt;code&gt;.babelrc&lt;/code&gt; congfiguration file.&lt;/p&gt;

&lt;h5&gt;
  
  
  .babelrc
&lt;/h5&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "presets": ["@babel/preset-env"]
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Add this &lt;code&gt;plugins&lt;/code&gt; property to require the autoprefixer postcss plugin to the &lt;code&gt;postcss.config.js&lt;/code&gt; configuration file.&lt;/p&gt;

&lt;h5&gt;
  
  
  postcss.config.js
&lt;/h5&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;module.exports = {
  plugins: [
    require('autoprefixer')
  ]
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Add a &lt;code&gt;browserslist&lt;/code&gt; property to the &lt;code&gt;package.json&lt;/code&gt; file to inform our transpilers which browsers to support. Here, we're targeting browsers greater than 2% according to global usage statistics and Internet Explorer versions greater than 10.&lt;/p&gt;

&lt;h5&gt;
  
  
  package.json
&lt;/h5&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "name": "mytwentyseventeen",
  "version": "1.0.0",
  "description": "WordPress Twenty Seventeen Theme",
  "main": "index.js",
  "browserslist": [
    "&amp;gt; 2%",
    "last 2 versions",
    "ie &amp;gt; 10"
  ],

  ...
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In the &lt;code&gt;src&lt;/code&gt; folder, create a &lt;code&gt;js&lt;/code&gt; folder containing an &lt;code&gt;index.js&lt;/code&gt; entrypoint that imports the Sass.&lt;/p&gt;

&lt;h5&gt;
  
  
  index.js
&lt;/h5&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import style from '../sass/style.scss'
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h4&gt;
  
  
  &lt;a href="https://docs.npmjs.com/cli/run-script"&gt;npm-run-script&lt;/a&gt;
&lt;/h4&gt;

&lt;p&gt;In the &lt;code&gt;package.json&lt;/code&gt; file, add &lt;code&gt;dev&lt;/code&gt; and &lt;code&gt;prod&lt;/code&gt; properties to the &lt;code&gt;scripts&lt;/code&gt; object for running webpack.&lt;/p&gt;
&lt;h5&gt;
  
  
  package.json
&lt;/h5&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  ...

  "scripts": {
    "dev": "webpack --mode=development --watch --progress --colors --config webpack/dev.config.js",
    "build": "webpack --mode=production --progress --hide-modules --config webpack/prod.config.js",
    "test": "echo \"Error: no test specified\" &amp;amp;&amp;amp; exit 1"
  },

  ...
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;
  
  
  Lazy Load Album Images
&lt;/h3&gt;

&lt;p&gt;This technique defers downloading of the images making the page load faster.&lt;/p&gt;

&lt;p&gt;Inside the &lt;code&gt;src/js&lt;/code&gt;, create a &lt;code&gt;lazyimage.js&lt;/code&gt; module file.&lt;/p&gt;
&lt;h5&gt;
  
  
  lazyimage.js
&lt;/h5&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export default class Lazyimage {
  constructor(options) {

      this.init();
  }

  init() {

      [].forEach.call(document.querySelectorAll('img[data-src]'), function(img) {
          img.setAttribute('src', img.getAttribute('data-src'));
          img.onload = function() {
              img.removeAttribute('data-src');
          };
      });
  }

}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;To import the &lt;code&gt;Lazyimage&lt;/code&gt; class from the module, add this code to the &lt;code&gt;src/js/index.js&lt;/code&gt; file.&lt;/p&gt;

&lt;h5&gt;
  
  
  index.js
&lt;/h5&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...

import Lazyimage from './lazyimage'

new Lazyimage();
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Inside the &lt;code&gt;src/sass&lt;/code&gt; folder, create a &lt;code&gt;_photogrid.scss&lt;/code&gt; and a &lt;code&gt;_lazyimage.scss&lt;/code&gt; file. The Sass partial filenames have leading underscore to indicate they only get processed when imported.&lt;/p&gt;

&lt;h5&gt;
  
  
  _photogrid.scss
&lt;/h5&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ul.photogrid {
  margin: 0.5vw 0.5vw 0.5vw -0.5vw;
  font-size: 0;
  flex-flow: row wrap;
  display: flex;

  li {
    flex: auto;
    width: 200px;
    margin: 0.5vw;
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h5&gt;
  
  
  _lazyimage.scss
&lt;/h5&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;img {
  opacity: 1;
  transition: opacity 0.3s;
}

img[data-src] {
  opacity: 0;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Update &lt;code&gt;src/sass/style.scss&lt;/code&gt; to import the Sass partials.&lt;/p&gt;

&lt;h5&gt;
  
  
  style.scss
&lt;/h5&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...

@import "photogrid";
@import "lazyimage";
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h4&gt;
  
  
  Run the Build
&lt;/h4&gt;

&lt;p&gt;One sec, we need to link the &lt;code&gt;dist/app.js&lt;/code&gt; that is going to be built in the theme footer. Add a script element before the closing &lt;code&gt;body&lt;/code&gt; tag.&lt;/p&gt;
&lt;h5&gt;
  
  
  footer.php
&lt;/h5&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...

&amp;lt;script async src="/wp-content/themes/mytwentyseventeen/dist/app.js"&amp;gt;&amp;lt;/script&amp;gt;

&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Before moving onto the lightbox and Slick slider Sass and JavaScript code, run the build to verify that everything is styled and working properly.&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm run build
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If all looks good after clearing the cache, run the development build to watch for changes and build incrementally when the remaining lightbox and slider code is added.&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm run dev
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;
  
  
  Slick Slider Lightbox
&lt;/h3&gt;

&lt;p&gt;Install &lt;a href="http://kenwheeler.github.io/slick/"&gt;Slick&lt;/a&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm i slick-carousel --save
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Inside the &lt;code&gt;src/js&lt;/code&gt;, create a &lt;code&gt;lightbox.js&lt;/code&gt; module file.&lt;/p&gt;

&lt;h5&gt;
  
  
  lightbox.js
&lt;/h5&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import $ from 'jquery'
import 'slick-carousel'

export default class Lightbox {
  constructor(options) {
    this.settings = $.extend({/* defaults */}, options);
    this.init();
  }

  init() {
    let source = $(this.settings.source);

    if (source.length) {
      source.each((index, el) =&amp;gt; {
        this.create(index, el);
      });
    }
  }

  create(index, el) {
    let lightbox = this.settings.name + '__' + index,
    opener = $(el).find(this.settings.opener);

    $('body').append('&amp;lt;div data-lightbox="' + lightbox + '" class="lightbox"&amp;gt;&amp;lt;div&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/div&amp;gt;');
    if (this.settings.type === 'slider') {
      $('div[data-lightbox="' + lightbox + '"] &amp;gt; div')
        .append('&amp;lt;div class="lightbox-slider"&amp;gt;&amp;lt;/div&amp;gt;');

      var slider = $('div[data-lightbox="' + lightbox + '"] .lightbox-slider');
      slider.slick({
        dots: true
      });

      opener.each((index, el) =&amp;gt; {
        this.popSlider(lightbox, slider, el);
      });
    }

    // close button
    $('div[data-lightbox="' + lightbox + '"] &amp;gt; div')
      .prepend('&amp;lt;a class="lightbox-close" href="javascript:void(0)"&amp;gt;+&amp;lt;/a&amp;gt;');

    $('.lightbox-close').on( 'click', function() {
      $('[data-lightbox="' + lightbox + '"]').removeClass('is-open');
    });

    //close on outside click
    window.onclick = function(evt) {
      if (evt.target.dataset.lightbox == lightbox) {
        $('[data-lightbox="' + lightbox + '"]').removeClass('is-open');
      }
    }

    // close on escape
    $(document).keyup(function(evt) {
      if (evt.which === 27) {
        $('[data-lightbox="' + lightbox + '"]').removeClass('is-open');
      }
    });
  }

  popSlider(lightbox, slider, el) {
    let img = $(el).find('img'),
        src = img.prop('src'),
        slide = document.createElement('div'),
        slideImg = document.createElement('img');

    slideImg.src = src;
    slide.appendChild(slideImg);

    if (img.attr('alt')) {
      let caption = document.createElement('p'),
      captionText = document.createTextNode(img.attr('alt'));
      caption.appendChild(captionText);
      slide.appendChild(caption);
    }

    slider.slick('slickAdd', slide);

    img.wrap('&amp;lt;a href="' + src + '"&amp;gt;&amp;lt;/a&amp;gt;').on( 'click', function(evt) {
      evt.preventDefault();
      $('[data-lightbox="' + lightbox + '"]').addClass('is-open');
      let index = $(this).closest(el).index();
      slider.slick('slickGoTo', index);
    });
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Update the &lt;code&gt;src/js/index.js&lt;/code&gt; to import the &lt;code&gt;Lightbox&lt;/code&gt; class from the module.&lt;/p&gt;

&lt;h5&gt;
  
  
  index.js
&lt;/h5&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import style from '../sass/style.scss'
import Lazyimage from './lazyimage'
import Lightbox from './lightbox'

new Lazyimage();

new Lightbox({
  name: 'lightbox',
  source: '.photogrid',
  opener: 'li',
  type: 'slider'
});
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Inside the &lt;code&gt;src/sass&lt;/code&gt; folder, create a &lt;code&gt;_lightbox.scss&lt;/code&gt;&lt;/p&gt;

&lt;h5&gt;
  
  
  _lightbox.scss
&lt;/h5&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/* overlay (background) */
.lightbox {
  max-height: 0; /* instead of `display: none` so slider can init properly. */

  position: fixed; /* stay in place */
  z-index: 9;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  overflow: auto; /* enable scroll if needed */
  background-color: rgb(0,0,0); /* fallback color */
  background-color: rgba(0,0,0,0.80); /* black w/ opacity */

  &amp;gt; div {
    position: relative;
    background-color: rgb(0,0,0);
    padding: 20px;
    color: #fff;
    //width: 100%; /* could be more or less, depending on screen size */
    width: 90vw;
    margin: 5vw auto;

    .slick-prev,
    .slick-next {
      z-index: 10;
    }
    .slick-prev {
      left: -20px;
    }
    .slick-next {
      right: -20px;
    }
    .slick-dots {
      li button:before {
        color: #fff;
      }
    }
  }

  &amp;amp;.is-open {
    max-height: 100%; /* unhide */
  }

  @media only screen and (max-width: 600px) {
    background-color: rgba(0,0,0,0.95); /* black w/ opacity */

    &amp;gt; div {
      padding: 40px 0 20px 0;
      width: 100vw;
      margin: 0 auto;

      .slick-slide p {
        padding: 0 15px;
      }

      .slick-next, .slick-prev {
        display: none;
      }
    }
  }

  @media only screen and (min-width: 1025px) {
    &amp;gt; div {
      max-width: 1024px;
    }
  }
}

/* close button */
.lightbox-close {
  position: absolute;
  top: 2px;
  right: 2px;
  text-align: center;
  line-height: 20px;
  font-size: 20px;
  font-weight: bold;
  color: rgba(255,255,255,0.75);
  width: 20px;
  height: 20px;
  transform: rotate(45deg);
  text-decoration: none;
  z-index: 10;

  &amp;amp;:hover {
    color: rgb(255,255,255);
  }

  @media only screen and (max-width: 600px) {
    top: 4px;
    right: 4px;
    line-height: 32px;
    font-size: 32px;
    width: 32px;
    height: 32px;
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Update &lt;code&gt;src/sass/style.scss&lt;/code&gt; adding the &lt;code&gt;lightbox&lt;/code&gt; and slick-carousel imports.&lt;/p&gt;

&lt;h5&gt;
  
  
  style.scss
&lt;/h5&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...

@import "photogrid";
@import "lazyimage";
@import "lightbox";

/* node_modules */
@import "~slick-carousel/slick/slick.scss";
@import "~slick-carousel/slick/slick-theme.scss";
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;For a complete listing of the source files that have been created or updated, I advise you to examine the &lt;a href="https://github.com/jimfrenette/slickflickrshortcode"&gt;source code repository&lt;/a&gt; on GitHub.&lt;/p&gt;

&lt;h5&gt;
&lt;i class="icon-github"&gt;&lt;/i&gt; &lt;a href="https://github.com/jimfrenette/slickflickrshortcode"&gt;Source Code&lt;/a&gt;
&lt;/h5&gt;

&lt;p&gt;Originally posted at &lt;a href="https://jimfrenette.com/2018/11/how-to-create-wordpress-shortcode-for-flickr-albums/"&gt;jimfrenette.com/2018/11/how-to-create-wordpress-shortcode-for-flickr-albums&lt;/a&gt;&lt;/p&gt;

</description>
      <category>wordpress</category>
      <category>css</category>
      <category>javascript</category>
      <category>webpack</category>
    </item>
    <item>
      <title>CSS Responsive Hotspots</title>
      <dc:creator>Jim Frenette</dc:creator>
      <pubDate>Sun, 22 Sep 2019 15:52:02 +0000</pubDate>
      <link>https://dev.to/jimfrenette/css-responsive-hotspots-1j25</link>
      <guid>https://dev.to/jimfrenette/css-responsive-hotspots-1j25</guid>
      <description>&lt;p&gt;This code sample shows how to create hotspots for a responsive image entirely in CSS and HTML. When the image scales according to changes in viewport width, the hotspots and their respective tool tips will move accordingly.&lt;/p&gt;

&lt;p&gt;Originally published at &lt;a href="https://jimfrenette.com/css/responsive-hotspots/" rel="noopener noreferrer"&gt;jimfrenette.com/css/responsive-hotspots&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://jimfrenette.com/code-editors/sandbox/responsive-hotspots/" title="Demo and edit in our sandbox" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fs1h55ebp3d2cg1rb4l6v.jpg" alt="Photo of my dog with the hotspots and active tooltip"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://jimfrenette.com/code-editors/sandbox/responsive-hotspots/" rel="noopener noreferrer"&gt;Demo and edit in our sandbox&lt;/a&gt;&lt;/p&gt;

&lt;h5&gt;
  
  
  HTML
&lt;/h5&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"hotspot-demo-1"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"hotspot-demo-1-left"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/images/2015/05/kingston.jpg"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"spots"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"spot-01"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"spot"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;+&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;blockquote&amp;gt;&lt;/span&gt;These are my dog tags
                    &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"notch notch-right"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;/blockquote&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"spot-02"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"spot"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;+&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;blockquote&amp;gt;&lt;/span&gt;I am loyal and love my humans 
                    &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"notch notch-top"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;/blockquote&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"spot-03"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"spot"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;+&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;blockquote&amp;gt;&lt;/span&gt;My coat has brindle in it
                    &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"notch notch-left"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;/blockquote&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h5&gt;
  
  
  CSS
&lt;/h5&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;
&lt;span class="nt"&gt;blockquote&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;relative&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;none&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;text-align&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;line-height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.5em&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#fff&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;0.7&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;blockquote&lt;/span&gt; &lt;span class="nc"&gt;.notch&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;absolute&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;blockquote&lt;/span&gt; &lt;span class="nc"&gt;.notch-top&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;-10px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;50%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;margin-left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;-10px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;border-top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;border-right&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10px&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt; &lt;span class="nb"&gt;transparent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;border-bottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10px&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;0.7&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nl"&gt;border-left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10px&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt; &lt;span class="nb"&gt;transparent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;blockquote&lt;/span&gt; &lt;span class="nc"&gt;.notch-right&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;50%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;right&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;-10px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;margin-top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;-10px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;border-top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10px&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt; &lt;span class="nb"&gt;transparent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;border-right&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;border-bottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10px&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt; &lt;span class="nb"&gt;transparent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;border-left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10px&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;0.7&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;blockquote&lt;/span&gt; &lt;span class="nc"&gt;.notch-bottom&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;bottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;-10px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;50%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;margin-left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;-10px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;border-top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10px&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;0.7&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nl"&gt;border-right&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10px&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt; &lt;span class="nb"&gt;transparent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;border-bottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;border-left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10px&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt; &lt;span class="nb"&gt;transparent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;blockquote&lt;/span&gt; &lt;span class="nc"&gt;.notch-left&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;50%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;-10px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;margin-top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;-10px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;border-top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10px&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt; &lt;span class="nb"&gt;transparent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;border-right&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10px&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;0.7&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nl"&gt;border-bottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10px&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt; &lt;span class="nb"&gt;transparent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;border-left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;img&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;block&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.hotspot-demo-1-left&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;relative&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;50%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.spots&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;absolute&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.spot&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;absolute&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;text-align&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;line-height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;32px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;32px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;font-weight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bold&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#fff&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;32px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;32px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1px&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt; &lt;span class="m"&gt;#5FB404&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;16px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#5FB404&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.spot&lt;/span&gt;&lt;span class="nd"&gt;:hover&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;-webkit-transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;rotate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;45deg&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nl"&gt;-moz-transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;rotate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;45deg&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nl"&gt;-ms-transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;rotate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;45deg&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nl"&gt;-o-transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;rotate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;45deg&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nl"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;rotate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;45deg&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nf"&gt;#spot-01&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;#spot-02&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;#spot-03&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;inline-block&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;min-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;250px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;   
&lt;span class="nf"&gt;#spot-01&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;absolute&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;65%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;78%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nf"&gt;#spot-01&lt;/span&gt;&lt;span class="nd"&gt;:hover&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;blockquote&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;block&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;-16px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;-91%&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nf"&gt;#spot-02&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;absolute&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;28%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;57%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nf"&gt;#spot-02&lt;/span&gt;&lt;span class="nd"&gt;:hover&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;blockquote&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;block&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;36px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;-43%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nf"&gt;#spot-03&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;absolute&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;45%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;20%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nf"&gt;#spot-03&lt;/span&gt;&lt;span class="nd"&gt;:hover&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;blockquote&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;block&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;-16px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;18px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>css</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
