<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>
      Alex T.
      </title>
    <link>https://htr3n.github.io/</link>
    <description>
      Recent content on Alex T.
    </description>
    <generator>Hugo -- gohugo.io</generator>
    
      <language>en</language>
    
    
    
    
    
      <lastBuildDate>Fri, 22 Mar 2024 00:00:00 +0000</lastBuildDate>
    
    
	    <atom:link href="https://htr3n.github.io/index.xml" rel="self" type="application/rss+xml" />
    
    
      <item>
        <title>Bringing Maven and AWS CodeArtifact Together</title>
        <link>https://htr3n.github.io/2024/03/maven-aws-code-artifact/</link>
        <pubDate>Fri, 22 Mar 2024 00:00:00 +0000</pubDate>
        
        <guid>35f6d6cea94fe7c83a44c9f05ea6b1d7</guid>
        <description>&lt;p&gt;As a part of migrating our infrastructure fo AWS, we use CodeArtifact for hosting and caching Maven dependencies as well as mirroring the external repositories. Setting up CodeArtifact repositories is not too difficult, but making it work with Maven in a local environemnt is very chalengging due to a lot of AWS security constrains. In this post, I would like to share some experience and ideas on harmonising Maven and CodeArtifact when setting up my working environment.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s assume that &lt;a href=&#34;https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html&#34;&gt;AWS CLI v2&lt;/a&gt; has been installed&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ aws --version
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;aws-cli/2.15.30 Python/3.11.8 Linux/6.5.0-26-generic exe/x86_64.ubuntu.23 prompt/off
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;and there is an AWS profile &lt;code&gt;dev&lt;/code&gt; configured properly in &lt;code&gt;~/.aws/config&lt;/code&gt;. This is an example AWS profile using the new AWS SSO:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ini&#34; data-lang=&#34;ini&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;[profile dev]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;sso_session&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;dev-sso&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;sso_account_id&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;0123456789&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;sso_role_name&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;Developer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;region&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;ap-southeast-2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;output&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;json&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;[sso-session dev-sso]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;sso_region&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;ap-southeast-2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;sso_start_url&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;https://d-9876543210.awsapps.com/start&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That is, if we test the account with &lt;code&gt;aws sts get-caller-identity&lt;/code&gt;, it returns a good response&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ aws sts get-caller-identity --profile dev
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;UserId&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;.....&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Account&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;....&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Arn&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;arn:aws:sts::...&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then we need &lt;a href=&#34;https://maven.apache.org&#34;&gt;Apache Maven&lt;/a&gt; version 3.6 or later.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ mvn --version
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Apache Maven 3.8.8 &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;4c87b05d9aedce574290d1acc98575ed5eb6cd39&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;aws-codeartifact-repositories&#34;&gt;AWS CodeArtifact Repositories&lt;/h2&gt;
&lt;p&gt;Let&amp;rsquo;s also assume that, we set up a CodeArtifact repository with details can be found via AWS Web console, then a repository of the owner  &lt;code&gt;0123456789&lt;/code&gt; as summarized below:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Region: &lt;code&gt;ap-southeast-2&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Owner: &lt;code&gt;0123456789&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Domain: &lt;code&gt;company-repositories&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So the repository URL would be &lt;code&gt;https://company-repositories-0123456789.d.codeartifact.ap-southeast-2.amazonaws.com/maven/dev/&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&#34;apache-maven-settings&#34;&gt;Apache Maven Settings&lt;/h2&gt;
&lt;p&gt;By default, Maven will look for a file &lt;code&gt;settings.xml&lt;/code&gt; in its installation directory &lt;code&gt;${maven.home}/conf/&lt;/code&gt; or the current&amp;rsquo;s user home directory &lt;code&gt;~/.m2&lt;/code&gt;. You can also explicitly specify a settings file using &lt;code&gt;mvn -s path/to/settings.xml&lt;/code&gt; but that&amp;rsquo;s another story. It&amp;rsquo;s safe to assume we use the &lt;code&gt;~/.m2/settings.xml&lt;/code&gt; file with the content as below (the XML namespaces are removed for readability)&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-xml&#34; data-lang=&#34;xml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;settings&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;profiles&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;profile&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;id&amp;gt;&lt;/span&gt;default&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/id&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;repositories&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;repository&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;id&amp;gt;&lt;/span&gt;dev-repo&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/id&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;url&amp;gt;&lt;/span&gt;https://company-repositories-0123456789.d.codeartifact.ap-southeast-2.amazonaws.com/maven/dev/&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/url&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;layout&amp;gt;&lt;/span&gt;default&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/layout&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/repository&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/repositories&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/profile&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/profiles&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;&amp;lt;!-- Authentication part --&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;servers&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;server&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;id&amp;gt;&lt;/span&gt;dev-repo&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/id&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;username&amp;gt;&lt;/span&gt;aws&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/username&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;password&amp;gt;&lt;/span&gt;${env.CODEARTIFACT_AUTH_TOKEN}&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/password&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/server&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/servers&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;activeProfiles&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;activeProfile&amp;gt;&lt;/span&gt;default&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/activeProfile&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/activeProfiles&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/settings&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;These settings can also be taken from CodeArtifact instructions. Just open AWS Web console, go to CodeArtifact, choose the corresponding repository then &amp;ldquo;View connection instructions&amp;rdquo;. In the pop-up dialog, choose &amp;ldquo;Maven mvn&amp;rdquo; as package manager client, then copy Step 4, 5, and 6 (optional for mirroring) to the corresponding section of &lt;code&gt;~/.m2/settings.xml&lt;/code&gt; as above.&lt;/p&gt;
&lt;h3 id=&#34;codeartifact-authentication&#34;&gt;CodeArtifact Authentication&lt;/h3&gt;
&lt;p&gt;In order to fetch Maven resources from CodeArtifact, we must set up the &lt;code&gt;&amp;lt;server&amp;gt;&lt;/code&gt; section, in which the &lt;code&gt;&amp;lt;username&amp;gt;&lt;/code&gt;, by CodeArtifact convention, must be &lt;code&gt;aws&lt;/code&gt;. The &lt;code&gt;&amp;lt;password&amp;gt;&lt;/code&gt; element must contain a Base64 encoded authentication token generated by the following AWS CLI command:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;aws codeartifact get-authorization-token &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;  --domain &amp;lt;repo_domain&amp;gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;  --domain-owner &amp;lt;domain_owner_id&amp;gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;  --region &amp;lt;region&amp;gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;  --query authorizationToken &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;  --output text
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Using shell script syntax, we can create an environment variable &lt;code&gt;CODEARTIFACT_AUTH_TOKEN&lt;/code&gt;, assign it with the token, and expose it to be used by Maven. Please note that, we need to specify the AWS profile &lt;code&gt;dev&lt;/code&gt;, too.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;export CODEARTIFACT_AUTH_TOKEN&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;aws codeartifact --profile dev get-authorization-token &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;  --domain company-repositories &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;  --domain-owner &lt;span style=&#34;color:#ae81ff&#34;&gt;0123456789&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;  --region ap-southeast-2 &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;  --query authorizationToken &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;  --output text&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;After that, we can run any Maven commands and Maven will use the generated &lt;code&gt;CODEARTIFACT_AUTH_TOKEN&lt;/code&gt; variable, respectively. Otherwise, you will see an error message with the code &lt;code&gt;Unauthorized (401)&lt;/code&gt;.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;[WARNING] Could not transfer metadata ... from/to dev-repo (https://company-repositories-0123456789.d.codeartifact.ap-southeast-2.amazonaws.com/maven/dev/): status code: 401, reason phrase: Unauthorized (401)
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;problems--solutions&#34;&gt;Problems &amp;amp; Solutions&lt;/h2&gt;
&lt;p&gt;In summary, after completing the configuration, there are few steps to enable Maven access to CodeArtifact repository.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;AWS authentication: This step is required when using AWS SSO (recommended). In case you use the legacy credentials-based configuration, this step can be skipped.&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ aws sso login --sso-session dev-session
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Attempting to automatically open the SSO authorization page in your default browser.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Successfully logged into Start URL: https://d-9876543210.awsapps.com/start
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol start=&#34;2&#34;&gt;
&lt;li&gt;Generate the token and assign to the environment variable &lt;code&gt;CODEARTIFACT_AUTH_TOKEN&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;export CODEARTIFACT_AUTH_TOKEN&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;...&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol start=&#34;3&#34;&gt;
&lt;li&gt;Now we can run Maven commands, e.g. &lt;code&gt;mvn install&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;There would be no problem at all if the CodeArtifact authentication token does not have an expiry time. A token is only valid, by default, for 12 hours (perhaps enough for a working day 😅). You would need a new token after that. It would not be a big issue if you work solely with the command line all the time. You just have to ensure AWS session is not expired and repeat Step 2 to get a new token.&lt;/p&gt;
&lt;p&gt;However, it&amp;rsquo;s very common that we devs are often using some Java IDEs, such as Eclipse, IntelliJ IDEA for development and testing. The IDEs often bundle their own version of Apache Maven but still use the settings file &lt;code&gt;~/.m2/settings.xml&lt;/code&gt; if not specified otherwise.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;idea-maven.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;Here comes the tricky part. How can an IDE pick up a valid environment variable &lt;code&gt;CODEARTIFACT_AUTH_TOKEN&lt;/code&gt;  to ensure their built-in Maven work with CodeArtifact? We can be creative and write a wrapper script that generates the token before launching our favourite IDE. The IDE will pick up the token at startup time. Unfortunately, there are no easy ways to feed a running process with a new value of that variable when it expires. That means we might have to close the IDE app and open it again 😢.&lt;/p&gt;
&lt;p&gt;There might be some third-party add-ons, for instance, &lt;a href=&#34;https://plugins.jetbrains.com/plugin/16777-aws-codeartifact--maven&#34;&gt;AWS CodeArtifact + Maven&lt;/a&gt; for IntelliJ IDEA, that can update &lt;code&gt;~/.m2/settings.xml&lt;/code&gt;  with the token as shown below:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;idea-plugin.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;Using the plugin is very convenient when we are working a lot or solely with the IDE and do not have to leave or restart it to pick up a new token.  It can be combined with the &lt;a href=&#34;https://plugins.jetbrains.com/plugin/11349-aws-toolkit&#34;&gt;AWS Toolkit&lt;/a&gt; plugin to manage AWS SSO profiles so that you don&amp;rsquo;t have to leave the IDE for (re)authentication.&lt;/p&gt;
&lt;p&gt;In case of a mixed working environment of IDE and Maven CLI, it becomes less convenient as you would have to turn to the IDE plugin to update the token. For instance, I don&amp;rsquo;t build with the IDE built-in Maven often as they are struggling with large Java projects. Most of my Java builds are done via Maven CLI. The IDE is merely for code editing and debugging.&lt;/p&gt;
&lt;p&gt;Even worse in case the IDE Maven and Maven CLI share the same &lt;code&gt;settings.xml&lt;/code&gt;, it won&amp;rsquo;t work well because the plugin will replace the part &lt;code&gt;${env.CODEARTIFACT_AUTH_TOKEN}&lt;/code&gt; in &lt;code&gt;settings.xml&lt;/code&gt; with the actual token whilst Maven CLI expects &lt;code&gt;&amp;lt;password&amp;gt;${env.CODEARTIFACT_AUTH_TOKEN}&amp;lt;/password&amp;gt;&lt;/code&gt; to be intact.&lt;/p&gt;
&lt;p&gt;There are two potential solutions for a mixed environment like that.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Create a wrapper that takes care of obtaining the token before actually executing Maven CLI. Then we can use it for both IDE and CLI. For instance, IntelliJ IDEA lets us choose our own Maven.&lt;/li&gt;
&lt;li&gt;Create a script to obtain the token and replace the content of the element &lt;code&gt;&amp;lt;password&amp;gt;...&amp;lt;/password&amp;gt;&lt;/code&gt; in &lt;code&gt;settings.xml&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The biggest advantage of these solutions is that you don&amp;rsquo;t have to rely on IDE plugins and they work well for both IDE&amp;rsquo;s Maven and CLI.&lt;/p&gt;
&lt;h3 id=&#34;maven-cli-wrapper&#34;&gt;Maven CLI Wrapper&lt;/h3&gt;
&lt;p&gt;We can create a simple wrapper, namely, &lt;code&gt;mvn-wrapper&lt;/code&gt; for Maven CLI as following.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#!/usr/bin/env bash
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; ! command -v aws &amp;gt;/dev/null 2&amp;gt;&amp;amp;1; &lt;span style=&#34;color:#66d9ef&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;The command &amp;#39;aws&amp;#39; not found, you must install AWS CLI v2.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  exit &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; ! env | grep -i &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;^AWS_ACCESS_KEY_ID&amp;#39;&lt;/span&gt; &amp;gt;/dev/null 2&amp;gt;&amp;amp;1; &lt;span style=&#34;color:#66d9ef&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; ! env | grep -i &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;^AWS_PROFILE&amp;#39;&lt;/span&gt; &amp;gt;/dev/null 2&amp;gt;&amp;amp;1; &lt;span style=&#34;color:#66d9ef&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;AWS credentials are not available and AWS_PROFILE is not set.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;You must either login using &amp;#39;aws sso login --profile &amp;lt;profile_name&amp;gt;&amp;#39;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;or use &amp;#39;AWS_PROFILE=&amp;lt;profile_name&amp;gt; &lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;basename -- $0&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    exit &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Generating CODEARTIFACT_AUTH_TOKEN ...&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;export CODEARTIFACT_AUTH_TOKEN&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;aws codeartifact &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;  get-authorization-token &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;   --output text &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;  --query authorizationToken &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;  --domain &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;DOMAIN&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;  --domain-owner &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;OWNER&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;[[&lt;/span&gt; -n &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$CODEARTIFACT_AUTH_TOKEN&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;]]&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  mvn &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$*&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Failed to generate CodeArtifact authentication token&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  exit &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The wrapper checks for the AWS CLI &lt;code&gt;aws&lt;/code&gt;, then verifies whether the AWS access key or profile is provided. If everything is okay, it will generate the token and call the actuall Maven CLI with the arguments &lt;code&gt;mvn &amp;quot;$*&amp;quot;&lt;/code&gt;. Just to make sure it&amp;rsquo;s executable&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;chmod +x mvn-wrapper
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then, you can use it in place of &lt;code&gt;mvn&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ DOMAIN&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;company-repositories&amp;#39;&lt;/span&gt; OWNER&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;0123456789&amp;#39;&lt;/span&gt; AWS_PROFILE&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;dev ./mvn-wrapper compile
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Generating CODEARTIFACT_AUTH_TOKEN ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;INFO&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; Scanning &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; projects...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;INFO&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;INFO&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; -------------------&amp;lt; com.example:hello &amp;gt;--------------------
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;INFO&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; Building hello 0.0.1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;INFO&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;   from pom.xml
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;INFO&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; --------------------------------&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt; war &lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;---------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;INFO&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;INFO&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; --- resources:3.3.1:resources &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;default-resources&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; @ hello ---
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;INFO&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; Copying &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; resource from src/main/resources to target/classes
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;INFO&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;INFO&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; --- compiler:3.8.1:compile &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;default-compile&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; @ hello ---
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;INFO&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; Nothing to compile - all classes are up to date
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;INFO&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; ------------------------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;INFO&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; BUILD SUCCESS
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;INFO&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; ------------------------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;INFO&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; Total time:  0.413 s
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;INFO&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; Finished at: 2024-03-23T10:44:21+11:00
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you use Maven mostly with the aforementioned CodeArtifact repository, you can hard code the value of &lt;code&gt;AWS_PROFILE&lt;/code&gt;,  &lt;code&gt;DOMAIN&lt;/code&gt;, and &lt;code&gt;OWNER&lt;/code&gt; within &lt;code&gt;mvn-wrapper&lt;/code&gt;  in this way so that you don&amp;rsquo;t have to type a long command, just simply use  &lt;code&gt;mvn-wrapper install&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;export AWS_PROFILE&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;AWS_PROFILE&lt;span style=&#34;color:#66d9ef&#34;&gt;:-&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;dev&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;export DOMAIN&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;DOMAIN&lt;span style=&#34;color:#66d9ef&#34;&gt;:-&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;company-repositories&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;export OWNER&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;OWNER&lt;span style=&#34;color:#66d9ef&#34;&gt;:-&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;0123456789&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We then configure both IDE and Maven CLI to use the wrapper.&lt;/p&gt;
&lt;h3 id=&#34;updating-maven-settings&#34;&gt;Updating Maven Settings&lt;/h3&gt;
&lt;p&gt;In this approach, we don&amp;rsquo;t create any wrapper for Maven CLI but update directly &lt;code&gt;~/.m2/settings.xml&lt;/code&gt;. This solution is inspired by the idea of the IntelliJ plugin mentioned above without any IDE. Let&amp;rsquo;s create a simple script &lt;code&gt;update-maven-settings&lt;/code&gt; with the content as following:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#!/usr/bin/env bash
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; ! command -v xmlstarlet &amp;gt;/dev/null 2&amp;gt;&amp;amp;1; &lt;span style=&#34;color:#66d9ef&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;The command &amp;#39;xmlstarlet&amp;#39; not found, you must install it beforehand.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  exit &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; ! command -v aws &amp;gt;/dev/null 2&amp;gt;&amp;amp;1; &lt;span style=&#34;color:#66d9ef&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;The command &amp;#39;aws&amp;#39; not found, you must install AWS CLI v2.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  exit &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; ! env | grep -i &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;^AWS_ACCESS_KEY_ID&amp;#39;&lt;/span&gt; &amp;gt;/dev/null 2&amp;gt;&amp;amp;1; &lt;span style=&#34;color:#66d9ef&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; ! env | grep -i &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;^AWS_PROFILE&amp;#39;&lt;/span&gt; &amp;gt;/dev/null 2&amp;gt;&amp;amp;1; &lt;span style=&#34;color:#66d9ef&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;AWS credentials are not available and AWS_PROFILE is not set.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;You must either login using &amp;#39;aws sso login --profile &amp;lt;profile_name&amp;gt;&amp;#39;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;or use &amp;#39;AWS_PROFILE=&amp;lt;profile_name&amp;gt; &lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;basename -- $0&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    exit &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Generating CODEARTIFACT_AUTH_TOKEN ...&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;export CODEARTIFACT_AUTH_TOKEN&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;aws codeartifact &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;  get-authorization-token &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;   --output text &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;  --query authorizationToken &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;  --domain &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;DOMAIN&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;  --domain-owner &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;OWNER&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;[[&lt;/span&gt; -n &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$CODEARTIFACT_AUTH_TOKEN&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;]]&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  settings&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;HOME&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;/.m2/settings.xml&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;CODEARTIFACT_AUTH_TOKEN is set, start updating &amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;settings&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  xmlstarlet edit --inplace -u &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;_:settings/_:servers/_:server/_:password&amp;#34;&lt;/span&gt; -v &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$CODEARTIFACT_AUTH_TOKEN&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;settings&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Maven settings &amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;settings&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;, the element &amp;#39;&amp;lt;password&amp;gt;&amp;#39; has been updated.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  exit &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Failed to generate CodeArtifact authentication token.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  exit &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;After ensuring the script is executable with &lt;code&gt;chmod +x update-maven-settings&lt;/code&gt;, we can just run it&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ DOMAIN&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;company-repositories&amp;#39;&lt;/span&gt; OWNER&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;0123456789&amp;#39;&lt;/span&gt; AWS_PROFILE&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;dev ./update-maven-settings
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Generating CODEARTIFACT_AUTH_TOKEN ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;CODEARTIFACT_AUTH_TOKEN is set, start updating &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;/home/alext/.m2/settings.xml&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Maven settings &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;/home/alext/.m2/settings.xml&amp;#39;&lt;/span&gt;, the element &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;&amp;lt;password&amp;gt;&amp;#39;&lt;/span&gt; has been updated.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you check &lt;code&gt;~/.m2/settings.xml&lt;/code&gt;, you will see  the updated token&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-xml&#34; data-lang=&#34;xml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;password&amp;gt;&lt;/span&gt;eyJ2ZXIiOjE....&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/password&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Again, if only working with the same repository, we can hard code the variables as with &lt;code&gt;mvn-wrapper&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;After updating &lt;code&gt;settings.xml&lt;/code&gt; with the token, you can freely use Maven CLI or IDE until the token expires. Then you just need to re-run  &lt;code&gt;update-maven-settings&lt;/code&gt;.  You can even go hard-core with setting up a cron-job that automatically runs the script &lt;code&gt;update-maven-settings&lt;/code&gt; to update the token before it expires. Just ensure that the corresponding AWS profile is authenticated, though.&lt;/p&gt;
&lt;p&gt;In this approach, we need an extra tool &lt;a href=&#34;https://xmlstar.sourceforge.net/&#34;&gt;xmlstarlet&lt;/a&gt; to update XML files. The tool is often packaged by most of the common Linux distros but not readily installed. On a Debian/Ubuntu alike system, use&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo apt install -y xmlstarlet
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;On a CentOS / RHEL / Amazon Linux system&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Use YUM&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo yum -y install xmlstarlet
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# or DNF&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo dnf -y install xmlstarlet
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;On Mac OS, we might need &lt;a href=&#34;https://brew.sh/&#34;&gt;Homebrew&lt;/a&gt; to install &lt;code&gt;xmlstarlet&lt;/code&gt;&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;brew install xmlstarlet
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;On Windows, you can download the binary package and install it or use a package manager such as &lt;a href=&#34;https://chocolatey.org/&#34;&gt;Chocolatey&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The second solution is my favourite and I have been using it for my daily development with Java and Maven. You can opt for either that fits well with your own working style and environment.&lt;/p&gt;
&lt;h4 id=&#34;happy-coding-&#34;&gt;Happy Coding 💪&lt;/h4&gt;
&lt;h1 id=&#34;references&#34;&gt;References&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://docs.aws.amazon.com/codeartifact/latest/ug/maven-mvn.html&#34;&gt;https://docs.aws.amazon.com/codeartifact/latest/ug/maven-mvn.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://maven.apache.org/&#34;&gt;https://maven.apache.org/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
      </item>
    
      <item>
        <title>Building Node Canvas Container for AWS Lambda</title>
        <link>https://htr3n.github.io/2021/10/node-canvas-aws-lambda/</link>
        <pubDate>Tue, 19 Oct 2021 11:36:00 +1000</pubDate>
        
        <guid>528e0b69d3d806704dfa77209e5af3db</guid>
        <description>&lt;p&gt;The Cairo-backed &lt;a href=&#34;https://www.npmjs.com/package/canvas/&#34;&gt;node-canvas&lt;/a&gt; has been a pillar for many Node.js based projects that need to simulate a browser canvas on the server-side. One of our recent projects uses &lt;a href=&#34;https://echarts.apache.org/&#34;&gt;Apache ECharts&lt;/a&gt; to render some graphs. We have successfully shifted the rendering part of ECharts to the server side to ease the burden on the front-end Web browsers using &lt;code&gt;node-canvas&lt;/code&gt; and &lt;a href=&#34;https://www.npmjs.com/package/jsdom&#34;&gt;jsdom&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Thing goes well until we decided to migrate the rendering task to &lt;a href=&#34;https://docs.aws.amazon.com/lambda/latest/dg/lambda-nodejs.html&#34;&gt;AWS Lambda Node.js 14.x&lt;/a&gt;. Unfortunately, AWS Lambda runtime environment is quite slim and hence, insufficient for &lt;code&gt;node-canvas&lt;/code&gt;. There are &lt;a href=&#34;https://github.com/Automattic/node-canvas/issues?q=is%3Aissue+aws&#34;&gt;many issues reported&lt;/a&gt; on the project Github page. In summary, the root cause is that &lt;code&gt;node-canvas&lt;/code&gt; must be built with native libraries when we run &lt;code&gt;npm install&lt;/code&gt;. Unless you are running &lt;a href=&#34;https://aws.amazon.com/amazon-linux-2/&#34;&gt;Amazon Linux 2&lt;/a&gt;, which is the native runtime environment for AWS Lambda functions, there will be discrepancy between your local environment with AWS Lambda runtime environment. The typical error message is &lt;code&gt; Error: libXXX: cannot open shared object file: No such file or directory&lt;/code&gt; . I&amp;rsquo;m developing on a Ubuntu 20 LTS box but still got many of those errors.&lt;/p&gt;
&lt;p&gt;After giving exhaustive trials and errors adding missing libraries, there is &lt;a href=&#34;https://github.com/Automattic/node-canvas/issues/1779&#34;&gt;a final and ultimate error&lt;/a&gt; regarding the &lt;code&gt;libz&lt;/code&gt;. Adding &lt;code&gt;libz&lt;/code&gt; even with the exact version 1.2.9 into the Lambda layer does not make the error go away. I came across &lt;a href=&#34;http://blog.maxieduncan.co.nz/aws/2021/07/07/lambda-container-image-support&#34;&gt;a post&lt;/a&gt; by Max Duncan and realised I haven&amp;rsquo;t thought about the other option with AWS Lambda, i.e. &lt;a href=&#34;https://docs.aws.amazon.com/lambda/latest/dg/images-create.html&#34;&gt;creating a container image&lt;/a&gt;. This approach &lt;a href=&#34;https://aws.amazon.com/blogs/aws/new-for-aws-lambda-container-image-support/&#34;&gt;has been introduced recently&lt;/a&gt;, around Dec 2020.&lt;/p&gt;
&lt;p&gt;Using a similar approach, I can successfully build an AWS Node.js 14.x container for &lt;code&gt;node-canvas&lt;/code&gt; for ECharts. Nevertheless, the same approach can be used to build working node-canvas containers for any other libraries as well.&lt;/p&gt;
&lt;p&gt;Create a simple project as following&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;.
├── Dockerfile
├── index.js
└── package.json
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The file &lt;code&gt;index.js&lt;/code&gt;will be the entry point with the &lt;a href=&#34;https://docs.aws.amazon.com/lambda/latest/dg/nodejs-handler.html&#34;&gt;handler&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;use strict&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;exports&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;handler&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;async&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;event&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;context&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;callback&lt;/span&gt;) =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;result&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;body&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;isBase64Encoded&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;statusCode&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;200&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;console&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;Received a render request event&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;try&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;result&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;body&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; ... ; &lt;span style=&#34;color:#75715e&#34;&gt;// call another function using Node Canvas
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;  } &lt;span style=&#34;color:#66d9ef&#34;&gt;catch&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;error&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;console&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;error&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;result&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;statusCode&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;500&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;result&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;body&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;JSON&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;stringify&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;error&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;callback&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;result&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;callback&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;result&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;package.json&lt;/code&gt; is a simple NPM specification with the dependency to &lt;code&gt;canvas&lt;/code&gt;, for instance&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;name&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;node-canvas-lambda-container&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;version&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;1.0.0&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;dependencies&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;canvas&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;^2.8.0&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;license&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;MIT&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;Dockerfile&lt;/code&gt; is the &lt;a href=&#34;https://docs.docker.com/engine/reference/builder/&#34;&gt;Docker container specification&lt;/a&gt; in which we create a new container image based on AWS public Node.js 14 image.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-dockerfile&#34; data-lang=&#34;dockerfile&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;FROM&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt; public.ecr.aws/lambda/nodejs:14&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;##&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Install necessary package for building Node.js Canvas&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;##&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;RUN&lt;/span&gt; yum -y update &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; yum -y groupinstall &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Development Tools&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; yum install -y nodejs gcc-c++ cairo-devel &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;	libjpeg-turbo-devel pango-devel giflib-devel &lt;span style=&#34;color:#ae81ff&#34;&gt;\ &lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&lt;/span&gt;	zlib-devel librsvg2-devel&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;COPY&lt;/span&gt; *.js package* ./&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;RUN&lt;/span&gt; npm install&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;ENV&lt;/span&gt; LD_PRELOAD&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;/var/task/node_modules/canvas/build/Release/libz.so.1&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;RUN&lt;/span&gt; yum remove -y cairo-devel libjpeg-turbo-devel &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;		pango-devel giflib-devel zlib-devel librsvg2-devel&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Set the CMD to your handler&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;CMD&lt;/span&gt; [ &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;index.handler&amp;#34;&lt;/span&gt; ]&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now we can build the container&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker build -t node-canvas-lambda .
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If the build is successful, we can see the new Docker image in our local environment&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ docker images | grep node-canvas
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;node-canvas-lambda				latest			ae9f63e1981a   &lt;span style=&#34;color:#ae81ff&#34;&gt;11&lt;/span&gt; seconds ago   1.72GB
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Start the container for testing (no need to deploy to AWS yet)&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ docker run -p 3000:8080 node-canvas-lambda
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;time&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;2021-10-19T01:27:46.528&amp;#34;&lt;/span&gt; level&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;info msg&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;exec &amp;#39;/var/runtime/bootstrap&amp;#39; (cwd=/var/task, handler=)&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Per &lt;a href=&#34;https://docs.aws.amazon.com/lambda/latest/dg/images-create.html&#34;&gt;AWS documentation&lt;/a&gt;, the container includes the AWS &lt;a href=&#34;https://docs.aws.amazon.com/lambda/latest/dg/runtimes-images.html#runtimes-api-client&#34;&gt;runtime interface clients&lt;/a&gt; needed to run. We can test the Lambda locally with &lt;code&gt;curl&lt;/code&gt; or similar tools. Note that, the port has to be exact Docker port mapping &lt;code&gt;3000:8080&lt;/code&gt;. The rest of the URL has to be &lt;code&gt;2015-03-31/functions/function/invocations&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Open another teminal (as we need to keep the Docker Node.js container running) and use the following command:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ curl -X POST &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;http://localhost:3000/2015-03-31/functions/function/invocations&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;\ &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	--data &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;{}&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;body&amp;#34;&lt;/span&gt;:null,&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;isBase64Encoded&amp;#34;&lt;/span&gt;:false,&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;statusCode&amp;#34;&lt;/span&gt;:200&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If thing goes well, we should see some JSON outputs from the Lambda handler (i.e &lt;code&gt;index.handler&lt;/code&gt;).&lt;/p&gt;
</description>
      </item>
    
      <item>
        <title>Chromium and macOS Environment Variables</title>
        <link>https://htr3n.github.io/2019/07/chromium-macos-environment/</link>
        <pubDate>Fri, 05 Jul 2019 12:33:36 +1000</pubDate>
        
        <guid>2a00c8f1203280ca2ba56bc94d3c55a2</guid>
        <description>&lt;p&gt;Trying Chromium in macOS Mojave (10.14), I confronted with the popular issue regarding &lt;a href=&#34;https://www.google.com/search?q=chromium+google+api+key+missing&#34;&gt;Google API key missing&lt;/a&gt;. After obtaining an API key along with client ID and secret, I put it on some shell startup scripts as following.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;export GOOGLE_API_KEY&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;your_google_api_key&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;export GOOGLE_DEFAULT_CLIENT_ID&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;your_client_id&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;export GOOGLE_DEFAULT_CLIENT_SECRET&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;your_client_secret&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Even more careful, I also use &lt;code&gt;launchctl setenv&lt;/code&gt; to ensure these variables are available for macOS GUI applications (usually launched via Finder, Dock, Spotlight or so).&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[[&lt;/span&gt; -x /bin/launchctl &lt;span style=&#34;color:#f92672&#34;&gt;]]&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; /bin/launchctl setenv GOOGLE_API_KEY $GOOGLE_API_KEY
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[[&lt;/span&gt; -x /bin/launchctl &lt;span style=&#34;color:#f92672&#34;&gt;]]&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; /bin/launchctl setenv GOOGLE_DEFAULT_CLIENT_ID $GOOGLE_DEFAULT_CLIENT_ID
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[[&lt;/span&gt; -x /bin/launchctl &lt;span style=&#34;color:#f92672&#34;&gt;]]&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; /bin/launchctl setenv GOOGLE_DEFAULT_CLIENT_SECRET $GOOGLE_DEFAULT_CLIENT_SECRET
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Sadly, it didn&amp;rsquo;t work under Mojave. When launching Chrome from Finder or Dock, the warning is still there. It seems Apple has silently altered macOS a lot and many existing work-arounds stop working under Mojave.&lt;/p&gt;
&lt;p&gt;There are also some working methods involving renaming the original executable binary &lt;code&gt;/Applications/Chromium.app/Contents/MacOS/Chromium&lt;/code&gt;, creating a new script to launch Chrome in which the aforementioned variables are set properly (even leading to automated scripts like &lt;a href=&#34;https://github.com/ezeeyahoo/ChromiumSyncEnabler&#34;&gt;this&lt;/a&gt;). Personally, I don&amp;rsquo;t like these ways as they are rather intrusive and therefore less upgrade-proof (I guess future updates of Chromium will override these launching scripts and you must circumvent that) and only consider them last resort.&lt;/p&gt;
&lt;p&gt;Fortunately, I have found an &lt;a href=&#34;https://stackoverflow.com/q/25385934&#34;&gt;old StackOverflow&amp;rsquo;s topic&lt;/a&gt; with two methods that work perfectly fine for macOS Mojave and systems before that as you can see in that SO&amp;rsquo;s topic. Better then, they are much less intrusive and upgrade-friendly.&lt;/p&gt;
&lt;h2 id=&#34;method-1-using-login-items&#34;&gt;Method 1: Using Login Items&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Step 1&lt;/strong&gt;: Open the built-in app &amp;ldquo;Script Editor&amp;rdquo; in &lt;code&gt;/Applications/Utilities/&lt;/code&gt;, enter the following content&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-applescript&#34; data-lang=&#34;applescript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;do shell script &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/bin/launchctl setenv GOOGLE_API_KEY your_google_api_key&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;do shell script &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/bin/launchctl setenv GOOGLE_DEFAULT_CLIENT_ID your_client_id&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;do shell script &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/bin/launchctl setenv GOOGLE_DEFAULT_CLIENT_SECRET your_client_secret&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;and then save (&lt;!-- raw HTML omitted --&gt;⌘&lt;!-- raw HTML omitted --&gt; + &lt;!-- raw HTML omitted --&gt;s&lt;!-- raw HTML omitted --&gt;) under the format &amp;ldquo;&lt;strong&gt;Application&lt;/strong&gt;&amp;rdquo;. Behind the scene, it will create a new macOS application and wraps the script content inside.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 2&lt;/strong&gt;: Go to &amp;ldquo;Settings&amp;rdquo;  &amp;ndash;&amp;gt; &amp;ldquo;Users and Groups&amp;rdquo; &amp;ndash;&amp;gt; choose the tab &amp;ldquo;Login Items&amp;rdquo;, click &lt;!-- raw HTML omitted --&gt;+&lt;!-- raw HTML omitted --&gt; and either point to the newly created application or simply drag and drop it to the box above.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 3&lt;/strong&gt;: Log out and log in again. Chromium should see the variables and shows no warning.&lt;/p&gt;
&lt;h2 id=&#34;method-2-via-launchagents&#34;&gt;Method 2: Via LaunchAgents&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Step 1&lt;/strong&gt;: Create a file &lt;code&gt;environments.plist&lt;/code&gt; inside the folder &lt;code&gt;~/Library/LaunchAgents&lt;/code&gt; with the following content:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-plist&#34; data-lang=&#34;plist&#34;&gt;&amp;lt;?xml version=&amp;#34;1.0&amp;#34; encoding=&amp;#34;UTF-8&amp;#34;?&amp;gt;
&amp;lt;!DOCTYPE plist PUBLIC &amp;#34;-//Apple//DTD PLIST 1.0//EN&amp;#34; &amp;#34;http://www.apple.com/DTDs/PropertyList-1.0.dtd&amp;#34;&amp;gt;
&amp;lt;plist version=&amp;#34;1.0&amp;#34;&amp;gt;
&amp;lt;dict&amp;gt;
  &amp;lt;key&amp;gt;Label&amp;lt;/key&amp;gt;
  &amp;lt;string&amp;gt;gui-environments&amp;lt;/string&amp;gt;
  &amp;lt;key&amp;gt;ProgramArguments&amp;lt;/key&amp;gt;
  &amp;lt;array&amp;gt;
    &amp;lt;string&amp;gt;sh&amp;lt;/string&amp;gt;
    &amp;lt;string&amp;gt;-c&amp;lt;/string&amp;gt;
    &amp;lt;string&amp;gt;
    /bin/launchctl setenv GOOGLE_API_KEY your_google_api_key
    /bin/launchctl setenv GOOGLE_DEFAULT_CLIENT_ID your_client_id
    /bin/launchctl setenv GOOGLE_DEFAULT_CLIENT_SECRET your_client_secret
    &amp;lt;/string&amp;gt;
  &amp;lt;/array&amp;gt;
  &amp;lt;key&amp;gt;RunAtLoad&amp;lt;/key&amp;gt;
  &amp;lt;true/&amp;gt;
&amp;lt;/dict&amp;gt;
&amp;lt;/plist&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;Step 2&lt;/strong&gt;: Enable it with &lt;code&gt;launchctl&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;launchctl load ~/Library/LaunchAgents/environments.plist
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Step 3&lt;/strong&gt;: There is no step 3, just launch &lt;code&gt;Chromium&lt;/code&gt; and see that it should work without warning ;)&lt;/p&gt;
&lt;p&gt;In this method, you don&amp;rsquo;t even need to log out or reboot. The variables are made available to &lt;code&gt;launchctl&lt;/code&gt; after Step 2.&lt;/p&gt;
&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;The aforementioned methods work flawlessly under macOS Mojave (10.14) and less intrusive with respect to the target applications. As a result, we can upgrade or change the applications without concerning about re-creating, updating or changing the launching scripts. The only caveat is that, the environment variables will be exposed to all applications, and hence, could lead to some security concerns (e.g. regarding Google keys and secrets).&lt;/p&gt;
&lt;p&gt;In that same SO&amp;rsquo;s topic, there is also &lt;a href=&#34;https://stackoverflow.com/a/26477515&#34;&gt;a slightly different way&lt;/a&gt; to elevate a bit more to make it work for the whole system instead of only the particular user. It involves in putting the main script where environment vars are set in &lt;code&gt;/etc/environment&lt;/code&gt; and creating a launching agent in &lt;code&gt;/Library/LaunchAgents/&lt;/code&gt; along with another daemon service in &lt;code&gt;/Library/LaunchDaemons/&lt;/code&gt; to monitor the content of &lt;code&gt;/etc/environment&lt;/code&gt;.&lt;/p&gt;
</description>
      </item>
    
      <item>
        <title>Lenovo Thinkpad T430s Supervisor Password Removal</title>
        <link>https://htr3n.github.io/2019/06/t430s-supervisor-password-removal/</link>
        <pubDate>Mon, 24 Jun 2019 10:50:24 +1000</pubDate>
        
        <guid>065fbee3fa9e5d629405d8b14c22147e</guid>
        <description>&lt;p&gt;After a while merely working with macOS and Linux, I have recently decided to have an additional Windows box for some Windows-specific tools and development. I could be able to secure a second-hand &lt;a href=&#34;https://www.lenovo.com/us/en/laptops/thinkpad/t-series/t430s/&#34;&gt;Lenovo Thinkpad T430s&lt;/a&gt; on eBay for around 130 AUD, which is quite a decent price with CPU i5-3320M (2.6GHz), 4GB RAM, 14in 1600x900 LCD and its battery could last about two hours.&lt;/p&gt;
&lt;p&gt;I was away when the seller delivered the laptop and thus unable to check anything right after receiving. It turns out the seller (or his seller before that, as he claimed) had lost or could not retrieve the BIOS &lt;a href=&#34;https://support.lenovo.com/au/en/solutions/ht036206&#34;&gt;supervisor password&lt;/a&gt;. I only noticed this issue when I tried unsuccessfully to alter the BIOS to UEFI mode in order to install and dual boot Windows and Ubuntu in UEFI. Without the correct supervisor password, I am not allowed to make any meaningful changes in the BIOS.&lt;/p&gt;
&lt;p&gt;You got supervisor password locked when you see this after pressing &lt;!-- raw HTML omitted --&gt;F1&lt;!-- raw HTML omitted --&gt; to enter the BIOS at boot time.&lt;/p&gt;
&lt;!-- raw HTML omitted --&gt;
&lt;p&gt;You may just &lt;!-- raw HTML omitted --&gt;Enter&lt;!-- raw HTML omitted --&gt; with blank and can still get into BIOS but most of the options are grayed out to your dismay.&lt;/p&gt;
&lt;!-- raw HTML omitted --&gt;
&lt;p&gt;Searching around on the Internet, most of Lenovo forum experts will tell you that the only way is to get Lenovo replacing the mainboard due to security setting. Some will point to &lt;a href=&#34;http://www.ja.axxs.net&#34;&gt;Joe&amp;rsquo;s KeyMaker kit&lt;/a&gt; that costs at least 113 USD (98 plus 15 USD for shipping and handling).&lt;/p&gt;
&lt;p&gt;Fortunately, there are some workarounds like this &lt;a href=&#34;https://www.reddit.com/r/thinkpad/comments/4z9czz/resetting_the_eepromlost_supervisor_password_on/&#34;&gt;Reddit thread&lt;/a&gt;, David Zou&amp;rsquo;s &lt;a href=&#34;https://davidzou.com/articles/bios-password-bypass&#34;&gt;post&lt;/a&gt;, this SuperUser&amp;rsquo;s &lt;a href=&#34;https://superuser.com/questions/393922/how-to-remove-the-supervisor-bios-password-for-an-ibm-thinkpad&#34;&gt;thread&lt;/a&gt;, or this &lt;a href=&#34;https://www.facts-are-stubborn.com/reset-bios-password-on-lenovo-thinkpad/&#34;&gt;post&lt;/a&gt;, and many YouTube&amp;rsquo;s video like &lt;a href=&#34;https://www.youtube.com/watch?v=ANZjUPUYE7s&#34;&gt;here&lt;/a&gt; or &lt;a href=&#34;https://www.youtube.com/watch?v=FW-RLkzjAS8&#34;&gt;there&lt;/a&gt;. After few trials, I could successfully reset the supervisor password in my T430s. Here I will summarize some basic and working steps with some important notes that might save you some money, time, and effort.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;IMPORTANT&lt;/p&gt;
&lt;p&gt;The following procedure involves some risky short-circuit of a mainboard&amp;rsquo;s component. I will bear no responsibility when you damage your own computers using these guidance. Proceed at your own risk.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The main idea is to locate and short-circuit the pins SDA and SCL of the EEPROM during the process of supervisor password checking.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Disassemble T430s to expose the EEPROM&lt;/li&gt;
&lt;li&gt;Clear supervisor password by short-circuiting the EEPROM&amp;rsquo;s pins
&lt;ul&gt;
&lt;li&gt;Turn on and keep short-circuiting the pins &lt;code&gt;SDA&lt;/code&gt; and &lt;code&gt;SCL&lt;/code&gt; of the EEPROM when entering the BIOS (pressing &lt;!-- raw HTML omitted --&gt;F1&lt;!-- raw HTML omitted --&gt;) and the BIOS is checking the password&lt;/li&gt;
&lt;li&gt;Enter the BIOS, change the supervisor password, and then save the changes (&lt;!-- raw HTML omitted --&gt;F10&lt;!-- raw HTML omitted --&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;disassemble-t430s&#34;&gt;Disassemble T430s&lt;/h2&gt;
&lt;p&gt;The EEPROM is on the mainboard under the keyboard. Hence, we must remove the keyboard to expose it. Unless you are too familiar with opening a T430s, you should refer to the Hardware Maintenance Manual (either &lt;a href=&#34;https://download.lenovo.com/ibmdl/pub/pc/pccbbs/mobiles_pdf/t430s_t430si_hmm_en_0b48538_01.pdf&#34;&gt;pdf&lt;/a&gt; or &lt;a href=&#34;https://support.lenovo.com/solutions/pd023494&#34;&gt;online&lt;/a&gt; version).&lt;/p&gt;
&lt;p&gt;Using the instructions for &lt;a href=&#34;https://support.lenovo.com/solutions/pd023557&#34;&gt;&amp;ldquo;Removing and Installing the Keyboard - ThinkPad T430s, T430si&amp;rdquo;&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Remove the &lt;a href=&#34;https://support.lenovo.com/documents/pd023501&#34;&gt;battery pack&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Remove the &lt;a href=&#34;https://support.lenovo.com/au/en/solutions/pd023551&#34;&gt;memory cover&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Locate and remove the two keyboard screws marked with red color.&lt;/li&gt;
&lt;/ul&gt;
&lt;!-- raw HTML omitted --&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Turn to the upper side, slightly press or push the keyboard a little towards the direction of the display to unlatch it.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You better use a small flat screwdriver to gently push and lift up the keyboard&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Pull the keyboard out gently to avoid breaking the thin keyboard cable.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;!-- raw HTML omitted --&gt;
&lt;p&gt;Now we need to locate the EEPROM. As the chip is very small, it will take a little effort. It would be faster with a good loupe or similar. In my T430s, the chip is south of the CPU and hidden under the black sticky isolation tape.&lt;/p&gt;
&lt;!-- raw HTML omitted --&gt;
&lt;p&gt;According to the &lt;a href=&#34;https://davidzou.com/user/pages/03.articles/bios-password-bypass/8pinEEPROM.png&#34;&gt;layout diagram&lt;/a&gt; shown by David Zou, the pins SCL and SDA are on the lower opposite side of the dot. The EEPROM in my laptop got some sticky from the isolation tape on the surface and therefore difficult to see the dot. In this case, you can use a pointy driver to gently scan all over the chip&amp;rsquo;s surface like I did.&lt;/p&gt;
&lt;!-- raw HTML omitted --&gt;
&lt;p&gt;The &lt;code&gt;SDA&lt;/code&gt; and &lt;code&gt;SCL&lt;/code&gt; pins are identified with two blue arrows. Note that the space between them is tiny, so make sure you are using appropriate tool to only short these pins and don&amp;rsquo;t touch anything else. In my case, I found it very precise and comfortable with a pointy driver from a cheap screwdriver set.&lt;/p&gt;
&lt;!-- raw HTML omitted --&gt;
&lt;h2 id=&#34;clear-supervisor-password&#34;&gt;Clear Supervisor Password&lt;/h2&gt;
&lt;p&gt;After successfully locating the EEPROM and identifying the two pins, as David Zou wrote &lt;a href=&#34;https://davidzou.com/articles/bios-password-bypass&#34;&gt;here&lt;/a&gt;, the steps and responses for BIOS and UEFI based computers are slightly different, please refer to his information in your particular case. As my T430s is UEFI based, the process is following.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Turn on the computer / laptop&lt;/li&gt;
&lt;li&gt;Short-circuit the two pins &lt;code&gt;SDA&lt;/code&gt; and &lt;code&gt;SCL&lt;/code&gt; and keep them shorted while pressing &lt;!-- raw HTML omitted --&gt;F1&lt;!-- raw HTML omitted --&gt; to enter BIOS setup. I was taken directly to the BIOS without any prompt or asking.&lt;/li&gt;
&lt;li&gt;Stop short-circuiting after successfully entering the BIOS (otherwise, start over from Step 1)&lt;/li&gt;
&lt;li&gt;Navigate to the menu &lt;!-- raw HTML omitted --&gt;Security&lt;!-- raw HTML omitted --&gt; &amp;gt; &lt;!-- raw HTML omitted --&gt;Password&lt;!-- raw HTML omitted --&gt; &amp;gt; &lt;!-- raw HTML omitted --&gt;Supervisor Password&lt;!-- raw HTML omitted --&gt; to change the supervisor password (&lt;em&gt;&lt;strong&gt;please read the following note&lt;/strong&gt;&lt;/em&gt;).&lt;/li&gt;
&lt;/ol&gt;
&lt;!-- raw HTML omitted --&gt;
&lt;p&gt;An important lesson I learned at this point (in a hard way) is that, you &lt;strong&gt;should change the supervisor password to something not blank&lt;/strong&gt;. After clearing the supervisor password as above, I tested few times and put back every thing just to realize that the old or locked supervisor password kicked back in. That means I got locked out as before and must re-open the keyboard to start over the short-circuit.&lt;/p&gt;
&lt;p&gt;The issue was somehow noticed by &lt;a href=&#34;https://www.reddit.com/user/clocow/&#34;&gt;clocow&lt;/a&gt; in &lt;a href=&#34;https://www.reddit.com/r/thinkpad/comments/4z9czz/resetting_the_eepromlost_supervisor_password_on/&#34;&gt;this Reddit thread&lt;/a&gt; and his suspect is due to the backup battery (the yellow one in the mainboard). He suggested to leave the battery disconnected for 3 hours and retried.&lt;/p&gt;
&lt;p&gt;Nonetheless, I have just changed the supervisor password and experienced no kick back or reset so far. My suspect is that the reverting of old/locked supervisor password happens when the supervisor password is blank after the hiccup (i.e. the attempt to clear password via short-circuiting). That&amp;rsquo;s why I got the aforementioned simple solution.&lt;/p&gt;
&lt;p&gt;Eventually, I am truly happy to gain control of my laptop without spending extra money and learn few more thing on the way.&lt;/p&gt;
&lt;p&gt;Happy hacking (aka short-circuiting), mates !!!&lt;/p&gt;
&lt;h3 id=&#34;ps&#34;&gt;P.S.&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;For other models, you should research carefully whether the supervisor password can be cleared using this method. In some models, the places to store passwords are totally different and you can risk burning or bricking a working laptop.&lt;/li&gt;
&lt;li&gt;Information about the location of EEPROM and two pins of other Lenovo models can be found &lt;a href=&#34;http://www.ja.axxs.net/eeprom_location.htm&#34;&gt;here&lt;/a&gt; or &lt;a href=&#34;https://www.allservice.ro/forum/viewtopic.php?t=52&#34;&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;references&#34;&gt;References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://support.lenovo.com/au/en/solutions/ht036206&#34;&gt;Lenovo Support: Types of password for ThinkPad&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://davidzou.com/articles/bios-password-bypass&#34;&gt;https://davidzou.com/articles/bios-password-bypass&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/thinkpad/comments/4z9czz/resetting_the_eepromlost_supervisor_password_on&#34;&gt;https://www.reddit.com/r/thinkpad/comments/4z9czz/resetting_the_eepromlost_supervisor_password_on&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
      </item>
    
      <item>
        <title>Making JSP work with Spring Boot 2</title>
        <link>https://htr3n.github.io/2018/12/jsp-spring-boot/</link>
        <pubDate>Mon, 24 Dec 2018 00:00:00 +0000</pubDate>
        
        <guid>44c8f2ad7da3b592464d0afad5a598dc</guid>
        <description>&lt;p&gt;One of my past projects relied heavily on XML based configurations and JSP technologies dated back to Spring Framework 3.x. It is still working fine after upgrading to Spring 5 and corresponding dependent libraries such as &lt;a href=&#34;https://hibernate.org/orm/&#34;&gt;Hibernate&lt;/a&gt; 5, &lt;a href=&#34;https://brettwooldridge.github.io/HikariCP/&#34;&gt;HikariCP&lt;/a&gt; 3 and &lt;a href=&#34;https://cxf.apache.org/&#34;&gt;Apache CXF&lt;/a&gt; 3.3.&lt;/p&gt;
&lt;p&gt;Exploring further into Spring ecosystem, I decided to give a shot on migrating to Spring Boot 2 whilst keeping most of the existing MVC (e.g. controllers, validations, JSP views) working. Most of the significant information are scattered throughout the Internet and most of the useful tutorials are sort of &amp;ldquo;&lt;em&gt;just-follow-these-steps-and-it-will-guarantee-to-work-but-nothing-will-be-explained&lt;/em&gt;&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;It took me much unexpected effort and trial-and-error to get things right not to mention numerous do&amp;rsquo;s and don&amp;rsquo;ts got undocumented or lost among a bunch of documentations. This post merely focuses some  on major aspects on bringing Spring Boot 2 and &lt;a href=&#34;https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html&#34;&gt;Spring Web&lt;/a&gt; with JSP together. The versions that I consider here are &lt;a href=&#34;https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-2.1-Release-Notes&#34;&gt;Spring Boot 2.1&lt;/a&gt; and respectively &lt;a href=&#34;https://github.com/spring-projects/spring-framework/wiki/What%27s-New-in-Spring-Framework-5.x#What&#39;s-New-in-Version-5.1&#34;&gt;Spring 5.1&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;creating-a-spring-boot-project&#34;&gt;Creating a Spring Boot Project&lt;/h2&gt;
&lt;p&gt;We can quickly create a new Spring Boot project using &lt;a href=&#34;https://start.spring.io/&#34;&gt;Spring Initializr&lt;/a&gt; web site or via &lt;a href=&#34;https://docs.spring.io/spring-boot/docs/2.1.1.RELEASE/reference/htmlsingle/#cli&#34;&gt;command line&lt;/a&gt; or IDE (e.g. Eclipse, IntelliJ IDEA). For less verbose build configuration, I will opt for &lt;a href=&#34;https://gradle.org/&#34;&gt;Gradle&lt;/a&gt; build instead of Maven.&lt;/p&gt;
&lt;!-- raw HTML omitted --&gt;
&lt;p&gt;For instance, with the &amp;ldquo;&lt;em&gt;New Project&lt;/em&gt;&amp;rdquo; wizard with Spring Initialzr in Intellij IDEA, I picked &amp;ldquo;&lt;em&gt;War&lt;/em&gt;&amp;rdquo; for &amp;ldquo;&lt;em&gt;Packaging&lt;/em&gt;&amp;rdquo;. The other non-default option is &amp;ldquo;&lt;em&gt;Gradle Config&lt;/em&gt;&amp;rdquo;, as mentioned above.&lt;/p&gt;
&lt;!-- raw HTML omitted --&gt;
&lt;h2 id=&#34;project-configurations&#34;&gt;Project Configurations&lt;/h2&gt;
&lt;h3 id=&#34;dependencies&#34;&gt;Dependencies&lt;/h3&gt;
&lt;p&gt;Spring Boot 2 comes with &lt;a href=&#34;https://docs.spring.io/spring-boot/docs/2.1.1.RELEASE/reference/htmlsingle/#using-boot-starter&#34;&gt;a number of starters&lt;/a&gt; (conventionally named as &lt;code&gt;spring-boot-starter-*&lt;/code&gt;) to help us integrating appropriate dependencies in our Spring projects. I pick the module &amp;ldquo;&lt;code&gt;spring-boot-starter-web&lt;/code&gt;&amp;rdquo; that adds an embedded &lt;a href=&#34;https://tomcat.apache.org/&#34;&gt;Tomcat&lt;/a&gt; servlet container and Spring MVC.&lt;/p&gt;
&lt;p&gt;Note that the embedded Tomcat package does not include JSP by default, we must add the module &amp;ldquo;&lt;code&gt;org.apache.tomcat.embed:tomcat-embed-jasper&lt;/code&gt;&amp;rdquo; as well.  In case you need JavaServer Pages Standard Tag Library (JSTL), just add  &amp;ldquo;&lt;code&gt;javax.servlet:jstl&lt;/code&gt;&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Apart from those, I also consider to use &lt;a href=&#34;https://www.webjars.org/&#34;&gt;WebJars&lt;/a&gt; as it provides client-side web libraries in terms of JAR files. Thus, It&amp;rsquo;s truly convenient for Java based web projects to bundle popular front-end libraries such as jQuery, Bootstrap, Font-Awesome, to name but a few. I will illustrate the use of WebJars Bootstrap 4 module to our demo project.&lt;/p&gt;
&lt;p&gt;Eventually, our main build configuration &lt;code&gt;build.gradle&lt;/code&gt; should look like this.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-groovy&#34; data-lang=&#34;groovy&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;buildscript &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ext &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    springBootVersion &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;2.1.1.RELEASE&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  repositories &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    mavenCentral&lt;span style=&#34;color:#f92672&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  dependencies &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    classpath&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apply plugin: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;org.springframework.boot&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apply plugin: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;io.spring.dependency-management&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apply plugin: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;war&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;group &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;io.github.htr3n&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;version &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;0.0.1-SNAPSHOT&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sourceCompatibility &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;1.8&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;repositories &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  mavenCentral&lt;span style=&#34;color:#f92672&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;dependencies &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  implementation &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;org.springframework.boot:spring-boot-starter-web&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  implementation &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;org.webjars:bootstrap:4.1.3&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  providedRuntime &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;javax.servlet:jstl:1.2&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  providedRuntime &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;org.apache.tomcat.embed:tomcat-embed-jasper:9.0.14&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  testImplementation &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;org.springframework.boot:spring-boot-starter-test&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You might notice that some Spring Boot modules such as &lt;code&gt;spring-boot-starter-*&lt;/code&gt; do not have their version numbers. The plugin &lt;a href=&#34;https://github.com/spring-gradle-plugins/dependency-management-plugin&#34;&gt;&lt;code&gt;io.spring.dependency-management&lt;/code&gt;&lt;/a&gt; will automatically &lt;a href=&#34;https://docs.spring.io/spring-boot/docs/current/gradle-plugin/reference/html/#reacting-to-other-plugins-dependency-management&#34;&gt;imports the &lt;code&gt;spring-boot-dependencies&lt;/code&gt; bom&lt;/a&gt; with adequate versions for Spring Boot&amp;rsquo;s dependencies.&lt;/p&gt;
&lt;h3 id=&#34;auto-configurations&#34;&gt;Auto-configurations&lt;/h3&gt;
&lt;p&gt;The aforementioned wizard created a &lt;code&gt;DemoApplication&lt;/code&gt; class annotated with &lt;a href=&#34;https://docs.spring.io/spring-boot/docs/2.1.1.RELEASE/api/org/springframework/boot/autoconfigure/SpringBootApplication.html&#34;&gt;&lt;code&gt;@SpringBootApplication&lt;/code&gt;&lt;/a&gt; to start our Spring Boot application. The &lt;code&gt;@SpringBootApplication&lt;/code&gt; annotation includes three other annotations that perform several configuration tasks automatically, which are,&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://docs.spring.io/spring-boot/docs/2.1.1.RELEASE/api/org/springframework/boot/SpringBootConfiguration.html&#34;&gt;&lt;code&gt;@SpringBootConfiguration&lt;/code&gt;&lt;/a&gt; embraces &lt;a href=&#34;https://docs.spring.io/spring-framework/docs/5.1.3.RELEASE/javadoc-api/org/springframework/context/annotation/Configuration.html?is-external=true&#34;&gt;&lt;code&gt;@Configuration&lt;/code&gt;&lt;/a&gt; (i.e. the annotated application class also provides Spring configurations)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://docs.spring.io/spring-boot/docs/2.1.1.RELEASE/api/org/springframework/boot/autoconfigure/EnableAutoConfiguration.html&#34;&gt;&lt;code&gt;@EnableAutoConfiguration&lt;/code&gt;&lt;/a&gt; will trigger Spring Boot &lt;a href=&#34;https://docs.spring.io/spring-boot/docs/2.1.1.RELEASE/reference/html/using-boot-auto-configuration.html&#34;&gt;auto-configuration mechanism&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://docs.spring.io/spring-framework/docs/5.1.3.RELEASE/javadoc-api/org/springframework/context/annotation/ComponentScan.html&#34;&gt;&lt;code&gt;@ComponentScan&lt;/code&gt;&lt;/a&gt; will enable the scanning for Spring components annotated with &lt;a href=&#34;https://docs.spring.io/spring-framework/docs/5.1.3.RELEASE/javadoc-api/org/springframework/stereotype/Component.html&#34;&gt;&lt;code&gt;@Component&lt;/code&gt;&lt;/a&gt; or its sub-types on the package of the main application.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It&amp;rsquo;s convenient but not mandatory to use &lt;code&gt;@SpringBootApplication&lt;/code&gt;. For advanced configuring or fine-tuning, one can surely pick apart individual annotations and add/customise them to particular needs.&lt;/p&gt;
&lt;p&gt;In order to create &lt;em&gt;a deployable WAR&lt;/em&gt; file, Spring Boot team &lt;a href=&#34;https://docs.spring.io/spring-boot/docs/2.1.1.RELEASE/reference/html/howto-traditional-deployment.html&#34;&gt;recommends to subclass &lt;code&gt;SpringBootServletInitializer&lt;/code&gt; and override its &lt;code&gt;configure()&lt;/code&gt; method&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;package&lt;/span&gt; io.github.htr3n;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; org.springframework.boot.SpringApplication;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; org.springframework.boot.autoconfigure.SpringBootApplication;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; org.springframework.boot.builder.SpringApplicationBuilder;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;@SpringBootApplication&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;DemoApplication&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;extends&lt;/span&gt; SpringBootServletInitializer {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;(String&lt;span style=&#34;color:#f92672&#34;&gt;[]&lt;/span&gt; args) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    SpringApplication.&lt;span style=&#34;color:#a6e22e&#34;&gt;run&lt;/span&gt;(DemoApplication.&lt;span style=&#34;color:#a6e22e&#34;&gt;class&lt;/span&gt;, args);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;@Override&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;protected&lt;/span&gt; SpringApplicationBuilder &lt;span style=&#34;color:#a6e22e&#34;&gt;configure&lt;/span&gt;(SpringApplicationBuilder application) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; application.&lt;span style=&#34;color:#a6e22e&#34;&gt;sources&lt;/span&gt;(DemoApplication.&lt;span style=&#34;color:#a6e22e&#34;&gt;class&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;view-resolvers&#34;&gt;View Resolvers&lt;/h3&gt;
&lt;p&gt;In Spring Web MVC, the return value of a &lt;code&gt;@Controller&lt;/code&gt;, if not a valid &lt;code&gt;View&lt;/code&gt; object, should be resolved by a &lt;a href=&#34;https://docs.spring.io/spring-framework/docs/5.1.2.RELEASE/javadoc-api/org/springframework/web/servlet/ViewResolver.html&#34;&gt;&lt;code&gt;ViewResolver&lt;/code&gt;&lt;/a&gt; . Spring Boot 2, by default, will load &lt;a href=&#34;https://docs.spring.io/spring-framework/docs/5.1.3.RELEASE/javadoc-api/org/springframework/web/servlet/view/InternalResourceViewResolver.html&#34;&gt;&lt;code&gt;InternalResourceViewResolver&lt;/code&gt;&lt;/a&gt; that combines with &lt;a href=&#34;https://docs.spring.io/spring/docs/5.1.3.RELEASE/javadoc-api/org/springframework/web/servlet/view/InternalResourceView.html&#34;&gt;&lt;code&gt;InternalResourceView&lt;/code&gt;&lt;/a&gt; for handling JSP based views. As such, a controller&amp;rsquo;s return values will be mapped to a JSP resource.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;InternalResourceViewResolver&lt;/code&gt;, which is based on &lt;a href=&#34;https://docs.spring.io/spring-framework/docs/5.1.3.RELEASE/javadoc-api/org/springframework/web/servlet/view/UrlBasedViewResolver.html&#34;&gt;&lt;code&gt;UrlBasedViewResolver&lt;/code&gt;&lt;/a&gt;, will use the following rule &amp;ldquo;&lt;code&gt;prefix + view_name + suffix&lt;/code&gt;&amp;rdquo; for view resolution. For instance, if a view&amp;rsquo;s logical name is &amp;ldquo;&lt;code&gt;index&lt;/code&gt;&amp;rdquo;, prefix = &amp;ldquo;&lt;code&gt;/WEB-INF/jsp/&lt;/code&gt;&amp;rdquo; and suffix = &amp;ldquo;&lt;code&gt;.jsp&lt;/code&gt;&amp;rdquo; then the resulting view will be  &amp;ldquo;&lt;code&gt;/WEB-INF/jsp/index.jsp&lt;/code&gt;&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Therefore, we need to configure the &lt;code&gt;prefix&lt;/code&gt; and &lt;code&gt;suffix&lt;/code&gt;. This can be done quite easily in Spring Boot , either using &lt;code&gt;application.properties&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-properties&#34; data-lang=&#34;properties&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;spring.mvc.view.prefix&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;/WEB-INF/jsp/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;spring.mvc.view.suffix&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;.jsp&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;or an equivalent but longer Java based configuration&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;@Configuration&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;WebConfig&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;implements&lt;/span&gt; WebMvcConfigurer {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;@Bean&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; ViewResolver &lt;span style=&#34;color:#a6e22e&#34;&gt;jspViewResolver&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    InternalResourceViewResolver viewResolver &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; InternalResourceViewResolver();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    viewResolver.&lt;span style=&#34;color:#a6e22e&#34;&gt;setPrefix&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/WEB-INF/jsp/&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    viewResolver.&lt;span style=&#34;color:#a6e22e&#34;&gt;setSuffix&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;.jsp&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; viewResolver;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Note that Spring Boot will map a logical view onto a JSP file inside the folder &amp;ldquo;&lt;code&gt;src/main/webapp/WEB-INF/jsp/&lt;/code&gt;&amp;rdquo;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;IMPORTANT&lt;/strong&gt;&lt;!-- raw HTML omitted --&gt;Many developers, especially who have a lot of experience with Spring Web MVC, tend to annotate the &lt;code&gt;@Configuration&lt;/code&gt; class with &lt;a href=&#34;https://docs.spring.io/spring-framework/docs/5.1.3.RELEASE/javadoc-api/org/springframework/web/servlet/config/annotation/EnableWebMvc.html&#34;&gt;&lt;code&gt;@EnableWebMvc&lt;/code&gt;&lt;/a&gt;. It&amp;rsquo;s crucial to notice that &lt;a href=&#34;https://docs.spring.io/spring-framework/docs/5.1.3.RELEASE/javadoc-api/org/springframework/web/servlet/config/annotation/EnableWebMvc.html&#34;&gt;&lt;code&gt;@EnableWebMvc&lt;/code&gt;&lt;/a&gt; will &lt;a href=&#34;https://docs.spring.io/spring-boot/docs/2.1.1.RELEASE/reference/htmlsingle/#howto-switch-off-default-mvc-configuration&#34;&gt;switch off all default Spring Boot auto-configuration&lt;/a&gt; for Spring Web MVC. That means, JSP files and other resources might not be served correctly without extra configurations.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;embedded-servlet-container&#34;&gt;Embedded Servlet Container&lt;/h3&gt;
&lt;p&gt;By default, Spring Boot package &lt;code&gt;spring-boot-starter-web&lt;/code&gt; includes Tomcat server via &lt;code&gt;spring-boot-starter-tomcat&lt;/code&gt; which is rather sufficient. As we adopt Spring Boot&amp;rsquo;s convention for the embedded Tomcat, it will be later accessible at the default address &amp;ldquo;&lt;a href=&#34;http://localhost:8080&#34;&gt;http://localhost:8080&lt;/a&gt;&amp;rdquo;. In case you want to fine tune Tomcat, please reference to the &lt;a href=&#34;https://docs.spring.io/spring-boot/docs/current/reference/html/howto-embedded-web-servers.html&#34;&gt;full documentation&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;spring-boot--jsp-login-page&#34;&gt;Spring Boot + JSP Login Page&lt;/h2&gt;
&lt;h3 id=&#34;login-view&#34;&gt;Login View&lt;/h3&gt;
&lt;p&gt;To illustrate how Spring Boot works with JSP technologies, I will use a simple login page that asks for an email and password, conducts some trivial validations, and then informs whether it&amp;rsquo;s successful or failed.&lt;/p&gt;
&lt;p&gt;First, let&amp;rsquo;s create a simple JSP file &amp;ldquo;&lt;code&gt;webapp/WEB-INF/jsp/login.jsp&lt;/code&gt;&amp;rdquo; as the login view.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-jsp&#34; data-lang=&#34;jsp&#34;&gt;&amp;lt;%@ taglib prefix=&amp;#34;form&amp;#34; uri=&amp;#34;http://www.springframework.org/tags/form&amp;#34; %&amp;gt;
&amp;lt;html lang=&amp;#34;en&amp;#34;&amp;gt;
&amp;lt;head&amp;gt;
  &amp;lt;link href=&amp;#34;webjars/bootstrap/4.1.3/css/bootstrap.min.css&amp;#34; rel=&amp;#34;stylesheet&amp;#34;&amp;gt;
  &amp;lt;title&amp;gt;Login&amp;lt;/title&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
&amp;lt;div class=&amp;#34;jumbotron&amp;#34;&amp;gt;
  &amp;lt;h1&amp;gt;Spring Boot 2 + JSP Demo&amp;lt;/h1&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;#34;container&amp;#34;&amp;gt;
  &amp;lt;div class=&amp;#34;row&amp;#34;&amp;gt;
    &amp;lt;form:form method=&amp;#34;POST&amp;#34; modelAttribute=&amp;#34;loginForm&amp;#34;&amp;gt;
      &amp;lt;div class=&amp;#34;form-group&amp;#34;&amp;gt;
        &amp;lt;label for=&amp;#34;email&amp;#34;&amp;gt;E-Mail&amp;lt;/label&amp;gt;
        &amp;lt;form:input path=&amp;#34;email&amp;#34; cssClass=&amp;#34;form-control&amp;#34;/&amp;gt;
        &amp;lt;form:errors path=&amp;#34;email&amp;#34; cssStyle=&amp;#34;color: red&amp;#34;/&amp;gt;
      &amp;lt;/div&amp;gt;
      &amp;lt;div class=&amp;#34;form-group&amp;#34;&amp;gt;
        &amp;lt;label for=&amp;#34;password&amp;#34;&amp;gt;Password&amp;lt;/label&amp;gt;
        &amp;lt;form:password path=&amp;#34;password&amp;#34; cssClass=&amp;#34;form-control&amp;#34;/&amp;gt;
        &amp;lt;form:errors path=&amp;#34;password&amp;#34; cssStyle=&amp;#34;color: red&amp;#34;/&amp;gt;
      &amp;lt;/div&amp;gt;
      &amp;lt;form:button class=&amp;#34;btn btn-primary&amp;#34;&amp;gt;Log in&amp;lt;/form:button&amp;gt;
    &amp;lt;/form:form&amp;gt;
  &amp;lt;/div&amp;gt;
  &amp;lt;!--- check login status and display message --&amp;gt;
  &amp;lt;div class=&amp;#34;row&amp;#34;&amp;gt;
    &amp;lt;% Object status = session.getAttribute(&amp;#34;loginStatus&amp;#34;);
      if (&amp;#34;OK&amp;#34;.equals(status)) { %&amp;gt;
    &amp;lt;div class=&amp;#34;alert alert-success&amp;#34; role=&amp;#34;alert&amp;#34;&amp;gt;
      Congratulations! Login successfully.
    &amp;lt;/div&amp;gt;
    &amp;lt;% }
      if (&amp;#34;FAILED&amp;#34;.equals(status)) { %&amp;gt;
    &amp;lt;div class=&amp;#34;alert alert-danger&amp;#34; role=&amp;#34;alert&amp;#34;&amp;gt;
      Login failed. Please try again!!!
    &amp;lt;/div&amp;gt;
    &amp;lt;% } %&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;script src=&amp;#34;webjars/bootstrap/4.1.3/js/bootstrap.min.js&amp;#34;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Nothing is spectacular here. I will use some tags from &lt;a href=&#34;https://docs.spring.io/spring/docs/4.2.x/spring-framework-reference/html/spring-form-tld.html&#34;&gt;Spring form library&lt;/a&gt; to conveniently define and bind HTML form elements with the back-end controllers and model. The major elements are&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;form:form method=&amp;quot;POST&amp;quot; modelAttribute=&amp;quot;loginForm&amp;quot;&amp;gt;&lt;/code&gt;&amp;mdash;indicates the HTTP method POST as well as a model attribute namely &lt;code&gt;loginForm&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;form:input path=&amp;quot;email&amp;quot;&amp;gt;&lt;/code&gt; &amp;mdash; the input element for email&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;form:input path=&amp;quot;password&amp;quot;&amp;gt;&lt;/code&gt;&amp;mdash;the input element for password&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;form:errors .../&amp;gt;&lt;/code&gt; are placeholders for Spring&amp;rsquo;s validation errors (if any)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The later part of &lt;code&gt;login.jsp&lt;/code&gt; is to check whether the login process succeeded or failed and display a corresponding message via access to a session attribute &lt;code&gt;loginStatus&lt;/code&gt; . The actual value of &lt;code&gt;loginStatus&lt;/code&gt; will be updated by the business logic of the controller. Other than that, the JSP view includes Bootstrap 4&amp;rsquo;s stylesheet and JavaScript as provided by WebJars and use Bootstrap 4 CSS classes for styling.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;link&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;href&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;webjars/bootstrap/4.1.3/css/bootstrap.min.css&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;rel&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;stylesheet&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;script&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;src&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;webjars/bootstrap/4.1.3/js/bootstrap.min.js&amp;#34;&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style=&#34;color:#f92672&#34;&gt;script&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;login-controller&#34;&gt;Login Controller&lt;/h3&gt;
&lt;p&gt;First of all, we will need a data object to transfer the login input data in the JSP view (e.g. email and password) with the controllers and models. Here comes the &lt;code&gt;LoginForm&lt;/code&gt; class.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;LoginForm&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; String email;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; String password;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;LoginForm&lt;/span&gt;() {}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; String &lt;span style=&#34;color:#a6e22e&#34;&gt;getEmail&lt;/span&gt;() { &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; email; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;setEmail&lt;/span&gt;(String email) { &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;email&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; email; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; String &lt;span style=&#34;color:#a6e22e&#34;&gt;getPassword&lt;/span&gt;() { &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; password; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;setPassword&lt;/span&gt;(String password) { &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;password&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; password; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;No worries about the annotations &lt;code&gt;@NotBlank&lt;/code&gt;, &lt;code&gt;@Email&lt;/code&gt; for now as they are part of &lt;a href=&#34;#data-validation&#34;&gt;data validation&lt;/a&gt;. Apart from those, &lt;code&gt;LoginForm&lt;/code&gt; is just a normal bean with a no-arg constructor and the getters / setters.&lt;/p&gt;
&lt;p&gt;Now, we create a &lt;code&gt;LoginHandler&lt;/code&gt; class to coordinate and handle the whole login process.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;@Controller&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;@RequestMapping&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/login&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;LoginHandler&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; String LOGIN_VIEW &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;login&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; String LOGOUT_VIEW &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;logout&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;// controller body  &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;LoginHandler&lt;/code&gt; class is annotated with &lt;a href=&#34;https://docs.spring.io/spring-framework/docs/5.1.3.RELEASE/javadoc-api/org/springframework/stereotype/Controller.html&#34;&gt;&lt;code&gt;@Controller&lt;/code&gt;&lt;/a&gt; to indicate it is a web controller that will be automatically detected by Spring Boot. In the &lt;code&gt;LoginHandler&lt;/code&gt; class, let&amp;rsquo;s define some handler methods.&lt;/p&gt;
&lt;h4 id=&#34;handling-get-requests&#34;&gt;Handling GET Requests&lt;/h4&gt;
&lt;p&gt;We create a &lt;code&gt;showLoginView()&lt;/code&gt; method annotated with &lt;code&gt;@GetMapping&lt;/code&gt; for handling GET requests, i.e. when a client opens the corresponding URL &amp;ldquo;&lt;a href=&#34;http://localhost:8080/login&#34;&gt;http://localhost:8080/login&lt;/a&gt;&amp;rdquo;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;@GetMapping&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/login&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; String &lt;span style=&#34;color:#a6e22e&#34;&gt;showLoginView&lt;/span&gt;(Model model) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  model.&lt;span style=&#34;color:#a6e22e&#34;&gt;addAttribute&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;loginForm&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; LoginForm());
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; LOGIN_VIEW;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This method simply adds a new model attribute &lt;code&gt;loginForm&lt;/code&gt; (explained later in &lt;a href=&#34;#data-binding&#34;&gt;Data Binding&lt;/a&gt;) and returns a logical login view name &amp;ldquo;&lt;code&gt;login&lt;/code&gt;&amp;rdquo; (which will be resolved to &amp;ldquo;&lt;code&gt;login.jsp&lt;/code&gt;&amp;rdquo;).&lt;/p&gt;
&lt;h4 id=&#34;handling-post-requests&#34;&gt;Handling POST Requests&lt;/h4&gt;
&lt;p&gt;For processing POST requests (i.e. when the client enters some input data and submits the form), we define a &lt;code&gt;login()&lt;/code&gt; method annotated with &lt;code&gt;@PostMapping&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;@PostMapping&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/login&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; String &lt;span style=&#34;color:#a6e22e&#34;&gt;login&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;@Valid&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;@ModelAttribute&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;loginForm&amp;#34;&lt;/span&gt;) LoginForm form,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    BindingResult bindingResult,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    HttpSession session) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#f92672&#34;&gt;!&lt;/span&gt;bindingResult.&lt;span style=&#34;color:#a6e22e&#34;&gt;hasErrors&lt;/span&gt;()) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;boolean&lt;/span&gt; authenticated &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;abc@test.com&amp;#34;&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;equals&lt;/span&gt;(form.&lt;span style=&#34;color:#a6e22e&#34;&gt;getEmail&lt;/span&gt;());
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; String loginStatus &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; authenticated &lt;span style=&#34;color:#f92672&#34;&gt;?&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;OK&amp;#34;&lt;/span&gt; : &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;FAILED&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    session.&lt;span style=&#34;color:#a6e22e&#34;&gt;setAttribute&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;loginStatus&amp;#34;&lt;/span&gt;, loginStatus);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; LOGIN_VIEW;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The input data of the submitted form will be explicitly mapped to the method parameter &lt;code&gt;form&lt;/code&gt; via the annotation &lt;code&gt;@ModelAttribute&lt;/code&gt;. The &lt;code&gt;@Valid&lt;/code&gt; annotation and the parameter &lt;code&gt;bindingResult&lt;/code&gt; are for &lt;a href=&#34;#data-validation&#34;&gt;data validation&lt;/a&gt;, and the &lt;code&gt;session&lt;/code&gt; is for storing session data indicating a valid authentication.&lt;/p&gt;
&lt;p&gt;The actual authentication business logic has been simplified so that an input email &amp;ldquo;&lt;code&gt;abc@test.com&lt;/code&gt;&amp;rdquo; will pass. Of course, it should be revised with proper data and authentication process in real apps.&lt;/p&gt;
&lt;h4 id=&#34;handling-log-out&#34;&gt;Handling Log-Out&lt;/h4&gt;
&lt;p&gt;For the sake of completeness, we should also add a handler method for logging out in which we remove the session attribute &lt;code&gt;loginStatus&lt;/code&gt; added in the POST method &lt;code&gt;login()&lt;/code&gt; and redirect to a &amp;ldquo;&lt;code&gt;logout.jsp&lt;/code&gt;&amp;rdquo; page.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;@RequestMapping&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/logout&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; String &lt;span style=&#34;color:#a6e22e&#34;&gt;logout&lt;/span&gt;(HttpSession session) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  session.&lt;span style=&#34;color:#a6e22e&#34;&gt;removeAttribute&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;loginStatus&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; LOGOUT_VIEW;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;data-binding-a-namedata-bindinga&#34;&gt;Data Binding &lt;!-- raw HTML omitted --&gt;&lt;!-- raw HTML omitted --&gt;&lt;/h4&gt;
&lt;p&gt;We need to connect the HTML login form to a data transfer object (also known as &lt;em&gt;command object&lt;/em&gt;, &lt;em&gt;form object&lt;/em&gt;,  &lt;em&gt;form-backing object&lt;/em&gt;) of type &lt;code&gt;LoginForm&lt;/code&gt;. Otherwise, Spring MVC will raise the infamous error &amp;ldquo;&lt;em&gt;Caused by: java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name &amp;rsquo;loginForm&amp;rsquo; available as request attribute&lt;/em&gt;&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;There are more than one way to do that:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Declare a new method that returns a &lt;code&gt;LoginForm&lt;/code&gt; object and is annotated with &lt;a href=&#34;https://docs.spring.io/spring-framework/docs/5.1.3.RELEASE/javadoc-api/org/springframework/web/bind/annotation/ModelAttribute.html&#34;&gt;&lt;code&gt;@ModelAttribute(&amp;quot;loginForm&amp;quot;)&lt;/code&gt;&lt;/a&gt;. Note that all &lt;code&gt;@ModelAttribute&lt;/code&gt; annotated methods will be invoked before any handler methods. Thus, &lt;code&gt;LoginForm&lt;/code&gt; objects can be fed with some initial data, for instance, from a database.&lt;/li&gt;
&lt;li&gt;For the GET method &lt;code&gt;showLoginView()&lt;/code&gt;, create a parameter of type &lt;code&gt;LoginForm&lt;/code&gt; and annotate it with &lt;code&gt;@ModelAttribute(&amp;quot;loginForm&amp;quot;)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Do the same as (2) but omit &lt;code&gt;@ModelAttribute&lt;/code&gt;  for the method parameter because according to &lt;a href=&#34;https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-ann-arguments&#34;&gt;Spring Web documentation&lt;/a&gt;, it will be resolved as &lt;code&gt;@ModelAttribute&lt;/code&gt; implicitly&lt;/li&gt;
&lt;li&gt;Create a parameter of type &lt;a href=&#34;https://docs.spring.io/spring-framework/docs/5.1.3.RELEASE/javadoc-api/org/springframework/ui/Model.html&#34;&gt;&lt;code&gt;Model&lt;/code&gt;&lt;/a&gt; for the GET method &lt;code&gt;showLoginView()&lt;/code&gt; and then invoke &lt;code&gt;Model.addAttribute(&amp;quot;loginForm&amp;quot;, new LoginForm())&lt;/code&gt; to add a model attribute &lt;code&gt;loginForm&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Even though I can just go with (3) for its simplicity, I always prefer the other three as they advocate explicit declaration. It might make the code a bit verbose but would be easy to understand and maintain later on. I exemplify (4) and implement in &lt;code&gt;showLoginView()&lt;/code&gt;.&lt;/p&gt;
&lt;h4 id=&#34;data-validationa-namedata-validationa&#34;&gt;Data Validation&lt;!-- raw HTML omitted --&gt;&lt;!-- raw HTML omitted --&gt;&lt;/h4&gt;
&lt;p&gt;In my previous Spring 3 projects, I used to create validators that implement the &lt;a href=&#34;https://docs.spring.io/spring-framework/docs/5.1.3.RELEASE/javadoc-api/org/springframework/validation/Validator.html&#34;&gt;&lt;code&gt;Validator&lt;/code&gt;&lt;/a&gt; interface and utilise &lt;a href=&#34;https://docs.spring.io/spring-framework/docs/5.1.3.RELEASE/javadoc-api/org/springframework/validation/ValidationUtils.html&#34;&gt;ValidationUtils&lt;/a&gt; helper methods to check the input data. These validator beans will be injected into Spring controllers to validate the input before handing over to the actual business logics.&lt;/p&gt;
&lt;p&gt;Nevertheless, we can also leverage &lt;a href=&#34;https://beanvalidation.org/1.0/&#34;&gt;Bean Validation 1.0&lt;/a&gt; (JSR-303) and &lt;a href=&#34;https://beanvalidation.org/1.1/&#34;&gt;1.1&lt;/a&gt; (JSR-349) supported since Spring 4 and &lt;a href=&#34;https://beanvalidation.org/2.0/&#34;&gt;Bean Validation 2.0&lt;/a&gt; (JSR-380) supported since Spring 5 via &lt;a href=&#34;http://hibernate.org/validator/&#34;&gt;Hibernate Validator&lt;/a&gt;. These modules are already included with &lt;code&gt;spring-boot-starter-web&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;First, we annotate &lt;code&gt;LoginForm&lt;/code&gt;&amp;rsquo;s fields with some Bean Validation constraints and corresponding messages.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;LoginForm&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;@NotBlank&lt;/span&gt;(message &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;E-Mail must not be empty.&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;@Email&lt;/span&gt;(message &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Please enter a valid e-mail address.&amp;#34;&lt;/span&gt;)  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; String email;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;@NotBlank&lt;/span&gt;(message &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Password must not be empty.&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; String password;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then we need to update &lt;code&gt;LoginHandler&lt;/code&gt; with respect to validation logics but mostly with the POST handler &lt;code&gt;login()&lt;/code&gt;.  The simplest way is to add a &lt;code&gt;@Valid&lt;/code&gt; annotation to the parameter &lt;code&gt;form&lt;/code&gt;. It indicates that Spring should pass &lt;code&gt;form&lt;/code&gt; to a &lt;code&gt;Validator&lt;/code&gt; beforehand. To get access to validation errors, we have to declare a parameter &lt;code&gt;bindingResult&lt;/code&gt; of type &lt;a href=&#34;https://docs.spring.io/spring-framework/docs/5.1.3.RELEASE/javadoc-api/org/springframework/validation/BindingResult.html&#34;&gt;&lt;code&gt;BindingResult&lt;/code&gt;&lt;/a&gt; and place it immediately next to &lt;code&gt;form&lt;/code&gt;. Inside &lt;code&gt;login()&lt;/code&gt;, we can invoke the method &lt;code&gt;BindingResult#hasErrors()&lt;/code&gt; to see whether there are some validation errors and act accordingly. In this case, the login process won&amp;rsquo;t proceed until no validation error occurs.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; String &lt;span style=&#34;color:#a6e22e&#34;&gt;login&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;@Valid&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;@ModelAttribute&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;loginForm&amp;#34;&lt;/span&gt;) LoginForm form,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    BindingResult bindingResult,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    HttpSession session) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#f92672&#34;&gt;!&lt;/span&gt;bindingResult.&lt;span style=&#34;color:#a6e22e&#34;&gt;hasErrors&lt;/span&gt;()) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Thanks to Spring tag &amp;ldquo;&lt;code&gt;&amp;lt;form:errors .../&amp;gt;&lt;/code&gt;&amp;rdquo;, any validation errors will be displayed on the JSP login view. For instance, when I left both email and password empty, I got the following messages.&lt;/p&gt;
&lt;!-- raw HTML omitted --&gt;
&lt;blockquote&gt;
&lt;p&gt;If the &lt;code&gt;BindingResult&lt;/code&gt; parameter &lt;em&gt;is not placed immediately next to&lt;/em&gt; the corresponding model attribute &lt;code&gt;loginForm&lt;/code&gt;, Spring Boot will throw a &lt;a href=&#34;https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/validation/BindException.html&#34;&gt;&lt;code&gt;BindException&lt;/code&gt;&lt;/a&gt; that will be resolved via &lt;a href=&#34;https://docs.spring.io/spring-framework/docs/5.1.3.RELEASE/javadoc-api/org/springframework/web/servlet/mvc/support/DefaultHandlerExceptionResolver.html&#34;&gt;&lt;code&gt;DefaultHandlerExceptionResolver&lt;/code&gt;&lt;/a&gt; as an error HTTP 404 - Bad Request.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;building-and-executing&#34;&gt;Building and Executing&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;build.gradle&lt;/code&gt; created previously is mainly based on the &lt;a href=&#34;https://docs.spring.io/spring-boot/docs/current/gradle-plugin/reference/html/&#34;&gt;Spring Boot Gradle plugin&lt;/a&gt; for dependency and task management.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;./gradlew bootRun
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;When visiting &lt;a href=&#34;http://localhost:8080/login&#34;&gt;http://localhost:8080/login&lt;/a&gt;, you can see the login page.&lt;/p&gt;
&lt;!-- raw HTML omitted --&gt;
&lt;p&gt;To build a WAR package that is executable and deployable&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;./gradlew bootWar
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The resulting WAR file is &amp;ldquo;&lt;code&gt;./build/libs/spring-boot-jsp-demo-0.0.1-SNAPSHOT.war&lt;/code&gt;&amp;rdquo;.  It&amp;rsquo;s interesting that you can deploy the WAR file to a standalone Tomcat server as well as directly execute it with &amp;ldquo;&lt;code&gt;java -jar&lt;/code&gt;&amp;rdquo; .&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;java -jar ./build/libs/spring-boot-jsp-demo-0.0.1-SNAPSHOT.war
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In case you want to change the WAR file name, Spring Boot Gradle plugin inherits from, and therefore, offers similar options as, the &lt;a href=&#34;https://docs.gradle.org/current/userguide/war_plugin.html&#34;&gt;official Gradle War plugin&lt;/a&gt;. For instance, I can get rid of the version and use the build project&amp;rsquo;s name to form the WAR file name by customise the task &lt;a href=&#34;https://docs.spring.io/spring-boot/docs/2.1.1.RELEASE/gradle-plugin/api/org/springframework/boot/gradle/tasks/bundling/BootWar.html&#34;&gt;&lt;code&gt;BootWar&lt;/code&gt;&lt;/a&gt; in &lt;code&gt;build.gradle&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-groovy&#34; data-lang=&#34;groovy&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;bootWar &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	archiveName &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;${project.name}.war&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Also note that, when applying together with Gradle war plugin, Spring Boot Gradle plugin &lt;a href=&#34;https://docs.spring.io/spring-boot/docs/current/gradle-plugin/reference/html/#reacting-to-other-plugins-war&#34;&gt;will disable the task &lt;code&gt;war&lt;/code&gt;&lt;/a&gt;. Should you want to use &lt;code&gt;war&lt;/code&gt; alongside &lt;code&gt;bootWar&lt;/code&gt;, just simply enable it.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-groovy&#34; data-lang=&#34;groovy&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;war &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	enabled &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;updates&#34;&gt;Updates&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;The original Git repository with Spring Boot v2 is here: &lt;a href=&#34;https://github.com/htr3n/spring-boot-jsp-demo&#34;&gt;https://github.com/htr3n/spring-boot-jsp-demo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2024-03-23: I created a demo with Spring Boot v3 and JSP/JSTL at &lt;a href=&#34;https://github.com/htr3n/springboot3-web-war&#34;&gt;https://github.com/htr3n/springboot3-web-war&lt;/a&gt;. There are few changes, especially with &lt;code&gt;jakarta.servlet&lt;/code&gt; instead of &lt;code&gt;javax.servlet&lt;/code&gt; and upgrading WebJars Bootstrap v5.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;references&#34;&gt;References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://spring.io/guides/gs/serving-web-content/&#34;&gt;https://spring.io/guides/gs/serving-web-content/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://stackoverflow.com/questions/46391915/how-to-render-jsp-using-spring-boot-application/46399638#46399638&#34;&gt;https://stackoverflow.com/questions/46391915/how-to-render-jsp-using-spring-boot-application/46399638#46399638&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://stackoverflow.com/questions/45533908/unable-to-render-the-jsp-using-spring-boot/45543355#45543355&#34;&gt;https://stackoverflow.com/questions/45533908/unable-to-render-the-jsp-using-spring-boot/45543355#45543355&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://stackoverflow.com/questions/24661289/spring-boot-not-serving-static-content&#34;&gt;https://stackoverflow.com/questions/24661289/spring-boot-not-serving-static-content&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
      </item>
    
      <item>
        <title>Tour de Spring Boot: DI meets CoC</title>
        <link>https://htr3n.github.io/2018/12/spring-boot-di-meets-coc/</link>
        <pubDate>Tue, 04 Dec 2018 00:00:00 +0000</pubDate>
        
        <guid>71e897404541b3b63ea375b4ade0d8c5</guid>
        <description>&lt;p&gt;I started using Spring framework few years back in 2009 to develop demo systems for some EU projects. These projects featured a number of Web services some of which share back-end databases and some other talk to external services or WS-BPEL business processes.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&#34;https://en.wikipedia.org/wiki/Dependency_injection&#34;&gt;dependency injection&lt;/a&gt; implemented in Spring works so well and on top of that, many other parts like Spring MVC,  data access, transactions messaging and even some third-party libraries such as Apache &lt;a href=&#34;http://activemq.apache.org/&#34;&gt;ActiveMQ&lt;/a&gt;, Apache &lt;a href=&#34;http://cxf.apache.org/&#34;&gt;CXF&lt;/a&gt; and JBoss (now Red Hat and likely IBM) &lt;a href=&#34;http://hibernate.org/orm/&#34;&gt;Hibernate ORM&lt;/a&gt;, and many other helper libraries all came to play nicely.&lt;/p&gt;
&lt;p&gt;One of my concerns is that configuring a complex Spring based project is truly tedious and error-prone. I have made countless trial-and errors and gone through lots of warning and errors, not to mention XML verbosity and complexity, Maven dependency hell, the conflicts or incompatibilities among numerous dependencies. Fast forward to 2018 I want to refresh my experience through existing Spring projects. I was thinking about similar rough paths when upgrading Spring and Hibernate to some prior versions until discovering &lt;a href=&#34;http://spring.io/projects/spring-boot&#34;&gt;Spring Boot&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To be precise, Spring Boot is not a magic wand that would help us to navigate through the forest of Spring framework complexity or automatically resolve certain problems. It is more or less some sort of &lt;a href=&#34;https://en.wikipedia.org/wiki/Convention_over_configuration&#34;&gt;&lt;em&gt;convention over configuration&lt;/em&gt;&lt;/a&gt; that might reduce significant effort on making Spring applications quickly up and running as well as ensure better compatibilities among integrated libraries.&lt;/p&gt;
&lt;h2 id=&#34;quickstart&#34;&gt;A Quick Start&lt;/h2&gt;
&lt;p&gt;Let&amp;rsquo;s consider the following Java code defining a REST controller for an endpoint &amp;ldquo;&lt;code&gt;/&lt;/code&gt;&amp;rdquo; that shall display a greeting.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;@RestController&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;HelloWorld&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;@RequestMapping&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; String &lt;span style=&#34;color:#a6e22e&#34;&gt;hello&lt;/span&gt;(){
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Hello World!&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Just with this very minimal code, we can have a working Spring application. Assume that the &lt;a href=&#34;https://docs.spring.io/spring-boot/docs/current/reference/html/cli.html&#34;&gt;Spring Boot CLI&lt;/a&gt; is available, start our application with the following command.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;spring run HelloWorld.java
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Spring Boot will launch an embedded Tomcat server and initialise a Web application to serve the endpoint at &amp;ldquo;&lt;a href=&#34;http://localhost:8080&#34;&gt;http://localhost:8080&lt;/a&gt;&amp;rdquo;. Visiting this address will give us &amp;ldquo;&lt;em&gt;Hello World!&lt;/em&gt;&amp;rdquo;. What could be cooler than that !?&lt;/p&gt;
&lt;p&gt;Now, let&amp;rsquo;s start a quick tour on some more appealing features that Spring Boot 2.1.0 offers.&lt;/p&gt;
&lt;h2 id=&#34;bootstrapping&#34;&gt;Project Bootstrapping&lt;/h2&gt;
&lt;p&gt;Using &lt;a href=&#34;https://start.spring.io/&#34;&gt;Spring Initializr&lt;/a&gt; directly or via IDE /CLI, we can quickly bootstrap a dead simple or full-blown Spring development project. For instance, this command will create a Spring application development project, namely, &lt;code&gt;hello-world&lt;/code&gt;, with JPA and H2 database.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;spring init --dependencies&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;web,data-jpa,h2 hello-world
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;After asking some questions such as the project&amp;rsquo;s and package&amp;rsquo;s names, the command line will download the core package and create a new development project that is ready to be imported to any IDE. Other than that, Eclipse or IntelliJ IDEA can just walk you through simple wizards in which you can craft your own project and choose the necessary components for the new project.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;spring-boot-in-ide.png&#34; alt=&#34;Spring Boot project in Eclipse&#34;&gt;&lt;/p&gt;
&lt;h2 id=&#34;dependency-management&#34;&gt;Build and Dependency Management&lt;/h2&gt;
&lt;p&gt;Spring Boot 2 works with Spring Framework 5 and requires at least Java 8. You can either choose Maven or Gradle build system when creating the project. An excerpt of Maven &lt;code&gt;pom.xml&lt;/code&gt; (stripped off few minor details) of our project is shown below.&lt;/p&gt;
&lt;div&gt;
  &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-xml&#34; data-lang=&#34;xml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;project&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;modelVersion&amp;gt;&lt;/span&gt;4.0.0&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/modelVersion&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;io.github.htr3n&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;hello-world&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;version&amp;gt;&lt;/span&gt;0.0.1-SNAPSHOT&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;packaging&amp;gt;&lt;/span&gt;jar&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/packaging&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;name&amp;gt;&lt;/span&gt;hello-world&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/name&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;description&amp;gt;&lt;/span&gt;Demo project for Spring Boot&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/description&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;parent&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-boot-starter-parent&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;version&amp;gt;&lt;/span&gt;2.1.0.RELEASE&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;relativePath/&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;&amp;lt;!-- lookup parent from repository --&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/parent&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;properties&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;project.build.sourceEncoding&amp;gt;&lt;/span&gt;UTF-8&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/project.build.sourceEncoding&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;project.reporting.outputEncoding&amp;gt;&lt;/span&gt;UTF-8&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/project.reporting.outputEncoding&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;java.version&amp;gt;&lt;/span&gt;1.8&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/java.version&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/properties&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;dependencies&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-boot-starter-data-jpa&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-boot-starter-web&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;com.h2database&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;h2&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;scope&amp;gt;&lt;/span&gt;runtime&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/scope&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-boot-starter-test&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;scope&amp;gt;&lt;/span&gt;test&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/scope&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/dependencies&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;build&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;plugins&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;plugin&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-boot-maven-plugin&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/plugin&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/plugins&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/build&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/project&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;div class=&#34;code--caption&#34;&gt;A simplified &lt;code&gt;pom.xml&lt;/code&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;This POM inherits many &lt;a href=&#34;https://docs.spring.io/spring-boot/docs/current/reference/html/using-boot-build-systems.html#using-boot-maven&#34;&gt;useful default settings and values&lt;/a&gt; from &lt;code&gt;spring-boot-starter-parent&lt;/code&gt;.  We might opt to not use &lt;code&gt;spring-boot-starter-parent&lt;/code&gt; and go old-school to set everything up on our own. I have just recalled working with Spring 3 and trying to integrate an embedded Jetty server. I really struggled with different Jetty versions as well as other libraries to make them click. When I tried to upgrade the legacy projects to newer Spring and Hibernate versions, things all turned out really messy with loads of mysterious errors.&lt;/p&gt;
&lt;p&gt;Spring Boot eases this kind of burden with some opinionated design and configuration decisions. We can truly leverage its strength and choose among a set of &lt;a href=&#34;https://docs.spring.io/spring-boot/docs/current/reference/html/using-boot-build-systems.html#using-boot-starter&#34;&gt;starters&lt;/a&gt; (beginning with &lt;code&gt;spring-boot-starter-&lt;/code&gt;). The starters are intended for better compatiblity and smooth integration.&lt;/p&gt;
&lt;p&gt;In the &lt;code&gt;hello-world&lt;/code&gt; project, we have chosen three components &lt;code&gt;spring-boot-starter-data-jpa&lt;/code&gt; (JPA), &lt;code&gt;spring-boot-starter-web&lt;/code&gt; (Web), &lt;code&gt;spring-boot-starter-test&lt;/code&gt; (for testing) along with &lt;code&gt;mysql-connector-java&lt;/code&gt; (MySQL).&lt;/p&gt;
&lt;h2 id=&#34;autoconfiguration&#34;&gt;Autoconfiguration&lt;/h2&gt;
&lt;p&gt;Intelligent autoconfiguration is perhaps one of the most prominent and important parts of Spring Boot. There are different levels of configuring a Spring based application. The simplest form of autoconfiguration is the &amp;ldquo;&lt;em&gt;Hello World&lt;/em&gt;&amp;rdquo; example mentioned above. The new Maven based project created via the wizard or command line consists of &lt;code&gt;pom.xml&lt;/code&gt; along with &lt;code&gt;application.properties&lt;/code&gt;, &lt;code&gt;HelloWorldApplication.java&lt;/code&gt; and &lt;code&gt;HelloWorldApplicationTest.java&lt;/code&gt; as shown in Figure 1.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;package&lt;/span&gt; io.github.htr3n;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; org.springframework.boot.SpringApplication;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; org.springframework.boot.autoconfigure.SpringBootApplication;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;@SpringBootApplication&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;HelloWorldApplication&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;(String&lt;span style=&#34;color:#f92672&#34;&gt;[]&lt;/span&gt; args) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    SpringApplication.&lt;span style=&#34;color:#a6e22e&#34;&gt;run&lt;/span&gt;(HelloWorldApplication.&lt;span style=&#34;color:#a6e22e&#34;&gt;class&lt;/span&gt;, args);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;HelloWorldApplication&lt;/code&gt; class is annotated with &lt;a href=&#34;https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/autoconfigure/SpringBootApplication.html&#34;&gt;&lt;code&gt;@SpringBootApplication&lt;/code&gt;&lt;/a&gt; which is actually an umbrella for three annotations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/autoconfigure/EnableAutoConfiguration.html&#34;&gt;&lt;code&gt;@EnableAutoConfiguration&lt;/code&gt;&lt;/a&gt; that triggers auto-configuration of Spring application context.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://docs.spring.io/spring-framework/docs/5.1.2.RELEASE/javadoc-api/org/springframework/context/annotation/ComponentScan.html?is-external=true&#34;&gt;&lt;code&gt;@ComponentScan&lt;/code&gt;&lt;/a&gt; that enables the scanning of classes annotated with &lt;code&gt;@Component&lt;/code&gt; or its sub-types on the package where the application is located (that&amp;rsquo;s why &lt;a href=&#34;https://docs.spring.io/spring-boot/docs/current/reference/html/using-boot-structuring-your-code.html#using-boot-locating-the-main-class&#34;&gt;it is often recommended&lt;/a&gt; to place the class annotated with &lt;code&gt;@SpringBootApplication&lt;/code&gt; at the root package above other classes)&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/SpringBootConfiguration.html&#34;&gt;&lt;code&gt;@SpringBootConfiguration&lt;/code&gt;&lt;/a&gt; is an alias to &lt;a href=&#34;https://docs.spring.io/spring-framework/docs/5.1.2.RELEASE/javadoc-api/org/springframework/context/annotation/Configuration.html?is-external=true&#34;&gt;&lt;code&gt;@Configuration&lt;/code&gt;&lt;/a&gt; allows for registering some more beans in the context or import additional configuration classes&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The aforementioned annotations are sufficient to launch not-so-complex Spring applications. In case one wants to fine-tune the application context autoloading, individual annocations mentioned above and/or customised annotations can be leveraged.&lt;/p&gt;
&lt;p&gt;Examining the Spring Boot &lt;a href=&#34;https://github.com/spring-projects/spring-boot/tree/master/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure&#34;&gt;auto-configure project&lt;/a&gt; on Github, we can see many &lt;a href=&#34;https://github.com/spring-projects/spring-boot/blob/v2.1.0.RELEASE/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories&#34;&gt;scripts&lt;/a&gt; for essential libraries. Depending on what are detected on the classpath and the application-specific configuration directives, Spring Boot will automatically include and configure the corresponding components.&lt;/p&gt;
&lt;p&gt;We can explicitly disable certain parts using &lt;code&gt;@EnableAutoConfiguration(exclude={class1, class2, ...})&lt;/code&gt; or the directive &amp;ldquo;&lt;code&gt;spring.autoconfigure.exclude=class1, class2, ...&lt;/code&gt;&amp;rdquo; in &lt;code&gt;application.properties&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&#34;app-launcher-configuration&#34;&gt;App Launcher Configuration&lt;/h3&gt;
&lt;p&gt;The &lt;a href=&#34;https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/SpringApplication.html&#34;&gt;&lt;code&gt;SpringApplication&lt;/code&gt;&lt;/a&gt; class is the main launcher of a Spring application. Prior to Spring Boot, in order to start a Spring app we have to manually initialise an &lt;a href=&#34;https://docs.spring.io/spring-framework/docs/5.1.2.RELEASE/javadoc-api/org/springframework/context/ApplicationContext.html?is-external=true&#34;&gt;&lt;code&gt;ApplicationContext&lt;/code&gt;&lt;/a&gt;, parse system- and application-specific properties and input arguments (if needed), load all necessary beans and/or launch an embedded Web server like &lt;a href=&#34;https://tomcat.apache.org/&#34;&gt;Tomcat&lt;/a&gt; or &lt;a href=&#34;https://www.eclipse.org/jetty/&#34;&gt;Jetty&lt;/a&gt;. Now, all of these tasks will be automatically done using &lt;code&gt;SpringApplication&lt;/code&gt; with &lt;code&gt;@SpringBootApplication&lt;/code&gt; (or a combination of its sub-annotations).&lt;/p&gt;
&lt;p&gt;Apart from &lt;a href=&#34;https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html#boot-features-external-config-application-property-files&#34;&gt;&lt;code&gt;application.properties&lt;/code&gt;&lt;/a&gt; (or &lt;code&gt;.yml&lt;/code&gt;), we can configure and customise a Spring app using a &lt;code&gt;SpringApplication&lt;/code&gt; or &lt;a href=&#34;https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-spring-application.html#boot-features-fluent-builder-api&#34;&gt;&lt;code&gt;SpringApplicationBuilder&lt;/code&gt;&lt;/a&gt; instance. For instance, the following code will turn off the banner when launching our Spring app&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;(String&lt;span style=&#34;color:#f92672&#34;&gt;[]&lt;/span&gt; args) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  SpringApplication app &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; SpringApplication(HelloWorldApplication.&lt;span style=&#34;color:#a6e22e&#34;&gt;class&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  app.&lt;span style=&#34;color:#a6e22e&#34;&gt;setBannerMode&lt;/span&gt;(Banner.&lt;span style=&#34;color:#a6e22e&#34;&gt;Mode&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;OFF&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  app.&lt;span style=&#34;color:#a6e22e&#34;&gt;run&lt;/span&gt;(args);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;which is equivalent to &lt;code&gt;spring.main.banner-mode=off&lt;/code&gt; in &lt;code&gt;application.properties&lt;/code&gt;. Spring Boot comes with numerous predefined properties. Indeed, almost every autoconfigured component offers some default property settings. These predefined settings will be overriden with our own settings, if exist.&lt;/p&gt;
&lt;h3 id=&#34;properties-loading&#34;&gt;Properties Loading&lt;/h3&gt;
&lt;p&gt;By default, Spring Boot will bind external properties from &lt;code&gt;application.properties&lt;/code&gt; (or &lt;code&gt;.yml&lt;/code&gt;) at runtime. That is called &lt;a href=&#34;https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html&#34;&gt;externalized configuration&lt;/a&gt;. More details on application properties can be found &lt;a href=&#34;https://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;blockquote class=&#34;warning&#34;&gt;
    &lt;strong&gt;Warning&lt;/strong&gt;&lt;br&gt;
    Please beware of the trailing whitespaces in Spring &lt;code&gt;.properties&lt;/code&gt; as Spring Boot &lt;a href=&#34;https://github.com/spring-projects/spring-boot/issues/4106#issuecomment-173278825&#34;&gt;won&amp;rsquo;t trim off any of them&lt;/a&gt; and in some cases that might lead to unexpected issues or even crash the applications (see &lt;a href=&#34;https://htr3n.github.io/2018/11/spring-boot-trailing-whitespaces/&#34;&gt;my other relevant post&lt;/a&gt;)
&lt;/blockquote&gt;

&lt;p&gt;Besides the default &lt;code&gt;application.properties&lt;/code&gt;, Spring allows us to activate various profiles using the naming convention &lt;code&gt;application-{profile}.properties&lt;/code&gt;. It comes very handy in case we look forward to separating testing-specific environments, for example, using &lt;code&gt;application-test.properties&lt;/code&gt;, from production environments. We can still ask to load property sources with &lt;a href=&#34;https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/annotation/PropertySource.html&#34;&gt;&lt;code&gt;@PropertySource&lt;/code&gt;&lt;/a&gt; as usual in Spring.&lt;/p&gt;
&lt;h3 id=&#34;components-and-beans-configuration&#34;&gt;Components and Beans Configuration&lt;/h3&gt;
&lt;p&gt;Other components and bean configurations can be loaded from different sources including XML files, Java classes (with &lt;a href=&#34;https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/annotation/Configuration.html&#34;&gt;&lt;code&gt;@Configuration&lt;/code&gt;&lt;/a&gt;), or Groovy (also annotated with &lt;code&gt;@Configuration&lt;/code&gt; as Java or via Groovy &lt;a href=&#34;https://docs.spring.io/spring-boot/docs/current/reference/html/cli-groovy-beans-dsl.html&#34;&gt;Beans DSL&lt;/a&gt; &amp;ldquo;&lt;code&gt;beans {...}&lt;/code&gt;&amp;rdquo;).&lt;/p&gt;
&lt;p&gt;Note that, all components in the sub-paths under the main class annotated with &lt;code&gt;@SpringBootApplication&lt;/code&gt; will be automatically scanned and initialised. The rest of beans configuration will be handed over to Spring&amp;rsquo;s &lt;a href=&#34;https://docs.spring.io/spring-boot/docs/current/reference/html/using-boot-spring-beans-and-dependency-injection.html&#34;&gt;&lt;em&gt;dependency injection mechanism&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;web-configuration&#34;&gt;Web Configuration&lt;/h3&gt;
&lt;p&gt;Spring Boot often &lt;a href=&#34;https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-spring-application.html#boot-features-web-environment&#34;&gt;tries to establish&lt;/a&gt; an appropriate &lt;a href=&#34;https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/ApplicationContext.html&#34;&gt;&lt;code&gt;ApplicationContext&lt;/code&gt;&lt;/a&gt; based on classpath scanning and app-specific configurations. For instance, to enable the traditional Spring Web MVC, I simply include the component &lt;code&gt;spring-boot-starter-web&lt;/code&gt; in the POM as &lt;a href=&#34;#dependency-management&#34;&gt;shown in the previous section&lt;/a&gt;. Spring Boot will automatically adds relevant components for resolving and serving Web pages and resources.&lt;/p&gt;
&lt;p&gt;We can add extra components such as &lt;a href=&#34;https://docs.spring.io/spring/docs/current/spring-framework-reference/web-reactive.html&#34;&gt;WebFlux&lt;/a&gt;&amp;mdash;the reactive framework added in Spring 5+  (&lt;code&gt;spring-boot-starter-webflux&lt;/code&gt;), &lt;a href=&#34;https://www.thymeleaf.org/&#34;&gt;Thymeleaf&lt;/a&gt; template engine (&lt;code&gt;spring-boot-starter-thymeleaf&lt;/code&gt;), Spring Web services (&lt;code&gt;spring-boot-starter-web-services&lt;/code&gt;) and &lt;a href=&#34;https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#websocket&#34;&gt;WebSocket&lt;/a&gt;  (&lt;code&gt;spring-boot-starter-websocket&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;Spring &lt;a href=&#34;https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html&#34;&gt;Web MVC&lt;/a&gt; is totally capable to handle most of HTTP requests via &lt;a href=&#34;https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html&#34;&gt;servlets&lt;/a&gt; or &lt;a href=&#34;https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/stereotype/Controller.html&#34;&gt;controllers&lt;/a&gt; like the simple Hello World example above. Should you need more advanced control of RESTful endpoints, just add either one of &lt;a href=&#34;http://spring.io/projects/spring-hateoas&#34;&gt;Spring HATEOAS&lt;/a&gt; (&lt;code&gt;spring-boot-starter-hateoas&lt;/code&gt;), &lt;a href=&#34;https://jersey.github.io/&#34;&gt;Jersey&lt;/a&gt; (&lt;code&gt;spring-boot-starter-jersey&lt;/code&gt;) or &lt;a href=&#34;https://cxf.apache.org/&#34;&gt;Apache CXF&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;By default, the Web starter will use Tomcat as the underlying embedded application server. When we opt for another server, we must explicitly exclude Tomcat and add either &lt;code&gt;spring-boot-starter-jetty&lt;/code&gt; (Jetty) or &lt;code&gt;spring-boot-starter-undertow&lt;/code&gt; (Undertow) in our POM.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-xml&#34; data-lang=&#34;xml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-boot-starter-web&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;exclusions&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;exclusion&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-boot-starter-tomcat&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/exclusion&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/exclusions&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-boot-starter-jetty&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Many of the embedded server&amp;rsquo;s settings can be defined in &lt;code&gt;application.properties&lt;/code&gt; such as the network address, port, sessions, and so on. These settings can also be done programmatically by defining bean implementing &lt;a href=&#34;https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/web/server/WebServerFactoryCustomizer.html&#34;&gt;&lt;code&gt;WebServerFactoryCustomizer&lt;/code&gt;&lt;/a&gt; that enables access to customise the underlying &lt;a href=&#34;https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/web/server/WebServerFactory.html&#34;&gt;&lt;code&gt;WebServerFactory&lt;/code&gt;&lt;/a&gt;. For instance, you can refer to more fine-tuned customisations for &lt;a href=&#34;https://github.com/spring-projects/spring-boot/blob/v2.1.0.RELEASE/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/JettyWebServerFactoryCustomizer.java&#34;&gt;Jetty&lt;/a&gt;, &lt;a href=&#34;https://github.com/spring-projects/spring-boot/blobv2.1.0.RELEASE/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizer.java&#34;&gt;Tomcat&lt;/a&gt;, or &lt;a href=&#34;https://github.com/spring-projects/spring-boot/blob/v2.1.0.RELEASE/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/UndertowWebServerFactoryCustomizer.java&#34;&gt;Undertow&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Following up our example on excluding Tomcat and adding Jetty, we can create a simple bean to change the Jetty server from the default port &lt;code&gt;8080&lt;/code&gt; to &lt;code&gt;9999&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;package&lt;/span&gt; io.github.htr3n;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; org.springframework.boot.web.server.ConfigurableWebServerFactory;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; org.springframework.boot.web.server.WebServerFactoryCustomizer;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; org.springframework.stereotype.Component;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;@Component&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;JettyServerCustomizer&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;implements&lt;/span&gt; WebServerFactoryCustomizer&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;ConfigurableWebServerFactory&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;@Override&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;customize&lt;/span&gt;(ConfigurableWebServerFactory factory) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    factory.&lt;span style=&#34;color:#a6e22e&#34;&gt;setPort&lt;/span&gt;(9999);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;data-access-configuration&#34;&gt;Data Access Configuration&lt;/h3&gt;
&lt;p&gt;Going through various versions, Spring framework always provides considerable support and different abstraction levels for &lt;a href=&#34;http://spring.io/projects/spring-data&#34;&gt;database access&lt;/a&gt;. In general, it often requires some configurations for data sources and sometimes the intermediate layers such as pooling or caching.&lt;/p&gt;
&lt;p&gt;Spring Boot has taken further steps forward by auto-configuring in some popular circumstances, for instance, embedded databases, database pooling, to name but a few. What we need to do is to add appropriate dependencies. In the &lt;code&gt;hello-world&lt;/code&gt; project, &lt;a href=&#34;https://www.h2database.com/html/main.html&#34;&gt;H2 database engine&lt;/a&gt; will be auto-configured by Spring Boot.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-xml&#34; data-lang=&#34;xml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;dependencies&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;com.h2database&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;h2&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;scope&amp;gt;&lt;/span&gt;runtime&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/scope&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/dependencies&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Note that, including database dependencies alone won&amp;rsquo;t trigger any auto-configuration. It&amp;rsquo;s only when Spring Boot found some sort of data access components such as &lt;code&gt;spring-boot-starter-jdbc&lt;/code&gt;, &lt;code&gt;spring-boot-starter-data-jpa&lt;/code&gt; (which transitively embraces &lt;code&gt;spring-jdbc&lt;/code&gt;) on the classpath.&lt;/p&gt;
&lt;p&gt;Atop the data connection layer, Spring Boot takes the liberty of &lt;a href=&#34;https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-sql.html#boot-features-connect-to-production-database&#34;&gt;choosing other data access components&lt;/a&gt;. Note that the design decisions taken by Spring Boot are often based on some popular and widely-used conventions in Spring based application developments. The decisions for data access, like other components, can be overriden with our own information. For example, I can define my own H2 data source in &lt;code&gt;application.properties&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-properties&#34; data-lang=&#34;properties&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;spring.datasource.url&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;jdbc:h2:mem:helloword_db;DB_CLOSE_ON_EXIT=FALSE&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;spring.datasource.driverClassName&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;org.h2.Driver&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;spring.datasource.username&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;sa&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;spring.datasource.password&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;sa&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Next, Spring Boot will try to initialise the database. High level data access components such as &lt;a href=&#34;https://spring.io/projects/spring-data-jpa&#34;&gt;Spring Data JPA&lt;/a&gt;, &lt;a href=&#34;http://hibernate.org/orm/&#34;&gt;Hibernate&lt;/a&gt; can be customised via &lt;a href=&#34;https://docs.spring.io/spring-boot/docs/current/reference/html/howto-database-initialization.html#howto-database-initialization&#34;&gt;specific properties&lt;/a&gt;. Nonetheless, Spring Boot can look into the classpath for a &lt;a href=&#34;https://en.wikipedia.org/wiki/Data_definition_language&#34;&gt;schema definition script&lt;/a&gt;, namely, &lt;code&gt;schema.sql&lt;/code&gt;, and a &lt;a href=&#34;https://en.wikipedia.org/wiki/Data_manipulation_language&#34;&gt;data manipulation script&lt;/a&gt;, namely, &lt;code&gt;data.sql&lt;/code&gt; and execute them if found. Here is an example of these scripts for a simple database &lt;code&gt;customer&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;-- schema.sql
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;DROP&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;TABLE&lt;/span&gt; customer;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;CREATE&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;TABLE&lt;/span&gt; customer(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  id integer &lt;span style=&#34;color:#66d9ef&#34;&gt;not&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt; auto_increment,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  name varchar(&lt;span style=&#34;color:#ae81ff&#34;&gt;255&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;not&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  email varchar (&lt;span style=&#34;color:#ae81ff&#34;&gt;255&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;not&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;primary&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;key&lt;/span&gt; (id)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;-- data.sql
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;INSERT&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;INTO&lt;/span&gt; customer(name, email) &lt;span style=&#34;color:#66d9ef&#34;&gt;VALUES&lt;/span&gt; (&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;Bob&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;bob@test.com&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Instead, you may indicate the initialising scripts for specific databases using the naming convention &lt;code&gt;schema-${platform}.sql&lt;/code&gt; and &lt;code&gt;data-${platform}.sql&lt;/code&gt; where &lt;code&gt;platform&lt;/code&gt; is taken from &lt;code&gt;spring.datasource.platform&lt;/code&gt;. This convention helps us to separate vendor-specific data creation and manipulation scripts.&lt;/p&gt;
&lt;p&gt;Last but not least, Spring Boot classpath scanning mechanism may help us to entirely skip JPA&amp;rsquo;s  &lt;code&gt;persistence.xml&lt;/code&gt; as it will try to search for all classes annotated with &lt;a href=&#34;https://docs.oracle.com/javaee/7/api/javax/persistence/Entity.html&#34;&gt;&lt;code&gt;@Entity&lt;/code&gt;&lt;/a&gt;, &lt;a href=&#34;https://docs.oracle.com/javaee/7/api/javax/persistence/Embeddable.html&#34;&gt;&lt;code&gt;@Embeddable&lt;/code&gt;&lt;/a&gt;, or &lt;a href=&#34;https://docs.oracle.com/javaee/7/api/javax/persistence/MappedSuperclass.html&#34;&gt;&lt;code&gt;@MappedSuperclass&lt;/code&gt;&lt;/a&gt; in our application&amp;rsquo;s classpath.&lt;/p&gt;
&lt;h2 id=&#34;development-support&#34;&gt;Development Support&lt;/h2&gt;
&lt;h3 id=&#34;testing&#34;&gt;Testing&lt;/h3&gt;
&lt;p&gt;Testing is always a crucial part of any development process and Spring apps are no exception. That&amp;rsquo;s why Spring Boot provides &lt;code&gt;spring-boot-starter-test&lt;/code&gt; that comprises several handy components such as &lt;a href=&#34;https://junit.org/junit4/&#34;&gt;JUnit&lt;/a&gt;, &lt;a href=&#34;https://docs.spring.io/spring/docs/current/spring-framework-reference/testing.html&#34;&gt;Spring Tests&lt;/a&gt;, &lt;a href=&#34;https://site.mockito.org/&#34;&gt;Mockito&lt;/a&gt;, to name but a few.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; org.junit.Test;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; org.junit.runner.RunWith;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; org.springframework.boot.test.context.SpringBootTest;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; org.springframework.test.context.junit4.SpringRunner;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;@RunWith&lt;/span&gt;(SpringRunner.&lt;span style=&#34;color:#a6e22e&#34;&gt;class&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;@SpringBootTest&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;`&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;{&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;@&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Test&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;contextLoads&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Consider inside the project &lt;code&gt;hello-world&lt;/code&gt;, we have a simple class &lt;code&gt;HelloWorldApplicationTests&lt;/code&gt; annotated with &lt;a href=&#34;https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/test/context/SpringBootTest.html&#34;&gt;&lt;code&gt;@SpringBootTest&lt;/code&gt;&lt;/a&gt; that detects and initialises Spring Boot&amp;rsquo;s application context and testing environment. We can fine tune the testing environment in a similar manner as production&amp;rsquo;s (i.e. with &lt;a href=&#34;https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/annotation/Configuration.html&#34;&gt;&lt;code&gt;@Configuration&lt;/code&gt;&lt;/a&gt;, &lt;a href=&#34;https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/test/context/ContextConfiguration.html&#34;&gt;&lt;code&gt;@ContextConfiguration&lt;/code&gt;&lt;/a&gt; along with &lt;a href=&#34;https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/test/context/TestConfiguration.html&#34;&gt;&lt;code&gt;@TestConfiguration&lt;/code&gt;&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;We won&amp;rsquo;t delve into evey detail of testing support but you can find &lt;a href=&#34;https://docs.spring.io/spring-boot/docs/current/reference/html/test-auto-configuration.html&#34;&gt;an extensive list of test auto-configurations&lt;/a&gt; for JDBC, JPA, Neo, Redis, REST, Web MVC, and WebFlux as well as a rich documentation of Spring Boot testing features &lt;a href=&#34;https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-testing.html&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In &lt;a href=&#34;https://htr3n.github.io/2018/11/test-driven-spring-jdbc/&#34;&gt;one of my previous posts&lt;/a&gt;, we can see that the annotation &lt;a href=&#34;https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/test/autoconfigure/jdbc/JdbcTest.html&#34;&gt;&lt;code&gt;@JdbcTest&lt;/code&gt;&lt;/a&gt; has simplified a lot of settings needed for loading up databases, testing CRUD app with automatic transactions. As such it truly helps me better focus on the actual testing logics.&lt;/p&gt;
&lt;h3 id=&#34;troubleshooting&#34;&gt;Troubleshooting&lt;/h3&gt;
&lt;p&gt;In order to dig deeper or to resolve bugs for our Spring apps, we may need more detailed information on logs and traces. Just start the Spring application under analysis with the command line option&amp;quot;&lt;code&gt;--debug&lt;/code&gt;&amp;quot;, system property &amp;ldquo;&lt;code&gt;-Ddebug&lt;/code&gt;&amp;rdquo;,  or set &amp;ldquo;&lt;code&gt;debug=true&lt;/code&gt;&amp;rdquo; in &lt;code&gt;application.properties&lt;/code&gt;. Here is an example of enabling debugging using command line.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mvn spring-boot:run --debug
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &amp;ldquo;&lt;code&gt;--debug&lt;/code&gt;&amp;rdquo; option will enable the &lt;code&gt;DEBUG&lt;/code&gt; logging level for &lt;em&gt;some selected core Spring components&lt;/em&gt;. Likewise, we can also enable &lt;code&gt;TRACE&lt;/code&gt; logging level with the &amp;ldquo;&lt;code&gt;--trace&amp;quot;&lt;/code&gt; or &amp;ldquo;&lt;code&gt;trace=true&lt;/code&gt;&amp;rdquo; in &lt;code&gt;application.properties&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&#34;developer-tools&#34;&gt;Developer Tools&lt;/h3&gt;
&lt;p&gt;Spring Boot equips us&amp;mdash;Spring app developers&amp;mdash;with a set of nice tools in hope that our life might become less miserable, or so they said ;)&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-xml&#34; data-lang=&#34;xml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;dependencies&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-boot-devtools&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;optional&amp;gt;&lt;/span&gt;true&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/optional&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/dependencies&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;One of my favourie features provided by &lt;code&gt;spring-boot-devtools&lt;/code&gt; is &lt;em&gt;automatic restart&lt;/em&gt;. That is, a Spring app can automatically reload whenever any changes on the classpath are detected. As &lt;a href=&#34;https://docs.spring.io/spring-boot/docs/current/reference/html/using-boot-devtools.html#using-boot-devtools-restart&#34;&gt;stated in the documentation&lt;/a&gt;, it works really well with &lt;a href=&#34;https://livereload.com/&#34;&gt;LiveReload&lt;/a&gt; to instantly refresh the corresponding Web browsers. The &lt;em&gt;automatic restart&lt;/em&gt; feature mimics &lt;a href=&#34;https://zeroturnaround.com/software/jrebel/&#34;&gt;JRebel&lt;/a&gt; but in a slower and less advanced manner using two classloaders: a &lt;em&gt;base classloader&lt;/em&gt; for unchanged resources and a &lt;em&gt;restart classloader&lt;/em&gt; for changable ones.&lt;/p&gt;
&lt;h2 id=&#34;finale&#34;&gt;Finale&lt;/h2&gt;
&lt;p&gt;Most of the decisions taken in Spring Boot are opinionated and some might like or dislike, especially hard-core experienced developers who know deeply about Spring.&lt;/p&gt;
&lt;p&gt;Fairly speaking, the way Spring Boot hides the underneath complexity turns out rather ideal for beginners. An inexperienced developer can start the journey with minimal effort and configuration to have a running application. After that, more and more advanced configurations or features can be gradually  added or customised until we no longer rely on Spring Boot. Instead of struggling with complex settings, Spring app developers can now better concentrate on the core system business logics to be designed and implemented.&lt;/p&gt;
&lt;p&gt;Having said that, a Spring lover like me would truly appreciate the ideas and massive efforts behind the Spring Boot project to achieve an integrated set of various in-house and third-party libraries working smoothly. I think Spring development teams have made some bold and good decisions. With simple starting points and open to a plethora of advanced features, configurations and customisations, even experienced teams and developers would greatly benefit from that with more focused system designs and better speed of development.&lt;/p&gt;
</description>
      </item>
    
      <item>
        <title>Spring Boot properties issues with trailing whitespaces</title>
        <link>https://htr3n.github.io/2018/11/spring-boot-trailing-whitespaces/</link>
        <pubDate>Tue, 27 Nov 2018 00:00:00 +0000</pubDate>
        
        <guid>f6a127f87a299bd30fc35bcbfe21cc88</guid>
        <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt;&lt;!-- raw HTML omitted --&gt;Spring Boot does not trim off the &lt;a href=&#34;#root-causes&#34;&gt;trailing whitespaces in &lt;code&gt;*.properties&lt;/code&gt;&lt;/a&gt; that in turn might lead to some &lt;a href=&#34;#problem&#34;&gt;unexpected errors&lt;/a&gt;. As the Spring development team decides to &lt;a href=&#34;https://github.com/spring-projects/spring-boot/issues/4106#issuecomment-173278825&#34;&gt;not fix this issue&lt;/a&gt;, we can &lt;a href=&#34;#solutions&#34;&gt;configure code editors&lt;/a&gt; to avoid some similar problems.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;fun&#34;&gt;The fun &amp;hellip;&lt;/h2&gt;
&lt;p&gt;Coming back working with Spring after few years, I was thrilled trying out Spring Boot 2 with its superb cool auto-configurations and many more. It&amp;rsquo;s a lot much more fun to work with than Spring 3 used in &lt;a href=&#34;https://github.com/htr3n/loan-approval-portal&#34;&gt;some&lt;/a&gt; of my previous projects.&lt;/p&gt;
&lt;h2 id=&#34;problem&#34;&gt;, the problem &amp;hellip;&lt;/h2&gt;
&lt;p&gt;When tinkering with Spring Boot, I found a half-funny half-annoying issue that made one of my Spring apps failed to launch. As the project is rather clumpy and full of experimenting code, here I will replicate this issue in a smaller and simpler scale.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s create a small Spring Boot project with JPA and H2. We can either use &lt;a href=&#34;https://start.spring.io/&#34;&gt;Spring Initialzr&lt;/a&gt;, &lt;a href=&#34;https://docs.spring.io/spring-boot/docs/current/reference/html/cli-using-the-cli.html&#34;&gt;Spring Boot CLI&lt;/a&gt;, or IDE such as IntelliJ IDEA, Eclipse or NetBeans. To keep it simple, I use Spring Boot CLI that &lt;a href=&#34;https://docs.spring.io/spring-boot/docs/current/reference/html/getting-started-installing-spring-boot.html#getting-started-installing-the-cli&#34;&gt;can be easily installed&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ spring version
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Spring CLI v2.1.0.RELEASE
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ spring init --dependencies&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;data-jpa,h2 spring-boot-trailing-spaces
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Using service at https://start.spring.io
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Project extracted to &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;/dev/spring-framework/spring-boot-trailing-spaces&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The newly created Spring application can be launched with Maven.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ cd spring-boot-trailing-spaces
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ mvn spring-boot:run
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;There should be no problem as we have not made any changes. Now, open &amp;ldquo;&lt;code&gt;src/main/resources/application.properties&lt;/code&gt;&amp;rdquo; with an editor, then copy and paste the following code. Promise me that you don&amp;rsquo;t change the pasted code ;)&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-properties&#34; data-lang=&#34;properties&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;spring.datasource.url&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;jdbc:h2:mem:testdb&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;spring.datasource.driverClassName&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;org.h2.Driver &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;spring.datasource.username&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;sa&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;spring.datasource.password&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;These lines are typical data source configuration of an embedded H2 database engine that you might have seen around or used many times. Unfortunately, this time they will crash the Spring application.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ mvn spring-boot:run
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;2018-11-27 21:20:54.289 ERROR &lt;span style=&#34;color:#ae81ff&#34;&gt;92868&lt;/span&gt; --- &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;           main&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; o.s.boot.SpringApplication               : Application run failed
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaConfiguration&amp;#39;&lt;/span&gt;: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;dataSource&amp;#39;&lt;/span&gt; defined in class path resource &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;org/springframework/boot/autoconfigure/jdbc/DataSourceConfiguration$Hikari.class&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;com.zaxxer.hikari.HikariDataSource&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;: Factory method &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;dataSource&amp;#39;&lt;/span&gt; threw exception; nested exception is java.lang.IllegalStateException: Cannot load driver class: org.h2.Driver
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Walking across the lengthy exception stack and error messages, the main culprit seems to be &amp;ldquo;&lt;em&gt;Cannot load driver class: org.h2.Driver&lt;/em&gt;&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Why is that?&lt;/p&gt;
&lt;h2 id=&#34;root-causes&#34;&gt;, the root causes? &amp;hellip;&lt;/h2&gt;
&lt;p&gt;The very first thing came to my mind is to check whether H2 jar is included properly in the classpath.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ mvn dependency:tree
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;INFO&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; +- com.h2database:h2:jar:1.4.197:runtime
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Yup, it&amp;rsquo;s there!&lt;/p&gt;
&lt;p&gt;You can try further on, like I did, to remove &lt;code&gt;$HOME/.m2&lt;/code&gt; and re-run Maven or even restart the machine (but the app still doesn&amp;rsquo;t work!!!).&lt;/p&gt;
&lt;p&gt;I have searched around for this specific issue and found some similar or the same exception, for instance, &lt;a href=&#34;https://stackoverflow.com/a/51193609&#34;&gt;here&lt;/a&gt;, &lt;a href=&#34;https://stackoverflow.com/q/40137347&#34;&gt;here&lt;/a&gt;, &lt;a href=&#34;https://stackoverflow.com/q/4008011&#34;&gt;here&lt;/a&gt; or &lt;a href=&#34;https://stackoverflow.com/q/43616563&#34;&gt;here&lt;/a&gt;. None of the solutions there can fix it.&lt;/p&gt;
&lt;p&gt;It took me nearly half an hour to figure out the root cause. That is the single &lt;em&gt;trailing space&lt;/em&gt; at the end of &lt;code&gt;org.h2.Driver&lt;/code&gt;. Here I intentionally added in order to replicate exactly the original problem in my experimenting project. And the fault was mine who just lazily copied and pasted these few lines of Spring Boot configurations. After I removed all trailing spaces, the error disappeared.&lt;/p&gt;
&lt;p&gt;Voilà!&lt;/p&gt;
&lt;h2 id=&#34;solutions&#34;&gt;&amp;hellip; and the solutions?!&lt;/h2&gt;
&lt;p&gt;No copy &amp;amp; paste please, you might say ;)&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;no-copy-paste.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;I would blame the Pivotal development team (just kidding ;) as they should have handled such a trivial issue better because trailing whitespaces, by default in most editors, are not always visible nor printable. Indeed, trailing whitespaces in Spring properties has driven many developers crazy &lt;a href=&#34;https://github.com/spring-projects/spring-boot/issues/7251&#34;&gt;here&lt;/a&gt;, &lt;a href=&#34;https://github.com/spring-projects/spring-boot/issues/7251&#34;&gt;here&lt;/a&gt;, &lt;a href=&#34;https://github.com/spring-projects/spring-boot/issues/13967&#34;&gt;here&lt;/a&gt;, &lt;a href=&#34;https://github.com/spring-projects/spring-boot/issues/5421&#34;&gt;here&lt;/a&gt; or &lt;a href=&#34;https://github.com/spring-projects/spring-boot/issues/4106&#34;&gt;here&lt;/a&gt;. Note that it&amp;rsquo;s for now &lt;a href=&#34;https://github.com/spring-projects/spring-boot/issues/4106&#34;&gt;official&lt;/a&gt; that the Spring Boot team won&amp;rsquo;t fix this because they &lt;a href=&#34;https://github.com/spring-projects/spring-boot/issues/4106#issuecomment-173278825&#34;&gt;cannot safely trim properties&lt;/a&gt;. So, it&amp;rsquo;s our responsibilities to take care of these whitespaces.&lt;/p&gt;
&lt;blockquote &gt;
    &lt;strong&gt;Sidenote:&lt;/strong&gt;&lt;br&gt;
    Whitespaces can also become &lt;a href=&#34;https://blog.codinghorror.com/whitespace-the-silent-killer/&#34;&gt;worst enemies to source code controls&lt;/a&gt; (but not all whitespaces are born equal, for instance, two continuous trailing spaces in some flavours of &lt;a href=&#34;https://daringfireball.net/projects/markdown/&#34;&gt;Markdown&lt;/a&gt; should be persisted as they are translated into HTML line-breaks &lt;code&gt;&amp;lt;br&amp;gt;&lt;/code&gt;).
&lt;/blockquote&gt;

&lt;p&gt;Fortunately, most of code editors somehow can help to remedy the aforementioned issue either with built-in features or extensions. There are two possible non-exclusive methods (which can be combined of course)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;M1&lt;/strong&gt;. Showing or highlighting whitespaces&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;M2&lt;/strong&gt;. (Automatically) trimming off whitespaces&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For the first method, we configure the editors to force hard-to-see non-printable characters like tabs and spaces become visible. For instance, the problematic example above is shown in Visual Studio Code with the extension &lt;a href=&#34;https://marketplace.visualstudio.com/items?itemName=shardulm94.trailing-spaces&#34;&gt;Trailing Spaces&lt;/a&gt; helps to highlight the trailing whitespaces in red. This way might be a bit UI-intrusive as highlighted whitespaces everywhere can distract many of us. I personally don&amp;rsquo;t really like having the whitespaces and tabs messing up with my code structure.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;trailing-space.png&#34; alt=&#34;Trailing spaces in code editor&#34;&gt;&lt;/p&gt;
&lt;p&gt;The second method can be automatic or manual in which the editors (maybe with support from extensions) can remove the whitespaces during saving or via some editing commands. However, beware the issues with Markdown trailing whitespaces, we should use this option per language specific settings if possible.&lt;/p&gt;
&lt;p&gt;We will examine few popular code editors (please add more of yours in the comment) regarding these two methods.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://atom.io/&#34;&gt;Atom&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Either &lt;span class=&#34;menu&#34;&gt;Preferences ▸ Show Invisibles&lt;/span&gt;
 or &lt;code&gt;config.cson&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;*&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;editor:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;showInvisibles:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://www.eclipse.org/&#34;&gt;Eclipse&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;(&lt;strong&gt;M1&lt;/strong&gt;) From version 3.7+:  &lt;span class=&#34;menu&#34;&gt;Preferences ▸ General ▸ Editors ▸ Text Editors &lt;/span&gt;
: Turn on &amp;ldquo;&lt;em&gt;Show whitespace characters&lt;/em&gt;&amp;rdquo; and fine-tune the option via &amp;ldquo;&lt;em&gt;configure visibility&lt;/em&gt;&amp;rdquo;&lt;/li&gt;
&lt;li&gt;(&lt;strong&gt;M2&lt;/strong&gt;) It&amp;rsquo;s rather tedious in Eclipse as many people have already complained. It&amp;rsquo;s perhaps due to the nature of Eclipse as a platform for several editors and plugins working together. IMHO, Eclipse should offer a common option to remove trailing whitespaces for all editors in the same level and place as &amp;ldquo;&lt;em&gt;Show whitespace characters&lt;/em&gt;&amp;rdquo; above. Each kind of editor then might offer specific and optimal ways for certain file types. Unfortunately, for now we have to configure for each file type editor or formatter. For instance, Java editor &lt;span class=&#34;menu&#34;&gt;Preferences ▸ Java ▸ Editor ▸ Save Actions&lt;/span&gt;
,  check &amp;ldquo;&lt;em&gt;Additional actions&lt;/em&gt;&amp;rdquo;, choose &amp;ldquo;&lt;em&gt;Configure&lt;/em&gt;&amp;rdquo;. Next, in the &amp;ldquo;&lt;em&gt;Code Organizing&lt;/em&gt;&amp;rdquo; tab check &amp;ldquo;&lt;em&gt;Remove trailing whitespace&lt;/em&gt;&amp;rdquo;. Unfortunately, properties file in our example does not provide such options in Eclipse.&lt;/li&gt;
&lt;li&gt;(&lt;strong&gt;M2&lt;/strong&gt;) You may want to use the plugin &lt;a href=&#34;https://github.com/iloveeclipse/anyedittools&#34;&gt;AnyEdit Tools&lt;/a&gt; to clean up trailing whitespaces for all file types:  &lt;span class=&#34;menu&#34;&gt;Preferences ▸ AnyEdit Tools ▸ Auto ▸ Convert ▸ Remove trailing whitespace&lt;/span&gt;
&lt;/li&gt;
&lt;li&gt;(&lt;strong&gt;M2&lt;/strong&gt;) A universal approach, also a little more difficult, is to use &amp;ldquo;&lt;em&gt;Search &amp;amp; Replace&lt;/em&gt;&amp;rdquo; to search with regular expressions for all of &lt;code&gt;&amp;quot;[\t ]+$&amp;quot;&lt;/code&gt; (i.e. more than one whitespaces and/or tabs, please note the whitespace between &lt;code&gt;\t&lt;/code&gt; and &lt;code&gt;]&lt;/code&gt;) and replace them with&lt;code&gt; &amp;quot;&amp;quot;&lt;/code&gt; (blank/empty).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://www.jetbrains.com/idea/&#34;&gt;IntelliJ IDEA&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;(&lt;strong&gt;M1&lt;/strong&gt;) &lt;span class=&#34;menu&#34;&gt;Preferences ▸ Editor ▸ Appearance ▸ Show whitespaces&lt;/span&gt;
 or &lt;span class=&#34;menu&#34;&gt;View ▸ Active Editor ▸ Show whitespaces&lt;/span&gt;
&lt;/li&gt;
&lt;li&gt;(&lt;strong&gt;M2&lt;/strong&gt;) Since 2017.2 and later, there is an option &lt;span class=&#34;menu&#34;&gt;Preferences ▸ Editor ▸ General ▸ Strip trailing whitespaces on Save&lt;/span&gt;
 with &amp;ldquo;&lt;code&gt;All&lt;/code&gt;&amp;rdquo;, &amp;ldquo;&lt;code&gt;Modified Lines&lt;/code&gt;&amp;rdquo; or &amp;ldquo;&lt;code&gt;None&lt;/code&gt;&amp;rdquo; but the IDE does not quite behave, i.e. I chose &amp;ldquo;&lt;code&gt;All&lt;/code&gt;&amp;rdquo; but the trailing spaces are still there after saving. It&amp;rsquo;s rather lame and embarrassing for such a highly praised and expensive IDEs.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://www.sublimetext.com/&#34;&gt;Sublime Text&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;(&lt;strong&gt;M1&lt;/strong&gt;) &lt;span class=&#34;menu&#34;&gt;Preferences ▸ Preferences.sublime-settings—User&lt;/span&gt;
: &lt;code&gt;&amp;quot;draw_white_space&amp;quot;: &amp;quot;all&amp;quot;&lt;/code&gt; (show all whitespaces) or &lt;code&gt;&amp;quot;draw_white_space&amp;quot;: &amp;quot;selection&amp;quot;&lt;/code&gt; (only show within the selection)&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;(&lt;strong&gt;M2&lt;/strong&gt;) &lt;span class=&#34;menu&#34;&gt;Preferences ▸ Preferences.sublime-settings—User&lt;/span&gt;
: &lt;code&gt;&amp;quot;trim_trailing_white_space_on_save&amp;quot;: false&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;(&lt;strong&gt;M2&lt;/strong&gt;) Use the plug-in &lt;a href=&#34;https://github.com/jonlabelle/Trimmer&#34;&gt;Trimmer&lt;/a&gt; for manually cleaning up whitespaces&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://code.visualstudio.com/&#34;&gt;Visual Studio Code&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;(&lt;strong&gt;M1&lt;/strong&gt;) Either &lt;span class=&#34;menu&#34;&gt;Preferences ▸ Settings ▸ Render Whitespace&lt;/span&gt;
 or &lt;code&gt;settings.json&lt;/code&gt; ▸ &lt;code&gt;&amp;quot;editor.renderWhitespace&amp;quot;: &amp;quot;boundary&amp;quot;&lt;/code&gt; (to render whitespaces everywhere except single space between words) or &lt;code&gt;&amp;quot;editor.renderWhitespace&amp;quot;: &amp;quot;all&amp;quot;&lt;/code&gt; (to render all whitespaces)&lt;/li&gt;
&lt;li&gt;(&lt;strong&gt;M2&lt;/strong&gt;) Either &lt;span class=&#34;menu&#34;&gt;Preferences ▸ Settings ▸ Render Whitespace&lt;/span&gt;
 or &lt;code&gt;settings.json&lt;/code&gt; ▸  &lt;code&gt;&amp;quot;files.trimTrailingWhitespace&amp;quot;: true&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;(&lt;strong&gt;M1+2&lt;/strong&gt;) I use the extension &lt;a href=&#34;https://marketplace.visualstudio.com/items?itemName=shardulm94.trailing-spaces&#34;&gt;Trailing Spaces&lt;/a&gt; that even goes further with red colour highlighting of whitespaces and provides extra commands for (manually) trimming whitespaces.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://www.vim.org/&#34;&gt;Vim&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You can follow the tips on &lt;a href=&#34;http://vim.wikia.com/wiki/Highlight_unwanted_spaces&#34;&gt;highlighting unwanted spaces&lt;/a&gt; and &lt;a href=&#34;http://vim.wikia.com/wiki/Remove_unwanted_spaces&#34;&gt;removing unwanted spaces&lt;/a&gt;, some other &lt;a href=&#34;https://vi.stackexchange.com/a/2285&#34;&gt;advanced tips on Vi and Vim SE&lt;/a&gt;, or using a plug-in that can highlight trailing whitespaces and provide commands to strip all of them
&lt;ul&gt;
&lt;li&gt;(&lt;strong&gt;M1+2&lt;/strong&gt;) &lt;a href=&#34;https://github.com/bronson/vim-trailing-whitespace&#34;&gt;vim-trailing-whitespace&lt;/a&gt; highlighting and trimming with &lt;code&gt;:FixWhitespace&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;(&lt;strong&gt;M1+2&lt;/strong&gt;) &lt;a href=&#34;ntpeters/vim-better-whitespace&#34;&gt;ntpeters/vim-better-whitespace&lt;/a&gt; highlighting and trimming with &lt;code&gt;:StripWhitespace&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;(&lt;strong&gt;M1&lt;/strong&gt;) &lt;a href=&#34;https://www.vim.org/scripts/script.php?script_id=3966&#34;&gt;ShowTrailingWhitespace&lt;/a&gt;: mostly trimming whitespaces&lt;/li&gt;
&lt;li&gt;(&lt;strong&gt;M2&lt;/strong&gt;) &lt;a href=&#34;https://www.vim.org/scripts/script.php?script_id=3967&#34;&gt;DeleteTrailingWhitespace&lt;/a&gt;: removing trailing whitespaces with &lt;code&gt;:DeleteTrailingWhitespace&lt;/code&gt; or automatically when the buffer is saved&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For the sake of completeness, there are some editor-independent solutions too.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://www.gnu.org/software/sed/manual/sed.html&#34;&gt;sed&amp;mdash;a stream editor&lt;/a&gt; (credits to Tim Pote&amp;rsquo;s excellent &lt;a href=&#34;https://stackoverflow.com/a/10711226/339302&#34;&gt;SO answer&lt;/a&gt;)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;For POSIX&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;find . -type f -name &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;*.properties&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt; -exec sed --in-place &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;s/[[:space:]]\+$//&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{}&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;\+&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;For macOS/BSD&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;find . -iname &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;*.properties&amp;#39;&lt;/span&gt; -type f &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt; -exec sed -i &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;s/[[:space:]]\{1,\}$//&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{}&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;\+&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Wow, quite a long post for such a trivial issue, eh?! Thanks for reading to the end and I hope that my wasted time and effort here would save some of yours in future.&lt;/p&gt;
&lt;p&gt;Cheers!&lt;/p&gt;
</description>
      </item>
    
      <item>
        <title>Back to basics: Test-driven Spring JDBC</title>
        <link>https://htr3n.github.io/2018/11/test-driven-spring-jdbc/</link>
        <pubDate>Tue, 20 Nov 2018 00:00:00 +0000</pubDate>
        
        <guid>1d7ad93289139560eb474345805b0c9b</guid>
        <description>&lt;p&gt;&lt;a href=&#34;https://spring.io&#34;&gt;Spring&lt;/a&gt; is a popular heavy-weight framework for developing Java/Groovy based applications. Its rich libraries and software stack can cover from front-end to back-end development. In 2009 I used Spring Framework 3 to develop &lt;a href=&#34;https://github.com/htr3n/loan-approval-portal&#34;&gt;web services and MVC + Hibernate portal&lt;/a&gt; for a fictious &lt;a href=&#34;https://github.com/htr3n/loan-approval&#34;&gt;loan approval process&lt;/a&gt;. Despite a tad steep learning-curve, I could manage to get the services and portal up and running and integrated with third-party libraries quite smoothly.&lt;/p&gt;
&lt;p&gt;In my prevous projects, I mostly used Spring with Hibernate and/or JPA for higher abstraction level of data access. Coming back working with Spring after few years, I want to delve into lower layer of data access to better understand what behind the scene of Hibernate/JPA abstraction layers. This post is sort of my note-to-self on Spring and JDBC (Java Database Connectivity), especially on &lt;a href=&#34;https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/jdbc/core/JdbcTemplate.html&#34;&gt;JdbcTemplate&lt;/a&gt;. Besides, it also reports a tricky case with retrieving data with &lt;code&gt;JdbcTemplate.queryForXXX()&lt;/code&gt; employed by several on-line tutorials which was efficiently exposed by appropriate tests.&lt;/p&gt;
&lt;h2 id=&#34;background&#34;&gt;Background&lt;/h2&gt;
&lt;p&gt;JDBC defines standard application programming interface (API) based on that a client can access a database. Each database vendor often provides low-level vendor-specific database drivers based on JDBC predefined interfaces. JDBC is considered the lowest recommended abstraction level to work with databases in Java.&lt;/p&gt;
&lt;p&gt;In short, a typical approach to database access using JDBC comprises these basic steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Obtain a &lt;a href=&#34;https://docs.oracle.com/javase/8/docs/api/java/sql/Connection.html&#34;&gt;Connection&lt;/a&gt;, e.g. via &lt;a href=&#34;https://docs.oracle.com/javase/8/docs/api/java/sql/DriverManager.html&#34;&gt;DriverManager&lt;/a&gt; or &lt;a href=&#34;https://docs.oracle.com/javase/8/docs/api/javax/sql/DataSource.html&#34;&gt;DataSource&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Create an instance of type &lt;a href=&#34;https://docs.oracle.com/javase/8/docs/api/java/sql/Statement.html&#34;&gt;Statement&lt;/a&gt; or its sub-types such as &lt;a href=&#34;https://docs.oracle.com/javase/8/docs/api/java/sql/CallableStatement.html&#34;&gt;CallableStatement&lt;/a&gt;, &lt;a href=&#34;https://docs.oracle.com/javase/8/docs/api/java/sql/PreparedStatement.html&#34;&gt;PreparedStatement&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Use the aforementioned statement to execute database queries&lt;/li&gt;
&lt;li&gt;Retrieve and process the &lt;a href=&#34;https://docs.oracle.com/javase/8/docs/api/java/sql/ResultSet.html&#34;&gt;ResultSet&lt;/a&gt; (if any)&lt;/li&gt;
&lt;li&gt;Close the statement and release all resources (connection is &lt;a href=&#34;https://docs.oracle.com/javase/8/docs/api/java/lang/AutoCloseable.html&#34;&gt;AutoCloseable&lt;/a&gt;)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Along these steps, we should also handle any &lt;a href=&#34;https://docs.oracle.com/javase/tutorial/jdbc/basics/sqlexception.html&#34;&gt;database exceptions&lt;/a&gt; as well. You can find more details on JDBC programming &lt;a href=&#34;https://docs.oracle.com/javase/tutorial/jdbc/basics/index.html&#34;&gt;here&lt;/a&gt;.  Here is a simple example of accessing databases using JDBC and &lt;a href=&#34;https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html&#34;&gt;&lt;em&gt;try-with-resources&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;DataSource ds &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; ...; &lt;span style=&#34;color:#75715e&#34;&gt;// obtain a DataSource object&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;try&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Connection conn &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; ds.&lt;span style=&#34;color:#a6e22e&#34;&gt;getConnection&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Statement stmt &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; conn.&lt;span style=&#34;color:#a6e22e&#34;&gt;createStatement&lt;/span&gt;()) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;try&lt;/span&gt; (ResultSet rs &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; smmt.&lt;span style=&#34;color:#a6e22e&#34;&gt;executeQuery&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;SELECT * FROM customer&amp;#34;&lt;/span&gt;)){
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;while&lt;/span&gt; (rs.&lt;span style=&#34;color:#a6e22e&#34;&gt;next&lt;/span&gt;()){
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#75715e&#34;&gt;// process the ResultSet&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  } &lt;span style=&#34;color:#66d9ef&#34;&gt;catch&lt;/span&gt; (SQLException e2) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    e2.&lt;span style=&#34;color:#a6e22e&#34;&gt;printStackTrace&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;} &lt;span style=&#34;color:#66d9ef&#34;&gt;catch&lt;/span&gt; (SQLException e1) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  e1.&lt;span style=&#34;color:#a6e22e&#34;&gt;printStackTrace&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Fortunately, Spring, via  &lt;a href=&#34;https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/jdbc/core/JdbcTemplate.html&#34;&gt;JdbcTemplate&lt;/a&gt;, ofters a higher level of abstraction on top of Java JDBC that would save us a lot of boiler plate code and enable smooth integration with the rest of Spring framework&amp;rsquo;s ecosystem. As such, we can leverage other parts of Spring farmework, for instance, the awesome &lt;a href=&#34;https://spring.io/projects/spring-boot&#34;&gt;Spring Boot&lt;/a&gt;, to automate lots of configuration effort.&lt;/p&gt;
&lt;h2 id=&#34;a-simple-crud-project-with-spring-jdbc&#34;&gt;A simple CRUD project with Spring JDBC&lt;/h2&gt;
&lt;p&gt;Nothing is better than a hand-on development project that demonstrate how Spring JDBC works. We can start with &lt;a href=&#34;https://start.spring.io/&#34;&gt;Spring Initialzr&lt;/a&gt; and &lt;a href=&#34;https://spring.io/projects/spring-boot&#34;&gt;Spring Boot&lt;/a&gt; to jump start and better concentrate on the main code instead of numerous dependencies and configurations.&lt;/p&gt;
&lt;p&gt;There are a few ways to bootstrap a project with Spring Initialzr. Most of the popular Java IDE such as Eclipse or Intellij IDEA with Spring extensions can create a new project via Spring Initialzr. You can also achieve the same result from the web site &lt;a href=&#34;https://start.spring.io&#34;&gt;https://start.spring.io&lt;/a&gt; or even using &lt;a href=&#34;https://docs.spring.io/spring-boot/docs/current/reference/html/getting-started-installing-spring-boot.html#getting-started-installing-the-cli&#34;&gt;Spring Boot CLI&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Here I will use Intellij IDEA for just showing the necessary steps and dependencies. You can use any of the aforementioned methods to obtain the same result.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 1&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;Create a new project and choose Spring Initialzr.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;ide-step-1.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 2&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;Fill in necessary project information, keep default values for project&amp;rsquo;s type (Maven), language (Java), packaging (Jar), Java version (8).&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;ide-step-2.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 3&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;Choose the section SQL and make sure the checkboxes of H2 and JDBC are ticked.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;ide-step-3.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 4&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;Finish the project creation wizard.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;ide-step-4.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;After Step 4, Intellij IDEA will create a new Maven Spring Boot project with some initial source and configuration files.&lt;/p&gt;
&lt;p&gt;By default, the main configuration file for Spring Boot is &lt;code&gt;application.properties&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;ide-main.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;h3 id=&#34;defining-domain-entities&#34;&gt;Defining Domain Entities&lt;/h3&gt;
&lt;p&gt;We might not need a complex domain model but rather a simple entity mapped to a database table. For example, a &lt;code&gt;Customer&lt;/code&gt; entity as shown in Java code and a corresponding &lt;code&gt;customer&lt;/code&gt; table.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;package&lt;/span&gt; io.github.htr3n.springjdbcsimple.entity;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Customer&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; Integer id;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; String name;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; String email;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; Integer &lt;span style=&#34;color:#a6e22e&#34;&gt;getId&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; id;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;setId&lt;/span&gt;(Integer id) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;id&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; id;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; String &lt;span style=&#34;color:#a6e22e&#34;&gt;getName&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; name;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;setName&lt;/span&gt;(String name) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; name;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; String &lt;span style=&#34;color:#a6e22e&#34;&gt;getEmail&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; email;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;setEmail&lt;/span&gt;(String email) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;email&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; email;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;configuring-database-connection&#34;&gt;Configuring Database Connection&lt;/h3&gt;
&lt;p&gt;Normally, we have to provide sufficient information to establish database connections, for instance, JDBC url, authentication, and maybe some extra parameters. &lt;a href=&#34;https://docs.spring.io/spring-boot/docs/current/reference/html/howto-data-access.html#howto-configure-a-datasource&#34;&gt;Per convention&lt;/a&gt;, Spring Boot can scan for data sources configurations as &lt;code&gt;@Bean&lt;/code&gt; or in &lt;code&gt;application.properties&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;For better concentraton on test-driven JDBC CRUD, we can leverage &lt;code&gt;@JdbcTest&lt;/code&gt; explained in the subsequent section to set up an in-memory embedded database and skip the details on data source configuration for now.&lt;/p&gt;
&lt;p&gt;However, we must still initialise the database (otherwise Spring will complain that the table &lt;code&gt;customer&lt;/code&gt; &lt;em&gt;does not exist&lt;/em&gt; when our application or a test starts). By convention documented &lt;a href=&#34;https://docs.spring.io/spring-boot/docs/current/reference/html/howto-database-initialization.html#howto-initialize-a-database-using-spring-jdbc&#34;&gt;here&lt;/a&gt;, we simply add a file &lt;code&gt;schema.sql&lt;/code&gt; in the folder &lt;code&gt;src/main/resources&lt;/code&gt; which contains a simple SQL DDL script for creating a table &lt;code&gt;customer&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;DROP&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;TABLE&lt;/span&gt; customer;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;CREATE&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;TABLE&lt;/span&gt; customer(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  id integer &lt;span style=&#34;color:#66d9ef&#34;&gt;not&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt; auto_increment,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  name varchar(&lt;span style=&#34;color:#ae81ff&#34;&gt;255&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;not&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  email varchar (&lt;span style=&#34;color:#ae81ff&#34;&gt;255&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;not&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;primary&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;key&lt;/span&gt; (id)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;test-driven-crud&#34;&gt;Test-Driven CRUD&lt;/h3&gt;
&lt;p&gt;At the heart of our JDBC project is a &lt;code&gt;CustomerDao.java&lt;/code&gt; with basic &lt;a href=&#34;https://en.wikipedia.org/wiki/Create,_read,_update_and_delete&#34;&gt;CRUD methods&lt;/a&gt;. The class &lt;code&gt;CustomerDao&lt;/code&gt; is annotated with &lt;a href=&#34;https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/stereotype/Repository.html&#34;&gt;@Repository&lt;/a&gt; to indicate this is a data access component that is autodetected through normal Spring&amp;rsquo;s classpath scanning.&lt;/p&gt;
&lt;p&gt;As &lt;code&gt;JdbcTemplate&lt;/code&gt; will be used to work with H2 database, we just declared an &lt;a href=&#34;https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/beans/factory/annotation/Autowired.html&#34;&gt;@Autowired&lt;/a&gt; field, the rest will be taken care by Spring.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;package&lt;/span&gt; io.github.htr3n.springjdbcsimple.dao;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; java.util.List;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; org.springframework.beans.factory.annotation.Autowired;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; org.springframework.jdbc.core.JdbcTemplate;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;@Repository&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;CustomerDao&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;@Autowired&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; JdbcTemplate jdbcTemplate;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;// Create&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; Customer &lt;span style=&#34;color:#a6e22e&#34;&gt;create&lt;/span&gt;(Customer customer) { ... }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;// Retrieve&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; List&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;Customer&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;findAll&lt;/span&gt;() {...}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;// Retrieve&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; Optional&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;Customer&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;findById&lt;/span&gt;(Integer id) { ... }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;// Update&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;boolean&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;update&lt;/span&gt;(Customer customer) { ... }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;// Delete&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;boolean&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;delete&lt;/span&gt;(Integer id) { ... }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;crud-tests&#34;&gt;CRUD Tests&lt;/h4&gt;
&lt;p&gt;Before starting implementing the CRUD methods, we create some unit tests in &lt;code&gt;CustomerDaoTest&lt;/code&gt;. Again, Spring Boot will help us a lot here with setting up and shutting down properly the testing environment via annotations such as &lt;code&gt;@RunWith&lt;/code&gt; and &lt;code&gt;@SpringBootTest&lt;/code&gt;. We only need to declare an &lt;em&gt;autowired&lt;/em&gt; object &lt;code&gt;CustomerDao&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Spring offers powerful means for database testing, for instance, &lt;code&gt;@Transational&lt;/code&gt; and &lt;code&gt;@Rollback&lt;/code&gt;. With these annotations, Spring will take care of database transactions as well as rollling back the testing databases to its initial state.&lt;/p&gt;
&lt;p&gt;Unfortunately, it would be too tedious to annotate each test method. Spring Boot comes to handy with  &lt;a href=&#34;https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/test/autoconfigure/jdbc/JdbcTest.html&#34;&gt;&lt;code&gt;@JdbcTest&lt;/code&gt;&lt;/a&gt; that enables several useful features for JDBC tests including an in-memory embedded database as well as transactional and roll back at the end of each test.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;IMPORTANT&lt;/strong&gt;&lt;!-- raw HTML omitted --&gt;By default, &lt;code&gt;@JdbcTest&lt;/code&gt; &lt;a href=&#34;https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-testing.html#boot-features-testing-spring-boot-applications-testing-autoconfigured-jdbc-test&#34;&gt;won&amp;rsquo;t load regular &lt;code&gt;Component&lt;/code&gt;&lt;/a&gt;, and as a result, &lt;code&gt;CustomerDao&lt;/code&gt; won&amp;rsquo;t be loaded because it is a &lt;code&gt;@Repository&lt;/code&gt;, i.e. a sub-type of &lt;code&gt;@Component&lt;/code&gt;. Spring will inform us that it fails to find the required autowire &lt;code&gt;CustomerDao&lt;/code&gt; for &lt;code&gt;CustomerDaoTest&lt;/code&gt;.  To fix this, simply annotation  &lt;code&gt;CustomerDaoTest&lt;/code&gt; with &lt;code&gt;@ComponentScan&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is the whole test case for our tentative CRUD methods.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;package&lt;/span&gt; io.github.htr3n.springjdbcsimple.dao;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; io.github.htr3n.springjdbcsimple.entity.Customer;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; org.junit.Before;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; org.junit.Test;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; org.junit.runner.RunWith;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; org.springframework.beans.factory.annotation.Autowired;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; org.springframework.boot.test.autoconfigure.jdbc.JdbcTest;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; org.springframework.context.annotation.ComponentScan;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; org.springframework.test.context.junit4.SpringRunner;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; java.util.List;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; java.util.Optional;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; java.util.Random;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import static&lt;/span&gt; org.assertj.core.api.Assertions.assertThat;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;@RunWith&lt;/span&gt;(SpringRunner.&lt;span style=&#34;color:#a6e22e&#34;&gt;class&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;@JdbcTest&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;@ComponentScan&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;CustomerDaoTest&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; String ALICE_NAME &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Alice&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; String ALICE_EMAIL &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;alice@test.com&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; String BOB_NAME &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Bob&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; String BOB_EMAIL &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;bob@test.com&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; ONE_CUSTOMER &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 1;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; TWO_CUSTOMERS &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 2;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;@Autowired&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; CustomerDao customerDao;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; Customer alice;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; Customer bob;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;@Before&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;setUp&lt;/span&gt;(){
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    alice &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Customer();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    alice.&lt;span style=&#34;color:#a6e22e&#34;&gt;setName&lt;/span&gt;(ALICE_NAME);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    alice.&lt;span style=&#34;color:#a6e22e&#34;&gt;setEmail&lt;/span&gt;(ALICE_EMAIL);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    bob &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Customer();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    bob.&lt;span style=&#34;color:#a6e22e&#34;&gt;setName&lt;/span&gt;(BOB_NAME);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    bob.&lt;span style=&#34;color:#a6e22e&#34;&gt;setEmail&lt;/span&gt;(BOB_EMAIL);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;@Test&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;create_shouldReturnValidCustomer_whenAddingNewCustomer&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    customerDao.&lt;span style=&#34;color:#a6e22e&#34;&gt;create&lt;/span&gt;(alice);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    assertThat(alice.&lt;span style=&#34;color:#a6e22e&#34;&gt;getId&lt;/span&gt;()).&lt;span style=&#34;color:#a6e22e&#34;&gt;isNotNull&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Optional&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;Customer&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; result &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; customerDao.&lt;span style=&#34;color:#a6e22e&#34;&gt;findById&lt;/span&gt;(alice.&lt;span style=&#34;color:#a6e22e&#34;&gt;getId&lt;/span&gt;());
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    assertThat(result).&lt;span style=&#34;color:#a6e22e&#34;&gt;isPresent&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    assertThat(alice).&lt;span style=&#34;color:#a6e22e&#34;&gt;hasFieldOrPropertyWithValue&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;name&amp;#34;&lt;/span&gt;, ALICE_NAME);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    assertThat(alice).&lt;span style=&#34;color:#a6e22e&#34;&gt;hasFieldOrPropertyWithValue&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;email&amp;#34;&lt;/span&gt;, ALICE_EMAIL);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;@Test&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;findById_shouldReturnInvalidCustomer_forEmptyDatabase&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Optional&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;Customer&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; invalidCustomer &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; customerDao.&lt;span style=&#34;color:#a6e22e&#34;&gt;findById&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Random().&lt;span style=&#34;color:#a6e22e&#34;&gt;nextInt&lt;/span&gt;());
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    assertThat(invalidCustomer.&lt;span style=&#34;color:#a6e22e&#34;&gt;isPresent&lt;/span&gt;()).&lt;span style=&#34;color:#a6e22e&#34;&gt;isFalse&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;@Test&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;findById_shouldReturnValidCustomer_forExistingCustomer&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    customerDao.&lt;span style=&#34;color:#a6e22e&#34;&gt;create&lt;/span&gt;(alice);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Optional&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;Customer&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; validCustomer &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; customerDao.&lt;span style=&#34;color:#a6e22e&#34;&gt;findById&lt;/span&gt;(alice.&lt;span style=&#34;color:#a6e22e&#34;&gt;getId&lt;/span&gt;());
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    assertThat(validCustomer).&lt;span style=&#34;color:#a6e22e&#34;&gt;isPresent&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    assertThat(validCustomer.&lt;span style=&#34;color:#a6e22e&#34;&gt;get&lt;/span&gt;().&lt;span style=&#34;color:#a6e22e&#34;&gt;getName&lt;/span&gt;()).&lt;span style=&#34;color:#a6e22e&#34;&gt;isEqualTo&lt;/span&gt;(alice.&lt;span style=&#34;color:#a6e22e&#34;&gt;getName&lt;/span&gt;());
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    assertThat(validCustomer.&lt;span style=&#34;color:#a6e22e&#34;&gt;get&lt;/span&gt;().&lt;span style=&#34;color:#a6e22e&#34;&gt;getEmail&lt;/span&gt;()).&lt;span style=&#34;color:#a6e22e&#34;&gt;isEqualTo&lt;/span&gt;(alice.&lt;span style=&#34;color:#a6e22e&#34;&gt;getEmail&lt;/span&gt;());
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;@Test&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;findAll_shouldYieldEmptyList_forEmptyDatabase&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    List&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;Customer&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; noCustomers &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; customerDao.&lt;span style=&#34;color:#a6e22e&#34;&gt;findAll&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    assertThat(noCustomers).&lt;span style=&#34;color:#a6e22e&#34;&gt;isNullOrEmpty&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;@Test&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;findAll_shouldYieldListOfCustomers_forNonemptyDatabase&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    customerDao.&lt;span style=&#34;color:#a6e22e&#34;&gt;create&lt;/span&gt;(alice);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    List&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;Customer&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; customers &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; customerDao.&lt;span style=&#34;color:#a6e22e&#34;&gt;findAll&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    assertThat(customers).&lt;span style=&#34;color:#a6e22e&#34;&gt;isNotNull&lt;/span&gt;().&lt;span style=&#34;color:#a6e22e&#34;&gt;hasSize&lt;/span&gt;(ONE_CUSTOMER);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Customer result &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; customers.&lt;span style=&#34;color:#a6e22e&#34;&gt;get&lt;/span&gt;(0);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    assertThat(result).&lt;span style=&#34;color:#a6e22e&#34;&gt;hasFieldOrPropertyWithValue&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;name&amp;#34;&lt;/span&gt;, ALICE_NAME);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    assertThat(result).&lt;span style=&#34;color:#a6e22e&#34;&gt;hasFieldOrPropertyWithValue&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;email&amp;#34;&lt;/span&gt;, ALICE_EMAIL);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    customerDao.&lt;span style=&#34;color:#a6e22e&#34;&gt;create&lt;/span&gt;(bob);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    customers &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; customerDao.&lt;span style=&#34;color:#a6e22e&#34;&gt;findAll&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    assertThat(customers).&lt;span style=&#34;color:#a6e22e&#34;&gt;isNotNull&lt;/span&gt;().&lt;span style=&#34;color:#a6e22e&#34;&gt;hasSize&lt;/span&gt;(TWO_CUSTOMERS);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;@Test&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;update_shouldYieldFalse_forEmptyDatabase&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Customer notFound &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Customer();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    notFound.&lt;span style=&#34;color:#a6e22e&#34;&gt;setId&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Random().&lt;span style=&#34;color:#a6e22e&#34;&gt;nextInt&lt;/span&gt;());
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    assertThat(customerDao.&lt;span style=&#34;color:#a6e22e&#34;&gt;update&lt;/span&gt;(notFound)).&lt;span style=&#34;color:#a6e22e&#34;&gt;isFalse&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;@Test&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;update_shouldYieldTrue_forExistingCustomer&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    customerDao.&lt;span style=&#34;color:#a6e22e&#34;&gt;create&lt;/span&gt;(alice);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    assertThat(alice.&lt;span style=&#34;color:#a6e22e&#34;&gt;getId&lt;/span&gt;()).&lt;span style=&#34;color:#a6e22e&#34;&gt;isNotNull&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    assertThat(customerDao.&lt;span style=&#34;color:#a6e22e&#34;&gt;update&lt;/span&gt;(alice)).&lt;span style=&#34;color:#a6e22e&#34;&gt;isTrue&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    alice.&lt;span style=&#34;color:#a6e22e&#34;&gt;setName&lt;/span&gt;(BOB_NAME);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    alice.&lt;span style=&#34;color:#a6e22e&#34;&gt;setEmail&lt;/span&gt;(BOB_EMAIL);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    assertThat(customerDao.&lt;span style=&#34;color:#a6e22e&#34;&gt;update&lt;/span&gt;(alice)).&lt;span style=&#34;color:#a6e22e&#34;&gt;isTrue&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Optional&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;Customer&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; found &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; customerDao.&lt;span style=&#34;color:#a6e22e&#34;&gt;findById&lt;/span&gt;(alice.&lt;span style=&#34;color:#a6e22e&#34;&gt;getId&lt;/span&gt;());
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    assertThat(found).&lt;span style=&#34;color:#a6e22e&#34;&gt;isPresent&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    assertThat(found.&lt;span style=&#34;color:#a6e22e&#34;&gt;get&lt;/span&gt;().&lt;span style=&#34;color:#a6e22e&#34;&gt;getName&lt;/span&gt;()).&lt;span style=&#34;color:#a6e22e&#34;&gt;isEqualTo&lt;/span&gt;(alice.&lt;span style=&#34;color:#a6e22e&#34;&gt;getName&lt;/span&gt;());
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    assertThat(found.&lt;span style=&#34;color:#a6e22e&#34;&gt;get&lt;/span&gt;().&lt;span style=&#34;color:#a6e22e&#34;&gt;getEmail&lt;/span&gt;()).&lt;span style=&#34;color:#a6e22e&#34;&gt;isEqualTo&lt;/span&gt;(alice.&lt;span style=&#34;color:#a6e22e&#34;&gt;getEmail&lt;/span&gt;());
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;@Test&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;delete_shouldYieldFalse_forEmptyDatabaseOrNonexistingCustomer&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    assertThat(customerDao.&lt;span style=&#34;color:#a6e22e&#34;&gt;delete&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Random().&lt;span style=&#34;color:#a6e22e&#34;&gt;nextInt&lt;/span&gt;())).&lt;span style=&#34;color:#a6e22e&#34;&gt;isFalse&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;@Test&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;delete_shouldYieldTrue_forExistingCustomer&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    customerDao.&lt;span style=&#34;color:#a6e22e&#34;&gt;create&lt;/span&gt;(alice);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    assertThat(customerDao.&lt;span style=&#34;color:#a6e22e&#34;&gt;findAll&lt;/span&gt;()).&lt;span style=&#34;color:#a6e22e&#34;&gt;hasSize&lt;/span&gt;(ONE_CUSTOMER);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    assertThat(customerDao.&lt;span style=&#34;color:#a6e22e&#34;&gt;delete&lt;/span&gt;(alice.&lt;span style=&#34;color:#a6e22e&#34;&gt;getId&lt;/span&gt;())).&lt;span style=&#34;color:#a6e22e&#34;&gt;isTrue&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    assertThat(customerDao.&lt;span style=&#34;color:#a6e22e&#34;&gt;findById&lt;/span&gt;(alice.&lt;span style=&#34;color:#a6e22e&#34;&gt;getId&lt;/span&gt;()).&lt;span style=&#34;color:#a6e22e&#34;&gt;isPresent&lt;/span&gt;()).&lt;span style=&#34;color:#a6e22e&#34;&gt;isFalse&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    assertThat(customerDao.&lt;span style=&#34;color:#a6e22e&#34;&gt;findAll&lt;/span&gt;()).&lt;span style=&#34;color:#a6e22e&#34;&gt;isEmpty&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;crud-implementation&#34;&gt;CRUD Implementation&lt;/h4&gt;
&lt;p&gt;With the tests defined, we can start implementing the CRUD using Spring &lt;code&gt;JdbcTemplate&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;C&lt;/strong&gt;reate&lt;/p&gt;
&lt;p&gt;To satisfy the test described in &lt;code&gt;create_shouldReturnValidCustomer_whenAddingNewCustomer()&lt;/code&gt;, our &lt;code&gt;Customer.create()&lt;/code&gt; must successfully save the input &lt;code&gt;Customer&lt;/code&gt; and return with an auto-generated primary key (e.g. customer ID). In order to obtain the key, we can use Spring&amp;rsquo;s helper class &lt;a href=&#34;https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/jdbc/support/KeyHolder.html&#34;&gt;&lt;code&gt;KeyHolder&lt;/code&gt;&lt;/a&gt; along with the standard &lt;a href=&#34;https://docs.oracle.com/javase/8/docs/api/java/sql/PreparedStatement.html&#34;&gt;&lt;code&gt;PreparedStatement&lt;/code&gt;&lt;/a&gt;. Note that the code was simplified with &lt;a href=&#34;https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html&#34;&gt;Java 8 Lambda notation&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// Create&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; Customer &lt;span style=&#34;color:#a6e22e&#34;&gt;create&lt;/span&gt;(Customer customer) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  String sql &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;INSERT INTO customer (name, email) VALUES (?, ?)&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  KeyHolder keyHolder &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; GeneratedKeyHolder();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;jdbcTemplate&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;update&lt;/span&gt;(connection &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    PreparedStatement statement &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; connection.&lt;span style=&#34;color:#a6e22e&#34;&gt;prepareStatement&lt;/span&gt;(sql, Statement.&lt;span style=&#34;color:#a6e22e&#34;&gt;RETURN_GENERATED_KEYS&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    statement.&lt;span style=&#34;color:#a6e22e&#34;&gt;setString&lt;/span&gt;(1, customer.&lt;span style=&#34;color:#a6e22e&#34;&gt;getName&lt;/span&gt;());
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    statement.&lt;span style=&#34;color:#a6e22e&#34;&gt;setString&lt;/span&gt;(2, customer.&lt;span style=&#34;color:#a6e22e&#34;&gt;getEmail&lt;/span&gt;());
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; statement;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }, keyHolder);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Integer newCustomerId &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; keyHolder.&lt;span style=&#34;color:#a6e22e&#34;&gt;getKey&lt;/span&gt;().&lt;span style=&#34;color:#a6e22e&#34;&gt;intValue&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  customer.&lt;span style=&#34;color:#a6e22e&#34;&gt;setId&lt;/span&gt;(newCustomerId);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; customer;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Please note that, Spring also provides another helper, namely, &lt;a href=&#34;https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/jdbc/core/simple/SimpleJdbcInsert.html&#34;&gt;&lt;code&gt;SimpleJdbcInsert&lt;/code&gt;&lt;/a&gt; with methods &lt;code&gt;executeAndReturnKey()&lt;/code&gt;. Per the class&amp;rsquo;s documentation, &lt;code&gt;SimpleJdbcInsert&lt;/code&gt;  is indeed a higher level wrapper of &lt;code&gt;JdbcTemplate&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;R&lt;/strong&gt;etrieve&lt;/p&gt;
&lt;p&gt;In this project, we develop two retrieval methods: &lt;code&gt;findAll()&lt;/code&gt; will return a list of all customers whilst &lt;code&gt;findById()&lt;/code&gt; will look for a certain customer using the input ID.&lt;/p&gt;
&lt;p&gt;The method &lt;code&gt;findAll()&lt;/code&gt; is rather a piece of cake but &lt;code&gt;findById()&lt;/code&gt; is quite tricky. Most of the tutorials or guides on Spring &lt;code&gt;JdbcTemplate&lt;/code&gt; I have found on the Internet blindly use the method &lt;a href=&#34;https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/jdbc/core/JdbcTemplate.html#queryForObject-java.lang.String-java.lang.Class-&#34;&gt;JdbcTemplate.queryForObject()&lt;/a&gt; to look up a database row. Trust me, I made the same mistake, too, along the line of this.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; Optional&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;Customer&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;findById&lt;/span&gt;(Integer id) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  String sql &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;SELECT id, name, email FROM customer WHERE id = ?&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; Optional.&lt;span style=&#34;color:#a6e22e&#34;&gt;of&lt;/span&gt;(jdbcTemplate.&lt;span style=&#34;color:#a6e22e&#34;&gt;queryForObject&lt;/span&gt;(sql, &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Object&lt;span style=&#34;color:#f92672&#34;&gt;[]&lt;/span&gt; { id }, &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; CustomerMapper()));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Neater and cleaner, eh!? Unfortunately, the aforementioned &lt;code&gt;findById()&lt;/code&gt; based on the problematic methods &lt;code&gt;JdbcTemplate.queryForXXX()&lt;/code&gt; which is recommended to use in case the query shall return a single row and fails miserably in other cases.&lt;/p&gt;
&lt;p&gt;This issue has been exposed by the test &lt;code&gt;findById_shouldReturnInvalidCustomer_forEmptyDatabase()&lt;/code&gt; and I was able to come up with a slightly better version that uses &lt;code&gt;JdbcTemplate.query()&lt;/code&gt; and checks for the returning &lt;code&gt;ResultSet&lt;/code&gt;, in case of non-exiting customer yielding correctly &lt;code&gt;null&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// Retrieve&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; List&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;Customer&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;findAll&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  String sql &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;SELECT * FROM customer&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;jdbcTemplate&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;query&lt;/span&gt;(sql, &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; CustomerMapper());
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// Retrieve&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; Optional&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;Customer&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;findCustomerById&lt;/span&gt;(Integer id) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  String sql &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;SELECT id, name, email FROM customer WHERE id = ?&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;jdbcTemplate&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;query&lt;/span&gt;(sql,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    rs &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; rs.&lt;span style=&#34;color:#a6e22e&#34;&gt;next&lt;/span&gt;() &lt;span style=&#34;color:#f92672&#34;&gt;?&lt;/span&gt; Optional.&lt;span style=&#34;color:#a6e22e&#34;&gt;of&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; CustomerMapper().&lt;span style=&#34;color:#a6e22e&#34;&gt;mapRow&lt;/span&gt;(rs, 1)): Optional.&lt;span style=&#34;color:#a6e22e&#34;&gt;empty&lt;/span&gt;(),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    id);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;When working with pure JDBC, we must map the database query result onto the domain entity on our own. This can be quickly done by implementing the interface &lt;a href=&#34;https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/jdbc/core/RowMapper.html&#34;&gt;&lt;code&gt;RowMapper&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;CustomerMapper&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;implements&lt;/span&gt; RowMapper&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;Customer&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;@Override&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; Customer &lt;span style=&#34;color:#a6e22e&#34;&gt;mapRow&lt;/span&gt;(ResultSet rs, &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; rowNum) &lt;span style=&#34;color:#66d9ef&#34;&gt;throws&lt;/span&gt; SQLException {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Customer customer &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Customer();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    customer.&lt;span style=&#34;color:#a6e22e&#34;&gt;setId&lt;/span&gt;(rs.&lt;span style=&#34;color:#a6e22e&#34;&gt;getInt&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;id&amp;#34;&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    customer.&lt;span style=&#34;color:#a6e22e&#34;&gt;setName&lt;/span&gt;(rs.&lt;span style=&#34;color:#a6e22e&#34;&gt;getString&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;name&amp;#34;&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    customer.&lt;span style=&#34;color:#a6e22e&#34;&gt;setEmail&lt;/span&gt;(rs.&lt;span style=&#34;color:#a6e22e&#34;&gt;getString&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;email&amp;#34;&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; customer;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;U&lt;/strong&gt;pdate / &lt;strong&gt;D&lt;/strong&gt;elete&lt;/p&gt;
&lt;p&gt;The implementation of updating and deletion is rather straightforward.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// Update&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;boolean&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;update&lt;/span&gt;(Customer customer) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  String sql &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;UPDATE customer SET name=?, email=? WHERE id=?&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Object&lt;span style=&#34;color:#f92672&#34;&gt;[]&lt;/span&gt; params &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Object&lt;span style=&#34;color:#f92672&#34;&gt;[]&lt;/span&gt;{customer.&lt;span style=&#34;color:#a6e22e&#34;&gt;getName&lt;/span&gt;(), customer.&lt;span style=&#34;color:#a6e22e&#34;&gt;getEmail&lt;/span&gt;(), customer.&lt;span style=&#34;color:#a6e22e&#34;&gt;getId&lt;/span&gt;()};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;jdbcTemplate&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;update&lt;/span&gt;(sql, params) &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; 1;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// Delete&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;boolean&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;delete&lt;/span&gt;(Integer id) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  String sql &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;DELETE FROM customer WHERE id = ?&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Object&lt;span style=&#34;color:#f92672&#34;&gt;[]&lt;/span&gt; params &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Object&lt;span style=&#34;color:#f92672&#34;&gt;[]&lt;/span&gt;{id};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;jdbcTemplate&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;update&lt;/span&gt;(sql, params) &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; 1;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Finally, we finish implementing all necessary CRUD methods and hopefully pass all the aforementioned tests.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;passed-tests.png&#34; alt=&#34;Passed tests&#34;&gt;&lt;/p&gt;
&lt;p&gt;You can check out the &lt;a href=&#34;https://github.com/htr3n/spring-jdbc-simple&#34;&gt;project source code&lt;/a&gt; available on Github.&lt;/p&gt;
</description>
      </item>
    
      <item>
        <title>Handy macOS QuickLook configurations</title>
        <link>https://htr3n.github.io/2018/07/handy-quicklook/</link>
        <pubDate>Mon, 30 Jul 2018 00:00:00 +0000</pubDate>
        
        <guid>36c9cfb0b3d4dd825754e43858531a0e</guid>
        <description>&lt;p&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/Quick_Look&#34;&gt;QuickLook&lt;/a&gt; is a simple but powerful feature of macOS that helps to preview the content of a file or folder in Finder without using any particular apps. This feature is very handy when we only want to have brief glance on a certain file or quickly examine its parts instead of opening a full-fledged app for that particular file.&lt;/p&gt;
&lt;p&gt;Even nicer, Apple provides &lt;a href=&#34;https://developer.apple.com/documentation/quicklook&#34;&gt;API&lt;/a&gt; for QuickLook programming and enables the use of &lt;a href=&#34;http://www.quicklookplugins.com/&#34;&gt;plugins&lt;/a&gt; that convert a certain document from its native format into QuickLook previewing format. Before, it was also possible to also &lt;a href=&#34;http://www.mactricksandtips.com/2013/01/22-finder-hacks-tricks-and-changes.html&#34;&gt;select and copy text from QuickLook previewing&lt;/a&gt; but then Apple removed that feature since macOS 10.11 El Capitan.&lt;/p&gt;
&lt;p&gt;QuickLook is well supported in Spotlight search. In Finder, it can be conveniently activated by selecting a file or folder and  then, for normal previewing, press &lt;!-- raw HTML omitted --&gt;Space&lt;!-- raw HTML omitted --&gt; or &lt;!-- raw HTML omitted --&gt;⌘&lt;!-- raw HTML omitted --&gt;+&lt;!-- raw HTML omitted --&gt;Y&lt;!-- raw HTML omitted --&gt;. For full-screen previewing, you can press &lt;!-- raw HTML omitted --&gt;⌥&lt;!-- raw HTML omitted --&gt;+&lt;!-- raw HTML omitted --&gt;Space&lt;!-- raw HTML omitted --&gt; (or using &lt;!-- raw HTML omitted --&gt;⌘&lt;!-- raw HTML omitted --&gt;+&lt;!-- raw HTML omitted --&gt;⌥&lt;!-- raw HTML omitted --&gt;+&lt;!-- raw HTML omitted --&gt;Y&lt;!-- raw HTML omitted --&gt; in case you have &lt;!-- raw HTML omitted --&gt;⌥&lt;!-- raw HTML omitted --&gt;+&lt;!-- raw HTML omitted --&gt;Space&lt;!-- raw HTML omitted --&gt; bound to some apps, for instance, &lt;a href=&#34;https://www.alfredapp.com&#34;&gt;Alfred&lt;/a&gt; in my case).&lt;/p&gt;
&lt;p&gt;We might also use the command &lt;code&gt;qlmanage&lt;/code&gt; but it works properly with built-in support and has issues with some external plugins.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# show the preview of file&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;qlmanage -p &amp;lt;path_to_file&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# or only show the thumpnail&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;qlmanage -t &amp;lt;path_to_file&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;quicklook-settings&#34;&gt;QuickLook Settings&lt;/h2&gt;
&lt;p&gt;QuickLook looks for and uses the plugins from both system-wide folders &amp;lsquo;&lt;em&gt;/System/Library/QuickLook&lt;/em&gt;&amp;rsquo; and  &amp;lsquo;&lt;em&gt;/Library/QuickLook&lt;/em&gt;&amp;rsquo; and also the home folder of each user in  &amp;lsquo;&lt;em&gt;~/Library/QuickLook&lt;/em&gt;&amp;rsquo;.&lt;/p&gt;
&lt;p&gt;A QuickLook plugin is organised in a folder with an extension &lt;code&gt;.qlgenerator&lt;/code&gt;. The main task of a plugin, as mentioned above, is to generate previewing contents for the corresponding file types.  We can see an example of the built-in plugin &lt;code&gt;Image.qlgenerator&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ tree /System/Library/QuickLook/Image.qlgenerator
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/System/Library/QuickLook/Image.qlgenerator
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;└── Contents
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ├── Info.plist
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ├── MacOS
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    │   └── Image
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ├── _CodeSignature
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    │   └── CodeResources
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    └── version.plist
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The command &lt;code&gt;qlmanage&lt;/code&gt; is provided in macOS since the announcement of QuickLook in 2007. It&amp;rsquo;s very helpful for manipulating QuickLook, for instance, reloading the generators, resetting cache, and many more.  We will walk through some handy usage of &lt;code&gt;qlmanage&lt;/code&gt;.&lt;/p&gt;
&lt;h5 id=&#34;forcing-reloading-the-list-of-generators&#34;&gt;Forcing reloading the list of generators&lt;/h5&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;qlmanage -r
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;qlmanage: resetting quicklookd
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h5 id=&#34;showing-the-list-of-generators&#34;&gt;Showing the list of generators&lt;/h5&gt;
&lt;p&gt;This command can be used to see the current QuickLook generators list and also check which generator handles what file types. You might then see a long list of generators in your macOS.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;qlmanage -m plugins
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h5 id=&#34;resetting-quicklook-caches&#34;&gt;Resetting QuickLook caches&lt;/h5&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;qlmanage -r cache
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;For more usage of &lt;code&gt;qlmanage&lt;/code&gt;, we can look into its manual.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;man qlmanage
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;quicklook-plugins&#34;&gt;QuickLook Plugins&lt;/h2&gt;
&lt;p&gt;&lt;a href=&#34;https://www.google.com/search?q=quicklook+plugins&#34;&gt;Looking around&lt;/a&gt;, we can easily find a lot of plugins to enhance the built-in support of macOS. Moreover, when we install some applications, there might be included QuickLook plugins too.&lt;/p&gt;
&lt;p&gt;Here is a list of plugins that I find very handy and use quite often in my macOS development box.&lt;/p&gt;
&lt;h4 id=&#34;qlstephen&#34;&gt;QLStephen&lt;/h4&gt;
&lt;p&gt;&lt;a href=&#34;https://whomwah.github.io/qlstephen&#34;&gt;QLStephen&lt;/a&gt; is sort of an awesome Swiss-army-knife that I ever used. It enables the preview of numerous plain text files not handled by the default support of macOS QuickLook, especially files having no extensions such as README, CHANGELOG, Makefile, Rakefile, etc.&lt;/p&gt;
&lt;p&gt;If you have already installed &lt;a href=&#34;https://brew.sh&#34;&gt;Homebrew&lt;/a&gt;, it takes only a simple command to install QLStephen (in case you haven&amp;rsquo;t, please feel free to head to &lt;a href=&#34;https://htr3n.github.io/2018/06/bootstrapping-macos-workspace/#homebrew&#34;&gt;another post&lt;/a&gt;).&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;brew cask install qlstephen
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  





&lt;figure &gt;
  
  &lt;img
      
        src=&#34;https://htr3n.github.io/2018/07/handy-quicklook/qlstephen.png&#34;
      
        alt=&#34;QLStephen preview&#34;
        
        
        
        width=&#34;80%&#34; style=&#34;max-width: 100%;&#34;
         /&gt;
  
  
  
    &lt;figcaption&gt;
      &lt;span class=&#34;img--caption&#34;&gt;
        Figure 1. Using QLStephen to preview a Makefile (which has no extension and is not supported by macOS)
        
      &lt;/span&gt;
    &lt;/figcaption&gt;
  
&lt;/figure&gt;



&lt;h4 id=&#34;qlcolorcode&#34;&gt;QLColorCode&lt;/h4&gt;
&lt;p&gt;I often quickly review my code using &lt;a href=&#34;https://github.com/anthonygelibert/QLColorCode&#34;&gt;this amazing plugin&lt;/a&gt; forked/derived from the &lt;a href=&#34;https://github.com/n8gray/QLColorCode&#34;&gt;original one&lt;/a&gt; developed by Nathan Gray (&lt;a href=&#34;https://github.com/n8gray&#34;&gt;n8gray&lt;/a&gt;). The preview code will be nicely formatted and highlighted.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;brew cask install qlcolorcode
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The default setting of QLColorCode is totall fine. Nonetheless, you might want to customise some of its settings to your tastes too. Here are some of my favourites.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;defaults write org.n8gray.QLColorCode textEncoding UTF-16
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;defaults write org.n8gray.QLColorCode webkitTextEncoding UTF-16
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;defaults write org.n8gray.QLColorCode font &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Source Code Pro&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;defaults write org.n8gray.QLColorCode fontSizePoints &lt;span style=&#34;color:#ae81ff&#34;&gt;10&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;defaults write org.n8gray.QLColorCode hlTheme zenburn
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;defaults write org.n8gray.QLColorCode extraHLFlags &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;-W -J 160&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;defaults write org.n8gray.QLColorCode pathHL /usr/local/bin/highlight
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Here is the result of previewing Java code.&lt;/p&gt;

  





&lt;figure &gt;
  
  &lt;img
      
        src=&#34;https://htr3n.github.io/2018/07/handy-quicklook/qlcolorcode.png&#34;
      
        alt=&#34;QLStephen preview&#34;
        
        
        
        width=&#34;80%&#34; style=&#34;max-width: 100%;&#34;
         /&gt;
  
  
  
    &lt;figcaption&gt;
      &lt;span class=&#34;img--caption&#34;&gt;
        Figure 2. Code preview with syntax highlighting
        
      &lt;/span&gt;
    &lt;/figcaption&gt;
  
&lt;/figure&gt;



&lt;h4 id=&#34;qlcommonmark&#34;&gt;QLCommonMark&lt;/h4&gt;
&lt;p&gt;I have been working with Markdown a lot, especially writing this blog all using Markdown and Hugo generator. It was quite a while I have searched around for a stable QuickLook plugin for Markdown. Before, I used &lt;a href=&#34;https://github.com/ttscoff/MMD-QuickLook&#34;&gt;MDD-QuickLook&lt;/a&gt;, an excellent fork of the well-known &lt;a href=&#34;https://github.com/fletcher&#34;&gt;Fletcher&lt;/a&gt;&amp;rsquo;s original &lt;a href=&#34;https://github.com/fletcher/MMD-QuickLook&#34;&gt;plugin&lt;/a&gt;. MDD-QuickLook allows me to customise the look of the Markdown preview using a Github based CSS file &lt;code&gt;~/.mdqlstyle.css&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;When I found &lt;a href=&#34;https://github.com/digitalmoksha/QLCommonMark&#34;&gt;QLCommonMark&lt;/a&gt;, it replaces MDD-QuickLook with a broader coverage including &lt;a href=&#34;http://commonmark.org/&#34;&gt;CommonMark&lt;/a&gt; and Markdown and can be configured in the same way, just different filename &lt;code&gt;~/.cmqlstyle.css&lt;/code&gt;. You can find my Markdown preview style &lt;a href=&#34;https://gist.github.com/htr3n/ffdcb6238f868dd1605af2bbd1e53546&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;brew cask install qlcommonmark
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  





&lt;figure &gt;
  
  &lt;img
      
        src=&#34;https://htr3n.github.io/2018/07/handy-quicklook/qlcommonmark.png&#34;
      
        alt=&#34;QLCommonMark preview&#34;
        
        
        
        width=&#34;80%&#34; style=&#34;max-width: 100%;&#34;
         /&gt;
  
  
  
    &lt;figcaption&gt;
      &lt;span class=&#34;img--caption&#34;&gt;
        Figure 3. Markdown preview with a Github based style
        
      &lt;/span&gt;
    &lt;/figcaption&gt;
  
&lt;/figure&gt;



&lt;h4 id=&#34;quicklook-json&#34;&gt;QuickLook JSON&lt;/h4&gt;
&lt;p&gt;Both front-end and back-end developers are somehow familiar with &lt;a href=&#34;https://www.json.org/&#34;&gt;JavaScript Object Notation&lt;/a&gt; (JSON) format. As JavaScript and its ecosystem are rapidly growing, JSON and its variations become extremely popular. Hence, a QuickLook plugin for JSON should be ready in your macOS dev box.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;brew cask install quicklook-json
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;quicklook-csv&#34;&gt;QuickLook CSV&lt;/h4&gt;
&lt;p&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/Comma-separated_values&#34;&gt;CSV&lt;/a&gt; is a very popular format due to its simplicity and commonly used in statistics and data analytics. It contains values separated by comma, tabs, semi-colons, or pipes. MacOS provides built-in support for CSV previewing but I prefer a nicer-looking preview with &lt;a href=&#34;https://github.com/p2/quicklook-csv&#34;&gt;QuickLook CSV&lt;/a&gt; developed by Pascal Pfiffner (&lt;a href=&#34;https://github.com/p2&#34;&gt;p2&lt;/a&gt;) with alternate row shading.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;brew cask install quicklook-csv
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  





&lt;figure &gt;
  
  &lt;img
      
        src=&#34;https://htr3n.github.io/2018/07/handy-quicklook/csv.png&#34;
      
        alt=&#34;CSV preview&#34;
        
        
        
        width=&#34;80%&#34; style=&#34;max-width: 100%;&#34;
         /&gt;
  
  
  
    &lt;figcaption&gt;
      &lt;span class=&#34;img--caption&#34;&gt;
        Figure 4. A CSV file preview
        
      &lt;/span&gt;
    &lt;/figcaption&gt;
  
&lt;/figure&gt;



&lt;h4 id=&#34;hetimazip&#34;&gt;HetimaZip&lt;/h4&gt;
&lt;p&gt;There are many formats and standards around for compressing and archiving files such as &lt;a href=&#34;https://www.7-zip.org/&#34;&gt;7z&lt;/a&gt;, &lt;a href=&#34;http://bzip.org&#34;&gt;bzip2&lt;/a&gt;,  &lt;a href=&#34;http://www.gzip.org&#34;&gt;gzip&lt;/a&gt;, &lt;a href=&#34;https://www.rarlab.com/rar_file.htm&#34;&gt;rar&lt;/a&gt;, &lt;a href=&#34;https://en.wikipedia.org/wiki/Zip_%28file_format%29&#34;&gt;zip&lt;/a&gt;, to name but a few. &lt;a href=&#34;http://hetima.com/hetimazipql&#34;&gt;HetimaZip&lt;/a&gt; can help to &lt;em&gt;look through&lt;/em&gt; a Zip archive without unzipping or opening it. Note that, this plugin also support well some file types based on Zip format such as &lt;a href=&#34;https://en.wikipedia.org/wiki/JAR_%28file_format%29&#34;&gt;Java ARchive&lt;/a&gt; (&lt;code&gt;.jar&lt;/code&gt;), iOS app (&lt;a href=&#34;https://en.wikipedia.org/wiki/.ipa&#34;&gt;&lt;code&gt;.ipa&lt;/code&gt;&lt;/a&gt;), and many more.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;brew cask install hetimazipql
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Unfortunately, HetimaZip cannot handle &lt;a href=&#34;https://en.wikipedia.org/wiki/Android_application_package&#34;&gt;Android application package&lt;/a&gt; (&lt;code&gt;.apk&lt;/code&gt;). Thus we can combine with another nice plugin, &lt;a href=&#34;https://github.com/hezi/QuickLookAPK&#34;&gt;QuickLook APK&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;brew cask install quicklookapk
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;There is an alternative to HetimaZip, namely, &lt;a href=&#34;https://macitbetter.com&#34;&gt;BetterZip&lt;/a&gt;. I have tried both but could not make BetterZip&amp;rsquo;s work in macOS High Sierra like HetimaZip&amp;rsquo;s to show the content of a normal Zip file.&lt;/p&gt;

  





&lt;figure &gt;
  
  &lt;img
      
        src=&#34;https://htr3n.github.io/2018/07/handy-quicklook/zip.png&#34;
      
        alt=&#34;Zip file preview&#34;
        
        
        
        width=&#34;80%&#34; style=&#34;max-width: 100%;&#34;
         /&gt;
  
  
  
    &lt;figcaption&gt;
      &lt;span class=&#34;img--caption&#34;&gt;
        Figure 5. Looking through a Zip file content
        
      &lt;/span&gt;
    &lt;/figcaption&gt;
  
&lt;/figure&gt;



&lt;h4 id=&#34;suspicious-package&#34;&gt;Suspicious Package&lt;/h4&gt;
&lt;p&gt;MacOs applications are sometimes distributed as &lt;a href=&#34;https://en.wikipedia.org/wiki/Installer_%28macOS%29&#34;&gt;installer packages&lt;/a&gt; (&lt;code&gt;.pkg&lt;/code&gt;). An installer package may run some scripts and install many files in your systems. A curious and careful user would need to find out what exactly the installation scripts doing and what files are going to be installed.&lt;/p&gt;
&lt;p&gt;Advanced macOS users can use &lt;span class=&#34;menu&#34;&gt;Show Package Contents&lt;/span&gt;
 to get inside the package, but it won&amp;rsquo;t show much details. We can use the app &lt;a href=&#34;https://www.mothersruin.com/software/SuspiciousPackage&#34;&gt;&lt;em&gt;Suspicious Package&lt;/em&gt;&lt;/a&gt; or its included QuickLook plugin to inspect any installer packages before approving for installation.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;brew cask install suspicious-package
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Note that it is a tad inconvenient that you &lt;a href=&#34;https://www.mothersruin.com/software/SuspiciousPackage/faq.html#plugin-only&#34;&gt;have to install the app&lt;/a&gt; &lt;em&gt;Suspicious Package&lt;/em&gt; only for its plugin. Copying the plugin alone won&amp;rsquo;t work because it depends on the core libraries for previewing. I&amp;rsquo;m not quite sure whether this is the developers&amp;rsquo; intention or there are actual technical difficulties behind the scene to solely deliver the QuickLook plugin.&lt;/p&gt;

  





&lt;figure &gt;
  
  &lt;img
      
        src=&#34;https://htr3n.github.io/2018/07/handy-quicklook/package.png&#34;
      
        alt=&#34;Installer package preview&#34;
        
        
        
        width=&#34;80%&#34; style=&#34;max-width: 100%;&#34;
         /&gt;
  
  
  
    &lt;figcaption&gt;
      &lt;span class=&#34;img--caption&#34;&gt;
        Figure 6. Looking through an installer package
        
      &lt;/span&gt;
    &lt;/figcaption&gt;
  
&lt;/figure&gt;



&lt;h4 id=&#34;qlimagesize&#34;&gt;qlImageSize&lt;/h4&gt;
&lt;p&gt;Normally macOS provides sufficient plugins for quick-looking images. &lt;a href=&#34;https://github.com/Nyx0uf/qlImageSize&#34;&gt;qlImageSize&lt;/a&gt; can enhance further by displaying the dimensions and size of the previewed image. These information is only available either when opening the image with an application or selecting the image file and pressing &lt;!-- raw HTML omitted --&gt;⌘&lt;!-- raw HTML omitted --&gt;+&lt;!-- raw HTML omitted --&gt;I&lt;!-- raw HTML omitted --&gt; in Finder. I like &lt;em&gt;qlImageSize&lt;/em&gt; a lot as many times I just want to quickly see an image&amp;rsquo;s dimensions and size this way.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;brew cask install qlimagesize
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
      </item>
    
      <item>
        <title>Faster and enjoyable ZSH (maybe)</title>
        <link>https://htr3n.github.io/2018/07/faster-zsh/</link>
        <pubDate>Mon, 23 Jul 2018 00:00:00 +0000</pubDate>
        
        <guid>a2a29bd804f6208e6f9139b3d171d9c5</guid>
        <description>&lt;p&gt;Z shell (Zsh) has been my shell of choice in both Linux and macOS. I used to install &lt;a href=&#34;https://github.com/robbyrussell/oh-my-zsh&#34;&gt;oh-my-zsh&lt;/a&gt; or the claimed-to-be-faster &lt;a href=&#34;https://github.com/sorin-ionescu/prezto&#34;&gt;Prezto&lt;/a&gt; or &lt;a href=&#34;https://github.com/zimfw/zimfw&#34;&gt;Zim&lt;/a&gt; to leverage some of their cool libraries.&lt;/p&gt;
&lt;p&gt;Unfortunately, I realised that my favourite terminal app, &lt;a href=&#34;https://www.iterm2.com&#34;&gt;iTerm 2&lt;/a&gt;, became more and more sluggish when loading a new tab or window with more than one and a half second (without some virtual environment loaders like &lt;a href=&#34;https://github.com/creationix/nvm&#34;&gt;nvm&lt;/a&gt;, &lt;a href=&#34;https://rvm.io/&#34;&gt;rvm&lt;/a&gt;, &lt;a href=&#34;https://github.com/rbenv/rbenv&#34;&gt;rbenv&lt;/a&gt;, &lt;a href=&#34;http://www.jenv.be&#34;&gt;jenv&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;A quick &lt;a href=&#34;https://www.google.com/search?q=faster+zsh&#34;&gt;&lt;em&gt;G-fu&lt;/em&gt;&lt;/a&gt; could yield numerous posts on how to debug, optimise, speed up Zsh. I spent some time to refactor my own lightweight scripts instead of using big frameworks and was able to reach nearly one third of a second.  In this post, I will share and discuss some aspects that might affect Zsh loading time and how to mitigate them. Most of the relevant code and configurations can be found &lt;a href=&#34;https://github.com/htr3n/zsh-config&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt;&lt;!-- raw HTML omitted --&gt;There are many aspects in Zsh that can potentially slow down its startup time and can be mitigated.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#organising-shell-startup-order&#34;&gt;Organising shell startup order&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#avoiding-creating-subprocesses&#34;&gt;Avoiding creating subprocesses&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#lazy-loading&#34;&gt;Lazy-loading instead of eager-loading&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#optimising-completion-system&#34;&gt;Optimising completion system&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#optimising-shell-prompts&#34;&gt;Optimising shell prompts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#macos-optimisations&#34;&gt;MacOS-specific optimisations&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;performance-analysis&#34;&gt;Performance Analysis&lt;/h2&gt;
&lt;h3 id=&#34;overall-execution-time&#34;&gt;Overall execution time&lt;/h3&gt;
&lt;p&gt;Crunching some numbers on Zsh loading time would be definitely useful for further in depth analysis of its performance. A simple timing of Zsh startup time can be measured approximately using the &lt;code&gt;time&lt;/code&gt; command that is available in most Unix/Linux/Mac systems.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ /usr/bin/time /bin/zsh -i -c exit
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        0.67 real         0.41 user         0.26 sys
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The output of the command shows the execution time of Zsh breaking down to user-land and system. In order to get a better approximation, we can make a loop that invokes &lt;code&gt;time&lt;/code&gt; for 10 or greater, if possible.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; i in &lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;seq &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; 10&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;do&lt;/span&gt; /usr/bin/time /bin/zsh -i -c exit; &lt;span style=&#34;color:#66d9ef&#34;&gt;done&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This timing method is very fast and handy in case you want to quickly see how your Zsh performs, especially to test some changes you have just made.&lt;/p&gt;
&lt;h3 id=&#34;profiling&#34;&gt;Profiling&lt;/h3&gt;
&lt;p&gt;Zsh provides a built-in module &lt;a href=&#34;http://zsh.sourceforge.net/Doc/Release/Zsh-Modules.html#The-zsh_002fzprof-Module&#34;&gt;&lt;code&gt;zsh/zprof&lt;/code&gt;&lt;/a&gt; that can be used to profile Zsh functions. At the beginning of &lt;code&gt;~/.zshrc&lt;/code&gt;, we add &lt;code&gt;zmodload zsh/zprof&lt;/code&gt;. After restart the shell, we can use the command &lt;code&gt;zprof&lt;/code&gt; to show a very rich output on Zsh startup loading. An illustrative output of &lt;code&gt;zprof&lt;/code&gt; is shown below.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ zprof
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;num  calls                time                       self            name
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;------------------------------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 1&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;          51.31    51.31   22.68%     49.68    49.68   21.96%  zle-line-init
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 2&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;          45.72    22.86   20.21%     45.72    22.86   20.21%  compaudit
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 3&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;195&lt;/span&gt;          34.71     0.18   15.34%     25.52     0.13   11.28%  _zsh_autosuggest_bind_widget
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ...
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Two aforementioned approaches can give us a rough analysis on what aspects are invoked during Zsh startup so that we might figure out the bottleneck. In case you need to dig deeper, Arnout wrote &lt;a href=&#34;http://blog.xebia.com/profiling-zsh-shell-scripts&#34;&gt;a nice article&lt;/a&gt; in which he suggested a in-depth analysis and visualisation of Zsh loading using &lt;code&gt;xtrace&lt;/code&gt; and &lt;code&gt;kcachegrind&lt;/code&gt;. Benjamin developed &lt;a href=&#34;https://esham.io/2018/02/zsh-profiling&#34;&gt;a similar approach&lt;/a&gt; to more thorough tracing and analysis Zsh execution.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;problematic-aspects-and-mitigation&#34;&gt;Problematic Aspects and Mitigation&lt;/h2&gt;
&lt;p&gt;Using two simple methods mentioned above, I was able to roughly understand some issues of my Zsh settings and tried to mitigate them to reduce startup time. I could not report the exact steps what have been done as it was a lot of trial-and-errors. Here I will discuss some major aspects combining my actual experiment and G-fu research.&lt;/p&gt;
&lt;h3 id=&#34;organising-shell-startup-order&#34;&gt;Organising shell startup order&lt;/h3&gt;
&lt;p&gt;The order that Zsh loads its configuration files are documented &lt;a href=&#34;http://zsh.sourceforge.net/Intro/intro_3.html&#34;&gt;here&lt;/a&gt; and &lt;a href=&#34;http://zsh.sourceforge.net/Doc/Release/Files.html&#34;&gt;here&lt;/a&gt;. Peter Ward &lt;a href=&#34;https://blog.flowblok.id.au/2013-02/shell-startup-scripts.html&#34;&gt;drew a nice diagram&lt;/a&gt; showing the loading process of Zsh alongside with Bash and Sh (note that he omitted the system-wide configurations in Zsh part).&lt;/p&gt;

  





&lt;figure &gt;
  
  &lt;img
      
        src=&#34;https://htr3n.github.io/2018/07/faster-zsh/shell-startup-actual.png&#34;
      
        alt=&#34;Shell startup order&#34;
        
        
        
         style=&#34;max-width: 100%;&#34;
         /&gt;
  
  
  
    &lt;figcaption&gt;
      &lt;span class=&#34;img--caption&#34;&gt;
        Figure 1. Bash, sh, and zsh shells startup order
        
          [&lt;a href=&#34;https://blog.flowblok.id.au/2013-02/shell-startup-scripts.html&#34;&gt;source&lt;/a&gt;]
        
      &lt;/span&gt;
    &lt;/figcaption&gt;
  
&lt;/figure&gt;



&lt;p&gt;It&amp;rsquo;s also useful to understand relevant shell concepts, such as &lt;em&gt;login&lt;/em&gt; vs. &lt;em&gt;non-login&lt;/em&gt;, &lt;em&gt;interactive&lt;/em&gt; vs. &lt;em&gt;non-interactive&lt;/em&gt; shown in the diagram. Please refer to, for example, &lt;a href=&#34;https://askubuntu.com/a/438170/115425&#34;&gt;here&lt;/a&gt; or &lt;a href=&#34;https://askubuntu.com/a/879400/115425&#34;&gt;here&lt;/a&gt; for further explanations.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Some shell examples:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;when opening a terminal emulator app (e.g. Terminal or iTerm 2), we are creating an &lt;em&gt;interactive, non-login shell&lt;/em&gt; (please see &lt;code&gt;login -pf&lt;/code&gt; later).&lt;/li&gt;
&lt;li&gt;when logging in into a machine using command line &lt;a href=&#34;https://en.wikipedia.org/wiki/Secure_Shell&#34;&gt; &lt;code&gt;ssh&lt;/code&gt;&lt;/a&gt; or &lt;a href=&#34;https://en.wikipedia.org/wiki/Su_%28Unix%29&#34;&gt;&lt;code&gt;su - username&lt;/code&gt;&lt;/a&gt;, we are working with an &lt;em&gt;interactive login&lt;/em&gt; shell.&lt;/li&gt;
&lt;li&gt;when executing a shell script, it is on a &lt;em&gt;non-interactive&lt;/em&gt;, &lt;em&gt;non-login&lt;/em&gt; shell.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;Grokking Zsh startup order will help us putting relevant configurations in right files as well as optimising the loading process. My local Zsh setting is orgranised as follow:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;.zshenv&lt;/code&gt;: invoked by all invocations of Zsh, so we should keep it small and merely initialise necessary variables.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.zlogin&lt;/code&gt;: will be loaded in login shells after &lt;em&gt;.zshrc&lt;/em&gt;. My &lt;a href=&#34;https://github.com/htr3n/zsh-config/blob/master/zlogin&#34;&gt;&lt;em&gt;.zlogin&lt;/em&gt;&lt;/a&gt; will compile &lt;code&gt;zcompdump&lt;/code&gt; in background as this is time-consuming and done only once per log-in session.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.zprofile&lt;/code&gt; : similar to &lt;em&gt;.zlogin&lt;/em&gt; but will be sourced before &lt;em&gt;.zshrc&lt;/em&gt;. Note that, both &lt;em&gt;.zprofile&lt;/em&gt; and &lt;em&gt;.zshrc&lt;/em&gt; are skipped in non-login non-interactive shells, as shown in Figure 1. So I learned a trick from &lt;a href=&#34;https://github.com/sorin-ionescu/prezto/tree/master/runcoms&#34;&gt;Prezto&lt;/a&gt; that declares environment variables in &lt;em&gt;.zprofile&lt;/em&gt; and uses &lt;em&gt;.zshenv&lt;/em&gt; to source &lt;em&gt;.zprofile&lt;/em&gt; (e.g. &lt;a href=&#34;https://github.com/htr3n/zsh-config/blob/master/zprofile&#34;&gt;&lt;em&gt;.zprofile&lt;/em&gt;&lt;/a&gt; and &lt;a href=&#34;https://github.com/htr3n/zsh-config/blob/master/zshenv&#34;&gt;&lt;em&gt;.zshenv&lt;/em&gt;&lt;/a&gt;). This way, non-login non-interactive shells will receive proper variable initialisations.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.zshrc&lt;/code&gt;: will be sourced in interactive shells. This contains the main part of Zsh configuration (e.g. my &lt;a href=&#34;https://github.com/htr3n/zsh-config/blob/master/zshrc&#34;&gt;&lt;em&gt;.zshrc&lt;/em&gt;&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;avoiding-creating-subprocesses&#34;&gt;Avoiding creating subprocesses&lt;/h3&gt;
&lt;p&gt;Some commands look totally innocent and standard in your shell scripts but might cost you dearly. Among them are commands that launch new &lt;a href=&#34;http://tldp.org/LDP/abs/html/othertypesv.html#CHILDREF2&#34;&gt;child processes&lt;/a&gt; such as &lt;a href=&#34;http://zsh.sourceforge.net/Doc/Release/Expansion.html#Command-Substitution&#34;&gt;&lt;em&gt;command substitutions&lt;/em&gt;&lt;/a&gt; and &lt;a href=&#34;https://www.unix.com/man-page/posix/1posix/eval&#34;&gt;&lt;em&gt;eval&lt;/em&gt; commands&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Command Substitutions&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In Zsh, a command enclosed in  &lt;code&gt;$(command)&lt;/code&gt; or quoted with backticks &lt;code&gt;`command`&lt;/code&gt; will be replaced with its standard output. Thus, it is very popular in Unix/Linux world when one wants to execute a command and get the output to process further on. The bad thing is that &lt;em&gt;command substitution&lt;/em&gt; will launch a new process (i.e. a &lt;a href=&#34;http://tldp.org/LDP/abs/html/subshells.html#SUBSHELLSREF&#34;&gt;subshell&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;eval&lt;/code&gt; command&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;eval &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;arg...&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The command &lt;code&gt;eval&lt;/code&gt; (sounds with &lt;em&gt;evil&lt;/em&gt;, ^_O) is part of POSIX standard and is available in most shells. It&amp;rsquo;s often used together with &lt;em&gt;command substitution&lt;/em&gt;. Essentially, &lt;code&gt;eval&lt;/code&gt; concats its arguments separated with spaces along with evaluating any variables or expressions to form a command with or without arguments. Then it executes the resulting command in the current shell. As such, &lt;code&gt;eval&lt;/code&gt; will cause side-effects as it must evaluate the inputs and perform expansions, if any.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ command&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;print &amp;#39;Hello World&amp;#39;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ command			   &lt;span style=&#34;color:#75715e&#34;&gt;# nothing happen&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ eval $command
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Hello World
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This feature makes &lt;code&gt;eval&lt;/code&gt; powerful as it can dynamically evaluate and execute code. But dynamic evaluation also makes &lt;code&gt;eval&lt;/code&gt;  risky and time-consuming.&lt;/p&gt;
&lt;p&gt;In some cases, for instance, simple string manipulation, we can consider to replace command substitutions and &lt;code&gt;eval&lt;/code&gt; commands that invoke &lt;code&gt;sed&lt;/code&gt;, &lt;code&gt;awk&lt;/code&gt;, etc., with Zsh built-in constructs or hard-coded constants. Zsh provides numerous powerful built-in mechanisms for substring matchings, string explosion/splitting, and &lt;a href=&#34;http://zsh.sourceforge.net/Doc/Release/Expansion.html&#34;&gt;expansions&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For instance, when using &lt;a href=&#34;https://brew.sh&#34;&gt;Homebrew&lt;/a&gt;, it is very convenient to get the path to an installed package using &lt;code&gt;$(brew --prefix &amp;lt;package&amp;gt;)&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;export PATH&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;$PATH:&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;brew --prefix httpd&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;/bin&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It turns out many calls to &lt;code&gt;$(brew --prefix ...)&lt;/code&gt; would launch many subprocesses and thus &lt;a href=&#34;https://kev.inburke.com/kevin/profiling-zsh-startup-time&#34;&gt;slow down Zsh notably&lt;/a&gt;. When replacing that &lt;code&gt;$()&lt;/code&gt; command with its actual output, I could gain certain improvement. The caveat is that some upgraded versions might break these hard-coded values.&lt;/p&gt;
&lt;h3 id=&#34;lazy-loading&#34;&gt;&lt;em&gt;Lazy-loading&lt;/em&gt; instead of &lt;em&gt;eager-loading&lt;/em&gt;&lt;/h3&gt;
&lt;h4 id=&#34;function-autoloading&#34;&gt;Function autoloading&lt;/h4&gt;
&lt;p&gt;We can define and source new functions in Zsh. In this way, a function is &lt;em&gt;eagerly loaded&lt;/em&gt; and always available for use. Note that most of these functions might be not really needed until being invoked.&lt;/p&gt;
&lt;p&gt;Zsh can help postponing their loading time and allow to &lt;em&gt;load-on-demand&lt;/em&gt; via &lt;a href=&#34;http://zsh.sourceforge.net/Doc/Release/Functions.html#Autoloading-Functions&#34;&gt;function autoloading&lt;/a&gt;. This technique is often called &lt;em&gt;lazy loading&lt;/em&gt;.  Performance-wise, &lt;em&gt;lazy loading&lt;/em&gt; will put less pressure to the underlying system and reduce memory footprint. The same techniques are also preferred in many other fields such as databases, dynamic runtime libraries, etc.&lt;/p&gt;
&lt;p&gt;In my codebase, I create a folder, namely, &lt;code&gt;autoloaded&lt;/code&gt;, to store functions that will be, er&amp;hellip;, autoloaded by Zsh. For each function, for instance, &lt;code&gt;function hello(){...}&lt;/code&gt;, I will create a corresponding file named &lt;code&gt;hello&lt;/code&gt; inside &lt;code&gt;autoloaded&lt;/code&gt;. The content of that file is the function body (i.e. without &lt;code&gt;function&lt;/code&gt; and &lt;code&gt;(){}&lt;/code&gt;).&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ mkdir autoloaded
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;print &amp;#39;Hello World&amp;#39;&amp;#34;&lt;/span&gt; &amp;gt;&amp;gt; autoloaded/hello
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ tree
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;└── autoloaded
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    └── hello
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The folder &lt;code&gt;autoloaded&lt;/code&gt; must be added to ZSH variable &lt;code&gt;fpath&lt;/code&gt; where ZSH will look for function definitions.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# add &amp;#39;autoload&amp;#39; to fpath&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ fpath&lt;span style=&#34;color:#f92672&#34;&gt;=(&lt;/span&gt;$fpath autoloaded&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# try to invoke &amp;#39;hello&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ hello
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;zsh: command not found: hello
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# now mark `hello` for autoloading.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ autoload hello
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# quickly check how `hello` will be loaded.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ which hello
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;hello &lt;span style=&#34;color:#f92672&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;# undefined&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	builtin autoload -X
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# now it works fine&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ hello
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Hello World
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The body of &lt;code&gt;hello&lt;/code&gt; was marked with &lt;code&gt;#undefined&lt;/code&gt; along with  &lt;code&gt;builtin autoload -X&lt;/code&gt; meaning it will be loaded on-demand. The first time &lt;code&gt;hello&lt;/code&gt; is called, Zsh will automatically load and execute it.&lt;/p&gt;
&lt;p&gt;In the same way, I configured Zsh to load all of my functions on-demand to reduce memory and loading time.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;:&lt;!-- raw HTML omitted --&gt;In &lt;a href=&#34;https://github.com/htr3n/zsh-config&#34;&gt;my scripts&lt;/a&gt;,  &lt;code&gt;autoload -Uz function_name&lt;/code&gt; was used. The option &lt;code&gt;-U&lt;/code&gt; prevents alias from being expanded. That is, whenever you define an alias and a function having the same name, the alias will be considered first instead, so &lt;code&gt;-U&lt;/code&gt; just skips alias expansion.  And the option &lt;code&gt;-z&lt;/code&gt; indicates that the function will be auto-loaded using &lt;code&gt;zsh&lt;/code&gt; or &lt;code&gt;ksh&lt;/code&gt; style.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4 id=&#34;loading-virtual-environments&#34;&gt;Selective- or lazy-loading virtual environments&lt;/h4&gt;
&lt;p&gt;Many virtual environment loaders like &lt;a href=&#34;https://rvm.io/&#34;&gt;rvm&lt;/a&gt;, &lt;a href=&#34;https://github.com/rbenv/rbenv&#34;&gt;rbenv&lt;/a&gt;,  &lt;a href=&#34;http://www.jenv.be&#34;&gt;jenv&lt;/a&gt;, &lt;a href=&#34;https://github.com/creationix/nvm&#34;&gt;nvm&lt;/a&gt; have been developed to manage different run-time versions and libraries.   While being very handy for software development, most of these tools need to be &lt;em&gt;eagerly loaded&lt;/em&gt; (e.g. directly &lt;code&gt;source&lt;/code&gt; in &lt;code&gt;.zshrc&lt;/code&gt;) to work properly.&lt;/p&gt;
&lt;p&gt;Instead, we can consider to transform these loaders as much as possible into &lt;em&gt;on-demand&lt;/em&gt; wrapper functions. You can find a good example &lt;a href=&#34;https://peterlyons.com/problog/2018/01/zsh-lazy-loading&#34;&gt;here&lt;/a&gt;. In summary, Peter&amp;rsquo;s trick is to override &lt;code&gt;nvm&lt;/code&gt; with his own autoloaded &lt;code&gt;nvm()&lt;/code&gt; (that eventually invokes the original &lt;code&gt;nvm&lt;/code&gt; loader).  Carlos also went to same way for &lt;code&gt;rbenv&lt;/code&gt;, his own &lt;code&gt;antibody&lt;/code&gt;, &lt;code&gt;pyenv&lt;/code&gt; and achieved &lt;a href=&#34;https://carlosbecker.com/posts/speeding-up-zsh&#34;&gt;some good results&lt;/a&gt;. Benny C. Wong &lt;a href=&#34;http://bennycwong.github.io/post/speeding-up-oh-my-zsh/&#34;&gt;did similarly&lt;/a&gt; for both &lt;code&gt;nvm&lt;/code&gt; and &lt;code&gt;rvm&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;You can also find &lt;a href=&#34;https://frederic-hemberger.de/articles/speed-up-initial-zsh-startup-with-lazy-loading&#34;&gt;another interesting post&lt;/a&gt; by Frederic about optimising Zsh loading time by converting Kubernetes&amp;rsquo;s initialisation code into a lazy-loading function. When not using lazy-loading, you might find Adam&amp;rsquo;s &lt;a href=&#34;https://coderwall.com/p/j6cjnq/make-your-zsh-startup-faster-oh-my-zsh-and-rbenv-fixes&#34;&gt;trick&lt;/a&gt; useful for reducing  &lt;code&gt;rbenv&lt;/code&gt; time.&lt;/p&gt;
&lt;h3 id=&#34;optimising-completion-system&#34;&gt;Optimising completion system&lt;/h3&gt;
&lt;p&gt;One of the beloved Zsh&amp;rsquo;s features is its new &lt;a href=&#34;http://zsh.sourceforge.net/Doc/Release/Completion-System.html&#34;&gt;&lt;em&gt;completion system&lt;/em&gt;&lt;/a&gt;, so-called &lt;a href=&#34;https://linux.die.net/man/1/zshcompsys&#34;&gt;&lt;em&gt;zshcompsys&lt;/em&gt;&lt;/a&gt;. That is, when you type half of a certain command and press &lt;!-- raw HTML omitted --&gt;Tab&lt;!-- raw HTML omitted --&gt;, Zsh is able to show some suggestions for completing that command.&lt;/p&gt;
&lt;p&gt;Zsh does ship with some built-in support for popular commands but not for all kinds of commands. Instead, Zsh offers powerful means for defining custom completion via &lt;a href=&#34;http://zsh.sourceforge.net/Doc/Release/Completion-System.html#Autoloaded-files&#34;&gt;underscored-autoloaded files&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Zsh completion system must be activated by calling function &lt;a href=&#34;http://zsh.sourceforge.net/Doc/Release/Completion-System.html#Use-of-compinit&#34;&gt;&lt;code&gt;compinit&lt;/code&gt;&lt;/a&gt;. Most of the framework like oh-my-zsh or Prezto will take care of initialising completion system. In my case, after getting rid of big frameworks, I have to manually activate it with &lt;code&gt;autoload -Uz compinit &amp;amp;&amp;amp; compinit&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Every time &lt;code&gt;compinit&lt;/code&gt; is invoked, it often checks its configurations and re-generates in case of changes. Some have investigated this matter and suggested improvements such as &lt;a href=&#34;https://gist.github.com/ctechols/ca1035271ad134841284&#34;&gt;checking &lt;em&gt;compinit&lt;/em&gt;&amp;rsquo;s cache  only once a day&lt;/a&gt;. A similar approach has also been implemented in &lt;a href=&#34;https://github.com/sorin-ionescu/prezto/blob/e149367445d2bcb9faa6ada365dfd56efec39de8/modules/completion/init.zsh#L34&#34;&gt;Prezto&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Here is a simple excerpt based on &lt;a href=&#34;https://carlosbecker.com/posts/speeding-up-zsh&#34;&gt;Carlos&amp;rsquo;s solution&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;autoload -Uz compinit
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;date +&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;%j&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt; !&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;/usr/bin/stat -f &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;%Sm&amp;#39;&lt;/span&gt; -t &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;%j&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;ZDOTDIR&lt;span style=&#34;color:#66d9ef&#34;&gt;:-&lt;/span&gt;$HOME&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;/.zcompdump&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  compinit
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  compinit -C
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;lessening-compinit-invocations&#34;&gt;Lessening &lt;code&gt;compinit&lt;/code&gt; invocations&lt;/h4&gt;
&lt;p&gt;When running &lt;code&gt;zprof&lt;/code&gt; to profile Zsh execution, as many others also found out, I noticed a lot of invocations to &lt;code&gt;compinit&lt;/code&gt;. It was because I used some smart plugins like &lt;a href=&#34;https://github.com/zsh-users/zsh-completions&#34;&gt;zsh-users/zsh-completions&lt;/a&gt; and &lt;a href=&#34;https://github.com/zsh-users/zsh-autosuggestions&#34;&gt;zsh-users/zsh-autosuggestions&lt;/a&gt; and scattered &lt;code&gt;compinit&lt;/code&gt; in many places. Using &lt;a href=&#34;https://beyondgrep.com&#34;&gt;&lt;em&gt;ack&lt;/em&gt;&lt;/a&gt;, I could quickly spot and remove all &lt;code&gt;compinit&lt;/code&gt;, then only call once at the end of my &lt;a href=&#34;https://github.com/htr3n/zsh-config/blob/master/zshrc&#34;&gt;.zshrc&lt;/a&gt;.&lt;/p&gt;
&lt;h4 id=&#34;compiling-completion-dumped-files&#34;&gt;Compiling completion dumped files&lt;/h4&gt;
&lt;p&gt;Note that by default &lt;code&gt;compinit&lt;/code&gt; will produce a dumped configuration for accelerating future access. The default dumped file is &lt;code&gt;.zcompdump&lt;/code&gt; (which can be changed with &lt;code&gt;compinit -d new_dump_file&lt;/code&gt; or totally disabled with &lt;code&gt;compinit -D&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;We can go further by compiling the dumped file with the built-in command &lt;a href=&#34;http://zsh.sourceforge.net/Doc/Release/Shell-Builtin-Commands.html#index-compilation&#34;&gt;&lt;code&gt;zcompile&lt;/code&gt; &lt;/a&gt; for faster autoloading of completion functions. As completion is only needed for interactive shell sessions, I put the &lt;code&gt;zcompile&lt;/code&gt; code inside &lt;a href=&#34;https://github.com/htr3n/zsh-config/blob/master/zlogin&#34;&gt;.zlogin&lt;/a&gt; and force it to run in background mode.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Execute code in the background to not affect the current session&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;# Compile zcompdump, if modified, to increase startup speed.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  zcompdump&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;ZDOTDIR&lt;span style=&#34;color:#66d9ef&#34;&gt;:-&lt;/span&gt;$HOME&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;/.zcompdump&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;[[&lt;/span&gt; -s &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$zcompdump&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;! -s &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;zcompdump&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;.zwc&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;||&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$zcompdump&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt; -nt &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;zcompdump&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;.zwc&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;]]&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    zcompile &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$zcompdump&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt; &amp;amp;!
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;optimising-shell-prompts&#34;&gt;Optimising shell prompts&lt;/h3&gt;
&lt;p&gt;You can find a lot of frameworks or plugins offer super duper cool command line prompts like &lt;a href=&#34;http://stevelosh.com/blog/2010/02/my-extravagant-zsh-prompt&#34;&gt;this&lt;/a&gt;, &lt;a href=&#34;https://denysdovhan.com/spaceship-prompt/&#34;&gt;this&lt;/a&gt;, or &lt;a href=&#34;https://github.com/bhilburn/powerlevel9k/wiki/Show-Off-Your-Config&#34;&gt;these&lt;/a&gt; that show rich information regarding your current working folder such as versioning status, virtual environments, and many more.&lt;/p&gt;
&lt;p&gt;Obviously getting these information will induce extra execution time, especially for checking large versioned repositories or virtual runtime libraries. That leads to many &lt;a href=&#34;https://github.com/robbyrussell/oh-my-zsh/pull/1570&#34;&gt;workarounds&lt;/a&gt;, &lt;a href=&#34;http://marc-abramowitz.com/archives/2012/04/10/fix-for-oh-my-zsh-git-svn-prompt-slowness&#34;&gt;tweaks&lt;/a&gt;, &lt;a href=&#34;https://github.com/robbyrussell/oh-my-zsh/pull/1570&#34;&gt;hacks&lt;/a&gt;, &lt;a href=&#34;https://github.com/creationix/nvm/issues/539&#34;&gt;other hacks&lt;/a&gt;, and more &lt;a href=&#34;https://github.com/denysdovhan/spaceship-prompt/issues/161&#34;&gt;hacks&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;You might want to consider some recent approaches on speeding up shell prompts such as Anish&amp;rsquo;s &lt;a href=&#34;https://www.anishathalye.com/2015/02/07/an-asynchronous-shell-prompt&#34;&gt;non-blocking prompt&lt;/a&gt; or Sindre Sorhus&amp;rsquo;s &lt;a href=&#34;https://github.com/sindresorhus/pure&#34;&gt;&lt;em&gt;pure&lt;/em&gt;&lt;/a&gt; based on Mathias Fredriksson&amp;rsquo;s &lt;a href=&#34;https://github.com/mafredri/zsh-async&#34;&gt;zsh-async&lt;/a&gt;. I have tried &lt;em&gt;pure&lt;/em&gt; and found out its timing is very close to &lt;a href=&#34;https://github.com/htr3n/zsh-config/blob/master/lib/prompts-htr3n.sh&#34;&gt;my own prompts&lt;/a&gt; based on vanilla Zsh scripts and built-in function &lt;a href=&#34;http://zsh.sourceforge.net/Doc/Release/User-Contributions.html#Version-Control-Information&#34;&gt;&lt;code&gt;vcs_info&lt;/code&gt;&lt;/a&gt;. Therefore, I mostly switch back and forth between these prompts in my dev box and totally satisfy with their performance thus far.&lt;/p&gt;
&lt;h3 id=&#34;macos-optimisations&#34;&gt;MacOS-specific optimisations&lt;/h3&gt;
&lt;h4 id=&#34;path-helper&#34;&gt;Optimising &lt;code&gt;path_helper&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;In the chain of Zsh startup order, &lt;code&gt;/etc/zprofile&lt;/code&gt; will be sourced before &lt;code&gt;~/.zprofile&lt;/code&gt;. So, macOS uses &lt;code&gt;/etc/profile&lt;/code&gt; to establish paths to executable files via &lt;a href=&#34;https://opensource.apple.com/source/shell_cmds/shell_cmds-162/path_helper/path_helper.c.auto.html&#34;&gt;&lt;em&gt;path_helper&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ cat /etc/zprofile
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# system-wide environment settings for zsh(1)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt; -x /usr/libexec/path_helper &lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	eval &lt;span style=&#34;color:#e6db74&#34;&gt;`&lt;/span&gt;/usr/libexec/path_helper -s&lt;span style=&#34;color:#e6db74&#34;&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To do that, &lt;em&gt;path_helper&lt;/em&gt; will read &lt;code&gt;/etc/paths&lt;/code&gt; and &lt;code&gt;/etc/manpaths&lt;/code&gt;, then read all files inside &lt;code&gt;/etc/paths.d&lt;/code&gt; and &lt;code&gt;/etc/manpaths.d&lt;/code&gt; and append their contents to &lt;code&gt;$PATH&lt;/code&gt; and &lt;code&gt;$MANPATH&lt;/code&gt;, respectively. New paths can be conveniently added by adding a plaintext file in &lt;code&gt;/etc/paths.d&lt;/code&gt; instead of messing common shared configuration files.&lt;/p&gt;
&lt;p&gt;Previously in some cases, &lt;em&gt;path_helper&lt;/em&gt; might be very slow as mentioned by Michael Tsai &lt;a href=&#34;https://mjtsai.com/blog/2009/04/01/slow-opening-terminal-windows&#34;&gt;here&lt;/a&gt; and even deserved a &lt;a href=&#34;https://gist.github.com/mkhl/123525&#34;&gt;patch&lt;/a&gt; and a &lt;a href=&#34;https://github.com/mgprot/path_helper&#34;&gt;Perl based alternative&lt;/a&gt;. I reckoned that &lt;em&gt;path_helper&lt;/em&gt; is getting notably slow when the number of paths are growing but its recent version is no longer a script but 64-bit binary executable and seems to work faster.&lt;/p&gt;
&lt;p&gt;If you notice that &lt;em&gt;path_helper&lt;/em&gt; makes Zsh slow, you can just put the contents of &lt;code&gt;/etc/paths&lt;/code&gt; and of all files in &lt;code&gt;/etc/paths.d&lt;/code&gt; directly in &lt;code&gt;.zprofile&lt;/code&gt; . After that, just comment out the corresponding code in &lt;code&gt;/etc/profile&lt;/code&gt;.&lt;/p&gt;
&lt;!-- raw HTML omitted --&gt;
&lt;h4 id=&#34;optimising-login-process&#34;&gt;Optimising the login process&lt;/h4&gt;
&lt;p&gt;The default &lt;a href=&#34;https://opensource.apple.com/source/system_cmds/system_cmds-541/login.tproj&#34;&gt;&lt;em&gt;login process&lt;/em&gt;&lt;/a&gt; of macOS could be the culprit too. Opening a terminal window or tab will trigger &lt;code&gt;login -pf username&lt;/code&gt;  which, in turn, reads from and writes into the logs file in &lt;code&gt;/var/log/asl&lt;/code&gt; (note &lt;code&gt;syslog()&lt;/code&gt; invocations in &lt;a href=&#34;https://opensource.apple.com/source/system_cmds/system_cmds-541/login.tproj/login.c.auto.html&#34;&gt;&lt;code&gt;login.c&lt;/code&gt;&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;We can check this out in any terminal app. The command &lt;code&gt;ps -ef | grep login&lt;/code&gt; will show details about the &lt;code&gt;login&lt;/code&gt; process.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ ps -ef | grep login
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;25142&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;25141&lt;/span&gt;   &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;  6:40AM ttys000    0:00.13 login -fp htr3n
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In case you want to dig deeper, execute the following command in a terminal tab/window,&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ sudo opensnoop | grep &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/var/log/asl&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;then open another tab or window to see a lot of accessing to ASLs (standing for &lt;strong&gt;A&lt;/strong&gt;pple &lt;strong&gt;S&lt;/strong&gt;ystem &lt;strong&gt;L&lt;/strong&gt;og, deprecated since macOS 10.12 but still in use somewhere).&lt;/p&gt;
&lt;p&gt;Thus, some have reported a &lt;em&gt;magic&lt;/em&gt; that somehow speeds up shell startup by &lt;a href=&#34;http://osxdaily.com/2010/05/06/speed-up-a-slow-terminal-by-clearing-log-files&#34;&gt;deleting macOS ASLs&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# remove all Apple system logs -- more destructive way&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ sudo rm -rf /private/var/log/asl/*.asl
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Nevertheless, these logs will continuously grow day after day.  We might configure &lt;code&gt;/etc/asl.conf&lt;/code&gt; to permanently reduce the amount of ASLs. Using &lt;a href=&#34;https://en.wikipedia.org/wiki/sudo&#34;&gt;&lt;code&gt;sudo&lt;/code&gt;&lt;/a&gt; to open that file in Text Editor (or your editor of choice),&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ sudo open -e /etc/asl.conf
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;then looking for the following lines and changing them accordingly and leaving the rest intact.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;...
# save everything from emergency to notice
# ? [&amp;lt;= Level notice] store
? [&amp;lt;= Level critical] store
...
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The idea is to change the log level from &lt;code&gt;notice&lt;/code&gt; to a higher level such as &lt;code&gt;warning&lt;/code&gt;, &lt;code&gt;error&lt;/code&gt;, or &lt;code&gt;critical&lt;/code&gt; (see more on &lt;em&gt;Syslog Message Severities&lt;/em&gt; in &lt;a href=&#34;https://tools.ietf.org/html/rfc5424#page-11&#34;&gt;RFC 5424&lt;/a&gt;. You might also look further in the folder &lt;code&gt;/etc/asl/&lt;/code&gt; to tinker log configurations of certain applications but that is beyond the scope of this article.&lt;/p&gt;
&lt;p&gt;Another way is to skip the process of accessing ASLs altogether. For instance, with iTerm 2, press &lt;!-- raw HTML omitted --&gt;⌘&lt;!-- raw HTML omitted --&gt; + &lt;!-- raw HTML omitted --&gt;,&lt;!-- raw HTML omitted --&gt; to open menu &lt;span class=&#34;menu&#34;&gt;Preferences&lt;/span&gt;
, then go to &lt;span class=&#34;menu&#34;&gt;Profiles ▸ General&lt;/span&gt;
.&lt;/p&gt;

  





&lt;figure &gt;
  
  &lt;img
      
        src=&#34;https://htr3n.github.io/2018/07/faster-zsh/iterm2-login.png&#34;
      
        alt=&#34;iTerm 2 login setting&#34;
        
        
        
         style=&#34;max-width: 100%;&#34;
         /&gt;
  
  
  
    &lt;figcaption&gt;
      &lt;span class=&#34;img--caption&#34;&gt;
        Figure 2. iTerm 2 login setting
        
      &lt;/span&gt;
    &lt;/figcaption&gt;
  
&lt;/figure&gt;



&lt;p&gt;The same way can be applied for Apple&amp;rsquo;s built-in Terminal app.&lt;/p&gt;

  





&lt;figure &gt;
  
  &lt;img
      
        src=&#34;https://htr3n.github.io/2018/07/faster-zsh/terminal-login.png&#34;
      
        alt=&#34;Built-in Terminal login setting&#34;
        
        
        
         style=&#34;max-width: 100%;&#34;
         /&gt;
  
  
  
    &lt;figcaption&gt;
      &lt;span class=&#34;img--caption&#34;&gt;
        Figure 3. Built-in Terminal login setting
        
      &lt;/span&gt;
    &lt;/figcaption&gt;
  
&lt;/figure&gt;



&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;We have walked through some major aspects that might affect Zsh in particular, and other shells, loading time. I hope these discussions can help you to pinpoint and address your shell startup issues and have better experience working with shells and command line. This is what I got after all these effort.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; i in &lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;seq &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; 5&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;do&lt;/span&gt; /usr/bin/time /bin/zsh -i -c exit; &lt;span style=&#34;color:#66d9ef&#34;&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        0.31 real         0.16 user         0.13 sys
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        0.28 real         0.15 user         0.12 sys
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        0.28 real         0.15 user         0.12 sys
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        0.28 real         0.15 user         0.12 sys
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        0.28 real         0.15 user         0.12 sys
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you have any suggestions for improvement or successful tweaks, please drop a comment below.&lt;/p&gt;
&lt;h2 id=&#34;reading-list&#34;&gt;Reading List&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&#34;https://kev.inburke.com/kevin/profiling-zsh-startup-time&#34;&gt;https://kev.inburke.com/kevin/profiling-zsh-startup-time&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://esham.io/2018/02/zsh-profiling&#34;&gt;https://esham.io/2018/02/zsh-profiling&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://carlosbecker.com/posts/speeding-up-zsh&#34;&gt;https://carlosbecker.com/posts/speeding-up-zsh&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/robbyrussell/oh-my-zsh/issues/5327&#34;&gt;https://github.com/robbyrussell/oh-my-zsh/issues/5327&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://coderwall.com/p/sladaq/faster-zsh-in-large-git-repository&#34;&gt;https://coderwall.com/p/sladaq/faster-zsh-in-large-git-repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://ahmadnazir.github.io/posts/2016-11-03-load-shell-faster/post.html&#34;&gt;https://ahmadnazir.github.io/posts/2016-11-03-load-shell-faster/post.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://superuser.com/a/47856/82870&#34;&gt;https://superuser.com/a/47856/82870&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/robbyrussell/oh-my-zsh&#34;&gt;https://github.com/robbyrussell/oh-my-zsh&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/sorin-ionescu/prezto&#34;&gt;https://github.com/sorin-ionescu/prezto&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
</description>
      </item>
    
      <item>
        <title>A mininal Hugo blogging workflow</title>
        <link>https://htr3n.github.io/2018/07/minimal-hugo-workflow/</link>
        <pubDate>Sat, 14 Jul 2018 00:00:00 +0000</pubDate>
        
        <guid>13fb977c832479e90a289586d1f904d8</guid>
        <description>&lt;p&gt;&lt;a href=&#34;https://gohugo.io&#34;&gt;Hugo&lt;/a&gt; is a blazingly fast static site generator based on &lt;a href=&#34;https://golang.org&#34;&gt;Go&lt;/a&gt;. My &lt;a href=&#34;https://htr3n.github.io/2018/01/first-experience-with-hugo/&#34;&gt;first experience with Hugo&lt;/a&gt; was truly pleasant. I appreciate the separation of contents, presentations, and site generation logics in Hugo  that leads to less effort for maintenance or switching themes.&lt;/p&gt;
&lt;p&gt;On the run-time side, it&amp;rsquo;s also nice that Hugo is often delivered as a reasonably fat executable binary (about 30~50 MB). We almost do not have to install anything else to make it work (although this is not entirely true since Hugo 0.43+).&lt;/p&gt;
&lt;p&gt;Using Hugo to &lt;a href=&#34;https://github.com/htr3n/htr3n-blog&#34;&gt;build&lt;/a&gt; this blog, I have learned a lot of things and tried to set up a simple blogging workflow to automate as much as possible the process from writing articles and altering themes to generating sites and watching for changes. My Hugo based blogging workflow comprises three aspects:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Content&lt;/em&gt; (mainly Markdown)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Presentation&lt;/em&gt; (theming)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Site generation&lt;/em&gt; (Hugo)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I will take &lt;a href=&#34;https://github.com/htr3n/htr3n-blog&#34;&gt;my own Hugo blogging project&lt;/a&gt; as an illustrative example. An overview of the project structure is shown in the picture below.&lt;/p&gt;

  





&lt;figure &gt;
  
  &lt;img
      
        src=&#34;https://htr3n.github.io/2018/07/minimal-hugo-workflow/project-structure.png&#34;
      
        alt=&#34;A simple Hugo project structure&#34;
        
        
        
         style=&#34;max-width: 100%;&#34;
         /&gt;
  
  
  
    &lt;figcaption&gt;
      &lt;span class=&#34;img--caption&#34;&gt;
        Figure 1. A simple Hugo project structure
        
      &lt;/span&gt;
    &lt;/figcaption&gt;
  
&lt;/figure&gt;



&lt;p&gt;&lt;strong&gt;Some relevant project resources:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;assets&lt;/code&gt;: my pre-processing resources (e.g. SASS, LESS, images, JavaScript).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;content&lt;/code&gt;: Markdown contents&lt;/li&gt;
&lt;li&gt;&lt;code&gt;public&lt;/code&gt;: the Web sites generated by Hugo&lt;/li&gt;
&lt;li&gt;&lt;code&gt;static&lt;/code&gt;: resources (e.g. CSS, images, JavaScript) to be copied directly to &lt;code&gt;public&lt;/code&gt; by Hugo.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;themes&lt;/code&gt;: Hugo themes (here I use my own theme &lt;a href=&#34;https://github.com/htr3n/hyde-hyde&#34;&gt;&lt;em&gt;hyde-hyde&lt;/em&gt;&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;package.json&lt;/code&gt;: Node.js / NPM main configuration&lt;/li&gt;
&lt;li&gt;&lt;code&gt;gulpfile.js&lt;/code&gt;: Gulp configuration&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;content&#34;&gt;Content&lt;/h2&gt;
&lt;p&gt;Among many nice features, Hugo supports Markdown contents out-of-the-box. Thus I can keep writing blog posts with my favourite Markdown editors. I have tried a number of editors in macOS, ranging from simple plain text with preview add-ons like &lt;a href=&#34;https://www.sublimetext.com&#34;&gt;Sublime Text&lt;/a&gt;, &lt;a href=&#34;https://macromates.com&#34;&gt;TextMate&lt;/a&gt;, &lt;a href=&#34;https://atom.io&#34;&gt;Atom&lt;/a&gt;, &lt;a href=&#34;https://code.visualstudio.com&#34;&gt;Visual Studio Code&lt;/a&gt;, &lt;a href=&#34;https://www.vim.org&#34;&gt;Vim&lt;/a&gt; to some built-in ones like &lt;a href=&#34;http://www.bear-writer.com&#34;&gt;Bear&lt;/a&gt;, &lt;a href=&#34;https://bywordapp.com&#34;&gt;Byword&lt;/a&gt;, &lt;a href=&#34;http://macdown.uranusjr.com&#34;&gt;MacDown&lt;/a&gt;, &lt;a href=&#34;http://mouapp.com&#34;&gt;Mou&lt;/a&gt;, &lt;a href=&#34;http://www.texts.io&#34;&gt;Texts&lt;/a&gt;, &lt;a href=&#34;https://ia.net/writer&#34;&gt;IA Writer&lt;/a&gt;, &lt;a href=&#34;http://marked2app.com&#34;&gt;Marked&lt;/a&gt; (only preview), &lt;a href=&#34;https://typora.io&#34;&gt;Typora&lt;/a&gt;, to name but by no means completed. You can see &lt;a href=&#34;https://github.com/mundimark/awesome-markdown-editors&#34;&gt;here&lt;/a&gt; a list including most of Markdown editors available and &lt;a href=&#34;https://www.sitepoint.com/the-best-markdown-editors-for-mac&#34;&gt;here&lt;/a&gt; are some for macOS.&lt;/p&gt;
&lt;p&gt;My first editor was Mou, due to its simplicity and highly customisable themes and rendering styles. Later on Mou&amp;rsquo;s developer decided to sell its ownership, then resumed working on its beta making the software status a bit unclear and frustrated. &lt;a href=&#34;https://uranusjr.com&#34;&gt;Tzu-ping Chung&lt;/a&gt; (@&lt;a href=&#34;https://github.com/uranusjr&#34;&gt;uranusjr&lt;/a&gt;) has created a similar editor, namely, &lt;a href=&#34;http://macdown.uranusjr.com&#34;&gt;MacDown&lt;/a&gt;, and &lt;a href=&#34;https://github.com/MacDownApp/macdown&#34;&gt;open-sourced it&lt;/a&gt;. Then I started using MacDown with the existing Mou&amp;rsquo;s themes and styles.&lt;/p&gt;
&lt;p&gt;I could not remember exactly when and how I found &lt;a href=&#34;https://typora.io&#34;&gt;Typora&lt;/a&gt; but it never ceases to amaze me. With Typora, I can enjoy seamless editing and rendering in the same window, i.e., I can write Markdown normally and directly see the content rendered. Typora is still free in its beta phase and will become paid software when released. It has become my Markdown editor of choice and will be in future should its price tag is reasonable. For quick fixes, I use any editors at hand, for instance Visual Studio Code when working on a Hugo project.&lt;/p&gt;
&lt;h2 id=&#34;presentation&#34;&gt;Presentation&lt;/h2&gt;
&lt;p&gt;The nice thing is that a Hugo theme is a standalone component for decorating Hugo generated sites. Nevertheless, I can override a theme&amp;rsquo;s settings (e.g. layouts, styles) with my own versions with respect to &lt;a href=&#34;https://gohugo.io/templates/lookup-order&#34;&gt;Hugo lookup order&lt;/a&gt;. A theme contains resources for templating, layouting, and styling. Hugo&amp;rsquo;s templating and layouting have been discussed a lot around. Styling resources in a typical Hugo project can be found inside its theme&amp;rsquo;s &lt;code&gt;static&lt;/code&gt; or the project root&amp;rsquo;s &lt;code&gt;static&lt;/code&gt; and &lt;code&gt;assets&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;I used to work with CSS styles. After learning more about CSS preprocessors and attracted by the abstraction levels and tooling they provide, I decide to give a try and refactored my existing codebase to SCSS. Hence, my workflow should include support for SCSS  (you might opt for LESS or Stylus but still can leverage a similar workflow with just right processing components).&lt;/p&gt;
&lt;h2 id=&#34;site-generation&#34;&gt;Site Generation&lt;/h2&gt;
&lt;p&gt;Hugo will be main element that generates the final Web site taking input resources from content and presentation components. Until version 0.43, Hugo has not provided support for SASS. Hence, many have to develop their own  &lt;a href=&#34;https://blog.carlmjohnson.net/post/2017/hugo-asset-pipeline&#34;&gt;&amp;rsquo;&lt;em&gt;asset pipeline&lt;/em&gt;&amp;rsquo;&lt;/a&gt;, i.e., incorporating preprocessors and post-processors with Hugo generation process.&lt;/p&gt;
&lt;h3 id=&#34;endogenous-pipeline&#34;&gt;Endogenous Pipeline&lt;/h3&gt;
&lt;p&gt;This approach, also called &lt;em&gt;in-line pipeline&lt;/em&gt;, only works since Hugo &lt;a href=&#34;https://gohugo.io/news/0.43-relnotes&#34;&gt;v0.43/extended&lt;/a&gt; and later that supports processing SASS/CSS with consideration for &lt;a href=&#34;https://en.wikipedia.org/wiki/Minification_%28programming%29&#34;&gt;minification&lt;/a&gt;, post-processing, and &lt;a href=&#34;https://www.keycdn.com/support/what-is-cache-busting&#34;&gt;cache busting&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In Hugo templates, I can refer to SCSS files via &lt;a href=&#34;https://gohugo.io/content-management/page-resources&#34;&gt;&lt;em&gt;page resources&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{{ $styles := resources.Get &amp;#34;scss/hyde-hyde.scss&amp;#34; | toCSS | postCSS (dict &amp;#34;use&amp;#34; &amp;#34;autoprefixer&amp;#34;) | minify | fingerprint }}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;link&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;rel&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;stylesheet&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;href&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;{{ $styles.Permalink }}&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;integrity&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;{{ $styles.Data.Integrity }}&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Note that Hugo will look for &lt;code&gt;scss/hyde-hyde.scss&lt;/code&gt; in the project&amp;rsquo;s root and then the theme&amp;rsquo;s root, in that order.&lt;/p&gt;
&lt;p&gt;Hugo retrieves the resource &lt;code&gt;hyde-hyde.scss&lt;/code&gt;  using &lt;code&gt;Resources.Get&lt;/code&gt;, then &lt;a href=&#34;https://gohugo.io/hugo-pipes/scss-sass&#34;&gt;transforms it&lt;/a&gt; into &lt;code&gt;hyde-hyde.css&lt;/code&gt; and passes it to &lt;a href=&#34;https://gohugo.io/hugo-pipes/postcss&#34;&gt;PostCSS&lt;/a&gt; for &lt;a href=&#34;https://github.com/postcss/autoprefixer&#34;&gt;autoprefixing&lt;/a&gt;. After that, it &lt;a href=&#34;https://gohugo.io/hugo-pipes/minification/&#34;&gt;minifies&lt;/a&gt; the CSS and generates a &lt;em&gt;fingerprinted version&lt;/em&gt;.  The second line simply links the resulting &lt;code&gt;hyde-hyde.css&lt;/code&gt; with HTML via the variable &lt;code&gt;$style&lt;/code&gt;. The result in the generated HTML will be like this (note that the code can be different to yours).&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;link&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;rel&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;stylesheet&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;href&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;http://localhost:1313/scss/hyde-hyde.4ff234ab46aa5302c7e0d2f35b9c76a8bba9fe42a9e8a6c7c47df7f85b8de122.css&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;integrity&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;sha256-T/I0q0aqUwLH4NLzW5x2qLup/kKp6KbHxH33&amp;amp;#43;FuN4SI=&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The fingerprint code is for &lt;em&gt;cache busting&lt;/em&gt; and only changed when the source file is altered.&lt;/p&gt;
&lt;p&gt;The biggest advantage of &lt;em&gt;in-line pipeline&lt;/em&gt; is that Hugo already provides a certain level of built-in support. Hugo&amp;rsquo;s &lt;em&gt;live reload&lt;/em&gt;, i.e. serving the resulting sites live and automatically refreshing whenever there are changes of contents or themes, also works superbly for this case.&lt;/p&gt;
&lt;p&gt;For many scenarios, we can use this approach instead of configuring complex tools like Gulp, Grunt, or Webpack. To be precise, I do need to install extra tools, which are &lt;code&gt;postcss-cli&lt;/code&gt; and &lt;code&gt;autoprefixer&lt;/code&gt;, for the aforementioned example to work and Hugo 0.43 extended version &lt;a href=&#34;https://github.com/Homebrew/homebrew-core/issues/29898&#34;&gt;partially depends on Cgo/libc++&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ npm i -g postcss-cli autoprefixer
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Another downside to consider is that, in this way, external tools like &lt;code&gt;postcss&lt;/code&gt; will slow down Hugo.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;As I checked out &lt;a href=&#34;https://discourse.gohugo.io/t/how-to-use-source-maps-with-hugo-0-43/12826&#34;&gt;this thread&lt;/a&gt; and &lt;a href=&#34;https://discourse.gohugo.io/t/how-to-use-source-maps-with-hugo-0-43/12826/9&#34;&gt;tried on my project&lt;/a&gt;, Hugo&amp;rsquo;s extensions like &lt;code&gt;postCSS&lt;/code&gt;, &lt;code&gt;minify&lt;/code&gt;, and &lt;code&gt;fingerprint&lt;/code&gt; could mess up CSS sourcemaps. If you need sourcemaps for developing and debugging, please ignore them and consider the &lt;em&gt;exogenous pipeline&lt;/em&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;exogenous-pipeline&#34;&gt;Exogenous Pipeline&lt;/h3&gt;
&lt;p&gt;When working on more complex asset pipelining, we have to involve external tools to build an &lt;em&gt;exogenous asset pipeline&lt;/em&gt;. This is also my blogging workflow before Hugo v0.43. Now, I can mostly get rid of this &lt;em&gt;exogenous pipeline&lt;/em&gt;. Here we will walk through this approach merely for the sake of completeness.&lt;/p&gt;
&lt;p&gt;There are several ways to handle Web resources. For instance, Netlify provides  a boilerplate project, namely, &lt;a href=&#34;https://github.com/netlify/victor-hugo&#34;&gt;&lt;em&gt;victor-hugo&lt;/em&gt;&lt;/a&gt; for starting a new Hugo project and preparing to deploy to its hosting. This boilerplate employs &lt;a href=&#34;https://gulpjs.com&#34;&gt;Gulp&lt;/a&gt;, &lt;a href=&#34;https://webpack.js.org&#34;&gt;Webpack&lt;/a&gt;, &lt;a href=&#34;https://github.com/postcss/postcss&#34;&gt;PostCSS&lt;/a&gt;, and &lt;a href=&#34;https://browsersync.io&#34;&gt;Browsersync&lt;/a&gt; around Hugo. There are many developers rooting for Gulp &lt;a href=&#34;(#references)&#34;&gt;[1, 2, 3, 4, 5]&lt;/a&gt; whilst some others go for Grunt &lt;a href=&#34;(#references)&#34;&gt;[6]&lt;/a&gt; or Webpack &lt;a href=&#34;#references&#34;&gt;[7, 8]&lt;/a&gt;. And even few brave ones use &lt;a href=&#34;http://thecodestead.com/post/how-to-use-npm-as-a-build-tool-with-hugo&#34;&gt;pure NPM&lt;/a&gt; &lt;a href=&#34;#references&#34;&gt;[9, 10]&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For starter projects with Hugo, you might want to consider some useful projects such as &lt;a href=&#34;https://github.com/jbrodriguez/hugulp&#34;&gt;hugulp&lt;/a&gt;, &lt;a href=&#34;http://ktmud.github.io/huggle/en/intro&#34;&gt;Huggle&lt;/a&gt;, &lt;a href=&#34;https://github.com/vseventer/hugo-webpack-boilerplate&#34;&gt;hugo-webpack-boilerplate&lt;/a&gt;. In my project, I combine Gulp with NPM and leverage some Gulp&amp;rsquo;s components for the asset pipeline.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;SASS/SCSS to CSS&lt;/em&gt;: a sensible choice is &lt;a href=&#34;https://www.npmjs.com/package/gulp-sass&#34;&gt;&lt;em&gt;gulp-sass&lt;/em&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Sourcemaps&lt;/em&gt; (optional): this is not mandatory but very handy for developing and debugging phase. I pick &lt;a href=&#34;https://www.npmjs.com/package/gulp-sourcemaps&#34;&gt;&lt;em&gt;gulp-sourcemaps&lt;/em&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Autoprefixing&lt;/em&gt;: it helps adding vendor-specific prefixes to CSS rules. We can use &lt;a href=&#34;https://www.npmjs.com/package/gulp-autoprefixer&#34;&gt;&lt;em&gt;gulp-autoprefixer&lt;/em&gt;&lt;/a&gt; but be careful to combine with &lt;em&gt;gulp-sourcemaps&lt;/em&gt; as it is &lt;a href=&#34;https://github.com/gulp-sourcemaps/gulp-sourcemaps/wiki/Plugins-with-gulp-sourcemaps-support#css&#34;&gt;currently broken&lt;/a&gt;. I decide to use &lt;a href=&#34;https://www.npmjs.org/package/gulp-postcss&#34;&gt;&lt;em&gt;gulp-postcss&lt;/em&gt;&lt;/a&gt; along with &lt;a href=&#34;https://www.npmjs.com/package/autoprefixer&#34;&gt;&lt;em&gt;postcss-autoprefixer&lt;/em&gt;&lt;/a&gt; instead.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Minification&lt;/em&gt;: &lt;a href=&#34;https://github.com/postcss/postcss&#34;&gt;PostCSS&lt;/a&gt; provides many plugins for CSS post-processing alongside &lt;em&gt;autoprefixer&lt;/em&gt;.  I choose &lt;a href=&#34;http://cssnano.co&#34;&gt;&lt;em&gt;cssnano&lt;/em&gt;&lt;/a&gt; to minify the CSSs.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ npm i -D gulp@next gulp-sass gulp-postcss autoprefixer gulp-sourcemaps cssnano
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In the same way, you can add more components to the list. Here I rather keep it short and simple for illustrative purpose. Now I start configuring Gulp to use them in my project.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;gulp&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;require&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;gulp&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;sass&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;require&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;gulp-sass&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;postcss&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;require&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;gulp-postcss&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;autoprefixer&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;require&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;autoprefixer&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;cssnano&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;require&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;cssnano&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;sourcemaps&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;require&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;gulp-sourcemaps&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;require&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;fancy-log&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;sassSourceFile&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;assets/scss/hyde-hyde.scss&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;outputFolder&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;static/css&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;watchedResources&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;assets/scss/**/*&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;gulp&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;task&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;scss&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;done&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;gulp&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;src&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;sassSourceFile&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    .&lt;span style=&#34;color:#a6e22e&#34;&gt;pipe&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;sourcemaps&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;init&lt;/span&gt;())
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    .&lt;span style=&#34;color:#a6e22e&#34;&gt;pipe&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;sass&lt;/span&gt;().&lt;span style=&#34;color:#a6e22e&#34;&gt;on&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;error&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;){
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;error&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;message&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    .&lt;span style=&#34;color:#a6e22e&#34;&gt;pipe&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;postcss&lt;/span&gt;([&lt;span style=&#34;color:#a6e22e&#34;&gt;autoprefixer&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;cssnano&lt;/span&gt;]))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    .&lt;span style=&#34;color:#a6e22e&#34;&gt;pipe&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;sourcemaps&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;write&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;.&amp;#39;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    .&lt;span style=&#34;color:#a6e22e&#34;&gt;pipe&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;gulp&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;dest&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;outputFolder&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    .&lt;span style=&#34;color:#a6e22e&#34;&gt;on&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;end&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;done&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;gulp&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;task&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;watch&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;gulp&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;series&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;scss&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;done&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;gulp&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;watch&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;watchedResources&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;gulp&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;parallel&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;scss&amp;#39;&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;done&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;gulp&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;task&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;default&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;gulp&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;series&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;watch&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt; () {}));
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Note that the syntax is Gulp v4.0.&lt;/p&gt;
&lt;p&gt;Now I just simply invoke Gulp to trigger its chaining pipeline.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ gulp
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;10:23:40&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; Using gulpfile ~/working/dev/htr3n-blog/gulpfile.js
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;10:23:40&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; Starting &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;default&amp;#39;&lt;/span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;10:23:40&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; Starting &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;watch&amp;#39;&lt;/span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;10:23:40&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; Starting &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;scss&amp;#39;&lt;/span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;10:23:40&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; Finished &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;scss&amp;#39;&lt;/span&gt; after &lt;span style=&#34;color:#ae81ff&#34;&gt;58&lt;/span&gt; ms
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;10:23:40&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; Starting &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;&amp;lt;anonymous&amp;gt;&amp;#39;&lt;/span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Gulp will transform &lt;code&gt;hyde-hyde.scss&lt;/code&gt; into &lt;code&gt;hyde-hyde.css&lt;/code&gt;  which is autoprefixed and saved in &lt;code&gt;static/css&lt;/code&gt; along with its sourcemaps. In the Hugo templates, I refer to &lt;code&gt;hyde-hyde.css&lt;/code&gt; normally.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;link&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;rel&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;stylesheet&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;href&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;{{ .Site.BaseURL }}/css/hyde-hyde.css&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I can combine &lt;a href=&#34;https://github.com/gulpjs/gulp/blob/master/docs/API.md#gulpwatchglobs-opts-fn&#34;&gt;Gulp.watch()&lt;/a&gt; with Hugo&amp;rsquo;s &lt;em&gt;live reload&lt;/em&gt; feature so that both will continuously monitors for changes and serve them instantly. This way, whenever I made any changes in a post in Typora, a SCSS/CSS file, or Go+HTML layout, I will instantly see the generated HTMLs.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ hugo server -w --cleanDestinationDir
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   | EN
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+------------------+-----+
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Pages            | &lt;span style=&#34;color:#ae81ff&#34;&gt;320&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Paginator pages  |   &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Non-page files   |  &lt;span style=&#34;color:#ae81ff&#34;&gt;14&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Static files     |  &lt;span style=&#34;color:#ae81ff&#34;&gt;14&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Processed images |   &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Aliases          |   &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Sitemaps         |   &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Cleaned          |   &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Total in &lt;span style=&#34;color:#ae81ff&#34;&gt;193&lt;/span&gt; ms
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Watching &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; changes in /Users/htr3n/working/dev/htr3n-blog/&lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;assets,content,data,layouts,static,themes&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Watching &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; config changes in /Users/htr3n/working/dev/htr3n-blog/config.toml
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Serving pages from memory
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Running in Fast Render Mode. For full rebuilds on change: hugo server --disableFastRender
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Web Server is available at http://localhost:1313/ &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;bind address 127.0.0.1&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Press Ctrl+C to stop
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Please note that, by default, Hugo will only keep watching the following folders  &lt;code&gt;{assets, content, data, layouts, static, themes}&lt;/code&gt;. Hence, our SCSS files might not be in one of these folders but we must ensure the resources generated from Gulp are. As I illustrated &lt;em&gt;endogenous pipeline&lt;/em&gt; above, my SCSSs are kept in &lt;code&gt;assets&lt;/code&gt; such that Hugo &lt;code&gt;Resources.Get&lt;/code&gt; can find them. If you opt for &lt;em&gt;exogenous pipeline&lt;/em&gt;, you should put the preprocessing resources elsewhere.&lt;/p&gt;
&lt;p&gt;After all, we can open the browser to &lt;a href=&#34;http://localhost:1313&#34;&gt;http://localhost:1313&lt;/a&gt; and enjoy the experience of live editing side-by-side.&lt;/p&gt;

  





&lt;figure &gt;
  
  &lt;img
      
        src=&#34;https://htr3n.github.io/2018/07/minimal-hugo-workflow/side-by-side.png&#34;
      
        alt=&#34;Typora (left) and the generated HTML pages (right)&#34;
        
        
        
        width=&#34;99%&#34; style=&#34;max-width: 100%;&#34;
         /&gt;
  
  
  
    &lt;figcaption&gt;
      &lt;span class=&#34;img--caption&#34;&gt;
        Figure 2. Typora (left) and the generated HTML pages (right)
        
      &lt;/span&gt;
    &lt;/figcaption&gt;
  
&lt;/figure&gt;



&lt;p&gt;At this point, we seem to miss &lt;em&gt;cache busting&lt;/em&gt; which is provided in the &lt;em&gt;endogenous pipeline&lt;/em&gt; with Hugo. That is also the biggest advantage of using external tools as we need to establish the connections between Hugo generated resources and Gulp&amp;rsquo;s manipulated resources on our own.&lt;/p&gt;
&lt;p&gt;It is a tad complicated as you can find &lt;a href=&#34;https://byteplumbing.net/2017/08/static-asset-cache-busting-for-hugo&#34;&gt;here&lt;/a&gt;, &lt;a href=&#34;https://blog.carlmjohnson.net/post/2017/hugo-asset-pipeline/&#34;&gt;here&lt;/a&gt; and &lt;a href=&#34;http://danbahrami.io/articles/building-a-production-website-with-hugo-and-gulp-js&#34;&gt;here&lt;/a&gt;. In summary, the idea is to generate &lt;a href=&#34;https://en.wikipedia.org/wiki/Hash_function&#34;&gt;&lt;em&gt;hash signatures&lt;/em&gt;&lt;/a&gt; for your CSSs, for instance, using &lt;a href=&#34;https://en.wikipedia.org/wiki/MD5&#34;&gt;MD5&lt;/a&gt; or &lt;a href=&#34;https://en.wikipedia.org/wiki/Secure_Hash_Algorithms&#34;&gt;SHA&lt;/a&gt;, store the relevant data as dictionary &lt;a href=&#34;https://en.wikipedia.org/wiki/Key-value_database&#34;&gt;key-value&lt;/a&gt; pairs, e.g. &lt;code&gt;&#39;hyde-hyde.css&#39; =&amp;gt; &#39;hyde-hyde.the-latest-hash-number.css&#39;&lt;/code&gt;,
then use Hugo’s &lt;a href=&#34;https://gohugo.io/templates/data-templates/&#34;&gt;data templates&lt;/a&gt; feature to refer to those pairs. This approach has actually been implemented in the aforementioned Hugo&amp;rsquo;s extensions.&lt;/p&gt;
&lt;p&gt;In case you really need &lt;em&gt;cache busting&lt;/em&gt;, we can utilise Hugo v0.43 extensions to complement Gulp on this matter (🐵). We just modify the Gulp configuration a bit so that the output folder is no longer &lt;code&gt;static&lt;/code&gt; but &lt;code&gt;assets/css&lt;/code&gt; as Hugo&amp;rsquo;s &lt;code&gt;Resources.Get&lt;/code&gt; rather strictly looks for resources in &lt;code&gt;assets&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;outputFolder&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;assets/css&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And in the HTML, we use similar templates without &lt;code&gt;toCSS&lt;/code&gt; and &lt;code&gt;postCSS&lt;/code&gt; that are done with Gulp.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{{ $styles := resources.Get &amp;#34;css/hyde-hyde.css&amp;#34; | minify | fingerprint }}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;link&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;rel&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;stylesheet&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;href&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;{{ $styles.Permalink }}&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;integrity&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;{{ $styles.Data.Integrity }}&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It seems Gulp becomes redundant here as Hugo can perform &lt;code&gt;toCSS&lt;/code&gt;, &lt;code&gt;postCSS&lt;/code&gt;, and &lt;code&gt;minify&lt;/code&gt; just fine. Nonetheless, in case you need other functionalities that are not yet provided by Hugo, Gulp will be what you should ask for. Besides, as per &lt;strong&gt;Note&lt;/strong&gt; above, there are still some issues with Hugo&amp;rsquo;s extension regarding sourcemaps whilst Gulp&amp;rsquo;s asset pipeline above works flawlessly.&lt;/p&gt;
&lt;h4 id=&#34;more-automation-please&#34;&gt;More automation, please!!!&lt;/h4&gt;
&lt;p&gt;There are still two manual tasks for the &lt;em&gt;exogenous pipeline&lt;/em&gt;, one for invoking Gulp and another one to start Hugo. Aiming to automate the workflow as much as possible, we can merge two tasks using one execution script, via NPM.&lt;/p&gt;
&lt;p&gt;There are a number of options for running tasks concurrently in NPM including &lt;a href=&#34;https://www.npmjs.com/package/npm-run-all&#34;&gt;npm-run-all&lt;/a&gt;, &lt;a href=&#34;https://www.npmjs.com/package/npm-run-parallel&#34;&gt;npm-run-parallel&lt;/a&gt;, &lt;a href=&#34;https://www.npmjs.com/package/concurrently&#34;&gt;concurrently&lt;/a&gt;, or using &lt;a href=&#34;https://en.wikipedia.org/wiki/Background_process&#34;&gt;background process&lt;/a&gt; if you are using Linux/macOS alike. Even Gulp also has some helper plugins like &lt;a href=&#34;https://www.npmjs.com/package/gulp-exec&#34;&gt;gulp-exec&lt;/a&gt; to execute child processes, &lt;a href=&#34;https://www.npmjs.com/package/gulp-nodemon&#34;&gt;gulp-nodemon&lt;/a&gt; to run in &lt;a href=&#34;https://en.wikipedia.org/wiki/Daemon_%28computing%29&#34;&gt;daemon mode&lt;/a&gt;,  and Gulp 4.0+ has &lt;a href=&#34;https://github.com/gulpjs/gulp/blob/4.0/docs/API.md#gulpparalleltasks&#34;&gt;Gulp.parallel()&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s consider a simple example with &lt;a href=&#34;https://www.npmjs.com/package/npm-run-all&#34;&gt;npm-run-all&lt;/a&gt;. Other tools can be used similarly.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ npm i -D npm-run-all
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then define some simple scripts in &lt;code&gt;package.json&lt;/code&gt; for executing Gulp and Hugo.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;scripts&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;scss-build&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;gulp scss&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;scss-watch&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;gulp watch&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;hugo-watch&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;hugo server -w --buildDrafts --cleanDestinationDir&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;dev&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;npm-run-all --parallel scss-watch hugo-watch&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;devDependencies&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;autoprefixer&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;^9.0.0&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;cssnano&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;^4.0.3&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;gulp&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;^4.0.0&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;gulp-postcss&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;^7.0.1&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;gulp-sass&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;^4.0.1&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;gulp-sourcemaps&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;^2.6.4&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;npm-run-all&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;^4.1.3&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Given no issues, we should execute &lt;code&gt;npm run dev&lt;/code&gt; and see both Hugo and Gulp running in parallel.&lt;/p&gt;
&lt;h2 id=&#34;further-optimisations&#34;&gt;Further Optimisations&lt;/h2&gt;
&lt;p&gt;As you might have noticed, the Web resources (e.g. HTML, CSS) generated by Hugo may contain a lot of whitespace and/or line-breaks. You can easily see this when viewing the source code of the generated Web pages.&lt;/p&gt;
&lt;p&gt;During the developing phase in my local machines, I always keep the generated resources untouched so that I can read the code for debugging or analysing. When deploying to hosting servers, we don&amp;rsquo;t often preserve the readability of the source code as the end-users mainly see and interact with the beautiful pages rendered by Web browsers.&lt;/p&gt;
&lt;p&gt;Therefore, I configure a simple Gulp task to optimise the generated Web resources before pushing them to the servers. What I need is &lt;a href=&#34;https://www.npmjs.com/package/gulp-htmlmin&#34;&gt;&lt;code&gt;gulp-htmlmin&lt;/code&gt;&lt;/a&gt;&amp;mdash;a Gulp front-end of &lt;a href=&#34;https://github.com/kangax/html-minifier&#34;&gt;&lt;em&gt;html-minifier&lt;/em&gt;&lt;/a&gt;. Please refer to &lt;em&gt;html-minifier&lt;/em&gt;&amp;rsquo;s &lt;a href=&#34;https://github.com/kangax/html-minifier&#34;&gt;documentations&lt;/a&gt; should you need to learn further about its options.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ npm i -D gulp-htmlmin
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And I create a simple Gulp task for minifying Web resources that can be invoked at command line as &lt;code&gt;gulp minify-html&lt;/code&gt;. This task should be performed after calling Hugo to generate the Web pages.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;htmlmin&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;require&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;gulp-htmlmin&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;//...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;gulp&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;task&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;minify-html&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;done&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;publicFolder&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;./public&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;html&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;publicFolder&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/**/*.html&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;css&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;publicFolder&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/**/*.css&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;js&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;publicFolder&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/**/*.js&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;dest&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;./dist&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Minifying HTML/CSS/JS in &amp;#39;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;publicFolder&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#39; to &amp;#39;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;dest&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#39;&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;gulp&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;src&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;publicFolder&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/**&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    .&lt;span style=&#34;color:#a6e22e&#34;&gt;pipe&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;gulp&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;dest&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;dest&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;gulp&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;src&lt;/span&gt;([&lt;span style=&#34;color:#a6e22e&#34;&gt;html&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;css&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;js&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    .&lt;span style=&#34;color:#a6e22e&#34;&gt;pipe&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;htmlmin&lt;/span&gt;({ &lt;span style=&#34;color:#a6e22e&#34;&gt;collapseWhitespace&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt; }))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    .&lt;span style=&#34;color:#a6e22e&#34;&gt;pipe&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;gulp&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;dest&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;dest&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    .&lt;span style=&#34;color:#a6e22e&#34;&gt;on&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;end&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;done&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The main idea is to use &lt;code&gt;gulp-htmlmin&lt;/code&gt; to minify HTMLs, JavaScripts, and CSSs whilst leaving others intact. Note that the place of the optimised resources is the folder &lt;code&gt;dist&lt;/code&gt; inside Hugo project.&lt;/p&gt;
&lt;h2 id=&#34;references&#34;&gt;References&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&#34;https://markus.oberlehner.net/blog/using-gulp-and-uncss-in-combination-with-sass-based-hugo-themes&#34;&gt;https://markus.oberlehner.net/blog/using-gulp-and-uncss-in-combination-with-sass-based-hugo-themes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://danbahrami.io/articles/building-a-production-website-with-hugo-and-gulp-js&#34;&gt;http://danbahrami.io/articles/building-a-production-website-with-hugo-and-gulp-js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://devotter.com/blog/using-gulp-with-hugo&#34;&gt;https://devotter.com/blog/using-gulp-with-hugo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://adamwills.io/blog/discovering-hugo-2-workflow&#34;&gt;https://adamwills.io/blog/discovering-hugo-2-workflow&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.sagarganatra.com/2016/12/building-your-static-site-with-hugo.html&#34;&gt;http://www.sagarganatra.com/2016/12/building-your-static-site-with-hugo.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://tjm.io/grunt-hugo&#34;&gt;http://tjm.io/grunt-hugo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://byteplumbing.net/2017/08/static-asset-cache-busting-for-hugo&#34;&gt;https://byteplumbing.net/2017/08/static-asset-cache-busting-for-hugo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://tomodwyer.com/post/2017-10-22-hugo---webpack--%EF%B8%8F/&#34;&gt;https://tomodwyer.com/post/2017-10-22-hugo---webpack--%EF%B8%8F/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://thecodestead.com/post/how-to-use-npm-as-a-build-tool-with-hugo&#34;&gt;http://thecodestead.com/post/how-to-use-npm-as-a-build-tool-with-hugo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.henriksommerfeld.se/build-steps-using-npm-scripts-for-my-hugo-blog&#34;&gt;https://www.henriksommerfeld.se/build-steps-using-npm-scripts-for-my-hugo-blog&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
</description>
      </item>
    
      <item>
        <title>Bootstrapping macOS workspace</title>
        <link>https://htr3n.github.io/2018/06/bootstrapping-macos-workspace/</link>
        <pubDate>Wed, 27 Jun 2018 00:00:00 +0000</pubDate>
        
        <guid>1894aa3d998a1542598f6a580a0c30bf</guid>
        <description>&lt;p&gt;I have experienced a number of different Mac systems, ranging from the old white MacBook 2006 to iMac and MacMini 2010 and lately MacBook Pro 13&amp;quot; and 15&amp;quot;. From time to time, Time Machine has become extremely handy for transferring my data from the old to the new machine.&lt;/p&gt;
&lt;p&gt;Nevertheless, a lot of changes, mostly for software development, have often been ignored or reset to the default values. As a result, I often find myself searching around over and over for some desirable settings. Thus, this post is kind of a note-to-self on few useful tweaks for my development box so that I can easily reach out later.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update&lt;/strong&gt;: As it turned out that the tweaks and configurations were getting longer and became tedious to follow, I split them into two parts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#system-tweak-and-configs&#34;&gt;Part 1: System tweaks and configurations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#dev-tools-and-configs&#34;&gt;Part 2: Development tools and configurations&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&#34;system-tweak-and-configs&#34;&gt;Part 1: System tweaks and configurations&lt;/h2&gt;
&lt;h3 id=&#34;disable-sip&#34;&gt;Disable System Integrity Protection (SIP)&lt;/h3&gt;
&lt;p&gt;&lt;a href=&#34;https://support.apple.com/en-us/ht204899&#34;&gt;System Integration Protection&lt;/a&gt; (SIP) is a security technology since OS X El Capitan 10.11 aiming at protecting certain system files and folders against malicious software. SIP even limits the access and actions of the root user account on protected parts of OS X. Unfortunately, the folder  &lt;code&gt;/usr/local&lt;/code&gt; needed for installing many development tools and utilities is under protection as well. That makes a lot of tools like &lt;a href=&#34;https://brew.sh&#34;&gt;Homebrew&lt;/a&gt; fail to install. We can easily check SIP&amp;rsquo;s current status.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ csrutil status
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;System Integrity Protection status: enabled.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The tweak I always do right after installing or recovering a Mac is to disable SIP. Just (re)start macOS in &lt;em&gt;Recovery Mode&lt;/em&gt; (restarting or turning on your Mac and immediately pressing &lt;!-- raw HTML omitted --&gt;⌘&lt;!-- raw HTML omitted --&gt; + &lt;!-- raw HTML omitted --&gt;R&lt;!-- raw HTML omitted --&gt;&amp;mdash;shortcut to remember &lt;!-- raw HTML omitted --&gt;R&lt;!-- raw HTML omitted --&gt; for &amp;lsquo;__R__ecovery&amp;rsquo;&amp;mdash;and wait until macOS boots into its recovery mode. Then open menu &lt;span class=&#34;menu&#34;&gt;Utility ▸ Terminal&lt;/span&gt;
 and execute the following commands.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ csrutil disable
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ reboot
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Your Mac will reboot and get back to the normal working mode. You can verify SIP status again.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ csrutil status
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;System Integrity Protection status: disabled.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;disable-gatekeeper&#34;&gt;Disable Gatekeeper&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;Gatekeeper&lt;/em&gt; was first introduced in OS X Mountain Lion. It is a security feature that prevents the users from launching potentially harmful apps.&lt;/p&gt;
&lt;p&gt;From macOS Sierra and later, however, Apple made Gatekeeper even more restricted. Normal users would see only two choices in &lt;em&gt;System Preferences&lt;/em&gt; &amp;ndash;&amp;gt; &lt;em&gt;Security &amp;amp; Privacy&lt;/em&gt; that &amp;ldquo;&lt;em&gt;Allow apps downloaded from&lt;/em&gt;&amp;rdquo; either &amp;ldquo;&lt;em&gt;App Store&lt;/em&gt;&amp;rdquo; or &amp;ldquo;&lt;em&gt;App Store and identified developers&lt;/em&gt;&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;That means only signed apps are allowed to launch, i.e. breaking a lot of useful unsigned apps whose developers cannot afford to pay US$99 yearly membership for &lt;em&gt;Apple Developer Program&lt;/em&gt;.&lt;/p&gt;

  





&lt;figure &gt;
  
  &lt;img
      
        src=&#34;https://htr3n.github.io/2018/06/bootstrapping-macos-workspace/enabled-gatekeeper.png&#34;
      
        alt=&#34;Enabled Gatekeeper&#34;
        
        align=&#34;center&#34;
        
        width=&#34;80%&#34; style=&#34;max-width: 100%;&#34;
         /&gt;
  
  
  
    &lt;figcaption&gt;
      &lt;span class=&#34;img--caption&#34;&gt;
        Figure 1. Enabled Gatekeeper
        
      &lt;/span&gt;
    &lt;/figcaption&gt;
  
&lt;/figure&gt;



&lt;p&gt;We can circumvent that by disabling Gatekeeper. You do not have to restart macOS but only executing the following command &lt;code&gt;sudo spctl --master-disable&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;After that, you will be able to see Gatekeeper being disabled.&lt;/p&gt;

  





&lt;figure &gt;
  
  &lt;img
      
        src=&#34;https://htr3n.github.io/2018/06/bootstrapping-macos-workspace/disabled-gatekeeper.png&#34;
      
        alt=&#34;Disabled Gatekeeper&#34;
        
        align=&#34;center&#34;
        
        width=&#34;80%&#34; style=&#34;max-width: 100%;&#34;
         /&gt;
  
  
  
    &lt;figcaption&gt;
      &lt;span class=&#34;img--caption&#34;&gt;
        Figure 2. Disabled Gatekeeper
        
      &lt;/span&gt;
    &lt;/figcaption&gt;
  
&lt;/figure&gt;



&lt;p&gt;Naturally Gatekeeper can be re-enabled at any time with &lt;code&gt;sudo spctl --master-enable&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&#34;reveal-library&#34;&gt;Revealing &amp;lsquo;~/Library&amp;rsquo;&lt;/h3&gt;
&lt;p&gt;In macOS, the folder &amp;lsquo;&lt;em&gt;~/Library&lt;/em&gt;&amp;rsquo; within users home folder is hidden (since 10.7!?) seemingly to prevent any unintentional changes. It&amp;rsquo;s not so difficult to navigate to this folder (and any other folders) using command line. In case you want to use Finder to navigate and explore &amp;lsquo;&lt;em&gt;~/Library&lt;/em&gt;&amp;rsquo;, we can simply use the following command.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ chflags nohidden ~/Library
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;enabling-key-repeating&#34;&gt;Enabling Key Repeating&lt;/h3&gt;
&lt;p&gt;The behaviour for keyboard long pressing in macOS is also of polarised personal taste. A typical behaviour that we often see is that the letter keeps popping out since one holds down a key until the key is released. Some years back this has been changed into &amp;lsquo;&lt;em&gt;Character Picker&lt;/em&gt;&amp;rsquo;. It means when a key is pressed and held, the non-standard characters corresponding characters will pop up as the picture below.&lt;/p&gt;

  





&lt;figure &gt;
  
  &lt;img
      
        src=&#34;https://htr3n.github.io/2018/06/bootstrapping-macos-workspace/enabled-character-picker.png&#34;
      
        alt=&#34;Character Picker in action&#34;
        
        align=&#34;center&#34;
        
        width=&#34;80%&#34; style=&#34;max-width: 100%;&#34;
         /&gt;
  
  
  
    &lt;figcaption&gt;
      &lt;span class=&#34;img--caption&#34;&gt;
        Figure 3. Character Picker in action
        
      &lt;/span&gt;
    &lt;/figcaption&gt;
  
&lt;/figure&gt;



&lt;p&gt;Not a big fan of Character Picker, I rather like characters keep repeating when a key is held. In many cases, this behavior becomes very handy, for instance, when selecting large texts with &lt;!-- raw HTML omitted --&gt;⇧&lt;!-- raw HTML omitted --&gt; + &lt;!-- raw HTML omitted --&gt;↓ ↑ ← →&lt;!-- raw HTML omitted --&gt;.&lt;/p&gt;
&lt;p&gt;For that reason, I always disable that feature in any macOS that I am working on. Unfortunately, this cannot be done with &lt;span class=&#34;menu&#34;&gt;System Preferences&lt;/span&gt;
 but command line. After each command, you must re-start the editors to see the effect.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# disable &amp;#39;Character Picker&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ defaults write -g ApplePressAndHoldEnabled -bool false
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# it can be enabled&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ defaults write -g ApplePressAndHoldEnabled -bool true
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Another option relating to key repeating is tuning its speed/rate and delay. Luckily, we can do this via &lt;span class=&#34;menu&#34;&gt;System Preferences ▸ Keyboard&lt;/span&gt;
. My favourite is &amp;lsquo;&lt;em&gt;fastest&lt;/em&gt;&amp;rsquo; repeating and &amp;lsquo;&lt;em&gt;shortest&lt;/em&gt;&amp;rsquo; delay as possible.&lt;/p&gt;

  





&lt;figure &gt;
  
  &lt;img
      
        src=&#34;https://htr3n.github.io/2018/06/bootstrapping-macos-workspace/speed-delay.png&#34;
      
        alt=&#34;Setting for key repeating and delay&#34;
        
        align=&#34;center&#34;
        
        width=&#34;80%&#34; style=&#34;max-width: 100%;&#34;
         /&gt;
  
  
  
    &lt;figcaption&gt;
      &lt;span class=&#34;img--caption&#34;&gt;
        Figure 4. Setting for key repeating and delay
        
      &lt;/span&gt;
    &lt;/figcaption&gt;
  
&lt;/figure&gt;



&lt;p&gt;Like many other options, we can change it via command line or fine tuning tool such as &lt;a href=&#34;https://pqrs.org/osx/karabiner&#34;&gt;Karabiner&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# InitialKeyRepeat: 120, 94, 68, 35, 25, 15 (lower is faster, default is 25)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ defaults write -g InitialKeyRepeat -int &lt;span style=&#34;color:#ae81ff&#34;&gt;15&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# KeyRepeat: 120, 90, 60, 30, 12, 6, 2 (lower is faster, default is 6)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ defaults write -g KeyRepeat -int 2	
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;changing-hostnames&#34;&gt;Changing Hostnames&lt;/h3&gt;
&lt;p&gt;Most of the time, the default host name is not satisfied and you might want to have a cool name for your dev box. Then you are surely not alone. Here and there, you might find some cool combo like &lt;code&gt;harry@hogwart&lt;/code&gt; , &lt;code&gt;alice@wonderland&lt;/code&gt;,  &lt;code&gt;yoda@dagobah&lt;/code&gt;,  &lt;code&gt;joker@gotham&lt;/code&gt;, &lt;code&gt;neo@matrix&lt;/code&gt;, &lt;code&gt;frodo@mordor&lt;/code&gt; you name it. You can quickly do this via command line.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# change the primary host name&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ sudo scutil --set HostName gotham
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# ... do the same for local (Bonjour) host name &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ sudo scutil --set LocalHostName gotham
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# and finally, keep the user-friendly computer&amp;#39;s name in Finder in sync&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ sudo scutil --set ComputerName gotham
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id=&#34;dev-tools-and-configs&#34;&gt;Part 2: Development tools and configurations&lt;/h2&gt;
&lt;p&gt;In this part, I will focus more on some handy tools and configurations often used for my software development tasks.&lt;/p&gt;
&lt;h3 id=&#34;homebrew&#34;&gt;&lt;a href=&#34;https://brew.sh&#34;&gt;Homebrew&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Homebrew provides a rich collection of tools I need, mostly open sources, that Apple does not. Installing Homebrew is super easy with a one-liner command. Before that, we only have to install the Xcode command line tools that Homebrew needs to build its tools.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# install Xcode command line developer tools&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ xcode-select --install
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# now install Homebrew&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ /usr/bin/ruby -e &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then we need to add &lt;code&gt;/usr/local/bin&lt;/code&gt; and &lt;code&gt;/usr/local/sbin &lt;/code&gt; (where Homebrew links the executable files) to the environment variable &lt;code&gt;PATH&lt;/code&gt;. This can be done by altering the shell startup scripts. For instance, for Bash shell it is &lt;code&gt;~/.bash_profile&lt;/code&gt;, for Zshell it is &lt;code&gt;~/.zsh_profile&lt;/code&gt;.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-bashell&#34; data-lang=&#34;bashell&#34;&gt;export PATH=$PATH:/usr/local/bin:/usr/local/sbin
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If you want the Homebrew tools have higher priority than the others, just switch &lt;code&gt;$PATH&lt;/code&gt; to the end instead. Moreover, there are many Finder-launched apps, agents and daemons in macOS might also need &lt;code&gt;PATH&lt;/code&gt; to find necessary executables (e.g. Intellij IDEA and Eclipse if I&amp;rsquo;m not mistaken). Fortunately, the launching of these tools would go through macOS &lt;a href=&#34;https://en.wikipedia.org/wiki/Launchd&#34;&gt;&lt;em&gt;launchd&lt;/em&gt;&lt;/a&gt; and therefore, can be configure with &lt;code&gt;launchctl&lt;/code&gt;. So I have to add this line to the end of my &lt;code&gt;.zshrc&lt;/code&gt; too.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# this line should be added at the end of .zshrc&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/bin/launchctl setenv PATH $PATH
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now I can install necessary tools using  &lt;code&gt;brew&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ brew install ack curl dnsmasq docker gcc git go gradle maven mysql node openssl openssh python3 php72 composer ruby rbenv sassc yarn zsh 
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Homebrew can also help handling macOS start-up services which are useful for managing servers like Apache httpd, nginx, php-fpm, MySQL, PostgreSQL, etc.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ brew services start httpd
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ brew services stop httpd
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;For quick re-installing or recovering Homebrew, I use &lt;a href=&#34;https://github.com/Homebrew/homebrew-bundle&#34;&gt;homebrew-bundle&lt;/a&gt; for backing up the current Homebrew&amp;rsquo;s installation and restoring later.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# tap the bundle&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ brew tap Homebrew/bundle
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# dump all existing Homebrew packages to Brewfile&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ brew bundle dump --force
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# check the list of entries&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ brew bundle list
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# restore/install all packages from the Brewfile &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ brew bundle
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Homebrew also incorporates &lt;a href=&#34;https://github.com/Homebrew/homebrew-cask&#34;&gt;Homebrew-Cask&lt;/a&gt; (formerly an independent plugin for Homebrew) that can help to install many macOS apps as you might see in the later sections.&lt;/p&gt;
&lt;h3 id=&#34;terminals-and-shells&#34;&gt;Terminals and Shells&lt;/h3&gt;
&lt;p&gt;Since working with Linux a lot and then macOS, I&amp;rsquo;m rather familiar with the command line. There are many cases using terminals would be more convenient than graphical editors. Thus, I need a good terminal app. The built-in Terminal app in macOS is not bad but I usually opt for &lt;a href=&#34;https://www.iterm2.com&#34;&gt;iTerm2&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ brew cask install iterm2
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Some of my favorite settings for iTerms are including dark themes such as &lt;a href=&#34;https://draculatheme.com/iterm&#34;&gt;Dracula&lt;/a&gt;, &lt;a href=&#34;https://gist.github.com/meqif/1238378&#34;&gt;IR_Black&lt;/a&gt;, &lt;a href=&#34;https://github.com/junegunn/seoul256-iTerm2&#34;&gt;seoul_256&lt;/a&gt;, &lt;a href=&#34;https://github.com/nathanbuchar/atom-one-dark-terminal&#34;&gt;Atom One Dark&lt;/a&gt; along with a fixed-width font like &lt;a href=&#34;https://github.com/adobe-fonts/source-code-pro&#34;&gt;Source Code Pro&lt;/a&gt;, &lt;a href=&#34;https://fonts.google.com/specimen/Cousine&#34;&gt;Cousine&lt;/a&gt;, &lt;a href=&#34;https://fonts.google.com/specimen/Roboto+Mono&#34;&gt;Roboto Mono&lt;/a&gt;, &lt;a href=&#34;https://github.com/tonsky/FiraCode&#34;&gt;Fira Code&lt;/a&gt; or &lt;a href=&#34;https://www.typography.com/fonts/operator/overview/&#34;&gt;Operator Mono&lt;/a&gt; (very nice ligatures and italic mode), &lt;a href=&#34;https://fonts.google.com/specimen/Inconsolata&#34;&gt;Inconsolata&lt;/a&gt; or its variants (Inconsolata-dz, Inconsolata-g), or &lt;a href=&#34;https://github.com/source-foundry/Hack&#34;&gt;Hack&lt;/a&gt;. Some of these fonts can be installed via Homebrew Cask.&lt;/p&gt;
&lt;p&gt;Along with iTerms 2, I also love &lt;a href=&#34;http://www.zsh.org&#34;&gt;Z shell&lt;/a&gt; (zsh) which is an extended version of Bash shell a lot with many nice features like directory alias, command completion, path expansion, etc. You might also find some Zsh configuration frameworks like &lt;a href=&#34;https://ohmyz.sh&#34;&gt;oh-my-zsh&lt;/a&gt; or &lt;a href=&#34;https://github.com/sorin-ionescu/prezto&#34;&gt;Prezto&lt;/a&gt; amazing to start with. I&amp;rsquo;ve tried both of them and found oh-my-zsh a bit sluggish and Prezto a bit difficult to add more extensions or customize. I have actually used a small piece from either of them and found myself quickly forgetting the customised parts taken from the others. Hence, I decided to develop a set of my own &lt;a href=&#34;https://github.com/htr3n/zsh-config&#34;&gt;Zsh configurations&lt;/a&gt;. Moreover, I often keep a habit of writting Shell scripts in standard sh/bash as much as possible and keep Zsh-specific separately for better portability and compatibility.&lt;/p&gt;
&lt;h3 id=&#34;textcode-editors&#34;&gt;Text/Code Editors&lt;/h3&gt;
&lt;p&gt;There are quite a number of editors in macOS for developers ranging from, er, the built-in Text Editor, &lt;a href=&#34;https://www.sublimetext.com/&#34;&gt;Sublime Text&lt;/a&gt;, &lt;a href=&#34;https://macromates.com&#34;&gt;TextMate&lt;/a&gt;, &lt;a href=&#34;https://www.barebones.com/products/textwrangler&#34;&gt;TextWrangler&lt;/a&gt;, the nerdy &lt;a href=&#34;https://www.vim.org&#34;&gt;Vim&lt;/a&gt;, &lt;a href=&#34;https://www.gnu.org/software/emacs&#34;&gt;Emacs&lt;/a&gt;, and recently &lt;a href=&#34;https://atom.io&#34;&gt;Atom&lt;/a&gt;, &lt;a href=&#34;https://code.visualstudio.com&#34;&gt;Visual Studio Code&lt;/a&gt;, &lt;a href=&#34;http://brackets.io&#34;&gt;Brackets&lt;/a&gt;, to name but a few. You might install these editos using Cask.&lt;/p&gt;
&lt;p&gt;In macOS, Sublime Text is often a powerful editor for many of us but it is quite costly. I used to love and work with Atom developed by Github as an effort to build a modern editor for developers. Atom has a plethora of extensions to become a very promising choice. Nevertheless, I was growing skeptical with its sluggishness in early days and therefore leaned to &lt;a href=&#34;https://code.visualstudio.com&#34;&gt;Visual Studio Code&lt;/a&gt;, my current Swiss-army-knife editor-of-choice instead.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ brew cask install visual-studio-code
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Frequently using terminal/console, I just grasp vim for quick editing tasks and &lt;a href=&#34;https://github.com/htr3n/vim-config&#34;&gt;customised it&lt;/a&gt; a little bit.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ brew install vim
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As working with larger and complex projects, I would need some full-fledged, heavy-weight IDEs such as Eclipse or Jetbrains Intellij IDEA and its brothers like PhpStorm, PyCharm. Other IDE including Netbeans, Visual Studio, Komodo can also be installed with &lt;em&gt;Cask&lt;/em&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ brew cask install eclipse-java intellij-idea
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;For Markdown editors, e.g. Github infamous &lt;em&gt;README.md&lt;/em&gt; or my blog posts, I used &lt;a href=&#34;http://macdown.uranusjr.com&#34;&gt;MacDown&lt;/a&gt;. After discovering &lt;a href=&#34;https://typora.io&#34;&gt;Typora&lt;/a&gt;, MacDown becomes second in the pecking order for now (at least until Typora&amp;rsquo;s developers announce their paid plans).&lt;/p&gt;
&lt;p&gt;With Typora, I can directly write Markdown articles just like Microsoft Word.  I can do &lt;!-- raw HTML omitted --&gt;⌘&lt;!-- raw HTML omitted --&gt; + &lt;!-- raw HTML omitted --&gt;/&lt;!-- raw HTML omitted --&gt; to instantly switch back and forth between &lt;em&gt;Visual Editing&lt;/em&gt; and &lt;em&gt;Source&lt;/em&gt; modes. Even better, I can adapt the Markdown render in Typora to be nearly indentical to my blog and therefore, experience a kind of semi-&lt;em&gt;WYSIWYG&lt;/em&gt; Markdown editing.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ brew cask install typora
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;other-tools&#34;&gt;Other nice-to-have tools&lt;/h3&gt;
&lt;h4 id=&#34;gnu-tools&#34;&gt;GNU Tools&lt;/h4&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ brew install coreutils autoconf automake findutils gawk gcc gnu-sed grep
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;ackhttpsbeyondgrepcom&#34;&gt;&lt;a href=&#34;https://beyondgrep.com&#34;&gt;Ack&lt;/a&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Ack is faster and easier to use than grep&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ brew install ack
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;dropboxhttpswwwdropboxcom&#34;&gt;&lt;a href=&#34;https://www.dropbox.com&#34;&gt;Dropbox&lt;/a&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Many of our customers and friends are sharing files using Dropbox, so are we ;). Note that Dropbox app must be installed in &lt;code&gt;/Applications&lt;/code&gt; to work properly.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ brew cask install --appdir&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/Applications&amp;#34;&lt;/span&gt; dropbox
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;docker-cehttpswwwdockercomcommunity-edition-and-command-line&#34;&gt;&lt;a href=&#34;https://www.docker.com/community-edition&#34;&gt;Docker CE&lt;/a&gt; and command line&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Every serious developer is talking about and working with it ;)&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ brew cask install docker
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ brew install docker
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;spectaclehttpswwwspectacleappcom&#34;&gt;&lt;a href=&#34;https://www.spectacleapp.com&#34;&gt;Spectacle&lt;/a&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;This is an amazing free app for resizing windows using shortcuts. I use it a lot to quickly arrange the working windows.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ brew cask install spectacle
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;alfredhttpswwwalfredappcom--powerpack-&#34;&gt;&lt;a href=&#34;https://www.alfredapp.com&#34;&gt;Alfred&lt;/a&gt; + Powerpack ($)&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Alfred is a must-have for me and, maybe, many other macOS users. The free version is useful enough but the paid (for Powerpack) can blow anyone away. Alfred helps me much more when I prefer to use the keyboard as much as possible instead of reaching for the mice.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ brew cask install alfred
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;fluxhttpsjustgetfluxcom&#34;&gt;&lt;a href=&#34;https://justgetflux.com&#34;&gt;F.lux&lt;/a&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Saving my eyes staring daily at computer&amp;rsquo;s monitors (macOS also has Night Shift mode but my eyes still find F.lux more pleasant at night)&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ brew cask install flux
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;web-browsers&#34;&gt;Web Browsers&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Installing Firefox and Google Chrome mainly for Web development, testing and debugging as I find Safari is, not perfect though, sufficient for daily use and conveniently sharing bookmarks and history links between macOS and my iPad and iPhone.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ brew cask install google-chrome firefox
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;remote-access&#34;&gt;Remote Access&lt;/h4&gt;
&lt;p&gt;Nothing is more convenient than &lt;a href=&#34;https://en.wikipedia.org/wiki/Secure_Shell&#34;&gt;SSH&lt;/a&gt; and &lt;a href=&#34;https://en.wikipedia.org/wiki/SSH_File_Transfer_Protocol&#34;&gt;SFTP&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# I prefer OpenSSH to the stock BSD SSH&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ brew install openssh
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# ...  love to quickly copy my public key to the servers&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ brew install ssh-copy-id
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# generate key pair&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ ssh-keygen -t rsa -b &lt;span style=&#34;color:#ae81ff&#34;&gt;4096&lt;/span&gt; -C &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;MacBookPro email@example.com&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# copy the public key to the host for passwordless authentication&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ ssh-copy-id user@host
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;networking-tools&#34;&gt;Networking Tools&lt;/h4&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ brew install netcat curl wget nmap
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;communication&#34;&gt;Communication&lt;/h4&gt;
&lt;p&gt;&lt;a href=&#34;https://www.skype.com&#34;&gt;Skype&lt;/a&gt;, &lt;a href=&#34;https://www.slack.com&#34;&gt;Slack&lt;/a&gt;, &lt;a href=&#34;https://keybase.io&#34;&gt;Keybase&lt;/a&gt; (open source end-to-end encryption)&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ brew cask install skype slack keybase
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;1passwordhttps1passwordcom-&#34;&gt;&lt;a href=&#34;https://1password.com&#34;&gt;1Password&lt;/a&gt; ($)&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Help storing all of my private information and authentication in iCloud or Dropbox and using them in macOS or iOS.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ brew cask install 1password
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;heading&#34;&gt;&lt;/h4&gt;
</description>
      </item>
    
      <item>
        <title>A journey from Apache CXF 2.2 to 3.2</title>
        <link>https://htr3n.github.io/2018/06/apache-cxf-2-to-3/</link>
        <pubDate>Fri, 15 Jun 2018 00:00:00 +0000</pubDate>
        
        <guid>338598d0bf4fe86e650ab08497668c09</guid>
        <description>&lt;p&gt;I have used &lt;a href=&#34;https://cxf.apache.org&#34;&gt;Apache CXF&lt;/a&gt; 2.2 to develop Web services for some R&amp;amp;D projects that I took part in. At that time, it was a choice between &lt;a href=&#34;http://axis.apache.org/axis2/java/core&#34;&gt;Apache Axis/Axis2&lt;/a&gt; and CXF (formerly Codehaus XFire project).&lt;/p&gt;
&lt;p&gt;I eventually decided to get along with CXF due to its simplicity, quite clear documentation, good support for document-style Web services (+) and many standards, especially JAX-WS and JAX-RS.&lt;/p&gt;
&lt;p&gt;Moreover, Apache CXF also embraces smooth integration with Spring Framework (big plus for me as I was using Spring Web MVC 3 to develop the Web front-end). Everything went well for me on modelling and developing Web services based on JAX-WS for both directions: WSDL-first and Java-first.&lt;/p&gt;
&lt;p&gt;In my projects, I designed the WSDLs and used &lt;a href=&#34;http://cxf.apache.org/docs/wsdl-to-java.html&#34;&gt;WSDL2Java&lt;/a&gt; Maven plugin or command line to generate skeleton Java code of the Web services. The Java service implementations were kept separately in a package/folder to avoid any code overwriting. CXF services are so easy to configure with Spring Framework 3.0. The implementations of the services were loaded as Spring managed beans. The expose of a service is done via a CXF directive &lt;code&gt;&amp;lt;jaxws:endpoint&amp;gt;&lt;/code&gt; of which the &lt;code&gt;implementor &lt;/code&gt; attribute refers to the corresponding bean.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-xml&#34; data-lang=&#34;xml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;beans&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;xmlns=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;http://www.springframework.org/schema/beans&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#a6e22e&#34;&gt;xmlns:jaxws=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;http://cxf.apache.org/jaxws&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;import&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;resource=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;classpath:META-INF/cxf/cxf.xml&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;import&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;resource=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;classpath:META-INF/cxf/cxf-extension-soap.xml&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;import&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;resource=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;classpath:META-INF/cxf/cxf-extension-jaxws.xml&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;import&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;resource=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;classpath:META-INF/cxf/cxf-servlet.xml&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&amp;gt;&lt;/span&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;bean&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;id=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;CreditWorthinessImpl&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;class=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;westbank.ws.impl.CreditWorthinessImpl&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;p:dataAccessObject-ref=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;dataAccessObject&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/bean&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;jaxws:endpoint&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;id=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;CreditWorthiness&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  &lt;span style=&#34;color:#a6e22e&#34;&gt;implementor=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;#CreditWorthinessImpl&amp;#34;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  &lt;span style=&#34;color:#a6e22e&#34;&gt;address=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/CreditWorthiness&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/jaxws:endpoint&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/beans&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In the Web app configuration &lt;code&gt;web.xml&lt;/code&gt;, CXF Servlet must be loaded by the container.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-xml&#34; data-lang=&#34;xml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;servlet&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;servlet-name&amp;gt;&lt;/span&gt;cxf&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/servlet-name&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;servlet-class&amp;gt;&lt;/span&gt;org.apache.cxf.transport.servlet.CXFServlet&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/servlet-class&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;load-on-startup&amp;gt;&lt;/span&gt;2&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/load-on-startup&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/servlet&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;servlet-mapping&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;servlet-name&amp;gt;&lt;/span&gt;cxf&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/servlet-name&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;url-pattern&amp;gt;&lt;/span&gt;/services/*&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/url-pattern&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/servlet-mapping&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;upgrading-apache-cxf&#34;&gt;Upgrading Apache CXF&lt;/h2&gt;
&lt;p&gt;For a while I haven&amp;rsquo;t taken part in further WS development, i.e. not using Apache CXF a lot. One day I thought I could use the WS project to showcase and review my relevant knowledge. The codebase still works well after some mysterious library missing that I have not seen before. It is possible due to the built-in libraries for XML parsing that were implicitly used but now changed in the newer JRE. Apart from that, most of the libraries are also outdated. So I dedice to spend some time to exercise upgrading the project and refactor a bit its source code. Here I jot down some major points on upgrading Apache CXF.&lt;/p&gt;
&lt;p&gt;The upgrading was not as easy and smooth as just changing the dependencies&amp;rsquo; versions. A lot of conflicts or major refactoring happened. I had to read thoroughly the &lt;a href=&#34;http://cxf.apache.org/docs/migration-guides.html&#34;&gt;documentation on CXF site for migration&lt;/a&gt; and decided to go gradually over each major version of Apache CXF.&lt;/p&gt;
&lt;h2 id=&#34;-from-version-22-to-27-&#34;&gt;&amp;hellip; from version 2.2 to 2.7 &amp;hellip;&lt;/h2&gt;
&lt;p&gt;From Apache CXF 2.2 to 2.6, not so many changes are relevant for the project as I mainly used &lt;code&gt;cxf-rt-frontend-jaxws&lt;/code&gt;.  Another &lt;a href=&#34;http://cxf.apache.org/docs/embedding-cxf-inside-spring.html&#34;&gt;significant change since 2.4&lt;/a&gt; causes errors for Spring / Jetty server regarding importing CXF&amp;rsquo;s XML resources. Recall the aforementioned Spring bean configuration where CXF service implementations were loaded and published? There are a number of &lt;code&gt;&amp;lt;import&amp;gt;&lt;/code&gt; directives. These directives advise Spring to load the corresponding CXF resources. Now we only need &amp;ldquo;&lt;em&gt;one to rule them all&lt;/em&gt;&amp;rdquo;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-xml&#34; data-lang=&#34;xml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;import&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;resource=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;classpath:META-INF/cxf/cxf.xml&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To upgrade to version 2.6, I have to revise the project with respect to the merging of &lt;code&gt;cxf-common-utilites&lt;/code&gt; into &lt;code&gt;cxf-api&lt;/code&gt;, the removal of &lt;code&gt;cxf-rt-binding-http&lt;/code&gt;, and the refactoring that impact &lt;code&gt;cxf-rt-core&lt;/code&gt;.  Most of the other changes from 2.2 to 2.7 are for JAX-RS, which were used very little or none in my project.&lt;/p&gt;
&lt;h2 id=&#34;-and-to-version-30&#34;&gt;&amp;hellip; and to version 3.0+&lt;/h2&gt;
&lt;p&gt;Apache CXF 3.0 requires a rather disruptive change, from Spring Framework 3.0 to 3.2+. Again, I used standard Spring bean configurations which are still valid for Spring 3.2. Hence, the project works well with Spring 3.2.18-RELEASE. I only need to remove all version numbers in the Spring XML schemas. The major change I must deal with is to remove the dependency of &lt;code&gt;cxf-api&lt;/code&gt; as it was merged with &lt;code&gt;cxf-core&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Then there comes the most dramatic issue with CXF 3.0.16 (sic!). &lt;code&gt;cxf-codegen-plugin&lt;/code&gt; used to generate Java code from WSDLs refused to work (which was no problem in earlier verions) and spit out errors like this.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;[ERROR] Failed to execute goal org.apache.cxf:cxf-codegen-plugin:3.0.16:wsdl2java (generate-sources) on project loan-approval-portal: Execution generate-sources of goal org.apache.cxf:cxf-codegen-plugin:3.0.16:wsdl2java failed: org.apache.cxf.wsdl11.WSDLRuntimeException: Fail to create wsdl definition file:%3c?xml%20version=%221.0%22%20encoding=%22UTF-8%22?%3e: WSDLException: faultCode=PARSER_ERROR: Problem parsing &amp;#39;file:%3c?xml%20version=%221.0%22%20encoding=%22UTF-8%22?%3e&amp;#39;.: java.io.FileNotFoundException: &amp;lt; (No such file or directory) -&amp;gt; [Help 1]
org.apache.maven.lifecycle.LifecycleExecutionException: Failed to execute goal org.apache.cxf:cxf-codegen-plugin:3.0.16:wsdl2java (generate-sources) on project loan-approval-portal: Execution generate-sources of goal org.apache.cxf:cxf-codegen-plugin:3.0.16:wsdl2java failed: org.apache.cxf.wsdl11.WSDLRuntimeException: Fail to create wsdl definition file:%3c?xml%20version=%221.0%22%20encoding=%22UTF-8%22?%3e: WSDLException: faultCode=PARSER_ERROR: Problem parsing &amp;#39;file:%3c?xml%20version=%221.0%22%20encoding=%22UTF-8%22?%3e&amp;#39;.: java.io.FileNotFoundException: &amp;lt; (No such file or directory)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;What puzzles me is that I have tried the command tool &lt;code&gt;wsdl2java&lt;/code&gt; of Apache CXF 3.0.16 with each WSDL and, strangely, found no errors at all. After some extra trial-and-error effort, I eventually figured out that an extra option for &lt;code&gt;cxf-codegen-plugin&lt;/code&gt; causes the error. The old/original plugin configuration in &lt;code&gt;pom.xml&lt;/code&gt; is as following.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-xml&#34; data-lang=&#34;xml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;plugin&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.apache.cxf&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;cxf-codegen-plugin&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;version&amp;gt;&lt;/span&gt;${cxf.version}&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;executions&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;execution&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;id&amp;gt;&lt;/span&gt;generate-sources&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/id&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;phase&amp;gt;&lt;/span&gt;generate-sources&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/phase&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;configuration&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;sourceRoot&amp;gt;&lt;/span&gt;${basedir}/src/main/java&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/sourceRoot&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;wsdlRoot&amp;gt;&lt;/span&gt;${basedir}/src/main/webapp/WEB-INF/wsdl/&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/wsdlRoot&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;defaultOptions&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;validateWsdl&amp;gt;&lt;/span&gt;true&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/validateWsdl&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;wsdlList&amp;gt;&lt;/span&gt;true&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/wsdlList&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;defaultExcludesNamespace&amp;gt;&lt;/span&gt;true&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/defaultExcludesNamespace&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;extraargs&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;extraarg&amp;gt;&lt;/span&gt;-defaultValues&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/extraarg&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;extraarg&amp;gt;&lt;/span&gt;-quiet&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/extraarg&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;extraarg&amp;gt;&lt;/span&gt;-wsdlLocation&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/extraarg&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;extraarg&amp;gt;&amp;lt;/extraarg&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/extraargs&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/defaultOptions&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/configuration&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;goals&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;goal&amp;gt;&lt;/span&gt;wsdl2java&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/goal&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/goals&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/execution&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/executions&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/plugin&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The option &lt;code&gt;&amp;lt;wsdlList&amp;gt;&lt;/code&gt; is the culprit. It was declared &lt;code&gt;boolean&lt;/code&gt; since CXF 2.2 to 2.7.0 as I found &lt;a href=&#34;https://cxf.apache.org/javadoc/latest-2.7.x/org/apache/cxf/maven_plugin/wsdl2java/Option.html&#34;&gt;here&lt;/a&gt;. However, in &lt;a href=&#34;http://cxf.apache.org/docs/wsdl-to-java.html&#34;&gt;the most recent documentation&lt;/a&gt; of CXF 3, &lt;code&gt;wsdlList&lt;/code&gt; is still listed as an option for &lt;code&gt;wsdl2java&lt;/code&gt; but no longer of type &lt;code&gt;boolean&lt;/code&gt;  (&lt;code&gt;-wsdlList &amp;lt;wsdlurl&amp;gt;&lt;/code&gt;). To make it worse, the option is totally hidden/undocumented. So all I have to do is to disable the line &lt;code&gt;&amp;lt;wsdlList&amp;gt;true&amp;lt;/wsdlList&amp;gt;&lt;/code&gt; and  &lt;code&gt;cxf-codegen-plugin&lt;/code&gt; works again in CXF 3.0+.&lt;/p&gt;
&lt;p&gt;The problems with &lt;code&gt;cxf-codegen-plugin&lt;/code&gt; keep raising when upgrading CXF to 3.2.4. This time, it threw another exception though.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;[ERROR] Failed to execute goal org.apache.cxf:cxf-codegen-plugin:3.2.4:wsdl2java (generate-sources) on project loan-approval-portal: Execution generate-sources of goal org.apache.cxf:cxf-codegen-plugin:3.2.4:wsdl2java failed: org.xml.sax.SAXNotRecognizedException: Property &amp;#39;http://javax.xml.XMLConstants/property/accessExternalSchema&amp;#39; is not recognized. -&amp;gt; [Help 1]
org.apache.maven.lifecycle.LifecycleExecutionException: Failed to execute goal org.apache.cxf:cxf-codegen-plugin:3.2.4:wsdl2java (generate-sources) on project loan-approval-portal: Execution generate-sources of goal org.apache.cxf:cxf-codegen-plugin:3.2.4:wsdl2java failed: org.xml.sax.SAXNotRecognizedException: Property &amp;#39;http://javax.xml.XMLConstants/property/accessExternalSchema&amp;#39; is not recognized.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We can see that the error is due to schema validation. Before, I wanted to make sure that the WSDLs were valid before generating Java code. Thus, I chose to enable validation by &lt;code&gt;&amp;lt;validateWsdl&amp;gt;true&amp;lt;/validateWsdl&amp;gt;&lt;/code&gt;. This option is actually the root cause of the aforementioned exception during validation. The problem seems to stem from &lt;a href=&#34;http://docs.oracle.com/javase/tutorial/jaxp/properties/properties.html&#34;&gt;new XML security properties in JAXB 1.5&lt;/a&gt; introduced in Java 8. When I disable that option, the plugin works fine again (voila!). But that means I must live in a maybe-not-error-free world (D&amp;rsquo;oh!). But we are all, aren&amp;rsquo;t we?&lt;/p&gt;
&lt;p&gt;After all of the above, I can get my project to work with Apache CXF 3.2.4 while keeping the business logic of services intact.&lt;/p&gt;
&lt;h2 id=&#34;update-2018-06-25-xml-less-spring-configuration&#34;&gt;Update 2018-06-25: XML-less Spring Configuration&lt;/h2&gt;
&lt;p&gt;As deciding to switch to XML-less Spring configuration to learn more about Spring Java annotations, I also tried to migrate CXF settings, too. Here are some last updates.&lt;/p&gt;
&lt;h3 id=&#34;loading-cxfservlet&#34;&gt;Loading CXFServlet&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;MyWebApplicationInitializer&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;implements&lt;/span&gt; org.&lt;span style=&#34;color:#a6e22e&#34;&gt;springframework&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;web&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;WebApplicationInitializer&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;@Override&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;onStartup&lt;/span&gt;(ServletContext container) &lt;span style=&#34;color:#66d9ef&#34;&gt;throws&lt;/span&gt; ServletException {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    AnnotationConfigWebApplicationContext root &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; AnnotationConfigWebApplicationContext();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    root.&lt;span style=&#34;color:#a6e22e&#34;&gt;register&lt;/span&gt;(ServiceConfiguration.&lt;span style=&#34;color:#a6e22e&#34;&gt;class&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    root.&lt;span style=&#34;color:#a6e22e&#34;&gt;refresh&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// Register and map the CXF servlet&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    CXFServlet cxfServlet &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; CXFServlet();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ServletRegistration.&lt;span style=&#34;color:#a6e22e&#34;&gt;Dynamic&lt;/span&gt; reg &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; container.&lt;span style=&#34;color:#a6e22e&#34;&gt;addServlet&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;cxf&amp;#34;&lt;/span&gt;, cxfServlet);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    reg.&lt;span style=&#34;color:#a6e22e&#34;&gt;setLoadOnStartup&lt;/span&gt;(1);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    reg.&lt;span style=&#34;color:#a6e22e&#34;&gt;addMapping&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/services/*&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;publishing-services&#34;&gt;Publishing Services&lt;/h3&gt;
&lt;p&gt;I configured the CXF bus used for publishing web services and defining JAX-WS service endpoints. Instead of importing existing CXF&amp;rsquo;s XML resources as many developers have chosen, I opted for a pure Java approach. What we have to do is to create a bean named &amp;lsquo;&lt;em&gt;cxf&lt;/em&gt;&amp;rsquo; (defined as &lt;code&gt;org.apache.cxf.Bus.DEFAULT_BUS_ID&lt;/code&gt;) and use that bean for defining service endpoints.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; com.example.HelloWorldImpl;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; org.apache.cxf.Bus;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; org.apache.cxf.bus.spring.SpringBus;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; org.apache.cxf.jaxws.EndpointImpl;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; org.springframework.context.annotation.Bean;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; org.springframework.context.annotation.Configuration;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; javax.xml.ws.Endpoint;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;@Configuration&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ServiceConfiguration&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;@Bean&lt;/span&gt;(name&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;Bus.&lt;span style=&#34;color:#a6e22e&#34;&gt;DEFAULT_BUS_ID&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; SpringBus &lt;span style=&#34;color:#a6e22e&#34;&gt;cxf&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; SpringBus();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;@Bean&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; Endpoint &lt;span style=&#34;color:#a6e22e&#34;&gt;helloWorld&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    HelloWorldImpl implementor &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; HelloWorldImpl();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    EndpointImpl endpoint &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; EndpointImpl(cxf(), implementor);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    endpoint.&lt;span style=&#34;color:#a6e22e&#34;&gt;publish&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/HelloWorld&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; endpoint;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;IMPORTANT&lt;/strong&gt;&lt;!-- raw HTML omitted --&gt; &lt;code&gt;Endpoint.publish()&lt;/code&gt; must be called to expose the service endpoint instead of &lt;code&gt;Endpoint.setAddress()&lt;/code&gt; as above.&lt;/p&gt;
&lt;/blockquote&gt;
</description>
      </item>
    
      <item>
        <title>Integration Laravel 5 and Gentelella admin theme</title>
        <link>https://htr3n.github.io/2018/05/integration-laravel-gentelella/</link>
        <pubDate>Wed, 09 May 2018 00:00:00 +0000</pubDate>
        
        <guid>13e8df15f76277f3d85e59f5ffa36246</guid>
        <description>&lt;p&gt;&lt;a href=&#34;https://github.com/puikinsh/gentelella&#34;&gt;Gentelella&lt;/a&gt; is a very nice and gently-looking &lt;a href=&#34;https://getbootstrap.com&#34;&gt;Bootstrap&lt;/a&gt; based admin theme developed by Aigars Silkalns (aka &lt;a href=&#34;https://github.com/puikinsh&#34;&gt;puikinsh&lt;/a&gt;). It can be integrated into several Web application frameworks. This post is one of my development exercises in which Gentelella is used to decorate a &lt;a href=&#34;https://github.com/laravel/laravel&#34;&gt;Laravel&lt;/a&gt; 5 based Web application. This task is part of building my PHP based framework &lt;a href=&#34;https://github.com/htr3n/laramod&#34;&gt;LaraMod&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Laravel can act as backend for any Web application. At the moment of this writing, Laravel includes several &lt;a href=&#34;https://laravel.com/docs/frontend&#34;&gt;good supports&lt;/a&gt; for popular front-ends such as Bootstrap, &lt;a href=&#34;https://vuejs.org&#34;&gt;Vue.js&lt;/a&gt;, and &lt;a href=&#34;https://reactjs.org&#34;&gt;React&lt;/a&gt;. The included tool &lt;a href=&#34;https://github.com/JeffreyWay/laravel-mix&#34;&gt;Laravel Mix&lt;/a&gt;, which runs on top of  &lt;a href=&#34;https://webpack.js.org/&#34;&gt;Webpack&lt;/a&gt;, can significantly lessen development effort on compiling and mixing Web resources. Thus, I have just leveraged Laravel Mix for this integration task. Further details on Laravel Mix can be found &lt;a href=&#34;https://laravel.com/docs/mix&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;installation&#34;&gt;Installation&lt;/h2&gt;
&lt;p&gt;Laravel provides built-in support for some front-end frameworks but they might cause some conflicts and incompability with Gentelella&amp;rsquo;s own libraries. Therefore, I have decided to start from scratch, i.e. using basic Laravel without any front-end scaffolding&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# remove all scaffolding&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;php artisan preset none
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This command will remove all relevant scaffolding components including Bootstrap, Vue or React. Note that Laravel configuration for Bootstrap and Vue might still exist. For instance, check &lt;code&gt;resource/assets/js/app.js&lt;/code&gt;  for the following line and make sure it is commented out.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// require(&amp;#39;./bootstrap&amp;#39;);
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now we just add Gentelella&amp;rsquo;s dependencies.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# adding Gentelella&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;yarn add --save gentelella 		&lt;span style=&#34;color:#75715e&#34;&gt;# or npm install gentelella --save&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# update dependencies&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;yarn install					&lt;span style=&#34;color:#75715e&#34;&gt;# or  npm install&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;After this step, Gentelella should be available in the local &lt;code&gt;node_modules&lt;/code&gt; folder.&lt;/p&gt;
&lt;h2 id=&#34;compiling-and-mixing-resources&#34;&gt;Compiling and Mixing Resources&lt;/h2&gt;
&lt;p&gt;The main configuration file of Laravel Mix is &lt;code&gt;webpack.mix.js&lt;/code&gt;. The fundamental tasks are defined as following.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;mix&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;require&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;laravel-mix&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;mix&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;js&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;resources/assets/js/app.js&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;public/js&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   .&lt;span style=&#34;color:#a6e22e&#34;&gt;sass&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;resources/assets/sass/app.scss&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;public/css&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That is, Mix will compile JavaScript and SASS resources in &lt;code&gt;resources/assets/js/app.js&lt;/code&gt; and &lt;code&gt;resources/assets/sass/app.scss&lt;/code&gt; to &lt;code&gt;public/js&lt;/code&gt; and &lt;code&gt;public/css&lt;/code&gt;, respectively.&lt;/p&gt;
&lt;p&gt;We shall use the same way to compile necessary Gentelella resources. The full configuration can be found in the LaraMod project &lt;a href=&#34;https://github.com/htr3n/laramod/blob/master/webpack.mix.js&#34;&gt;&lt;code&gt;webpack.mix.js&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Some common variables are defined to reduce duplicates.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// general resources
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;public_js&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;public/js/&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;public_css&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;public/css/&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;resource_sass&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;resources/assets/sass/&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// Gentelella resources
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;gentelella_home&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;node_modules/gentelella/&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;gentelella_vendor&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;gentelella_home&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;/vendors/&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As using separate styles for different pages, e.g. Login, Dashboard, etc., I configure Mix to compile them accordingly.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;mix&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;js&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;resources/assets/js/app.js&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;public_js&lt;/span&gt;).
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;sass&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;resource_sass&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;app.scss&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;public_css&lt;/span&gt;).
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;sass&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;resource_sass&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;home.scss&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;public_css&lt;/span&gt;).
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;options&lt;/span&gt;({&lt;span style=&#34;color:#a6e22e&#34;&gt;processCssUrls&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;}).
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;sass&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;resource_sass&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;login.scss&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;public_css&lt;/span&gt;).
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;options&lt;/span&gt;({&lt;span style=&#34;color:#a6e22e&#34;&gt;processCssUrls&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;}).
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;sass&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;resource_sass&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;dashboard.scss&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;public_css&lt;/span&gt;).
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;options&lt;/span&gt;({&lt;span style=&#34;color:#a6e22e&#34;&gt;processCssUrls&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;For each component of Gentelella that we need for our project or certain pages, we can copy them into Laravel public folders.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt; *  Copy dependent JavaScripts and CSSs
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;mix&lt;/span&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// gentelella
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;copy&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;gentelella_home&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;build/css/custom.css&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;public_css&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;gentelella-custom.css&amp;#39;&lt;/span&gt;).
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;copy&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;gentelella_home&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;build/js/custom.js&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;public_js&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;gentelella-custom.js&amp;#39;&lt;/span&gt;).
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We can definitely use Mix/Webpack tools for optimising/minimising/transforming Gentelella resources. I will leave it as extra deployment exercises. For now, I will mainly concentrate on development aspects. When I need to use a Gentelella&amp;rsquo;s component for a certain page, I will include the following directives in the corresponding Laravel Blade templates for that page.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-php+HTML&#34; data-lang=&#34;php+HTML&#34;&gt;&amp;lt;!-- Styles --&amp;gt;
&amp;lt;link href=&amp;#34;{{ asset(&amp;#39;css/font-awesome.css&amp;#39;) }}&amp;#34; rel=&amp;#34;stylesheet&amp;#34;&amp;gt;
&amp;lt;link href=&amp;#34;{{ asset(&amp;#39;css/bootstrap.css&amp;#39;) }}&amp;#34; rel=&amp;#34;stylesheet&amp;#34;&amp;gt;
&amp;lt;link href=&amp;#34;{{ asset(&amp;#39;css/gentelella-custom.css&amp;#39;) }}&amp;#34; rel=&amp;#34;stylesheet&amp;#34;&amp;gt;
...
&amp;lt;!-- Scripts --&amp;gt;
&amp;lt;script src=&amp;#34;{{ asset(&amp;#39;js/jquery.min.js&amp;#39;) }}&amp;#34;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script src=&amp;#34;{{ asset(&amp;#39;js/bootstrap.js&amp;#39;) }}&amp;#34;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script src=&amp;#34;{{ asset(&amp;#39;js/gentelella-custom.js&amp;#39;) }}&amp;#34;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script src=&amp;#34;{{ asset(&amp;#39;js/app.js&amp;#39;) }}&amp;#34;&amp;gt;&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Note that the specific Laravel Blade directive &lt;code&gt;{{ }}&lt;/code&gt; and &lt;code&gt;asset(...)&lt;/code&gt; are used to refer to the resources inside Laravel &lt;code&gt;public/&lt;/code&gt; folder accordingly. A working example of Laravel and Gentelella integration is illustrated via the &lt;a href=&#34;https://github.com/htr3n/laramod&#34;&gt;LaraMod&lt;/a&gt; project that you can check out and have a deeper look.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;login.png&#34; alt=&#34;Login&#34;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;dashboard.png&#34; alt=&#34;Dashboard&#34;&gt;&lt;/p&gt;
&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Integration Laravel 5 and Gentelella is a simple but interesting exercise showing many nice features of Laravel for supporting common front-ends. Laravel Mix provides a good wrapper on top of Webpack that really reduces the complexity of Webpack and lessens considerable amount of development effort.&lt;/p&gt;
</description>
      </item>
    
      <item>
        <title>Node.js package managers: NPM and Yarn</title>
        <link>https://htr3n.github.io/2018/04/node.js-package-managers-npm-and-yarn/</link>
        <pubDate>Mon, 23 Apr 2018 00:00:00 +0000</pubDate>
        
        <guid>2e0e4e60333cf9df4e8c34fcf1d65d61</guid>
        <description>&lt;p&gt;Node.js is an increasingly popular and widely used JavaScript runtime nowadays. One of the important aspects of Node.js is to manage the dependencies among software artefacts. Better dependency management would advocate modularisation and decoupling of software components. Since the dawn of Node.js, &lt;a href=&#34;https://stackoverflow.com/questions/35062852/npm-vs-bower-vs-browserify-vs-gulp-vs-grunt-vs-webpack&#34;&gt;several package managers&lt;/a&gt; have been developed, notably, &lt;a href=&#34;https://www.npmjs.org/&#34;&gt;npm&lt;/a&gt;, &lt;a href=&#34;https://anymod.com&#34;&gt;anymod&lt;/a&gt; (formerly &lt;code&gt;component&lt;/code&gt;), &lt;a href=&#34;http://volojs.org&#34;&gt;volo&lt;/a&gt;, &lt;a href=&#34;http://packages.ringojs.org&#34;&gt;ringojs&lt;/a&gt;, &lt;a href=&#34;https://bower.io&#34;&gt;bower&lt;/a&gt;, &lt;a href=&#34;https://yarnpkg.com&#34;&gt;yarn&lt;/a&gt;, &lt;a href=&#34;https://pnpm.js.org&#34;&gt;&lt;code&gt;pnpm&lt;/code&gt;&lt;/a&gt;, to name but a few.&lt;/p&gt;
&lt;p&gt;In this post, we shall walk through the two tools that have been seemingly living up to the high expectation of a majority of JavaScript developers and communities, &lt;code&gt;npm&lt;/code&gt; and &lt;code&gt;yarn&lt;/code&gt;. &lt;code&gt;pnpm&lt;/code&gt; is an improvement that &lt;a href=&#34;https://github.com/pnpm/node-package-manager-benchmark&#34;&gt;performs sometimes better&lt;/a&gt; than &lt;code&gt;npm&lt;/code&gt; and &lt;code&gt;yarn&lt;/code&gt;. The great advantage of using &lt;code&gt;pnpm&lt;/code&gt; is that we just replace the command &lt;code&gt;npm&lt;/code&gt; by &lt;code&gt;pnpm&lt;/code&gt; and keep the rest intact.  Bower is a powerful tool that supports not only JS but also various types of Web resources including HTML, CSS, fonts, images. Nevertheless, the core Bower developers and maintainers &lt;a href=&#34;https://bower.io/blog/2017/how-to-migrate-away-from-bower&#34;&gt;had recently recommended the users to switch to &lt;code&gt;yarn&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;npm&lt;/code&gt; seems to be the &lt;em&gt;de facto&lt;/em&gt; package management included with Node.js. When Node.js is installed, &lt;code&gt;npm&lt;/code&gt; will also be available and ready to use as well. This is one among many reasons why &lt;code&gt;npm&lt;/code&gt; is well-known and widely used by JS developers.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;yarn&lt;/code&gt; was &lt;a href=&#34;https://code.facebook.com/posts/1840075619545360&#34;&gt;originally developed by Facebook&lt;/a&gt; to overcome existing problems of existing package management tools. Some notable &lt;code&gt;yarn&lt;/code&gt;&amp;rsquo;s features are &lt;em&gt;deterministic model&lt;/em&gt; (producing the same result when repeating), &lt;em&gt;flat mode&lt;/em&gt; (resolving mismatching versions of dependencies to a single version to avoid duplicate), &lt;em&gt;security first&lt;/em&gt;, &lt;em&gt;offline mode&lt;/em&gt;, &lt;em&gt;network performance&lt;/em&gt;, and so forth. Nevertheless, recent versions of &lt;code&gt;npm&lt;/code&gt; also improve significantly by learning  and incorporate several good features from &lt;code&gt;yarn&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;walking-through&#34;&gt;Walking Through&lt;/h2&gt;
&lt;p&gt;In this part, we will go through a typical development workflow that each tool provides with basic steps and some commonly used options.&lt;/p&gt;
&lt;h3 id=&#34;0-installing-and-upgrading&#34;&gt;0. Installing and Upgrading&lt;/h3&gt;
&lt;h5 id=&#34;npm&#34;&gt;NPM&lt;/h5&gt;
&lt;p&gt;As mentioned above, &lt;code&gt;npm&lt;/code&gt; is available wherever Node.js is installed. So, the only thing to do is to upgrade &lt;code&gt;npm&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;npm install npm@latest -g
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# you can also use the alias &amp;#39;i&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;npm i npm@latest -g
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h5 id=&#34;yarn&#34;&gt;Yarn&lt;/h5&gt;
&lt;p&gt;Yarn can be installed via &lt;code&gt;npm&lt;/code&gt; but this method is &lt;a href=&#34;https://yarnpkg.com/en/docs/install#install-via-npm&#34;&gt;not recommended due to security reason&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;npm install --g yarn
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;macOS users can install Yarn using &lt;a href=&#34;https://brew.sh&#34;&gt;Homebrew&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# installing&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;brew update &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; brew install yarn
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# upgrading&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;brew upgrade yarn
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;There are also &lt;a href=&#34;https://yarnpkg.com/en/docs/install&#34;&gt;concrete instructions&lt;/a&gt; for Linux and Windows users, too.&lt;/p&gt;
&lt;h3 id=&#34;1-starting-new-projects&#34;&gt;1. Starting New Projects&lt;/h3&gt;
&lt;h5 id=&#34;npm-1&#34;&gt;NPM&lt;/h5&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;npm init &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;-f|--force&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;-y|--yes&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;npm init&lt;/code&gt; will ask you a number of questions and create an initial configuration file &lt;code&gt;package.json&lt;/code&gt;. In case you do not want to answer the questions one by one, you can use any option &lt;code&gt;-f&lt;/code&gt;, &lt;code&gt;--force&lt;/code&gt;,  &lt;code&gt;-y&lt;/code&gt; or &lt;code&gt;--yes&lt;/code&gt; to skip all questions and get a default &lt;code&gt;package.json&lt;/code&gt; in the current directory.&lt;/p&gt;
&lt;h5 id=&#34;yarn-1&#34;&gt;Yarn&lt;/h5&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;yarn init &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;-y | --yes&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;-p | --private&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This command is totally similar to &lt;code&gt;npm init&lt;/code&gt; and the outcome will be &lt;code&gt;package.json&lt;/code&gt;. The only difference is &lt;code&gt;-p&lt;/code&gt; or &lt;code&gt;--private&lt;/code&gt; to set &lt;code&gt;&amp;quot;private&amp;quot;: true&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&#34;2-getting-information&#34;&gt;2. Getting Information&lt;/h3&gt;
&lt;h5 id=&#34;npm-2&#34;&gt;NPM&lt;/h5&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# display a particular package&amp;#39;s information&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;npm view eslint
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;npm info eslint
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# search for a package/name&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;npm search eslint
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# list installed packages&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;npm ls
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h5 id=&#34;yarn-2&#34;&gt;Yarn&lt;/h5&gt;
&lt;p&gt;Yarn developers deliberately do not add support for searching packages like &lt;code&gt;npm&lt;/code&gt; as &lt;a href=&#34;https://github.com/yarnpkg/yarn/issues/778#issuecomment-253146299&#34;&gt;explained here&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# display a particular package&amp;#39;s information&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;yarn info eslint
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# list installed packages&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;yarn list
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Yarn provodes a nice command for showing why a certain package was installed.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;yarn why eslint
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;3-installing-dependencies&#34;&gt;3. Installing Dependencies&lt;/h3&gt;
&lt;p&gt;Both &lt;code&gt;npm&lt;/code&gt; and &lt;code&gt;yarn&lt;/code&gt; provide several options to add dependencies ranging from registered packages, tarballs, to git repositories. Please note that, &lt;code&gt;npm&lt;/code&gt; and &lt;code&gt;yarn&lt;/code&gt; also support manipulating global package repositories, i.e. installed packages that are available to the whole working system instead of local projects. In most of the case, we can use the option &lt;code&gt;-g&lt;/code&gt; for &lt;code&gt;npm&lt;/code&gt; and the command &lt;code&gt;global&lt;/code&gt; for &lt;code&gt;yarn&lt;/code&gt;. Thus, in the following steps, we mainly concentrate on local repositories.&lt;/p&gt;
&lt;h5 id=&#34;npm-3&#34;&gt;NPM&lt;/h5&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# install all dependencies defined in package.json&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;npm install
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# add a registered package and record it in &amp;#39;dependencies&amp;#39; &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;npm install eslint
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# add an exact version&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;npm install eslint@3.0.0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# add and record in &amp;#39;devDependencies&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;npm install --save-dev eslint
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# add a git repos&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;npm install git@github.com:eslint/eslint.git
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h5 id=&#34;yarn-3&#34;&gt;Yarn&lt;/h5&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# install all dependencies defined in package.json&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;yarn install
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# add a registered package&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;yarn add eslint
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# add an exact version&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;yarn add eslint@3.0.0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# add to dev dependencies&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;yarn add --dev eslint
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# add a git repos&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;yarn add git@github.com:eslint/eslint.git
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;4-upgrading-packages&#34;&gt;4. Upgrading Packages&lt;/h3&gt;
&lt;h5 id=&#34;npm-4&#34;&gt;NPM&lt;/h5&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# check outdated packages&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;npm outdated
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# upgrade all to the latest versions w.r.t version ranges in &amp;#39;package.json&amp;#39; (since 2.6.1 default to top level packages)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;npm update
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# upgrade a specific package&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;npm update eslint
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h5 id=&#34;yarn-4&#34;&gt;Yarn&lt;/h5&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# check outdated packages&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;yarn outdated
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# upgrade all&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;yarn upgrade
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# upgrade all and ignore version ranges in &amp;#39;package.json&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;yarn upgrade --latest
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# upgrade a specific package&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;yarn upgrade eslint
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# upgrade packages match a pattern&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;yarn upgrade --pattern eslint
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;5-removing-packages&#34;&gt;5. Removing Packages&lt;/h3&gt;
&lt;h5 id=&#34;npm-5&#34;&gt;NPM&lt;/h5&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;npm uninstall eslint
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h5 id=&#34;yarn-5&#34;&gt;Yarn&lt;/h5&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;yarn remove eslint
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;6-running-commands&#34;&gt;6. Running Commands&lt;/h3&gt;
&lt;h5 id=&#34;npm-6&#34;&gt;NPM&lt;/h5&gt;
&lt;p&gt;&lt;code&gt;npm&lt;/code&gt; allows users to define executable scripts in &lt;code&gt;package.json&lt;/code&gt; under the section&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;scripts&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;:&lt;/span&gt; { &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;test&amp;#34;&lt;/span&gt; : &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;...&amp;#34;&lt;/span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;then use &lt;code&gt;npm run script-name&lt;/code&gt; to execute the predefined scripts.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;npm run test
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Nevertheless, &lt;code&gt;npm&lt;/code&gt; provides a short form for executing testing scripts as well.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;npm test
&lt;/code&gt;&lt;/pre&gt;&lt;h5 id=&#34;yarn-6&#34;&gt;Yarn&lt;/h5&gt;
&lt;p&gt;Similar to &lt;code&gt;npm&lt;/code&gt;, &lt;code&gt;yarn&lt;/code&gt; users can execute scripts with &lt;code&gt;yarn run script-name&lt;/code&gt; and &lt;code&gt;yarn test&lt;/code&gt; for testing.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;yarn run start
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;yarn test
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So far, we have walked through some basic steps of a typical development workflow, ranging from initialisation to inquiring and manipulating packages. Apart from that, both &lt;code&gt;npm&lt;/code&gt; and &lt;code&gt;yarn&lt;/code&gt; also go extra length with many more different functionality. Backing by very strong and active communities, your development projects will surely in safe hands when choosing either of them.&lt;/p&gt;
</description>
      </item>
    
      <item>
        <title>Confusing Hugo issues: datetime and &#39;isset&#39;</title>
        <link>https://htr3n.github.io/2018/03/confusing-hugo-issues-datetime-and-isset/</link>
        <pubDate>Sat, 31 Mar 2018 00:00:00 +0000</pubDate>
        
        <guid>9f40fad1fb27b5f60b32d7d5452b6831</guid>
        <description>&lt;p&gt;Yesterday I got notified from Github for &lt;a href=&#34;https://github.com/htr3n/hyde-hyde/issues?q=is%3Aissue&#34;&gt;two opening issues&lt;/a&gt; of the Hugo&amp;rsquo;s theme &lt;a href=&#34;https://github.com/htr3n/hyde-hyde&#34;&gt;hyde-hyde&lt;/a&gt; I have ported and developed further.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&#34;https://github.com/htr3n/hyde-hyde/issues/2&#34;&gt;newest one&lt;/a&gt; is reported by &lt;a href=&#34;https://github.com/jdayton3&#34;&gt;jdayton3&lt;/a&gt; (Jonathan Dayton) on wrong dates shown up. The issue seems very strange and difficult to spot. It took me a while to research around and found some relevant reports by &lt;a href=&#34;https://www.madboa.com/blog/2016/08/24/hugo-dateformat&#34;&gt;Paul Heinlein&lt;/a&gt; and &lt;a href=&#34;https://github.com/gohugoio/hugo/issues/163&#34;&gt;Dana Woodman&lt;/a&gt;, that Hugo date/time formatting is internally based on Golang, and therefore, uses &lt;a href=&#34;https://golang.org/pkg/time/#example_Time_Format&#34;&gt;a smart but confusing convention&lt;/a&gt;. It&amp;rsquo;s funny that I made almost the same mistake as Dana (i.e. he used the format string &amp;ldquo;March 1, 2010&amp;rdquo; whilst mine is &amp;ldquo;Jan 1, 2006&amp;rdquo;). As such, the generated dates were totally incorrect.&lt;/p&gt;
&lt;p&gt;Paul&amp;rsquo;s post summarise excellently the Go&amp;rsquo;s date/time format convention:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Format strings absolutely must adhere to the 1-2-3-4-5-6-7 order:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Month must be Jan, January, 01, or 1&lt;/li&gt;
&lt;li&gt;Date must be 02 or 2&lt;/li&gt;
&lt;li&gt;Hour must be 03, 3, or 15&lt;/li&gt;
&lt;li&gt;Minute must 04&lt;/li&gt;
&lt;li&gt;Second must be 05&lt;/li&gt;
&lt;li&gt;Year must be 2006&lt;/li&gt;
&lt;li&gt;Timezone must be MST or -7&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;After changing the format string, the aforementioned issue surely disappears. Even better, &lt;code&gt;hyde-hyde&lt;/code&gt; date/time formatting can also now adopt a default option to prevent such potential issues.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;{{ .Date.Format (.Site.Params.dateformat | default &amp;#34;Jan 02, 2006&amp;#34;) }}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;a href=&#34;https://github.com/htr3n/hyde-hyde/issues/1&#34;&gt;The other issue&lt;/a&gt; reported by &lt;a href=&#34;https://github.com/paskal&#34;&gt;paskal&lt;/a&gt; (Dmitry Verkhoturov) is an error Dmitry spotted when compiling and testing his blog against several Hugo themes including mine, &lt;code&gt;hyde-hyde&lt;/code&gt;.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Building sites … ERROR 2018/03/20 20:35:56 Error while rendering &amp;#34;page&amp;#34; in &amp;#34;&amp;#34;: template: /srv/hugo/themes/hyde-hyde/layouts/_default/single.html:6:7: executing &amp;#34;content&amp;#34; at &amp;lt;partial &amp;#34;post_conten...&amp;gt;: error calling partial: template: theme/partials/post_content.html:22:21: executing &amp;#34;theme/partials/post_content.html&amp;#34; at &amp;lt;len .Params.tags&amp;gt;: error calling len: len of untyped nil
ERROR 2018/03/20 20:35:56 Error while rendering &amp;#34;page&amp;#34; in &amp;#34;post/&amp;#34;: template: /srv/hugo/themes/hyde-hyde/layouts/_default/single.html:6:7: executing &amp;#34;content&amp;#34; at &amp;lt;partial &amp;#34;post_conten...&amp;gt;: error calling partial: template: theme/partials/post_content.html:22:21: executing &amp;#34;theme/partials/post_content.html&amp;#34; at &amp;lt;len .Params.tags&amp;gt;: error calling len: len of untyped nil
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The problem related to accessing &lt;a href=&#34;https://gohugo.io/variables/page/#page-level-params&#34;&gt;the tags&lt;/a&gt; of each post via &lt;code&gt;.Params.tags&lt;/code&gt;. The function &lt;code&gt;len .Params.tags&lt;/code&gt; receives an untyped &lt;code&gt;nil&lt;/code&gt; value. Strangely, there is a conditional check using the function &lt;a href=&#34;https://github.com/gohugoio/hugo/blob/1823c053c8900cb6ee53b8e5c02939c7398e34dd/tpl/collections/collections.go#L315&#34;&gt;isset&lt;/a&gt; right before that.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;{{ if isset .Params &amp;#34;tags&amp;#34; }}
   {{ $total := len .Params.tags }}
   ...
{{ end }}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The &lt;a href=&#34;https://gohugo.io/functions/isset&#34;&gt;semantics&lt;/a&gt; of &lt;code&gt;isset&lt;/code&gt; is a bit vague:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Returns true if the parameter is set.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;isset COLLECTION INDEX
isset COLLECTION KEY
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;It does not say anything when either &lt;code&gt;COLLECTION&lt;/code&gt; or &lt;code&gt;INDEX/KEY&lt;/code&gt; is &lt;code&gt;nil&lt;/code&gt; or empty. As such, perhaps Dmitry&amp;rsquo;s blog contains some posts with empty tags. Hence, the variable &lt;code&gt;.Params.tags&lt;/code&gt; yields &lt;code&gt;&amp;quot;&amp;quot;&lt;/code&gt; whilst &lt;code&gt;isset.Params &amp;quot;tags&amp;quot;&lt;/code&gt; evaluates to &lt;code&gt;true&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;One of the temporary mitigation is to use &lt;a href=&#34;https://gohugo.io/functions/with&#34;&gt;with&lt;/a&gt; instead. The semantics of &lt;code&gt;with&lt;/code&gt; is a bit clearer.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Rebinds the context (&lt;code&gt;.&lt;/code&gt;) within its scope and skips the block if the variable is absent.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Nevertheless, the error is dismissed when replacing the above code with the following. Hoooraaay!!!&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;{{ with .Params.tags }}
	{{ $total := len . }}
{{ end }}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Hugo is quite tricky, eh?&lt;/p&gt;
</description>
      </item>
    
      <item>
        <title>Getting started with Webpack</title>
        <link>https://htr3n.github.io/2018/02/getting-started-webpack/</link>
        <pubDate>Fri, 16 Feb 2018 00:00:00 +0000</pubDate>
        
        <guid>71224263d56c60161679a3312c052f95</guid>
        <description>&lt;p&gt;Webpack is a &lt;a href=&#34;https://webpack.js.org/concepts&#34;&gt;&lt;em&gt;static module bundler&lt;/em&gt;&lt;/a&gt; for Web applications. It analyses and processes the &lt;em&gt;input application&lt;/em&gt; and generates output &lt;em&gt;bundles&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;The design of Webpack architecture is highly modularised and extendable. In this post, I share here some notes on major aspects of Webpack since I&amp;rsquo;ve started learning it.&lt;/p&gt;

  





&lt;figure &gt;
  
  &lt;img
      
        src=&#34;https://htr3n.github.io/2018/02/getting-started-webpack/what-is-webpack.png&#34;
      
        alt=&#34;Webpack overview&#34;
        
        
        
         style=&#34;max-width: 100%;&#34;
         /&gt;
  
  
  
    &lt;figcaption&gt;
      &lt;span class=&#34;img--caption&#34;&gt;
        Figure 1. Webpack overview
        
          [&lt;a href=&#34;https://webpack.github.io&#34;&gt;source&lt;/a&gt;]
        
      &lt;/span&gt;
    &lt;/figcaption&gt;
  
&lt;/figure&gt;



&lt;h3 id=&#34;main-concepts&#34;&gt;Main Concepts&lt;/h3&gt;
&lt;h5 id=&#34;configurationhttpswebpackjsorgconceptsconfiguration&#34;&gt;&lt;a href=&#34;https://webpack.js.org/concepts/configuration&#34;&gt;Configuration&lt;/a&gt;&lt;/h5&gt;
&lt;p&gt;Webpack&amp;rsquo;s configuration is conventionally defined using a file &lt;code&gt;webpack.config.js&lt;/code&gt;. It is a JavaScript/Node.js source file. A comprehensive example of &lt;code&gt;webpack.config.js&lt;/code&gt; can be found &lt;a href=&#34;https://webpack.js.org/configuration/#options&#34;&gt;here&lt;/a&gt;. The four major parts of Webpack&amp;rsquo;s configuration are &lt;em&gt;entry&lt;/em&gt;, &lt;em&gt;output&lt;/em&gt;, &lt;em&gt;loaders&lt;/em&gt; and &lt;em&gt;plugins&lt;/em&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://webpack.js.org/concepts/entry-points&#34;&gt;Entry&lt;/a&gt;: An entry denotes the starting point where Webpack  commences buidling the internal &lt;em&gt;dependency graph&lt;/em&gt; by analysing all direct and indirect dependencies. There might be more than one entry.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://webpack.js.org/concepts/output&#34;&gt;Output&lt;/a&gt;: The output part defines the places where Webpack stores and how to name the outputs.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://webpack.js.org/concepts/loaders&#34;&gt;Loaders&lt;/a&gt;: Webpack uses loaders to handle files other than JavaScript by transform them into modules that can be processed by Webpack. Loaders are configured using &lt;code&gt;module.rules&lt;/code&gt; that specify the properties &lt;code&gt;test&lt;/code&gt; (what/which files to be transformed) and &lt;code&gt;use&lt;/code&gt; (which loaders to be used).&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://webpack.js.org/concepts/plugins&#34;&gt;Plugins&lt;/a&gt;: Plugins are important part of Webpack that will carry out different kinds of tasks such as checking, combining files, optimised outputs, and so on. Webpack provides a &lt;a href=&#34;https://webpack.js.org/api/plugins&#34;&gt;clear interface&lt;/a&gt; for creating and/or extending plugins.&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id=&#34;moduleshttpswebpackjsorgconceptsmodules&#34;&gt;&lt;a href=&#34;https://webpack.js.org/concepts/modules&#34;&gt;Modules&lt;/a&gt;&lt;/h5&gt;
&lt;p&gt;Webpack considers almost each file of any kinds a &lt;em&gt;module&lt;/em&gt;. The dependencies between modules can be described via various ways, for instance using ES2015&amp;rsquo;s &lt;a href=&#34;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import&#34;&gt;&lt;code&gt;import&lt;/code&gt;&lt;/a&gt;, CommonJS&amp;rsquo;s &lt;a href=&#34;http://www.commonjs.org/specs/modules/1.0&#34;&gt;&lt;code&gt;require()&lt;/code&gt;&lt;/a&gt;, &lt;a href=&#34;https://github.com/amdjs/amdjs-api/blob/master/AMD.md&#34;&gt;AMD&lt;/a&gt;&amp;rsquo;s &lt;code&gt;define&lt;/code&gt; and &lt;code&gt;require&lt;/code&gt;, and CSS&amp;rsquo;s &lt;a href=&#34;https://developer.mozilla.org/en-US/docs/Web/CSS/@import&#34;&gt;&lt;code&gt;@import&lt;/code&gt;&lt;/a&gt;. Some built-in module types supported by Webpack are including CoffeeScript, TypeScript, Babel, Sass, Less, and Stylus.&lt;/p&gt;
&lt;h5 id=&#34;dependency-graphhttpswebpackjsorgconceptsdependency-graph&#34;&gt;&lt;a href=&#34;https://webpack.js.org/concepts/dependency-graph&#34;&gt;Dependency Graph&lt;/a&gt;&lt;/h5&gt;
&lt;p&gt;When a file or module needs another, it is considered a &lt;em&gt;dependency&lt;/em&gt;. Webpack analyses all possible dependencies and builds a &lt;a href=&#34;https://en.wikipedia.org/wiki/Dependency_graph&#34;&gt;graph&lt;/a&gt; that includes all &lt;em&gt;needed modules&lt;/em&gt; starting from the &lt;em&gt;entry points&lt;/em&gt;. The &lt;em&gt;dependency graph&lt;/em&gt; is then used to package these modules into the &lt;em&gt;output bundles&lt;/em&gt;.&lt;/p&gt;
&lt;h3 id=&#34;some-typical-usage-scenarios&#34;&gt;Some Typical Usage Scenarios&lt;/h3&gt;
&lt;h5 id=&#34;1-a-simple-greeting&#34;&gt;1. A Simple Greeting&lt;/h5&gt;
&lt;p&gt;To demonstrate the simplest and, somewhat naive, usage of Webpack, we will create a small project as following.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;simple-greeting
 ├── package.json
 ├── public
 │   └── index.html
 ├── src
 │   └── main.js
 └── webpack.config.js
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The &lt;code&gt;package.json&lt;/code&gt; can be quickly instantiated using &lt;a href=&#34;https://www.npmjs.com&#34;&gt;npm&lt;/a&gt; or &lt;a href=&#34;https://yarnpkg.com&#34;&gt;yarn&lt;/a&gt;, as I prefer)&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ cd simple-greeting
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# create a package.json with default options&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ yarn init -y
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# now we use npm install webpack as a dependency of our project&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ yarn add --dev webpack
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Let&amp;rsquo;s create a JavaScript &lt;code&gt;src/main.js&lt;/code&gt; that contains our main business logic, i.e. writing out a heading 1 &lt;code&gt;Hello Webpack!&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;document.&lt;span style=&#34;color:#a6e22e&#34;&gt;write&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;&amp;lt;h1&amp;gt;Hello Webpack!&amp;lt;/h1&amp;gt;&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And we edit &lt;code&gt;public/index.html&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;html&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;lang&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;en&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;head&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;meta&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;charset&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;UTF-8&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;title&lt;/span&gt;&amp;gt;Getting Started with Webpack - A Simple Greeting&amp;lt;/&lt;span style=&#34;color:#f92672&#34;&gt;title&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;/&lt;span style=&#34;color:#f92672&#34;&gt;head&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;body&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;script&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;src&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;bundle.js&amp;#34;&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style=&#34;color:#f92672&#34;&gt;script&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;/&lt;span style=&#34;color:#f92672&#34;&gt;body&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;/&lt;span style=&#34;color:#f92672&#34;&gt;html&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You might have noticed that &lt;code&gt;index.html&lt;/code&gt; uses &lt;code&gt;bundle.js&lt;/code&gt; instead of &lt;code&gt;main.js&lt;/code&gt; that we created above. You are right, &lt;code&gt;bundle.js&lt;/code&gt; is generated by Webpack given the input &lt;code&gt;main.js&lt;/code&gt;. Let&amp;rsquo;s create a config file &lt;code&gt;webpack.config.js&lt;/code&gt; to do that.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;webpack&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;require&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;webpack&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;path&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;require&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;path&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;module&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;exports&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;entry&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;./src/main.js&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;output&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;path&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;path&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;resolve&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;__dirname&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;public&amp;#39;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;filename&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;bundle.js&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;After that, a simple invocation of &lt;code&gt;webpack&lt;/code&gt; at the command line will work. Please note that &lt;code&gt;npm&lt;/code&gt; installs the executable &lt;code&gt;webpack&lt;/code&gt; inside &lt;code&gt;node_modules/.bin&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ node_modules/.bin/webpack
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Hash: 9300b893968675cae1ef
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Version: webpack 3.11.0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Time: 81ms
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Asset     Size  Chunks             Chunk Names
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;bundle.js  2.52 kB       &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;emitted&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;  main
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;0&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; ./src/main.js &lt;span style=&#34;color:#ae81ff&#34;&gt;43&lt;/span&gt; bytes &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;0&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;built&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The execution of &lt;code&gt;webpack&lt;/code&gt; command should be successful. Now should you open &lt;code&gt;public/index.html&lt;/code&gt; using a Web browser, you will see &amp;ldquo;&lt;strong&gt;Hello Webpack&lt;/strong&gt;&amp;rdquo;.&lt;/p&gt;
&lt;h4 id=&#34;2-using-loaders&#34;&gt;2. Using Loaders&lt;/h4&gt;
&lt;p&gt;Several loaders have been developed for Webpack in order to handle various application resource types. An incompleted list of Webpack loaders can be found &lt;a href=&#34;https://github.com/webpack-contrib/awesome-webpack#loaders&#34;&gt;here&lt;/a&gt;. We will exemplify &lt;a href=&#34;https://github.com/webpack-contrib/eslint-loader&#34;&gt;&lt;code&gt;eslint-loader&lt;/code&gt;&lt;/a&gt; for analysing JavaScript sources and reporting errors, if any.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s reuse the previous example &lt;code&gt;webpack.config.js&lt;/code&gt; and add the &lt;code&gt;eslint-loader&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;module&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;exports&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;entry&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;./src/main.js&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;output&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;path&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;path&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;resolve&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;__dirname&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;public&amp;#39;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;filename&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;bundle.js&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    },    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;module&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;rules&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; [
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#a6e22e&#34;&gt;test&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;/\.js$/&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#a6e22e&#34;&gt;exclude&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;/node_modules/&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#a6e22e&#34;&gt;loader&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;eslint-loader&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ],   
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We also needs, at least, the following packages: &lt;code&gt;eslint&lt;/code&gt; and &lt;code&gt;eslint-loader&lt;/code&gt; which can be easily installed. In case you need further styles or rules, you can install more packages, for instance, &lt;code&gt;eslint-config-airbnb&lt;/code&gt;, &lt;code&gt;eslint-config-google&lt;/code&gt;, to name but a few.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ yarn add --dev eslint eslint-loader
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;For starting, we can initialise a simple configuration for &lt;em&gt;eslint&lt;/em&gt; using the option &lt;code&gt;--init&lt;/code&gt; and answer the corresponding questions.  &lt;code&gt;eslint&lt;/code&gt; will create a file &lt;code&gt;.eslintrc.xxx&lt;/code&gt; where &amp;ldquo;xxx&amp;rdquo; is either &amp;ldquo;js&amp;rdquo;, &amp;ldquo;json&amp;rdquo;, or &amp;ldquo;yaml&amp;rdquo; depending on which file format you had chosen.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ eslint --init
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then we can invoke &lt;code&gt;webpack&lt;/code&gt; to trigger the loader. For example, we can add the following line in the &lt;code&gt;src/main.js&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;document.&lt;span style=&#34;color:#a6e22e&#34;&gt;write&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;&amp;lt;h1&amp;gt;Hello Webpack!&amp;lt;/h1&amp;gt;&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;document.&lt;span style=&#34;color:#a6e22e&#34;&gt;write&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;x&lt;/span&gt;); &lt;span style=&#34;color:#75715e&#34;&gt;// eslint will report an error here
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ webpack
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Hash: 9b7cb596310bf077e30b
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Version: webpack 3.11.0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Time: 622ms
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Asset     Size  Chunks             Chunk Names
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;bundle.js  2.53 kB       &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;emitted&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;  main
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;0&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; ./src/main.js &lt;span style=&#34;color:#ae81ff&#34;&gt;61&lt;/span&gt; bytes &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;0&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;built&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; error&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ERROR in ./src/main.js
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/Users/huytran/working/dev/dev-web/webpack-demo/using-linter/src/main.js
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  2:16  error  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;x&amp;#39;&lt;/span&gt; is not defined  no-undef
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;✖ &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; problem &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; error, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; warnings&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So you can see that &lt;code&gt;eslint-loader&lt;/code&gt; indeed caught the intended error. All errors should be fixed such that Webpack can move forward.&lt;/p&gt;
&lt;h4 id=&#34;3-using-plugins&#34;&gt;3. Using Plugins&lt;/h4&gt;
&lt;p&gt;As mentioned above, Webpack architecture enables the use of plugins for performing various kinds of tasks, for example, merging, minimising or uglifying source code. Many of Webpack plugins and guides can be found &lt;a href=&#34;https://webpack.js.org/plugins&#34;&gt;here&lt;/a&gt; or &lt;a href=&#34;https://github.com/webpack-contrib/awesome-webpack#webpack-plugins&#34;&gt;here&lt;/a&gt;. We take an example of &lt;a href=&#34;https://webpack.js.org/plugins/uglifyjs-webpack-plugin&#34;&gt;&lt;code&gt;UglifyjsWebpackPlugin&lt;/code&gt;&lt;/a&gt; to illustrate how plugins actually work.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s modify the file &lt;code&gt;webpack.config.js&lt;/code&gt; taken from the previous scenarios and add the &lt;code&gt;plugins&lt;/code&gt; part.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;module&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;exports&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;entry&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;./src/main.js&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;output&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;path&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;path&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;resolve&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;__dirname&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;public&amp;#39;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;filename&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;bundle.js&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;plugins&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; [
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;webpack&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;optimize&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;UglifyJsPlugin&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;After executing &lt;code&gt;node_modules/.bin/webpack&lt;/code&gt; again, you can see that JavaScript source in &lt;code&gt;public/bundle.js&lt;/code&gt; has been uglified/minimised whilst the ouput of &lt;code&gt;public/index.html&lt;/code&gt; remains in tact.&lt;/p&gt;
&lt;p&gt;So far, we have walked through some simple scenarios. They are not quite complex and might have not yet shown all aspects and power of Webpack. Nevertheless, I hope they are sufficient for just showing the basis of Webpack architecture and how it works.&lt;/p&gt;
&lt;p&gt;The aforementioned demo projects are hosted at Github, respectively.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/htr3n/webpack-simple-greeting&#34;&gt;https://github.com/htr3n/webpack-simple-greeting&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/htr3n/webpack-with-loaders&#34;&gt;https://github.com/htr3n/webpack-with-loaders&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/htr3n/webpack-with-plugins&#34;&gt;https://github.com/htr3n/webpack-with-plugins&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
      </item>
    
      <item>
        <title>First experience with Hugo</title>
        <link>https://htr3n.github.io/2018/01/first-experience-with-hugo/</link>
        <pubDate>Tue, 23 Jan 2018 00:00:00 +0000</pubDate>
        
        <guid>11639daeef3737a97d95ac3a0db3dcc3</guid>
        <description>&lt;p&gt;To commence my journey in software development, I have looked for a Web framework to build my personal blog.  I have started writing blog posts mainly using (Multi)Markdown and plan to migrate other posts to Markdown too. Thus, it&amp;rsquo;s rather natural to go with built-in or first-class support for Markdown to minimise the migration effort.&lt;/p&gt;
&lt;p&gt;I have not foreseen any great use of extensive backend storage and computation thus far. Therefore, I narrowed down my search to static site generators with two prominent candidates &lt;a href=&#34;https://jekyllrb.com&#34;&gt;Jekyll&lt;/a&gt; and &lt;a href=&#34;https://gohugo.io&#34;&gt;Hugo&lt;/a&gt; popping up, for instance, &lt;a href=&#34;https://www.staticgen.com&#34;&gt;here&lt;/a&gt;, &lt;a href=&#34;https://www.smashingmagazine.com/2015/11/static-website-generators-jekyll-middleman-roots-hugo-review&#34;&gt;here&lt;/a&gt;, and &lt;a href=&#34;https://www.netlify.com/blog/2017/05/25/top-ten-static-site-generators-of-2017&#34;&gt;here&lt;/a&gt;. Both offer all essential features to bootstrap a new site or migrate existing sites. Nothing can go wrong when you pick either one.&lt;/p&gt;
&lt;p&gt;After a week trying both Jekyll and Hugo, I ended up deciding to go with Hugo. It&amp;rsquo;s not to say I hate Jekyll but quite the opposite. Jekyll is a rather well-engineered piece of software (by the guys behind &lt;a href=&#34;https://github.com&#34;&gt;Github&lt;/a&gt;).  I love its design, strong community, rich ecosystem, a lot of beautiful themes and good integration with Github.&lt;/p&gt;
&lt;p&gt;There is just one thing I do not feel comfortable working with Jekyll is the way to apply a theme. As far as I know, most of Jekyll&amp;rsquo;s themes ask for copying and pasting theme resources (e.g. CSS, templates) into an existing Jekyll site (please correct me if I am wrong).&lt;/p&gt;
&lt;p&gt;This is quite strange regarding the conventional approach of Ruby &amp;ndash; the backend of Jekyll. As predicted, I had way too many problems changing themes that cross various Jekyll versions. It should be the other way around. That is, a theme would remain in tact inside predefined folders and be plugged into the Jekyll site via the configuration file. I think this approach, in terms of software design, would be less intrusive and much lower &lt;a href=&#34;https://en.wikipedia.org/wiki/Coupling_(computer_programming)&#34;&gt;coupling&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Hugo gets this design decision quite right. That&amp;rsquo;s why I prefer Hugo, apart from its amazing performance. You can easily find numerous compliments for Hugo around the Internet. I just fall in love with the way Hugo allows me to apply and adapt any themes (of course with some extra effort as each theme might often introduce some additional customizable features or variables). Besides, as I desire to learn more about &lt;a href=&#34;https://golang.org&#34;&gt;Golang&lt;/a&gt;, Hugo would be definitely a nice start.&lt;/p&gt;
&lt;p&gt;The longer I play around with Hugo, the more I become passionate about Hugo in particular and Golang in general. The first week working with Hugo has yielded a Hugo&amp;rsquo;s theme for my personal use that you might find useful,  namely, &lt;a href=&#34;https://github.com/htr3n/hyde-hyde&#34;&gt;hyde-hyde&lt;/a&gt; (based on spf13&amp;rsquo;s &lt;a href=&#34;https://github.com/spf13/hyde&#34;&gt;Hyde&lt;/a&gt;). My journey with Hugo and Golang has just started but it looks quite bright and promising thus far.&lt;/p&gt;
&lt;p&gt;I &amp;#x2764;&amp;#xfe0f; Hugo.&lt;/p&gt;
</description>
      </item>
    
      <item>
        <title>LaraMod - Modularised Laravel 5</title>
        <link>https://htr3n.github.io/2018/01/laramod/</link>
        <pubDate>Fri, 19 Jan 2018 00:00:00 +0000</pubDate>
        
        <guid>10d8221d50b03b8ce8a93f95013529ea</guid>
        <description>&lt;p&gt;&lt;a href=&#34;https://laravel.com&#34;&gt;Laravel&lt;/a&gt; is an amazing emerging, well-designed and well-developed PHP framework. It is currently under active development and has been among top Web development frameworks. For a simple development project, the structure is totally fine. Nevertheless, you might not want to mix up your source code and resources with Laravel&amp;rsquo;s except some really necessary configurations.&lt;/p&gt;
&lt;p&gt;Moreover, you might also want to organise your project into submodules that are assigned to more than one team/person such that they can be developed silmutaneously. Thus, the need for complex submodule organisation is quite inevitable.&lt;/p&gt;
&lt;p&gt;From my struggle to organise a Laravel-based project such that I can divide and work on individual submodules such as &lt;code&gt;UserManagement&lt;/code&gt;, &lt;code&gt;Authentication&lt;/code&gt;, &lt;code&gt;Dashboard&lt;/code&gt;, etc. whilst keeping the Laravel code base intact as much as possible (this could be convenient for upgrading Laravel) and keeping my code base separate from Laravel&amp;rsquo;s.&lt;/p&gt;
&lt;p&gt;There are a number decent attempts on modalurasing Laravel projects for example &lt;a href=&#34;https://nicolaswidart.com/blog/writing-modular-applications-with-laravel-modules&#34;&gt;here&lt;/a&gt;, &lt;a href=&#34;https://github.com/caffeinated/modules&#34;&gt;here&lt;/a&gt; or &lt;a href=&#34;http://kamranahmed.info/blog/2015/12/03/creating-a-modular-application-in-laravel&#34;&gt;here&lt;/a&gt;. Being inspired and learning from these articles, I decided to start a simple project on my own, namely, &lt;a href=&#34;https://github.com/htr3n/laramod&#34;&gt;&lt;code&gt;LaraMod&lt;/code&gt;&lt;/a&gt;, for many reasons, but the biggest one is to dig deeper into Laravel 5 and PHP.&lt;/p&gt;
&lt;p&gt;Here I only emphasize some major aspects of LaraMod. The rest, including code and extra improvements can be found at LaraMod&amp;rsquo;s &lt;a href=&#34;https://github.com/htr3n/laramod&#34;&gt;repository&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update 1 @ 2018-04-25&lt;/strong&gt;: &lt;code&gt;LaraMod&lt;/code&gt; has been revised and updated to work with the most recent version of Laravel framework, &lt;code&gt;5.6.17&lt;/code&gt;. Instead of a standalone git repos, LaraMod is from now on a fork of &lt;a href=&#34;https://github.com/laravel/laravel&#34;&gt;Laravel repos&lt;/a&gt; enhanced with better modularisation.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update 2 @ 2018-11-30&lt;/strong&gt;: &lt;code&gt;LaraMod&lt;/code&gt; has been upgraded and merged with Laravel &lt;code&gt;master&lt;/code&gt; in which the stable release version is &lt;code&gt;5.7.15&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&#34;modularising-laravel-5&#34;&gt;Modularising Laravel 5&lt;/h2&gt;
&lt;h3 id=&#34;a-simple-submodule-structure&#34;&gt;A Simple Submodule Structure&lt;/h3&gt;
&lt;p&gt;Assuming that I want to divide my project into submodules of which each comprises own controllers, views, models (MVC) and others such as database migration, i18n, and routes. A simple structure of the submodule &lt;code&gt;Authentication&lt;/code&gt; is shown as following.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Authentication
├──Controllers
├──Lang
├──Migrations
├──Models
├──View
└──routes.php
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Such a structure can be very useful for different teams/people working independently. In LaraMod, there is an &lt;code&gt;artisan&lt;/code&gt; command &lt;code&gt;gen:module&lt;/code&gt; provided in &lt;a href=&#34;https://github.com/htr3n/laramod/blob/master/app/Console/Commands/GenModuleCommand.php&#34;&gt;&lt;code&gt;App\Console\Commands\GenModuleCommand&lt;/code&gt;&lt;/a&gt; that can quickly create a submodule following that structure.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ php artisan gen:module Authentication
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;how-to-proceed&#34;&gt;How to Proceed&lt;/h3&gt;
&lt;p&gt;An easy approach is to rely on Laravel&amp;rsquo;s &lt;a href=&#34;https://laravel.com/docs/providers&#34;&gt;&lt;code&gt;ServiceProvider&lt;/code&gt;&lt;/a&gt; to load the submodules and register the necessary components of the submodules.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;?&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;php&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;XYZServiceProvider&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;extends&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;\Illuminate\Support\ServiceProvider&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;boot&lt;/span&gt;() {}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;register&lt;/span&gt;() {}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;A &lt;code&gt;ServiceProvider&lt;/code&gt; contains two important methods &lt;code&gt;register()&lt;/code&gt; and &lt;code&gt;boot()&lt;/code&gt;. In this case, LaraMod mainly uses the method &lt;code&gt;boot()&lt;/code&gt; to load the corresponding submodule. LaraMod also adopts a simple, conventional method for defining a submodule. That is, all submodules will be subfolders of the folder &lt;code&gt;/modules&lt;/code&gt; and each module follows the conventional structure as mentioned above.&lt;/p&gt;
&lt;h4 id=&#34;automatically-loading-submodules&#34;&gt;Automatically Loading Submodules&lt;/h4&gt;
&lt;h5 id=&#34;loading-a-submodule&#34;&gt;Loading a Submodule&lt;/h5&gt;
&lt;p&gt;First, we create a method &lt;code&gt;loadModule()&lt;/code&gt; to load the resources such as views, i18n, database migration, and routes of a submodule using the provided methods &lt;code&gt;loadViewsFrom()&lt;/code&gt;, &lt;code&gt;loadTranslationsFrom()&lt;/code&gt;, &lt;code&gt;loadMigrationsFrom()&lt;/code&gt;, &lt;code&gt;loadRoutesFrom()&lt;/code&gt;, respectively. As models and controllers are essential PHP classes, they can be loaded using PSR-4 autoloaders as shown in the next parts.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;?&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;php&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;protected&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;loadModule&lt;/span&gt;($module)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; ($module) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#75715e&#34;&gt;// load the submodule&amp;#39;s routes
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;file_exists&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;__DIR__&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;/&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt; $module &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;/routes.php&amp;#39;&lt;/span&gt;)) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            $this&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;loadRoutesFrom&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;__DIR__&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;/&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt; $module &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;/routes.php&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#75715e&#34;&gt;// load the submodule&amp;#39;s views
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;is_dir&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;__DIR__&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;/&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt; $module &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;/Views&amp;#39;&lt;/span&gt;)) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            $this&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;loadViewsFrom&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;__DIR__&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;/&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt; $module &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;/Views&amp;#39;&lt;/span&gt;, $module);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#75715e&#34;&gt;// load the submodule&amp;#39;s translation
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;is_dir&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;__DIR__&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;/&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt; $module &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;/Lang&amp;#39;&lt;/span&gt;)) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            $this&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;loadTranslationsFrom&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;__DIR__&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;/&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt; $module &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;/Lang&amp;#39;&lt;/span&gt;, $module);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#75715e&#34;&gt;// load the submodule&amp;#39;s database migrations
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;is_dir&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;__DIR__&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;/&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt; $module &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;/Migrations&amp;#39;&lt;/span&gt;)) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            $this&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;loadMigrationsFrom&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;__DIR__&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;/&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt; $module &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;/Migrations&amp;#39;&lt;/span&gt;, $module);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h5 id=&#34;detecting-and-loading-submodules&#34;&gt;Detecting and Loading Submodules&lt;/h5&gt;
&lt;p&gt;Then we can walk through the folder &lt;code&gt;module&lt;/code&gt; and load all submodules using the method &lt;code&gt;loadModule()&lt;/code&gt; created above.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;?&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;php&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;protected&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;findAndLoadModules&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    $modules &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;config&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;module.modules&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#f92672&#34;&gt;!&lt;/span&gt;$modules) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        $modules &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; $this&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;getModuleNamesFromCurrentPath&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; ($modules) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;array_walk&lt;/span&gt;($modules, &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt; ($module) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            $this&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;loadModule&lt;/span&gt;($module);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        });
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Note that in this conventional approach, &lt;code&gt;findAndLoadModules()&lt;/code&gt; will look for submodule configurations either (1) explicitly in the file &lt;code&gt;/config/module.php&lt;/code&gt; with the following syntax or (2) implicitly as subfolders of &lt;code&gt;/modules&lt;/code&gt; (in case &lt;code&gt;/config/module.php&lt;/code&gt; does not exist).&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// module.php
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;?&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;php&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt;  [
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;modules&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&amp;gt;&lt;/span&gt; [
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;Core&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;Login&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;Dashboard&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;Home&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;User&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Finally we invoke &lt;code&gt;findAndLoadModules()&lt;/code&gt; within &lt;code&gt;boot()&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;?&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;php&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;namespace&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Laramod&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ModulesServiceProvider&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;extends&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;\Illuminate\Support\ServiceProvider&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;boot&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        $this&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;findAndLoadModules&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;register&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;registering-the-service-provider&#34;&gt;Registering the Service Provider&lt;/h4&gt;
&lt;p&gt;The &lt;code&gt;ModulesServiceProvider&lt;/code&gt; must be registered in &lt;code&gt;/config/app.php&lt;/code&gt; in order to be loaded by Laravel.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;?&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;php&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; [
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;providers&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&amp;gt;&lt;/span&gt; [
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;\Laramod\ModulesServiceProvider&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;class&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     ],
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;autoloading-submodules-classes&#34;&gt;Autoloading Submodules&amp;rsquo; Classes&lt;/h4&gt;
&lt;p&gt;Apart from resources like views, i18n, database migration loaded in the previous steps, a submodule can also contain other PHP classes such as database ORM models and controllers.&lt;/p&gt;
&lt;p&gt;One natural approach would be to leverage the &lt;a href=&#34;http://www.php-fig.org/psr/psr-4&#34;&gt;PSR-4 autoloader&lt;/a&gt; autoloading supported by Laravel 5.5. This approach also nicely fits when we want to define separate namespaces for each submodule and especially submodule&amp;rsquo;s components.&lt;/p&gt;
&lt;p&gt;For this, we can define the submodule&amp;rsquo;s namespace and manually specify the submodule&amp;rsquo;s classpaths to be loaded in &lt;code&gt;composer.json&lt;/code&gt; as following.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;psr-4&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;App\\&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;app/&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;Core\\&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;modules/Core/&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;Dashboard\\&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;modules/Dashboard/&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;Login\\&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;modules/Login/&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;User\\&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;modules/User/&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Another technique for autoloading classes in Laravel 5 is to dynamically add PSR4 classpaths in &lt;code&gt;ModulesServiceProvider.php&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// ModulesServiceProvider.php
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;?&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;php&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$loader &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;require&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;base_path&lt;/span&gt;() &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;/vendor/autoload.php&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$loader&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;setPsr4&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Core&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\\&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;__DIR__&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;./Core/&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$loader&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;setPsr4&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Dashboard&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\\&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;__DIR__&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;./Dashboard/&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$loader&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;setPsr4&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Login&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\\&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;__DIR__&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;./Login/&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$loader&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;setPsr4&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;User&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\\&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;__DIR__&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;./User/&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;One problem, though, is that LaraMod must be able to detect or guess the namespace classpaths. To do this, we can either use the configuration file &lt;code&gt;config/module.php&lt;/code&gt; or, even nicer and smarter, scan the submodule&amp;rsquo;s folders to extract the necessary information. However, loading time then will be really significant when the project grows because Laravel loaders willl do the scanning and loading whenever any classes are referenced.&lt;/p&gt;
&lt;h3 id=&#34;accessing-submodule-resources&#34;&gt;Accessing Submodule Resources&lt;/h3&gt;
&lt;p&gt;Given a submodule, for instance &lt;code&gt;SubmoduleA&lt;/code&gt;, most of its classes such as controllers and database mapping models, if configuring properly using PSR-4, will be automatically loaded and used straightforwardly. Nonetheless, acessing to resources such as views and i18n (languages) requires a slightly different syntax, for instance, &lt;code&gt;SubmoduleA::blade_view_name&lt;/code&gt; or &lt;code&gt;SubmoduleA::messages.error&lt;/code&gt;. If the &lt;code&gt;SubmoduleA::&lt;/code&gt; is missing, Laravel will look for views and language files in the default places.&lt;/p&gt;
&lt;h2 id=&#34;finale&#34;&gt;Finale&lt;/h2&gt;
&lt;p&gt;The outcome of my very first PHP project, LaraMod, would be a reasonable skeleton for modularising software projects based on Laravel 5. That is, you can just easily create a new submodule with the predefined conventional structure and add the PSR-4 namespaces and classpaths, then good you go. Each submodule should then be developed independently. Sure there are some areas that need improvement. For example, all testing stuffs are still under &lt;code&gt;/tests&lt;/code&gt; and database seeders are still in &lt;code&gt;database/seeds&lt;/code&gt;. The first one requires intervention with PHPUnit/&lt;code&gt;phpunit.xml&lt;/code&gt; whilst the later asks for further changes in built-in Laravel &lt;code&gt;artisan&lt;/code&gt; commands.&lt;/p&gt;
&lt;p&gt;For me&amp;mdash;a new bie, it was not quite an all-pleasant journey to experience several Laravel aspects. Nevertheless, developing and customising LaraMod are extremely valuable as I could learn a lot about not only Laravel in particular but also PHP in general. Achieving reasonable modularisation for a complex software development project requires a lot of thoughtful design and hard work and even sometimes trade-offs and compromises. In sharing this, I hope LaraMod might become handy and helpful start so that your journeys with Laravel can be more pleasant and joyful. I look forward to hearing and learning from your experience, too.&lt;/p&gt;
</description>
      </item>
    
      <item>
        <title>Ngụy biện / Fallacies (st)</title>
        <link>https://htr3n.github.io/2018/01/nguy-bien-fallacies/</link>
        <pubDate>Mon, 01 Jan 2018 00:00:00 +0000</pubDate>
        
        <guid>7797ffc49089eb016443cfc8214b9528</guid>
        <description>&lt;p&gt;Bài viết sưu tầm trên Internet về các hình thức ngụy biện khác nhau.&lt;/p&gt;
&lt;h2 id=&#34;thay-đổi-chủ-đề&#34;&gt;Thay đổi chủ đề&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Công kích cá nhân (ad hominem). Đây là một loại ngụy biện phổ biến nhất, nguy hiểm nhất, và có “công hiệu” nhất, vì nó tấn công vào cá nhân của người tranh luận, và tìm cách trốn tránh luận điểm của cá nhân đó. Hình thức ngụy biện này thường xuất hiện dưới dạng: Ông A phát biểu về một vấn đề; ông B tấn công vào cá nhân ông A, và làm cho người ta nghi ngờ luận điểm của ông A. Tuy nhiên, có thể không có mối liên hệ nào giữa cá nhân và luận điểm của ông A.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Có hai hình thức thuộc loại ngụy biện này. Thứ nhất là dưới hình thức sỉ nhục, hay chửi rủa. Khi bất đồng ý kiến, người ngụy biện chỉ việc công kích vào cá nhân của người phát biểu.&lt;/p&gt;
&lt;p&gt;Hình thức ngụy biện thứ hai trong loại này là người ngụy biện cố gắng thuyết phục người đối thoại chấp nhận luận điểm của họ bằng cách đề cập đến hoàn cảnh của cá nhân đó. Ví dụ: “Anh nói là không nên uống rượu, vậy mà anh đã từng ngất ngưởng cả năm qua.”&lt;/p&gt;
&lt;ol start=&#34;2&#34;&gt;
&lt;li&gt;
&lt;p&gt;Lợi dụng quyền lực (ad verecundiam). Đây là loại ngụy biện dùng những nhân vật nổi tiếng hay được nhiều người ái mộ để tìm sự ủng hộ cho luận điểm của mình.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Lợi dụng quyền lực nặc danh. Trong trường hợp này, người ngụy biện không nêu danh tính người có thẩm quyền, và vì không ai biết tên người có thẩm quyền nên không ai có thể kiểm chứng sự chính xác của lời phát biểu. Một loại ngụy biện khác có quan hệ với loại này là dùng lời đồn đại để làm cơ sở lập luận.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Lợi dụng tác phong. Loại ngụy biện này dùng tác phong hay cách làm việc hay một đặc tính nào đó của đối tượng để cố thuyết phục về sự hợp lí của phát biểu.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Luận điệu cá trích. Loại ngụy biện này thường hay được ứng dụng khi một người nào đó đưa vào những phát biểu không dính dáng gì đến vấn đề đang tranh luận, nhằm mục đích đánh lạc hướng vấn đề.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Luận điệu ngược ngạo (Burden of Proof). Bằng chứng luôn luôn là gánh nặng của người phát biểu. Do đó, tìm cách di chuyển gánh nặng đó cho một người khác là một thủ thuật giới ngụy biện hay dùng. Ví dụ: &amp;ldquo;Anh không tin là có UFO, vậy anh có thể chứng minh không?&amp;rdquo;, đáng lẽ người phát biểu phải chứng minh là có UFO, nhưng công việc đó đã được chuyển cho người đối thoại.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;lợi-dụng-cảm-tính-và-đám-đông&#34;&gt;Lợi dụng cảm tính và đám đông&lt;/h2&gt;
&lt;ol start=&#34;7&#34;&gt;
&lt;li&gt;
&lt;p&gt;Dựa vào bạo lực (ad baculum). Ngụy biện dựa vào bạo lực thực chất là một sự đe dọa, nhằm mục đích gây áp lực cho người đối thoại phải chấp nhận một kết luận nào đó. Ví dụ: &amp;ldquo;Không đồng ý với tôi thì vào game sẽ bị kill red&amp;rdquo;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Lợi dụng lòng thương hại (ad misericordiam). Đây là một loại ngụy biện dựa vào lòng trắc ẩn của người đối thoại để người đối thoại chấp nhận lí lẽ của mình. “Tôi hi vọng anh sẽ chấp nhận đề nghị này, chúng ta đã tiêu ra ba tháng nay rồi đấy.”&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Lợi dụng hậu quả (ad consequentiam). Ngụy biện loại này thường được biểu hiện qua cách phát biểu “A hàm ý B, B là sự thật, do đó A là sự thật”.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Lạm dụng chữ nghĩa. Đây là một loại ngụy biện dựa vào dùng những chữ mang cảm tính cao để gắn một giá trị đạo đức vào một đề nghị hay một câu phát biểu.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Dựa vào quần chúng (ad numerum). Loại ngụy biện này tin rằng nếu có nhiều người ủng hộ một đề nghị nào đó, thì đề nghị đó phải đúng. Ví dụ như “Đại đa số thành viên cũ của [Clan Spammer TM] ủng hộ Phantom, hẳn anh ấy phải luôn luôn đúng.” Liên hệ với loại ngụy biện này là hình thức tranh thủ sự ủng hộ của đám đông để cố gắng cho thấy luận điểm của mình là đúng.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;làm-lạc-hướng-vấn-đề&#34;&gt;Làm lạc hướng vấn đề&lt;/h2&gt;
&lt;ol start=&#34;12&#34;&gt;
&lt;li&gt;
&lt;p&gt;Lí lẽ chẻ đôi. Loại ngụy biện này thường phân định một vấn đề thành hai giá trị: trắng và đen, bạn và thù, có và không, v.v.. dù trong thực tế, có hơn hai lựa chọn. Ví dụ nói: &amp;ldquo;Bạn chọn đi, hoặc bán cây Peril cho tui giá 10m adena, hoặc đưa tui 5m adena ngay lập tức!&amp;rdquo;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Lí lẽ ngờ nghệch (ad ignorantiam). Loại ngụy biện này, như tên gọi ám chỉ, xuất phát từ sự ngờ nghệch. Một trong những cách nói thông thường nhất trong loại ngụy biện này mà giới ngụy biện dùng là nếu một điều gì đó chưa được chứng minh là sai (hay giả) thì điều đó là đúng (hay thật).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Lí luận lươn trạch. Loại ngụy biện này cho rằng nếu một sự kiện xảy ra, các sự kiện có hại khác sẽ xảy ra.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Mệnh đề rời rạc. Đây là loại ngụy biện dùng hai (hay nhiều hơn hai) mệnh đề chẳng dính dáng gì với nhau để làm thành một phát biểu hay kết luận. Ví dụ &amp;ldquo;Mày ngưng lừa đảo giá bán SS chưa&amp;rdquo;. Câu hỏi thực ra hỏi đến 2 vấn đề &amp;ldquo;Mày lừa đảo giá bán SS&amp;rdquo; và &amp;ldquo;Mày đã ngưng việc lừa đảo đó chưa&amp;rdquo; trong khi sự thật là người được hỏi chưa hề lừa đảo.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Đơn giản hóa. Đây là một loại ngụy biện mà người phát biểu cố tình biến một quan niệm trừu tượng thành một điều cụ thể để bắt lấy thế thượng phong trong đối thoại (nhưng là ngụy biện). Ví dụ: “Tôi để ý thấy anh mô tả Phantom là một người láo xược. Vậy tôi hỏi anh cái “láo xược” đó nó nằm ở đâu trong bộ não? Anh không chỉ ra được cho tôi; do đó, tôi có thể nói cái láo xược không có thực.”&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;qui-nạp-sai&#34;&gt;Qui nạp sai&lt;/h2&gt;
&lt;ol start=&#34;17&#34;&gt;
&lt;li&gt;
&lt;p&gt;Khái quát hóa vội vã. Loại ngụy biện này cũng khá phổ biến. Nó dùng một ví dụ hay trường hợp nhỏ và từ đó khái quát hóa cho một cộng đồng. Chẳng hạn như “PhuongDoan nhìn rất íu đúi, bởi vậy tụi [Clan Spammer TM] cũng íu đúi rốt”&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Khái quát hóa không đúng chỗ. Đây là loại ngụy biện mà người sử dụng chúng thường áp dụng một qui luật chung cho một tình huống hay một cá nhân. Chẳng hạn như &amp;ldquo;Clan FMW không ngại kill red người khác. Bé LeQuyen1987 cũng thuộc FMW, vậy bé ấy hẳn là thường xuyên kill red người khác.”&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Kéo dài tính tương đồng. Trong loại ngụy biện này, người dùng nó đề nghị một điều lệ chung chung, rồi ứng dụng nó cho mọi trường hợp và cá nhân. Ví dụ: “Tôi tin rằng chống luật cấm spam bằng cách cố ý spam là một điều sai trái”&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Lí lẽ quanh co. Loại ngụy biện này thường lẩn quẩn trong vài giả định và kết luận. Chẳng hạn như “Prophet nhất định không thể làm clan leader được. Do đó không thể để Prophet làm clan leader. Ví thể, các Prophet sẽ không cần phải đi đăng ký đánh thành. Do vậy, Prophet không thể nào làm leader được.&amp;rdquo; Tức là trong một lí giải như thế, cả hai giả thuyết và kết luận đều giống nhau.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Đảo ngược điều kiện. Loại ngụy biện này thường được biểu hiện qua hình thức “Nếu A xảy ra thì B sẽ xảy ra, do đó, nếu B xảy ra thì A sẽ xảy ra.”&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Lợi dụng rủi ro. Ngụy biện này thường dùng một qui luật chung và áp dụng nó cho một trường hợp cá biệt. Ví dụ: “Luật giao thông không cho anh chạy quá 50 km/h. Cho dù cha anh sắp chết anh cũng không được chạy quá tốc độ đó.”&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Lợi dụng trường hợp cá biệt. Ngụy biện này thường dùng một trường hợp cá biệt để đem ra ứng dụng cho một đám đông. Ví dụ: “A bận ôn thi nên không để đi kiếm tiền để nộp quỹ clan, vì thế A được miễn nộp quỹ clan tuần này. Mà thế là không công bằng, nên leader phải miễn quỹ clan tuần này cho tất cả thành viên.”&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Kết luận lạc đề. Loại ngụy biện này thường xuất hiện khi một kết luận chẳng dính dáng gì đến lí lẽ mà người biện luận trình bày. Một ví dụ tiêu biểu cho trường hợp ngụy biện này là: “Độ nhiễm sắt trong nước ở Việt Nam chưa cao và còn trong mức độ cho phép. Dữ kiện của Bangladesh cho thấy tình trạng nhiễm sắt ở Việt Nam rất trầm trọng.”&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Ngụy biện rơm. Loại ngụy biện này cố tình xuyên tạc, bóp méo quan điểm hay phát biểu của người khác, để làm luận điểm tấn công. Đây là một ngụy biện, vì nó không đương đầu với cái lí lẽ đang bàn. Chẳng hạn như: “Khi không có party thì mọi người nên đi solo vào lair. Nhiều người từ chối solo vào lair, nhưng họ nên thấy rằng vào lair train hiệu quả hơn là lê lết buôn dưa ở Giran.&amp;quot; Trong đây, ý tranh luận của người trước là không nên solo vào lair nhưng người phản biện lại nói đến tính hiệu quả khi train ở lair - điều mà ai cũng biết.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;nguyên-nhân-giả&#34;&gt;Nguyên nhân giả&lt;/h2&gt;
&lt;ol start=&#34;26&#34;&gt;
&lt;li&gt;
&lt;p&gt;“Postology”. Loại ngụy biện này phát biểu rằng hai sự kiện xảy ra, một trước và một sau, có quan hệ với nhau như nguyên nhân và hậu quả. Ví dụ: &amp;ldquo;Vài nick bị ban khi spam, vậy chúng ta không nên spam.&amp;rdquo; Thực tế là bạn có thể spam mà vẫn không bị ban nếu spam đúng chỗ.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Ảnh hưởng liên đới. Một sự kiện được cho là có ảnh hưởng đến một sự kiện khác, nhưng thực chất thì cả hai sự kiện đều có cùng một nguyên nhân. Đây cũng chính là một trường hợp ngụy biện dưới dạng “postology”. Ví dụ: “Chúng ta đang chứng kiến tình trạng Summoner không kiếm được clan rất cao, vì không clan nào muốn chứa Summoner” (Nhưng có thể cả hai sự kiện có nguyên nhân là một summoner cụ thể nào đó hay chơi bẩn nên không clan nào nhận.)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Ảnh hưởng không đáng kể. Đây là một loại ngụy biện mang tính phóng đại từ một ảnh hưởng rất nhỏ. Chẳng hạn như “Hút thuốc gây ra ô nhiễm môi trường” là một phát biểu đúng, nhưng ảnh hưởng của thuốc lá đến môi trường rất khiêm tốn khi so với ảnh hưởng của khói xe, chất thải công nghiệp từ các nhà máy&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Ảnh hưởng ngược chiều. Mối quan hệ giữa nguyên nhân và hậu quả bị đảo ngược chiều để tìm đến một kết luận mang tính ngụy biện. Ví dụ: “Ung thư gây ra thói quen hút thuốc lá”.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Nguyên nhân phức tạp. Một sự kiện xảy ra có thể do nhiều nguyên nhân khác nhau, nhưng người ngụy biện có thể đơn giản hóa thành một liên hệ đơn giản. Chẳng hạn như “Tai nạn xe cộ là do đường xá xấu” có thể đúng, nhưng tai nạn cũng có thể do người lái xe ẩu trong một điều kiện xấu.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Nguyên nhân sai (Non causa pro causa). Loại ngụy biện này xảy ra khi một điều nào đó được cho là nguyên nhân của một sự kiện, nhưng nó chưa thực sự được chứng minh là nguyên nhân. Ví dụ: “Tôi uống một viên aspirin và nhớ đến Lineage, và tôi không còn bị nhức đầu. Như vậy Lineage đã chữa trị tôi khỏi nhức đầu.”&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;nhập-nhằng&#34;&gt;Nhập nhằng&lt;/h2&gt;
&lt;ol start=&#34;32&#34;&gt;
&lt;li&gt;
&lt;p&gt;Lí lẽ mơ hồ. Dùng những chữ và lí lẽ mơ hồ, tối nghĩa là một hình thức ngụy biện, nhất là khi một chữ hay câu phát biểu được dùng với hai (hay nhiều hơn hai) ý nghĩa khác nhau. Ví dụ: &amp;ldquo;Giết người là xấu, vì thế những người đi giết những người đang red cũng là xấu&amp;rdquo;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Chơi chữ (Amphiboly). Ngụy biện bằng chơi chữ dựa vào những giả thuyết mơ hồ, nhập nhằng, do bất cẩn thận hay cách phát biểu sai văn phạm.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Trọng âm (accent). Đây là một hình thức ngụy biện bằng cách dùng thay đổi ý nghĩa của một câu văn qua nhấn mạnh.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;phạm-trù-sai&#34;&gt;Phạm trù sai&lt;/h2&gt;
&lt;ol start=&#34;35&#34;&gt;
&lt;li&gt;
&lt;p&gt;Hỗn hợp. Loại ngụy biện này thường dùng những đặc tính bề ngoài để suy luận cho một điều gì cá biệt. Ví dụ: “Xe đạp được làm bằng những dụng cụ nhẹ kí, do đó, xe đạp rất nhẹ”, hay “Xe hơi dùng ít xăng dầu và không gây ra ô nhiễm môi trường bằng xe bus. Do đó, xe hơi không gây hại cho môi trường bằng tác hại của xe bus.”&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Phi thể thức (ad hoc). Giải thích và lí lẽ là hai điều khác nhau. Nếu muốn xác minh A, và dùng B làm bằng cớ, thì câu phát biểu “A xảy ra bởi vì B xảy ra&amp;quot; là một lí lẽ. Tuy nhiên, nếu muốn xác minh một sự thật về B, thì câu phát biểu &amp;ldquo;A xảy ra bởi vì B xảy ra&amp;rdquo; không phải là một lí lẽ mà là một lời giải thích. Ngụy biện theo kiểu phi thể thức là hình thức dùng giải thích sau khi đã có sự thật mà sự thật không ứng dụng vào một bối cảnh khác. Thông thường ngụy biện phi thể thức được khoác vào chiếc áo lí lẽ. Chẳng hạn như nếu chúng ta giả định rằng clan leader đối xử công bằng với mọi member trong clan, thì những phát biểu sau đây là những lời giải thích phi thể thức: “Tôi mới được leader cho mượn tiền”, “Nói clan leader đi, ảnh nhiều tiền lắm”, “Nhưng ảnh có cho những người khác mượn tiền không”, “À, leader rất khó hiểu.”&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;phi-logic-non-sequitur-và-nhầm-lẫn-trong-tam-đoạn-luận&#34;&gt;Phi logic (non sequitur) và nhầm lẫn trong tam đoạn luận&lt;/h2&gt;
&lt;ol start=&#34;37&#34;&gt;
&lt;li&gt;
&lt;p&gt;Phi logic. Ngụy biện phi logic thường xảy ra trong trường hợp một lí lẽ mà kết luận được rút ra từ những tiêu đề không dính dáng gì với nhau. Chẳng hạn như “Người Ai Cập đã từng làm nhiều khai quật để xây dựng những kim tự tháp, họ chắc chắn phải rất thạo về cổ sinh vật học.”&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Loại bỏ tiền đề. Ngụy biện loại này thường xảy ra dưới hình thức “nếu A thì B, không phải A thì không phải B.” Ví dụ: “Nếu tôi ở TPHCM thì tôi đang ở Vietnam. Tôi hiện không ở TPHCM, do đó, tôi không ở Vietnam”.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Giả định hư. Đây là một loại ngụy biện bằng cách dùng kỹ thuật phỏng vấn. Một trường hợp cổ điển là “Ông đã ngưng đánh vợ chưa?” Tức là một câu hỏi với một giả định rằng người được hỏi từng hành hung vợ.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Ngụy biện bốn ngữ. ( Một tiêu chuẩn của tam đoạn luận gồm có 3 chữ). Ví dụ như trong câu phát biểu “Tất cả chó là thú vật, và tất cả mèo là loài động vật có vú, do đó tất cả chó là loài động vật có vú,” có bốn chữ: chó, mèo, động vật, và động vật có vú.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Đứt đoạn. Hai sự vật riêng biệt được xem là có liên hệ nhau nếu chúng có chung đặc tính. Người ngụy biện lợi dụng chữ giữa của một phát biểu để đưa đến một kết luận sai.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;các-nhầm-lẫn-khác&#34;&gt;Các nhầm lẫn khác&lt;/h2&gt;
&lt;ol start=&#34;42&#34;&gt;
&lt;li&gt;
&lt;p&gt;Dẫn chứng bằng giai thoại. Một trong những ngụy biện phổ biến nhất và đơn giản nhất là dựa vào những câu chuyện có tính vụn vặt, hay giai thoại.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Lợi dụng cổ tích. Đây là một loại ngụy biện cho rằng những gì đúng hay tốt chỉ đơn giản vì chúng là cổ xưa, và những người theo cách ngụy biện này thường nói “hồi nào đến giờ ai cũng vậy.”&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Dựa vào cái mới (ad novitatem). Ngược lại với loại ngụy biện dựa vào cái cũ, ngụy biện dựa vào cái mới cho rằng một điều gì đó tốt hơn và đúng hơn đơn giản chỉ vì nó mới hơn cái khác. “Windows XP phải tốt hơn Windows 2000.”&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Lí lẽ của đồng tiền. Loại ngụy biện này thường dựa vào một niềm tin duy nhất rằng đồng tiền là một tiêu chuẩn của sự đúng đắn. Những người có nhiều tiến có khả năng đúng hơn những người ít tiền.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Dựa vào cái nghèo. Ngược lại với ngụy biện dựa vào sự giàu có, có một loại ngụy biện khác dựa vào sự nghèo khổ.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Điệp khúc (ad nauseam). Loại ngụy biện này cho rằng một lí lẽ càng được lặp đi lặp lại nhiều chừng nào thì nó sẽ được người ta chấp nhận là đúng. Do đó, người ngụy biện thường chỉ lặp đi lặp lại những phát biểu, bất kể là quái dở thế nào, cho đến khi người đối thoại mệt mỏi không còn muốn nghe nữa.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Lạm dụng thiên nhiên. Tìm cái tương đồng giữa một kết luận nào đó và một khía cạnh của thế giới tự nhiên, rồi từ đó phát biểu rằng kết luận đó là không thể tránh khỏi.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Ngụy biện “Tu quoque”. Đây là một trong những ngụy biện rất phổ biến. Nó dựa vào lí lẽ rằng một hành động có thể chấp nhận được bởi vì người đối nghịch đã làm. Chẳng hạn như “Anh là một người lừa dối.” “Rồi sao? Anh cũng là một tay lừa dối vậy.”&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Lạm dụng thống kê. Thống kê thường được giới ngụy biện sử dụng tối đa, vì theo họ thống kê có thể dùng để “chứng minh” bất cứ điều gì. Người ta có thể vặn vẹo hai con số 1 và 3 điểm để sản xuất những phát biểu như “khác nhau 2 điểm”, “cao gấp 3 lần”, hay “tăng 200%”; người ta có thể dựa vào ý kiến đồng tình của 4 người trong 5 người để cho là “80% người được thăm dò”, hay thậm chí “đa số cộng đồng” đồng ý với một luận điểm nào đó. Tức là những khái quát hoá một cách vội vã, hay dựa vào một mẫu số cực kỳ thấp, thấp đến độ nó không có nghĩa lí gì. Thực ra, thống kê không chứng minh điều gì cả. Thống kê chỉ là một phương tiện hay thuật toán dùng để loại bỏ những trường hợp khả dĩ hay không khả dĩ. Vì có quá nhiều ngụy biện thống kê, nên vấn đề này sẽ được bàn tiếp trong một dịp khác. Tuy nhiên, những ai thích tìm hiểu vấn đề ngụy biện thống kê có thể tìm đọc cuốn sách rất nổi tiếng của Darrell. Huff, có tựa đề là “How to lie with statistics” (tạm dịch: “Làm thế nào để lừa dối bằng thống kê”).&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;mặc-định-ðề-các-hình-thức-ngụy-biện-khi-tranh-luận&#34;&gt;Mặc định Ðề: Các hình thức ngụy biện khi tranh luận&lt;/h2&gt;
&lt;p&gt;Có thể nói những loại ngụy biện trên đây có những đặc điểm chung là (a) phát biểu không dựa vào lí lẽ logic; (b) các định đề không vững để đi đến một kết luận; và (c) đưa ra giả định không đúng. Ngụy biện, do đó, nói cho cùng, là một sản phẩm của sự lười suy nghĩ. Và hầu như trong chúng ta, ai cũng có ít nhất là một lần lười suy nghĩ. Do đó, nếu điểm qua những loại ngụy biện trên đây, chúng ta tự cảm nhận rằng trong quá khứ mình chắc cũng có lần phạm vào lỗi lầm của ngụy biện. Điều này có thể đúng, và không nên lấy làm ngạc nhiên.&lt;/p&gt;
&lt;p&gt;Nhưng tại sao những ngụy biện vẫn còn có mặt? Theo tôi, bởi vì chúng vẫn có khách hàng. Vẫn có người, dù ít hay nhiều, tin tưởng vào ngụy biện, vì nó thuận nhĩ, trơn tru, và nhất là không thách thức. Sờ một hòn đá trơn tru đem lại cho chúng ta một cảm giác khoan khoái dễ chịu hơn là sờ một hòn đá lởm chởm, hay ngồi trên một cái ghế ghồ ghề. Người ta thích sự trơn tru, bởi vì trơn tru là dấu hiệu của sự khoan khoái, dễ chịu, là cái khoảng thời gian giải lao, không cần sự thách thức.&lt;/p&gt;
&lt;p&gt;Có lẽ, ở một khía cạnh nào đó, điều này cũng không đến nỗi tệ, bởi vì những ngụy biện phản ánh sự thành công [hay có người nói sự phong phú] của ngôn ngữ trong việc tách rời giữa những gì thô thiển, gồ ghề với những gì hoàn thiện, mỹ miều. Nhưng sự trơn tru của các vật thể và ngôn ngữ ngày nay đem lại cho chúng ta một cảm giác giả tạo về thế giới thực của các vật thể. Những kỳ kẹt xe trên đường xá mới để lộ trái tim phức tạp của một thành phố. Tương tự, một sự cố của internet sẽ nhắc nhở chúng ta về tình trạng hỗn mang và phức tạp của hệ thống thông tin điện tử. Sự hỗn mang và phức tạp là thực. Trơn tru, tròn trĩnh có thể là giả tạo. Những câu văn ngụy biện có thể chỉ là những lời phát biểu lém lỉnh thay vì lịch thiệp, hàm chứa mánh khóe thay vì thân thiện. Có thể nói, ngụy biện là những lối sáo ngữ liến thoắng nhằm vào mục đích lôi cuốn người nghe/đọc, thay vì cung cấp cho họ một sự thực.&lt;/p&gt;
&lt;p&gt;Bởi vì ngụy biện là những lí lẽ mà bề ngoài có vẻ logic, nên chúng có khả năng thuyết phục những người không chịu khó suy nghĩ, nhất là những người còn mang nặng cảm tính. Điều này giải thích tại sao nhiều người trong chúng ta tiếp nhận một cách thụ động quá nhiều những điều càn rỡ về thế giới chung quanh, kể cả những niềm tin tôn giáo, những mê tín dị đoan, những triết lí quái đảng, những thông tin sai lạc, v.v.. Cái tác hại của việc tiếp nhận thụ động này là nó làm cho chúng ta trở nên nô lệ với cảm tính, và dễ dàng trở thành những người cuồng tín.&lt;/p&gt;
&lt;p&gt;Để không trở thành những nô lệ, chúng ta cần phải suy nghĩ nghiêm túc. Suy nghĩ nghiêm túc là một quá trình hoạt động tri thức nhằm ý niệm hóa, ứng dụng, phân tích, tổng hợp, và (hay) đánh giá những thông tin được thu thập từ quan sát, kinh nghiệm, phản ánh, lí luận, hay liên lạc, như là một niềm tin cho hành động. Chúng ta cần phải dựa vào những giá trị tri thức với những đặc điểm như trong sáng, chính xác, nhất quán, có liên hệ, bằng chứng tốt, lí lẽ hợp lí, có chiều sâu, và công bình. Tức là, trước một câu phát biểu hay một đề nghị, chúng ta phải thẩm định lại kết cấu và nguyên tố của phát biểu hay đề nghị đó. Những kết cấu và nguyên tố này là: mục đích, vấn đề, giả định, quan niệm, bối cảnh, kết luận, ngụ ý, hậu quả, phạm vi tham khảo, và quan điểm khác.&lt;/p&gt;
&lt;p&gt;Theo dõi những tranh luận trên các forum, chúng ta thấy những hình thức tấn công cá nhân (thay vì tấn công vào luận điểm), xuyên tạc ý tưởng, chụp mũ, suy luận theo cảm tính, mỉa mai, đơn giản hóa vấn đề, v.v… xuất hiện hầu như hàng ngày, có khi hàng giờ. Vì những tần số của những loại ngụy biện xuất hiện quá nhiều như thế, nó thành một sự rập khuôn. Theo thời gian, rập khuôn trở thành “truyền thống”. Hậu quả của cái truyền thống này là những ai ra ngoài cái khuôn sáo của ngụy biện đều có thể bị xem là phi chính thống, dẫn đến một lối suy nghĩ và phán xét kỳ quặc&lt;/p&gt;
&lt;p&gt;Trong cái sự thực phức tạp, mờ mờ ảo ảo của vấn đề, có cái đẹp riêng. Không phải cái đẹp trơn tru, tròn trĩnh, nhưng là cái đẹp khắt khe của sự thật. Tương tự, một lời phát biểu nghịch lý có cái đẹp của nó, vì nó có thể đánh thức chúng ta về một thế giới phức tạp, một thế giới không nằm gọn trong đúng/sai, tốt/xấu, bạn/thù. Có lẽ đã đến lúc chúng ta nên vượt qua chính mình.&lt;/p&gt;
</description>
      </item>
    
      <item>
        <title>Apache httpd 2.4 and PHP 7 in macOS</title>
        <link>https://htr3n.github.io/2017/09/apache-httpd-php-macos/</link>
        <pubDate>Mon, 25 Sep 2017 00:00:00 +0000</pubDate>
        
        <guid>776fc45a8583b2f32643abe7df5de953</guid>
        <description>&lt;p&gt;Together, &lt;a href=&#34;https://httpd.apache.org&#34;&gt;Apache HTTP&lt;/a&gt; server, &lt;a href=&#34;https://php.net&#34;&gt;PHP&lt;/a&gt;, and &lt;a href=&#34;https://www.mysql.com&#34;&gt;MySQL&lt;/a&gt; form a powerful and popular combination for Web development. MacOS are often shipped with pre-installed versions of Apache HTTP server and PHP but these are often outdated and merely customised for macOS. The well-known bundles &lt;em&gt;*AMP&lt;/em&gt; (e.g. WAMP for Windows, LAMP for Linux, MAMP for Mac) are commonly used but also considered a tad bloated for the beginners like me ;).&lt;/p&gt;
&lt;p&gt;After few years of Java development, I turned myself into Web development, and in particular, PHP programming. As usual, I would start with pure PHP aspects that really help me to understand the fundamental concepts and techniques instead of being drown with everyone-known frameworks and their complexity and hard-to-understand magics. As a result, I first looked for a simple setup of Apache and PHP that best suits the beginning of my initial learning path. In this note, I write down what I learn from many sources on the Internet tweaked to suit my needs.&lt;/p&gt;
&lt;h2 id=&#34;goal&#34;&gt;Goal&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;Let&amp;rsquo;s assume that we want to set up an exemplary  Web development environment including Apache HTTP 2.4 server and PHP 7.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;strategies&#34;&gt;Strategies&lt;/h2&gt;
&lt;p&gt;A typical and well-documented approach is to load PHP processor as a module under Apache httpd using the directive &lt;code&gt;LoadModule&lt;/code&gt;. It is so-called &lt;a href=&#34;http://www.php.net/manual/en/install.unix.apache2.php&#34;&gt;&lt;em&gt;mod_php&lt;/em&gt;&lt;/a&gt; approach. However, this is now gradually out of favor of Web developers and hosting providers because the tight combination of PHP and Apache makes things difficult for monitoring, debugging, and scaling. One of the recent favorite strategies is to set up PHP as Fast-CGI using &lt;a href=&#34;http://php.net/manual/en/install.fpm.php&#34;&gt;PHP-FPM&lt;/a&gt; (FastCGI Process Manager). This method also brings several advantages including good support for nginx integration and &lt;a href=&#34;https://wiki.apache.org/httpd/PHP-FPM&#34;&gt;performance&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Based on the aforementioned analysis of strategies, I consider the following installation activities to fulfill that goal.&lt;/p&gt;
&lt;ol start=&#34;0&#34;&gt;
&lt;li&gt;Installing &lt;a href=&#34;https://brew.sh&#34;&gt;Homebrew&lt;/a&gt; (a sane package manager for macOS)&lt;/li&gt;
&lt;li&gt;Installing Apache HTTP server 2.4&lt;/li&gt;
&lt;li&gt;Installing PHP 7 and &lt;em&gt;PHP-FPM&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Putting all together&lt;/li&gt;
&lt;li&gt;Installing &lt;a href=&#34;http://www.thekelleys.org.uk/dnsmasq/doc.html&#34;&gt;DNSMasq&lt;/a&gt; (optional)&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;installation-and-configuration&#34;&gt;Installation and Configuration&lt;/h2&gt;
&lt;h3 id=&#34;homebrewhttpsbrewsh&#34;&gt;&lt;a href=&#34;https://brew.sh&#34;&gt;Homebrew&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Homebrew is currently a prominent and well-supported package managing solution for macOS. Installing Homebrew is rather straightforward. Nevertheless, you should be familiar with using the command line in order to easily get thing done. All you need is to launch the Terminal app (&lt;code&gt;/Applications/Utilities/Terminal.app&lt;/code&gt;) or even the better &lt;a href=&#34;https://www.iterm2.com&#34;&gt;iTerm 2&lt;/a&gt; and start executing terminal commands.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Note: From now on, the sign &lt;code&gt;$&lt;/code&gt; (if exists) will denote the user&amp;rsquo;s command line prompt where you will execute the terminal commands, except that you must not type &lt;code&gt;$&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Homebrew requires Xcode&amp;rsquo;s command line tooling so we must install it first.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Install Xcode command line tooling&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ xcode-select --install
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Next we start installing Homebrew using a one-line command.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/usr/bin/ruby -e &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;By default, Homebrew will be installed into &lt;code&gt;/usr/local/Cellar&lt;/code&gt; and use &lt;code&gt;/usr/local&lt;/code&gt; and its sub-folders for the its installed binary and configuration files. For more advanced settings and manual configurations, please refer &lt;a href=&#34;https://docs.brew.sh/Installation.html&#34;&gt;here&lt;/a&gt;. To ensure that Homebrew is properly installed, we can simply check.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ brew --version
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Homebrew 1.3.8
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Homebrew/homebrew-core &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;git revision 22ac3; last commit 2017-12-02&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The command &lt;code&gt;brew config&lt;/code&gt; shows more information about the installed Homebrew.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;brew config
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now we should add some extra &lt;em&gt;taps&lt;/em&gt; (i.e. package repositories in Homebrew&amp;rsquo;s world) that contain packages we need, for instance, Apache HTTP server, PHP, and MySQL along with tools for running them as macOS services.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;brew tap homebrew/apache
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;brew tap homebrew/php
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;brew tap homebrew/services
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Last but not least, always make sure Homebrew is up-to-date.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;brew update
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;brew doctor
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;apache-http-serverhttpshttpdapacheorg&#34;&gt;&lt;a href=&#34;https://httpd.apache.org&#34;&gt;Apache HTTP server&lt;/a&gt;&lt;/h3&gt;
&lt;h4 id=&#34;installing-apache-http-server-24&#34;&gt;Installing Apache HTTP server 2.4&lt;/h4&gt;
&lt;p&gt;We can also use the pre-installed Apache HTTP server (from now on, Apache &lt;code&gt;httpd&lt;/code&gt;, Apache, &lt;code&gt;httpd&lt;/code&gt; will be used interchangeably) shipped with macOS. Nevertheless, I want to play around with the newer version. Apart from the Homebrew-based installation commands, the steps for setting up Apache are the same in either way.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;brew install httpd
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE 1&lt;/strong&gt;: Since Sep 30th, 2017 the Apache HTTP server package in Homebrew has been renamed from &lt;code&gt;httpd24&lt;/code&gt; to &lt;code&gt;httpd&lt;/code&gt; and the corresponding folders are also changed from &lt;code&gt;apache2&lt;/code&gt; to &lt;code&gt;httpd&lt;/code&gt;. This note has been updated with the newer versions. Apart from the aforementioned updates, the configuration steps remain the same though.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE 2&lt;/strong&gt;: When we use &lt;code&gt;brew install &amp;lt;package_name&lt;/code&gt; without any further options, Homebrew often accomplishes the installation faster by downloading a &lt;em&gt;bottled version&lt;/em&gt; (i.e. a &lt;em&gt;pre-compiled package&lt;/em&gt;) from &lt;a href=&#34;https://homebrew.bintray.com&#34;&gt;homebrew.bintray.com&lt;/a&gt;. If there are any extra compling options, Homebrew can download the package&amp;rsquo;s source code and compile the source. The compilation of a source package usually takes a a bit longer. For a simple and quick start, I mostly opt for the bottled versions of Apache server and PHP as the configured and compiled options are rather sufficient. After learning the fundamental aspects, I can turn to a more complex approach with lots of tweaks for further needs or experiments.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;By default, the Homebrew-based Apache server will use the ports &lt;code&gt;http/8080&lt;/code&gt; and &lt;code&gt;https/8443&lt;/code&gt; that do not need system administrator privileges. In my setup, I will go with this option as I simply want to run Apache with my user account. Nonetheless, you can tell Homebrew to install a version that use ports &lt;code&gt;80&lt;/code&gt; and &lt;code&gt;443&lt;/code&gt; by the option &lt;code&gt;--with-privileged-ports&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;brew install httpd --with-privileged-ports
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In case you want to experiment with the bleeding edge Apache server pulled from its development repository, use the option &lt;code&gt;--HEAD&lt;/code&gt; along with other options. For example,&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;brew install httpd --HEAD --with-privileged-ports
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Let&amp;rsquo;s assume the bottled &lt;code&gt;httpd&lt;/code&gt; is installed. The Apache server will be installed in the following folder &lt;code&gt;/usr/local/Cellar/httpd/2.4.29&lt;/code&gt;  (which might be different in your computer). You can check the Homebrew&amp;rsquo;s &lt;em&gt;Cellar&lt;/em&gt;, i.e. where Homebrew puts installed packages, with &lt;code&gt;brew --cellar&lt;/code&gt;. The precise location of &lt;code&gt;httpd&lt;/code&gt; in a bit complex nerdy form is &lt;code&gt;$(brew --cellar)/httpd/$(brew list --versions httpd | cut -d &#39; &#39; -f 2)&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cd &lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;brew --cellar&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt;/httpd/&lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;brew list --versions httpd | cut -d &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39; &amp;#39;&lt;/span&gt; -f 2&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;configuring-apache-server&#34;&gt;Configuring Apache server&lt;/h4&gt;
&lt;p&gt;The main configuration file &lt;code&gt;httpd.conf&lt;/code&gt; can be located at &lt;code&gt;/usr/local/etc/httpd&lt;/code&gt;. There are some directives and options that you may want to notice or change ( &lt;code&gt;#&lt;/code&gt;  starts a comment).&lt;/p&gt;
&lt;p&gt;There is a default directive &lt;code&gt;Listen 8080&lt;/code&gt; denoting the port where Apache server will be listening. You can change it to your favourite one or the one that suits your projects. Note that if you change to a port in the range from &lt;code&gt;1-1023&lt;/code&gt; (so-called privileged ports), you need an administrator role to run the &lt;code&gt;httpd&lt;/code&gt; process. Because I need to create virtual hosts for various projects, I have to configure &lt;code&gt;httpd&lt;/code&gt; to listen at a particular address and port, which is &lt;code&gt;127.0.0.1:8080&lt;/code&gt; in my setting.&lt;/p&gt;
&lt;p&gt;The directives &lt;code&gt;LoadModule&lt;/code&gt; will enable some Apache HTTP modules we need for configuring PHP-FPM such as &lt;code&gt;mod_proxy&lt;/code&gt;and &lt;code&gt;mod_proxy_fcgi&lt;/code&gt; (disabled by default).&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-apacheconf&#34; data-lang=&#34;apacheconf&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Listen &lt;span style=&#34;color:#ae81ff&#34;&gt;127.0.0.1&lt;/span&gt;:8080
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# LoadModule proxy_module libexec/mod_proxy.so&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# LoadModule proxy_fcgi_module libexec/mod_proxy_fcgi.so&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Apache server can be started by using either &lt;code&gt;apachectl start&lt;/code&gt; or &lt;code&gt;brew services start httpd&lt;/code&gt;. Note that the latter also installs a snippet to run Apache &lt;code&gt;httpd&lt;/code&gt; as a startup service.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;brew services start httpd
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;brew services list
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;running-and-testing&#34;&gt;Running and Testing&lt;/h4&gt;
&lt;p&gt;We use the following commands to start, stop, or restart &lt;code&gt;httpd&lt;/code&gt;, respectively.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;brew services start httpd
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;brew services stop httpd
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;brew services restart httpd
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To see whether Apache &lt;code&gt;httpd&lt;/code&gt; is up and running, you just start your Web browser and point to the URL &lt;a href=&#34;http://localhost:8080&#34;&gt;&lt;code&gt;http://localhost:8080&lt;/code&gt;&lt;/a&gt; and should see a simple Web page saying &lt;em&gt;&amp;ldquo;It works&amp;rdquo;&lt;/em&gt;. We can also check from the command line as well.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ launchctl list | grep httpd
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;91962	0	homebrew.mxcl.httpd
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ ps -ef | grep httpd
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;501&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;91962&lt;/span&gt;     &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;   &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;  8:51AM ??         0:00.07 /usr/local/opt/httpd/bin/httpd -D FOREGROUND
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;501&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;91968&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;91962&lt;/span&gt;   &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;  8:51AM ??         0:00.04 /usr/local/opt/httpd/bin/httpd -D FOREGROUND
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;501&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;91969&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;91962&lt;/span&gt;   &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;  8:51AM ??         0:00.04 /usr/local/opt/httpd/bin/httpd -D FOREGROUND
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;501&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;91970&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;91962&lt;/span&gt;   &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;  8:51AM ??         0:00.04 /usr/local/opt/httpd/bin/httpd -D FOREGROUND
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ lsof -Pni4 | grep httpd
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;httpd     &lt;span style=&#34;color:#ae81ff&#34;&gt;91962&lt;/span&gt; huytran    5u  IPv4 0xd51255ae3385c3d7      0t0  TCP *:* &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;CLOSED&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;httpd     &lt;span style=&#34;color:#ae81ff&#34;&gt;91968&lt;/span&gt; huytran    5u  IPv4 0xd51255ae3385c3d7      0t0  TCP *:* &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;CLOSED&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;httpd     &lt;span style=&#34;color:#ae81ff&#34;&gt;91969&lt;/span&gt; huytran    5u  IPv4 0xd51255ae3385c3d7      0t0  TCP *:* &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;CLOSED&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;httpd     &lt;span style=&#34;color:#ae81ff&#34;&gt;91970&lt;/span&gt; huytran    5u  IPv4 0xd51255ae3385c3d7      0t0  TCP *:* &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;CLOSED&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We can also examine whether Apache server configuration file is correct:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ apachectl configtest
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Syntax OK
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ httpd -t
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Syntax OK
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;php-7httpphpnet&#34;&gt;&lt;a href=&#34;http://php.net&#34;&gt;PHP 7&lt;/a&gt;&lt;/h3&gt;
&lt;h4 id=&#34;install-php-and-php-fpm&#34;&gt;Install PHP and PHP-FPM&lt;/h4&gt;
&lt;p&gt;Likewise, I just use Homebrew to install newer/older versions of PHP ranging from 5.x to 7.x. I opt for the stable release of PHP 7.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;brew install php72
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The  default installation of PHP 7 almost covers several useful aspects including a PHP module &lt;code&gt;libphp7.so&lt;/code&gt; that can be integrated with Apache HTTP server via the directive &lt;code&gt;LoadModule&lt;/code&gt; and PHP-FPM that can be used as FastCGI.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ php -version
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;PHP 7.2.0 &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;cli&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;built: Dec  &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;2017&lt;/span&gt; 11:27:08&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt; NTS &lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Copyright &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;c&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; 1997-2017 The PHP Group
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Zend Engine v3.2.0, Copyright &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;c&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; 1998-2017 Zend Technologies
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;php-configurations&#34;&gt;PHP configurations&lt;/h4&gt;
&lt;p&gt;The main configuration file of PHP is &lt;code&gt;php.ini&lt;/code&gt; as shown below.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Configuration File &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;php.ini&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; Path: /usr/local/etc/php/7.2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Loaded Configuration File:         /usr/local/etc/php/7.2/php.ini
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Scan &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; additional .ini files in: /usr/local/etc/php/7.2/conf.d
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Additional .ini files parsed:      &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;none&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The default setting in &lt;code&gt;/usr/local/etc/php/7.2/php.ini&lt;/code&gt; is quite sufficient for simple development purposes. We may tweak later if necessary but can leave it for now.&lt;/p&gt;
&lt;h4 id=&#34;starting-php-fpm&#34;&gt;Starting PHP-FPM&lt;/h4&gt;
&lt;p&gt;The configuration for PHP-FPM is &lt;code&gt;/usr/local/etc/php/7.2/php-fpm.conf&lt;/code&gt;. Note the last lines in this file&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ini&#34; data-lang=&#34;ini&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;;include=/usr/local/etc/php/7.1/php-fpm.d/*.conf&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You can remove the semi-colon to enable the inclusion of other configurations and/or might also change the path to whether it fits your development environment. In the folder &lt;code&gt;/usr/local/etc/php/7.1/php-fpm.d/*&lt;/code&gt;, there is a file &lt;code&gt;www.conf&lt;/code&gt; that can be used as a starting point for setting up your own PHP-FPM.&lt;/p&gt;
&lt;p&gt;Now we can start PHP-FPM to see whether everything is fine before doing some extra configuration steps.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ brew services start php72
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt;&amp;gt; Successfully started &lt;span style=&#34;color:#e6db74&#34;&gt;`&lt;/span&gt;php72&lt;span style=&#34;color:#e6db74&#34;&gt;`&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;label: homebrew.mxcl.php72&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ brew services stop php72
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Stopping &lt;span style=&#34;color:#e6db74&#34;&gt;`&lt;/span&gt;php72&lt;span style=&#34;color:#e6db74&#34;&gt;`&lt;/span&gt;... &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;might take a &lt;span style=&#34;color:#66d9ef&#34;&gt;while&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt;&amp;gt; Successfully stopped &lt;span style=&#34;color:#e6db74&#34;&gt;`&lt;/span&gt;php72&lt;span style=&#34;color:#e6db74&#34;&gt;`&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;label: homebrew.mxcl.php72&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ brew services restart php72
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The command &lt;code&gt;brew services start php72&lt;/code&gt; can create the file &lt;code&gt;homebrew.mxcl.php72.plist&lt;/code&gt; in &lt;code&gt;~/Library/LaunchAgents&lt;/code&gt; for starting up.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ launchctl list | grep php
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;47728	0	homebrew.mxcl.php72
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ ps -ef | grep php-fpm
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;putting-all-together&#34;&gt;Putting all together&lt;/h3&gt;
&lt;p&gt;After basically finishing the installation of Apache, PHP 7 and PHP-FPM, we start putting these pieces together.&lt;/p&gt;
&lt;h4 id=&#34;configurating-a-php-fpm-pool&#34;&gt;Configurating a &amp;lsquo;PHP-FPM&amp;rsquo; pool&lt;/h4&gt;
&lt;p&gt;PHP-FPM supports multiple resource &lt;em&gt;&lt;strong&gt;pools&lt;/strong&gt;&lt;/em&gt;. Each pool defines how PHP-FPM will create and manage processes. Let&amp;rsquo;s start with enabling the inclusion and handling of pools in &lt;code&gt;/usr/local/etc/php/7.2/php-fpm.conf&lt;/code&gt; by changing the following line&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ini&#34; data-lang=&#34;ini&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;;include=/usr/local/etc/php/7.2/php-fpm.d/*.conf&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;to (i.e. uncommenting it)&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ini&#34; data-lang=&#34;ini&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;include&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;/usr/local/etc/php/7.2/php-fpm.d/*.conf&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then we can leverage the stock configuration in &lt;code&gt;/usr/local/etc/php/7.2/php-fpm.d/www.conf&lt;/code&gt;. In my case, I have cleaned up &lt;code&gt;www.conf&lt;/code&gt; and kept a simple configuration as following for the sake of readability. The configuration explains for itself.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ini&#34; data-lang=&#34;ini&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;[www]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;user&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;_www&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;group&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;_www&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;listen&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;127.0.0.1:9072&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;pm&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;dynamic&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;pm.max_children&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;5&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;pm.start_servers&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;pm.min_spare_servers&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;pm.max_spare_servers&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The most important setting of each pool is the &lt;em&gt;TCP socket&lt;/em&gt; (including &lt;em&gt;IP address&lt;/em&gt; and &lt;em&gt;port&lt;/em&gt;) or Unix domain socket (UDS) that PHP-FPM will be receiving FastCGI requests. This will be set using the directive &lt;code&gt;listen&lt;/code&gt; . A typical setting of PHP-FPM is &lt;code&gt;listen = 127.0.0.1:9000&lt;/code&gt;. As I might want to install multiple PHP versions for testing, I will change the port to &lt;code&gt;9072&lt;/code&gt; that corresponds to the PHP version 7.2.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Note that we can also configure PHP-FPM to serve at a &lt;a href=&#34;https://en.wikipedia.org/wiki/Unix_domain_socket&#34;&gt;Unix domain socket&lt;/a&gt; (UDS) because PHP-FPM and &lt;code&gt;httpd&lt;/code&gt; processes are running in the same host. To do that, the directive &lt;code&gt;listen&lt;/code&gt; must be changed, for example, &lt;code&gt;listen = /usr/local/var/run/php72-fpm.sock&lt;/code&gt;. This approach would need extra effort to configure Apache to use PHP-FPM via UDS that we will visit later near the end of this guide.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Now as I want to check whether PHP-FPM will be up and running with the above changes, I restart PHP-FPM and check the open ports &lt;code&gt;9072&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ brew services restart php72
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ ps -ef | grep php-fpm
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ lsof -Pni4 | grep php-fpm
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;php-fpm   &lt;span style=&#34;color:#ae81ff&#34;&gt;53180&lt;/span&gt; huytran    6u  IPv4 0xd51255ae2d4097b7      0t0  TCP 127.0.0.1:9072 &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;LISTEN&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;php-fpm   &lt;span style=&#34;color:#ae81ff&#34;&gt;53187&lt;/span&gt; huytran    0u  IPv4 0xd51255ae2d4097b7      0t0  TCP 127.0.0.1:9072 &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;LISTEN&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;php-fpm   &lt;span style=&#34;color:#ae81ff&#34;&gt;53188&lt;/span&gt; huytran    0u  IPv4 0xd51255ae2d4097b7      0t0  TCP 127.0.0.1:9072 &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;LISTEN&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;php-fpm-delegation&#34;&gt;PHP-FPM Delegation&lt;/h4&gt;
&lt;p&gt;I can define virtual hosts in Apache that suit my needs for separating different development projects. Instead of creating one large &lt;code&gt;httpd.conf&lt;/code&gt;, I will create separate virtual host configurations. Again, I will start with the exemplary virtual host configuration provided in &lt;code&gt;/usr/local/etc/httpd/extra/httpd-vhosts.conf&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Enabling &amp;lsquo;mod_proxy&amp;rsquo; and &amp;lsquo;mod_proxy_fcgi&amp;rsquo;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Change the following lines in &lt;code&gt;/usr/local/etc/httpd/httpd.conf&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-apacheconf&#34; data-lang=&#34;apacheconf&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# LoadModule proxy_module libexec/mod_proxy.so&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# LoadModule proxy_fcgi_module libexec/mod_proxy_fcgi.so&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;to&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-apacheconf&#34; data-lang=&#34;apacheconf&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;LoadModule proxy_module libexec/mod_proxy.so
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;LoadModule proxy_fcgi_module libexec/mod_proxy_fcgi.so
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Defining Virtual Hosts&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I want to define a PHP development project residing in &lt;code&gt;/Users/huytran/working/dev/dev-web/php&lt;/code&gt;. Therefore, I change &lt;code&gt;/usr/local/etc/httpd/httpd.conf&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-apacheconf&#34; data-lang=&#34;apacheconf&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Include /usr/local/etc/httpd/extra/httpd-vhosts.conf&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;to&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-apacheconf&#34; data-lang=&#34;apacheconf&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Include &lt;span style=&#34;color:#e6db74&#34;&gt;/usr/local/etc/httpd/extra/httpd-vhosts.conf&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;and then create a file &lt;code&gt;/usr/local/etc/httpd/extra/httpd-vhosts.conf&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-apacheconf&#34; data-lang=&#34;apacheconf&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;VirtualHost&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;*:8080&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ServerName php7.test
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    DocumentRoot &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/Users/huytran/working/dev/dev-web/php&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ProxyPassMatch ^/(.*\.php(/.*)?)$ fcgi://127.0.0.1:9072/Users/huytran/working/dev/dev-web/php/$1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    DirectoryIndex index.php index.html
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;Directory&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/Users/huytran/working/dev/dev-web/php&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		Require &lt;span style=&#34;color:#66d9ef&#34;&gt;all&lt;/span&gt; granted
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/Directory&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/VirtualHost&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Further information on Apache virtual hosts can be found &lt;a href=&#34;https://httpd.apache.org/docs/current/vhosts&#34;&gt;here&lt;/a&gt; or &lt;a href=&#34;https://httpd.apache.org/docs/current/vhosts/examples.html&#34;&gt;here&lt;/a&gt;. I can briefly explain some relevant directives used in my virtual host configuration:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;&amp;lt;VirtualHost&amp;gt;&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://httpd.apache.org/docs/current/mod/core.html#virtualhost&#34;&gt;&lt;!-- raw HTML omitted --&gt;&lt;/a&gt; is used to define a new virtual host with respect to a specific hostname or IP address.&lt;/li&gt;
&lt;li&gt;Syntax: &lt;code&gt;&amp;lt;VirtualHost addr[:port] [addr[:port]] ...&amp;gt; ... &amp;lt;/VirtualHost&amp;gt;&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;Here I use the wildcard &lt;code&gt;*:*&lt;/code&gt; to match any IP addresses and ports. Note that the port specified in a &lt;code&gt;&amp;lt;VirtualHost&amp;gt;&lt;/code&gt; does not affect the real port Apache 	&lt;code&gt;httpd&lt;/code&gt; is listening.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;ServerName&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://httpd.apache.org/docs/current/mod/core.html#servername&#34;&gt;ServerName&lt;/a&gt; is recommended in each &lt;code&gt;&amp;lt;VirtualHost&amp;gt;&lt;/code&gt; for resolution and matching. If absent, Apache will use the global &lt;code&gt;ServerName&lt;/code&gt; stated in &lt;code&gt;httpd.conf&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;In my case, I assign different &lt;code&gt;ServerName&lt;/code&gt;, &lt;code&gt;php7.test&lt;/code&gt; and &lt;code&gt;htmljs.test&lt;/code&gt;, respectively, for each project to distinguish them. As Apache mainly matches virtual hosts via IP addresses and it will resolve host names based on DNS servers, I will configure corresponding hostname resolution for &lt;code&gt;php7.test&lt;/code&gt; and &lt;code&gt;htmljs.test&lt;/code&gt; using &lt;code&gt;/etc/hosts&lt;/code&gt; or &lt;em&gt;DNSMasq&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;DocumentRoot&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://httpd.apache.org/docs/current/mod/core.html&#34;&gt;DocumentRoot&lt;/a&gt; specifies the place where Apache &lt;code&gt;httpd&lt;/code&gt; will look for files to serve relevant incoming request. In each case, &lt;code&gt;DocumentRoot&lt;/code&gt; will be the absolute path of my development project.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;ProxyPassMatch&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://httpd.apache.org/docs/current/mod/mod_proxy.html#proxypassmatch&#34;&gt;ProxyPassMatch&lt;/a&gt; is part of &lt;code&gt;mod_proxy&lt;/code&gt; that can map remote servers into local URLs using regular expressions.
&lt;ul&gt;
&lt;li&gt;Syntax: &lt;code&gt;ProxyPassMatch [regex] !|url [key=value [key=value ...]]&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;When Apache &lt;code&gt;httpd&lt;/code&gt; receives a request for a certain PHP file (e.g. &lt;code&gt;test.php&lt;/code&gt;) then it needs PHP to handle that request. The regular expression &lt;code&gt;^/(.*\.php(/.*)?)$&lt;/code&gt; is used to check whether the incoming request is for a &lt;code&gt;.php&lt;/code&gt; file.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$1&lt;/code&gt; is called back-reference, as it refers to the matched part of the regular expression corresponding to the outermost pair of parentheses. In case the expression matches the incoming request URI (i.e. the request corresponds to a file &lt;code&gt;.php&lt;/code&gt;, for instance, &lt;code&gt;/test.php&lt;/code&gt;) &lt;code&gt;$1&lt;/code&gt; will represent the request URI. As a request is often treated as relative path from the &lt;code&gt;DocumentRoot&lt;/code&gt;, we must add &lt;code&gt;DocumentRoot&lt;/code&gt; path before &lt;code&gt;$1&lt;/code&gt; to form an exact absolute path and hand it over to PHP-FPM by adding the prefix &lt;code&gt;fcgi://127.0.0.1:9072&lt;/code&gt;. Note that PHP-FPM is serving at &lt;a href=&#34;#configuring&#34;&gt;&lt;code&gt;127.0.0.1:9072&lt;/code&gt;&lt;/a&gt; and &lt;code&gt;fcgi://&lt;/code&gt; denotes the scheme FastCGI provided by &lt;code&gt;mod_proxy_fcgi&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;The project &lt;em&gt;&lt;strong&gt;htmljs.test&lt;/strong&gt;&lt;/em&gt; does not need PHP processing, therefore I do not set the directive &lt;code&gt;ProxyPassMatch&lt;/code&gt; there.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;DirectoryIndex&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://httpd.apache.org/docs/current/mod/mod_dir.html#directoryindex&#34;&gt;DirectoryIndex&lt;/a&gt; sets the list of resources for an indexing request. As I want to use PHP, I set &lt;code&gt;index.php&lt;/code&gt; as index resource backed up by the default &lt;code&gt;index.html&lt;/code&gt;. Note that &lt;code&gt;DirectoryIndex&lt;/code&gt; can also be set globally in &lt;code&gt;httpd.conf&lt;/code&gt; that affects the main server and can be inherited in all virtual hosts.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-apacheconf&#34; data-lang=&#34;apacheconf&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;IfModule&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;dir_module&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    DirectoryIndex index.php index.html
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/IfModule&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Note that &lt;code&gt;DirectoryIndex index.html&lt;/code&gt; is the default global option defined in &lt;code&gt;httpd.conf&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;&amp;lt;Directory&amp;gt;&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://httpd.apache.org/docs/current/mod/core.html#directory&#34;&gt;&lt;!-- raw HTML omitted --&gt;&lt;/a&gt; encloses the settings for folders, subfolders, and their contents.
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://httpd.apache.org/docs/current/mod/mod_authz_core.html#require&#34;&gt;&lt;code&gt;Require all granted&lt;/code&gt;&lt;/a&gt; : access is allowed unconditionally (authorization &lt;code&gt;mod_authz_core&lt;/code&gt;). We need this, otherwise Apache will return an error &lt;code&gt;403 Forbidden&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;hostname-resolution&#34;&gt;Hostname Resolution&lt;/h4&gt;
&lt;p&gt;As mentioned before, I will use the virtual host &lt;code&gt;php7.test&lt;/code&gt; in my macOS to refer to my corresponding Web development projects. The hostname is not known by Apache. Thus, I must tell it how to resolve this hostname. In my setting, all virtual hosts are sharing in the same local computer with the address &lt;code&gt;127.0.0.1&lt;/code&gt;. A simple  solution is to change the file &lt;code&gt;/etc/hosts&lt;/code&gt; where macOS will look for when resolving hostnames. This solution requires sufficient administration privilege.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ sudo open -e /etc/hosts
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Password: &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;enter your password here&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;After entering the administrator password, I will add two following lines to &lt;code&gt;/etc/hosts&lt;/code&gt;.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;127.0.0.1    php7.test
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;In case either you do not want to mess up system files like &lt;code&gt;/etc/hosts&lt;/code&gt; or you have several development projects, you can leverage &lt;code&gt;dnsmasq&lt;/code&gt; for automatically resolving hostnames with very simple configurations. Note that this is also the reason I chose the &lt;code&gt;.test&lt;/code&gt; for all of my development projects such that I can use &lt;code&gt;dnsmasq&lt;/code&gt; and only &lt;strong&gt;one line directive&lt;/strong&gt; to resolve the TLD (Top-Level Domain) &lt;code&gt;test&lt;/code&gt;. You can surely pick any TLD other than &lt;code&gt;test&lt;/code&gt; .&lt;/p&gt;
&lt;h4 id=&#34;testing-apache-and-php&#34;&gt;Testing Apache and PHP&lt;/h4&gt;
&lt;p&gt;Apart from the aforementioned tests, we need to check whether the integration of Apache and PHP-FPM is working. Let&amp;rsquo;s create a file &lt;code&gt;index.php&lt;/code&gt; in &lt;code&gt;/Users/huytran/working/dev/dev-web/php&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;?&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;php&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;echo&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;PHP Development Project&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Restart &lt;code&gt;httpd&lt;/code&gt; and PHP-FPM to apply these changes.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ brew services restart httpd
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ brew services restart php72
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Given no problems, the servers should be restarted smoothly. Then open your Web browser to the following URLs &lt;a href=&#34;http://php7.test:8080&#34;&gt;&lt;code&gt;http://php7.test:8080&lt;/code&gt;&lt;/a&gt;. If you see the content created above, our configuration is working.&lt;/p&gt;
&lt;h3 id=&#34;dnsmasqhttpwwwthekelleysorgukdnsmasqdochtml&#34;&gt;&lt;a href=&#34;http://www.thekelleys.org.uk/dnsmasq/doc.html&#34;&gt;DNSMasq&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Instead of altering system hosts &lt;code&gt;/etc/hosts&lt;/code&gt;, I can make use of &lt;code&gt;dnsmasq&lt;/code&gt; to conveniently resolve many hostnames used in my virtual hosts.&lt;/p&gt;
&lt;h4 id=&#34;installing-dnsmasq&#34;&gt;Installing DNSMasq&lt;/h4&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# update homebrew and install dnsmasq&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ brew update &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; brew install dnsmasq
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Copy the dnsmasq daemon configuration file to be loaded at system startup time&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ sudo cp &lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;brew list dnsmasq | grep /homebrew.mxcl.dnsmasq.plist$&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt; /Library/LaunchDaemons/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# start dnsmasq&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ sudo launchctl load -w /Library/LaunchDaemons/homebrew.mxcl.dnsmasq.plist
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;configuring-dnsmasq&#34;&gt;Configuring DNSMasq&lt;/h4&gt;
&lt;p&gt;After installing DNSMasq, let&amp;rsquo;s open the configuration file&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ open -e /usr/local/etc/dnsmasq.conf
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;and add the following line at the end.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;address=/app/127.0.0.1
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The above configuration line tells DNSMasq to resolve the TLD &lt;code&gt;dev&lt;/code&gt; to the local IP address &lt;code&gt;127.0.0.1&lt;/code&gt;. You can now use any hostnames like &lt;code&gt;this.is.a.development.project.test&lt;/code&gt; in Apache virtual hosts.&lt;/p&gt;
&lt;h4 id=&#34;configuring-macos-to-use-dnsmasq&#34;&gt;Configuring macOS to use DNSMasq&lt;/h4&gt;
&lt;p&gt;We have to tell macOS that DNSMasq is now a nameserver running at the local host. The configuration file is &lt;code&gt;/etc/resolv.conf&lt;/code&gt; specifies the nameservers for looking up hostnames. On the one hand, we should not mess up the system setting. Moreover, macOS might overwrite &lt;code&gt;/etc/resolv.conf&lt;/code&gt; when there are changes in Network setting. An elegant solution is to create a file in the folder &lt;code&gt;/etc/resolver/&lt;/code&gt;with the exact TLD managed by DNSMasq.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ sudo mkdir -p /etc/resolver/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ sudo sh -c &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;echo &amp;#34;nameserver 127.0.0.1&amp;#34; &amp;gt; /etc/resolver/test&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The aforementioned commands needs administrator privileges and will create a file &lt;code&gt;test&lt;/code&gt; with the content &lt;code&gt;nameserver 127.0.0.1&lt;/code&gt; in the folder &lt;code&gt;/etc/resolver/&lt;/code&gt;.&lt;/p&gt;
&lt;h4 id=&#34;testing-dnsmasq&#34;&gt;Testing DNSMasq&lt;/h4&gt;
&lt;p&gt;Now we can delete the lines added before in &lt;code&gt;/etc/hosts&lt;/code&gt; and start &lt;code&gt;dnsmasq&lt;/code&gt; (as &lt;code&gt;root&lt;/code&gt;) and test the resolving of hostnames.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# start dnsmasq&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ sudo brew services start dnsmasq
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# ping the hostnames&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ ping -c &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; php7.test
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;PING php7.test &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;127.0.0.1&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;56&lt;/span&gt; data bytes
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;64&lt;/span&gt; bytes from 127.0.0.1: icmp_seq&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; ttl&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;64&lt;/span&gt; time&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;0.040 ms
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# query hostname using dnsmasq running at 127.0.0.1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ dig php7.test @127.0.0.1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;;; ANSWER SECTION:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;php7.test.		0	IN	A	127.0.0.1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# test arbitrary hostnames ending with .test&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ dig an.arbitrary.host.test @127.0.0.1
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;using-proxy-fastcgi-via-handler&#34;&gt;Using Proxy FastCGI via Handler&lt;/h3&gt;
&lt;p&gt;Instead of configuring &lt;code&gt;ProxyPassMatch&lt;/code&gt; for each individual virtual host to handle &lt;code&gt;.php&lt;/code&gt; files, we can also set up directives in Apache &lt;code&gt;httpd.conf&lt;/code&gt; (global scope) or at the beginning of the virtual host configuration &lt;code&gt;localhost.conf&lt;/code&gt; (virtual host scope) via handlers.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;First comment out or delete the line &lt;code&gt;ProxyPassMatch ...&lt;/code&gt; in the virtual host configuration &lt;code&gt;/usr/local/etc/httpd/extra/httpd-vhosts.conf&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-apacheconf&#34; data-lang=&#34;apacheconf&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# ProxyPassMatch ^/(.*\.php(/.*)?)$ fcgi://127.0.0.1:9072/Users/huytran/working/dev/dev-web/php/$1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol start=&#34;2&#34;&gt;
&lt;li&gt;Then, add the following lines to either the end of  &lt;code&gt;/usr/local/etc/httpd/httpd.conf&lt;/code&gt; or the beginning of &lt;code&gt;/usr/local/etc/httpd/extra/httpd-vhosts.conf&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-apacheconf&#34; data-lang=&#34;apacheconf&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;Proxy&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;fcgi://localhost:9072/&amp;#34; enablereuse=on max=10&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/Proxy&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;FilesMatch&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;\.php$&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;If&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;-f %{REQUEST_FILENAME}&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        SetHandler &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;proxy:fcgi://127.0.0.1:9072/&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/If&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/FilesMatch&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://httpd.apache.org/docs/current/mod/core.html#filesmatch&#34;&gt;&amp;lt;FilesMatch&amp;gt;&lt;/a&gt; : defines the scope of the enclosed directives by filenames that match the regular expression.
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Syntax&lt;/em&gt;: &lt;code&gt;&amp;lt;FilesMatch regex&amp;gt; ... &amp;lt;/FilesMatch&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://httpd.apache.org/docs/current/mod/core.html#sethandler&#34;&gt;SetHandler&lt;/a&gt;: forces matching files to be processed by a handler.
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Syntax&lt;/em&gt;: &lt;code&gt;SetHandler handler-name|none|expression&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start=&#34;3&#34;&gt;
&lt;li&gt;Restart &lt;code&gt;httpd&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;handling-php-via-unix-domain-sockets&#34;&gt;Handling PHP via Unix Domain Sockets&lt;/h3&gt;
&lt;p&gt;As mentioned before, PHP-FPM can serve on &lt;em&gt;Unix domain sockets (UDS)&lt;/em&gt;, too. UDS is widely used in the Unix/Linux world for inter-process communication. To enable PHP-FPM listening on UDS, open file &lt;code&gt;/usr/local/etc/php/7.1/php-fpm.d/www.conf&lt;/code&gt; and change the directive  &lt;code&gt;listen&lt;/code&gt; .&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ini&#34; data-lang=&#34;ini&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;[www]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;listen&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;/usr/local/var/run/php72-fpm.sock&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now we must change the Apache configuration to adapt to UDS as well. In case we use &lt;code&gt;ProxyPassMatch&lt;/code&gt; directive, change it like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-apacheconf&#34; data-lang=&#34;apacheconf&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ProxyPassMatch ^/(.*\.php(/.*)?)$ unix:/usr/local/var/run/php72-fpm.sock|fcgi://127.0.0.1:9072/Users/huytran/working/dev/dev-web/php
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The change is to add &lt;code&gt;unix:/usr/local/var/run/php72-fpm.sock|&lt;/code&gt; before &lt;code&gt;fcgi://...&lt;/code&gt; and remove the captured request URI &lt;code&gt;/$1&lt;/code&gt; at the end.&lt;/p&gt;
&lt;p&gt;Similarly, if we switch to Apache handler as above, we update the Apache configuration accordingly.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-apacheconf&#34; data-lang=&#34;apacheconf&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;Proxy&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;unix:/usr/local/var/run/php72-fpm.sock|fcgi://localhost:9072/&amp;#34; enablereuse=on max=10&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/Proxy&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;FilesMatch&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;\.php$&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;If&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;-f %{REQUEST_FILENAME}&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        SetHandler &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;proxy:unix:/usr/local/var/run/php72-fpm.sock|fcgi://127.0.0.1:9072/&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/If&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/FilesMatch&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We should ensure the configurations are good and then restart the servers afterwards.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# check Apache config&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ apachectl -t
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Syntax OK
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# check php-fpm config&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ php-fpm -t
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;30-Sep-2017 19:39:46&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; NOTICE: configuration file /usr/local/etc/php/7.2/php-fpm.conf test is successful
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# restart servers&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ brew services restart httpd
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ brew services restart php72
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
      </item>
    
      <item>
        <title>Cách xưng hô họ hàng (st)</title>
        <link>https://htr3n.github.io/2016/08/cach-xung-ho/</link>
        <pubDate>Sun, 07 Aug 2016 00:00:00 +0000</pubDate>
        
        <guid>afeb8480d5ff6a6ebd77f63ec5194677</guid>
        <description>&lt;p&gt;Bài sưu tầm về cách xưng hô với họ hàng nội ngoại lưu lại đây thể tham khảo về sau.&lt;/p&gt;
&lt;h2 id=&#34;với-họ-nội-tức-là-họ-hàng-bên-cha&#34;&gt;Với họ nội (tức là họ hàng bên cha)&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Các anh của ba và vợ của họ = bác&lt;/li&gt;
&lt;li&gt;Các em trai của ba = chú.&lt;/li&gt;
&lt;li&gt;Vợ của em trai của ba = thím.&lt;/li&gt;
&lt;li&gt;Các em gái, chị gái của = cô.&lt;/li&gt;
&lt;li&gt;Chồng của em gái, chị gái của ba = dượng.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;với-họ-ngoại-tức-họ-hàng-bên-mẹ&#34;&gt;Với họ ngoại (tức họ hàng bên mẹ)&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Các anh, em trai của mẹ = cậu.&lt;/li&gt;
&lt;li&gt;Vợ của anh trai, em trai của mẹ = mợ&lt;/li&gt;
&lt;li&gt;Các chị, em gái của mẹ = dì.&lt;/li&gt;
&lt;li&gt;Chồng các chị, em gái của mẹ = dượng.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;còn-cách-xưng-hô-bên-gia-đình-sui-gia&#34;&gt;Còn cách xưng hô bên gia đình sui gia&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Vợ của em trai = em dâu.&lt;/li&gt;
&lt;li&gt;Chồng của em gái = em rể.&lt;/li&gt;
&lt;li&gt;Vợ của anh trai = chị dâu.&lt;/li&gt;
&lt;li&gt;Chồng của chị gái = anh rể.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Đặc biệt bạn có tới 8 cố gồm 4 cố là ông bà nội ba, ông bà ngoại ba và 4 cố nữa là ông bà nội mẹ, ông bà ngoại mẹ.&lt;/p&gt;
&lt;p&gt;Người miền Nam gộp chung các cố ông, cố bà (các cặp) thành một gọi cho dễ nhưng nên nhớ bạn chỉ có duy nhất 1 cố nội là ông bà nội của ba còn 3 cặp ông bà cố kia là cố ngoại hết theo quy định.&lt;/p&gt;
</description>
      </item>
    
      <item>
        <title>Khen con (st)</title>
        <link>https://htr3n.github.io/2015/07/khen-con-st/</link>
        <pubDate>Wed, 01 Jul 2015 00:00:00 +0000</pubDate>
        
        <guid>acedf56c9448764207b775b897edf09e</guid>
        <description>&lt;h2 id=&#34;thói-quen-khen-ngợi-con-giỏi-hay-khả-năng-sẵn-có-của-con&#34;&gt;Thói quen khen ngợi con giỏi hay khả năng sẵn có của con&lt;/h2&gt;
&lt;p&gt;Mình để thấy không chỉ cha mẹ Việt mà cả cha mẹ người nước ngoài nữa thường hay con &amp;ldquo;giỏi quá&amp;rdquo; &amp;ldquo;thông minh quá&amp;rdquo; &amp;ldquo;sao con làm nhanh vậy&amp;rdquo;. Mới hôm qua thôi, mình để ý có một bà mẹ đố đứa con hơn 2 tuổi của mình &amp;ldquo;con chó kêu như thế nào&amp;rdquo;, đứa bé trả lời &amp;ldquo;gâu,gâu&amp;rdquo;, thế là bà mẹ khen luôn &amp;ldquo;giỏi quá&amp;rdquo;. Ngày trước có dịp đi nhà thờ, mình để ý thấy những người ở trong Nam, cứ trẻ con làm gì tốt hay ngoan cũng quen miệng khen &amp;ldquo;giỏi quá&amp;rdquo; &amp;ldquo;ngoan quá&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Những khen ngợi như thế này có ảnh hưởng tới sự phát triển tính cách, cách nhìn nhận vấn đề của trẻ như thế nào?&lt;/p&gt;
&lt;h2 id=&#34;khen-ngợi-con-giỏi-thông-minh-là-không-tốt&#34;&gt;Khen ngợi con giỏi, thông minh là không tốt&lt;/h2&gt;
&lt;p&gt;Khen ngợi con cái là một việc bố mẹ nên làm vì lời khen giúp trẻ được khích lệ và tự tin hơn. Nhưng không phải lời khen nào cũng có tác dụng như vậy. Nghiên cứu chỉ ra rằng, khen ngợi con cái là &amp;ldquo;giỏi và thông minh&amp;rdquo; một cách chung chung thậm chí sẽ có tác dụng ngược lại. Cách cha mẹ khen ngợi con cái cũng ảnh hưởng rất lớn đến khả năng đối mặt với thất bại, sẵn sàng chấp nhận thử thách và kiên trì trước những vấn đề khó.&lt;/p&gt;
&lt;p&gt;Theo nghiên cứu của Carol Dwreck, Khi đối mặt với những vấn đề khó (hơn khả năng hiện tại của mình), những đứa trẻ quen được khen là thông minh có xu hướng rụt rè, không muốn giải quyết, do đó chúng tự hạn chế cơ hội học hỏi, nâng cao kiến thức, kĩ năng của mình. Ngược lại những đứa trẻ thường được khen ngợi bởi sự nỗ lực của mình thì vui vẻ, thậm chí rất yêu thích những vấn đề khó. Trước vấn đề khó, những đứa trẻ này thậm chí còn reo lên &amp;ldquo;Thật là thú vị, cháu thích những bài toán hóc búa kiểu này&amp;rdquo;. Và khi chúng thất bại, những đứa trẻ được khen là thông minh thường cảm thấy mất đi tự tin, trong khi những đứa trẻ được khen đã nỗ lực nói &amp;ldquo;có thể cháu đã chưa cố gắng hết sức mình&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Dr. Dweck nói &amp;ldquo;Khen ngợi trí thông minh của trẻ không những không nâng cao sự tự tin của trẻ mà còn khuyến khích chúng quen với việc lo lắng sợ thất bại và sẽ lảng tránh không chấp nhận thử thách&amp;rdquo; &amp;ldquo;Tuy nhiên khi trẻ được dạy về gia trị của việc tập trung, tìm chiến lược và chăm chỉ hết sức mình khi đối mắt với những vấn đề khó trong học tập, chúng sẽ được khuyến khích giữ vững động lực, sự tự tin và thành thích của mình&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&amp;ldquo;Những đứa trẻ được khen ngợi là thông minh thường quan tâm đến việc xem những bạn khác làm như thế nào hơn là quan tâm đến việc tìm tòi chiến lược mới để giải quyết vấn đề&amp;rdquo;&lt;/p&gt;
&lt;h2 id=&#34;khen-con-như-thế-nào&#34;&gt;Khen Con Như Thế Nào&lt;/h2&gt;
&lt;h3 id=&#34;khen-ngợi-sự-cẩn-thận&#34;&gt;Khen ngợi sự cẩn thận&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&amp;ldquo;Con làm rất là tỉ mỉ, cẩn thận. Thảo nào mà mẹ thấy không vết mực nào rây ra ngoài cả&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Sự tỉ mỉ cẩn thận của con đã đem lại kết quả tốt rồi, con thấy ko?&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;khen-ngợi-sự-bình-tĩnh&#34;&gt;Khen ngợi sự bình tĩnh&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Mẹ rất vui vì con đã giữ được bình tĩnh mặc dù khối gỗ xây dựng của con cứ đổ xuống.&lt;/li&gt;
&lt;li&gt;Hôm nay con đã dạy mẹ một bài học về sự cần thiết của việc giữ bình tĩnh đó.&lt;/li&gt;
&lt;li&gt;Bình tĩnh luôn luôn giúp con đạt được mục đích đúng ko?&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;khen-ngợi-sự-nỗ-lực-kiên-trì-cố-gắng&#34;&gt;Khen ngợi sự nỗ lực, kiên trì, cố gắng&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&amp;ldquo;cuối cùng thì con cũng làm được rồi&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Mẹ rất hạnh phúc khi con biết nỗ lực như vậy&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Con đã rất cố gắng kiên trì và con đã thành công rồi&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;khen-ngợi-sự-chăm-chỉ&#34;&gt;Khen ngợi sự chăm chỉ&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&amp;ldquo;Con đã rất chăm chỉ ôn bài. Mẹ nghĩ con hoàn toàn xứng đáng với điểm 10 này&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&amp;ldquo;UI, hôm nay con mẹ chăm chỉ, hang say quá. Con thực sự làm mẹ tự hào về con.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;khen-ngợi-sự-tập-trung&#34;&gt;Khen ngợi sự tập trung&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&amp;ldquo;Mẹ để ý thấy con rất say sưa, tập trung xếp hình&amp;rdquo;. Có lẽ vì thế mà hôm nay con xếp tiến bộ hơn hẳn&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Mẹ để ý thấy con đã rất tập trung đọc sách. Chắc con đã thấy rất nhiều điều thú vị trong câu chuyện đó&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Mỗi lần trẻ thành công trong bất cứ việc gì, đặc biệt những việc đòi hỏi sự cố gắng, nỗ lực, cha mẹ hãy áp dụng những câu khen ngợi này. Sau một thời gian, hãy để ý sự thay đổi trong cách ứng xử của con trước thất bại hay những vấn đề khó và chờ đợi cảm giác hạnh phúc khi nghe con hào hứng khoe thành quả của mình và nói &amp;ldquo;Mẹ ơi, con làm đi làm lại, làm mãi cũng được, con đã rất kiên trì mẹ ạ&amp;rdquo;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Mỗi lời nói của cha mẹ đều có ảnh hưởng đến sự phát triển tính cách của con, tương lai của con&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;(Bài viết sưu tầm đâu đó trên mạng)&lt;/p&gt;
</description>
      </item>
    
      <item>
        <title>Transitional words (st)</title>
        <link>https://htr3n.github.io/2013/08/transitional-words-st/</link>
        <pubDate>Tue, 20 Aug 2013 00:00:00 +0000</pubDate>
        
        <guid>3abe7f511ad6afeffd4e79b792219df6</guid>
        <description>&lt;p&gt;Một số transitional words rất hữu dụng trong việc nối hoặc liên kết câu hoặc đoạn văn trong tiếng Anh. Để tránh sự lặp lại gây nhàm chán, các transitional words tương đương nên được dùng xen kẽ.&lt;/p&gt;
&lt;h3 id=&#34;addition&#34;&gt;Addition&lt;/h3&gt;
&lt;p&gt;also, besides, furthermore, in addition, moreover, again&lt;/p&gt;
&lt;h3 id=&#34;consequence&#34;&gt;Consequence&lt;/h3&gt;
&lt;p&gt;accordingly, as a result, consequently, hence, otherwise, so then, therefore, thus, there upon&lt;/p&gt;
&lt;h3 id=&#34;summarizing&#34;&gt;Summarizing&lt;/h3&gt;
&lt;p&gt;after all, all in all, all things considered, briefly, by and large, in any case, in any event, in brief, in conclusion, on the whole, in short, in summary, in the final analysis, in the long run, on balance, to sum up, to summarize, finally&lt;/p&gt;
&lt;h3 id=&#34;generalizing&#34;&gt;Generalizing&lt;/h3&gt;
&lt;p&gt;as a rule, as usual, for the most part, generally, generally speaking, ordinarily, usually&lt;/p&gt;
&lt;h3 id=&#34;restatement&#34;&gt;Restatement&lt;/h3&gt;
&lt;p&gt;in essence, in other words, namely, that is, that is to say, in short, in brief, to put it differently&lt;/p&gt;
&lt;h3 id=&#34;contrast-and-comparison&#34;&gt;Contrast and Comparison&lt;/h3&gt;
&lt;p&gt;contrast, by the same token, conversely, instead, likewise, on one hand, on the other hand, on the contrary, rather, similarly, yet, but, however, still, nevertheless, in contrast&lt;/p&gt;
&lt;h3 id=&#34;sequence&#34;&gt;Sequence&lt;/h3&gt;
&lt;p&gt;at first, first of all, to begin with, in the first place, at the same time, for now, for the time being, the next step, in time, in turn, later on, meanwhile, next, then, soon, the meantime, later, while, earlier, simultaneously, afterward, in conclusion&lt;/p&gt;
&lt;h3 id=&#34;diversion&#34;&gt;Diversion&lt;/h3&gt;
&lt;p&gt;by the way, incidentally&lt;/p&gt;
&lt;h3 id=&#34;illustration&#34;&gt;Illustration&lt;/h3&gt;
&lt;p&gt;for example, for instance, for one thing&lt;/p&gt;
&lt;h3 id=&#34;similarity&#34;&gt;Similarity&lt;/h3&gt;
&lt;p&gt;likewise, similar, moreover&lt;/p&gt;
&lt;h3 id=&#34;direction&#34;&gt;Direction&lt;/h3&gt;
&lt;p&gt;here, there, over there, beyond, nearly, opposite, under, above, to the left, to the right, in the distance&lt;/p&gt;
</description>
      </item>
    
      <item>
        <title>Sắp xếp trích dẫn (citations) trong (La)TeX</title>
        <link>https://htr3n.github.io/2009/01/sap-xep-trich-dan-latex/</link>
        <pubDate>Thu, 15 Jan 2009 00:00:00 +0000</pubDate>
        
        <guid>3946525e2c9e696fdfff110dcd1bd0ea</guid>
        <description>&lt;p&gt;LaTeX cho phép tạo các trích dẫn (citations) để tham chiếu đến các tài liệu tham khảo tương ứng. Các trích dẫn, tùy theo định dạng (format/style) của tài liệu, có thể dạng số như &lt;code&gt;[1, 2]&lt;/code&gt; hoặc dạng chữ như &lt;code&gt;[Lamport94]&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Một ví dụ đơn giản như sau&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-tex&#34; data-lang=&#34;tex&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;\LaTeX&lt;/span&gt;{} &lt;span style=&#34;color:#66d9ef&#34;&gt;\cite&lt;/span&gt;{latex} is a document preparation system for the &lt;span style=&#34;color:#66d9ef&#34;&gt;\TeX&lt;/span&gt;{} &lt;span style=&#34;color:#66d9ef&#34;&gt;\cite&lt;/span&gt;{tex} typesetting program.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;sẽ tạo ra kết quả&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-tex&#34; data-lang=&#34;tex&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;LaTeX [1] is a document preparation system for the TeX [2] typesetting program.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Trong ví dụ trên, &lt;code&gt;[1]&lt;/code&gt; và &lt;code&gt;[2]&lt;/code&gt; là các trích dẫn. Tài liệu tham khảo tương ứng sẽ được để trong phần &lt;code&gt;\bibliography{}&lt;/code&gt;. Nhiều trích dẫn liên kế có thể được gom lại và liệt kê chung trong một cặp dấu ngoặc vuông như sau &lt;code&gt;[6, 4, 5, 22, 27, 29]&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Mặc định trong trường hợp nhiều trích dẫn, LaTeX không xếp thứ tự và không thu gọn cho dễ nhìn. Nếu muốn thu gọn, ví dụ như &lt;code&gt;[4–6, 22, 27, 29]&lt;/code&gt; thì có thể dùng &lt;a href=&#34;http://www.ctan.org/tex-archive/help/Catalogue/entries/natbib.html&#34;&gt;natbib&lt;/a&gt; hoặc &lt;a href=&#34;http://www.ctan.org/tex-archive/macros/latex/contrib/cite&#34;&gt;cite&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Hãy đặt những dòng sau ở phần đầu file &lt;code&gt;.tex&lt;/code&gt;, trước &lt;code&gt;\begin{document}&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-tex&#34; data-lang=&#34;tex&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;\usepackage&lt;/span&gt;{cite}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;hoặc&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-tex&#34; data-lang=&#34;tex&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;\usepackage&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;[sort&amp;amp;compress]&lt;/span&gt;{natbib}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Sau đó, chạy latex/pdflatex và bibtex như bình thường. Dạng trích dẫn trong bài sẽ được sắp xếp và nhóm lại hợp lý và dễ nhìn hơn. Gói &lt;code&gt;natbib&lt;/code&gt; có một đặc điểm là tương thích tốt với gói &lt;code&gt;hyperref&lt;/code&gt; (dùng để tạo các liên kết trong tài liệu pdf). Do đó, nếu cần dùng &lt;a href=&#34;http://tug.ctan.org/pkg/hyperref&#34;&gt;hyperref&lt;/a&gt; thì bạn nên sử dụng &lt;a href=&#34;http://www.ctan.org/tex-archive/help/Catalogue/entries/natbib.html&#34;&gt;natbib&lt;/a&gt;.&lt;/p&gt;
</description>
      </item>
    
  </channel>
</rss>
