<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Daniel Ziltener</title>
    <description>The latest articles on DEV Community by Daniel Ziltener (@zilti_500).</description>
    <link>https://dev.to/zilti_500</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F343933%2F7e615a43-b99a-4d2c-904a-897fc8068ba4.jpeg</url>
      <title>DEV Community: Daniel Ziltener</title>
      <link>https://dev.to/zilti_500</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/zilti_500"/>
    <language>en</language>
    <item>
      <title>BastilleBSD Jail Manager - Containers Done Light</title>
      <dc:creator>Daniel Ziltener</dc:creator>
      <pubDate>Fri, 07 May 2021 12:28:46 +0000</pubDate>
      <link>https://dev.to/zilti/bastillebsd-jail-manager-containers-done-light-4iac</link>
      <guid>https://dev.to/zilti/bastillebsd-jail-manager-containers-done-light-4iac</guid>
      <description>&lt;h1&gt;
  
  
  What is BastilleBSD?
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;Bastille is an open-source system for automating deployment and management of containerized applications on FreeBSD.&lt;br&gt;
  -- &lt;em&gt;bastillebsd.org&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://bastillebsd.org"&gt;BastilleBSD&lt;/a&gt; is, at its core, a set of scripts to manage your FreeBSD jails. It handles things like creation, starting, stopping, port forwarding, and using and composing templates. It allows you to manage both "normal" and VNET jails, and if you use ZFS as your file system, it helps you to take snapshots from running jails and lets you restore them, even on other machines, too. And it's in the pipeline to even support Linux as a jail guest.&lt;/p&gt;

&lt;h1&gt;
  
  
  What are jails?
&lt;/h1&gt;

&lt;p&gt;Jails are a FreeBSD technology that started back in the 90s. The developers needed something more powerful and safe than a simple &lt;code&gt;chroot&lt;/code&gt; to isolate web applications and do things like having multiple different versions of PHP running on the same server. If you want to know a bit more about the history behind it, see &lt;em&gt;&lt;a href="http://phk.freebsd.dk/sagas/jails/"&gt;Jails - High value but shitty Virtualization&lt;/a&gt;&lt;/em&gt;. A jail is a virtual environment that takes a directory of the host's file system as its root, and uses the host's kernel, which makes it a very lightweight solution.&lt;/p&gt;

&lt;p&gt;You can actually use jails without a tool like BastilleBSD, they're built-in to FreeBSD, like the jails-inspired LXC is in the Linux kernel. But while that is possible and sometimes done, it is just more convenient to have tools to manage it and hide away some of the low level verbosity.&lt;/p&gt;

&lt;h1&gt;
  
  
  What will this series teach?
&lt;/h1&gt;

&lt;p&gt;Starting next week, we will dive into setting up the host machine, setting up different kinds of jails, how to create and use templates, how to test these templates, and how to snapshot/restore jails.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>freebsd</category>
      <category>docker</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Updated: Write and auto-deploy daemons on FreeBSD</title>
      <dc:creator>Daniel Ziltener</dc:creator>
      <pubDate>Wed, 28 Apr 2021 16:28:54 +0000</pubDate>
      <link>https://dev.to/zilti/updated-write-and-auto-deploy-daemons-on-freebsd-k7i</link>
      <guid>https://dev.to/zilti/updated-write-and-auto-deploy-daemons-on-freebsd-k7i</guid>
      <description>&lt;h2&gt;
  
  
  Goal
&lt;/h2&gt;

&lt;p&gt;Our goal is to write an rc.d file that allows us to start anything as a daemon, and an accompanying settings file, and to get to know the commands to use for automated deploy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Settings File
&lt;/h2&gt;

&lt;p&gt;We will start with the settings file. &lt;em&gt;Technically&lt;/em&gt; you can do in there whatever you want; if you have any sanity left, you will simply use it to set environment variables. This makes it easy to follow &lt;a href="https://12factor.net/config"&gt;the third rule of the Twelve-Factor App&lt;/a&gt;. And it really is that simple, you just add export statements, and make "dummy values" you will replace in your CI/CD script using sed, or replace them with variables and use &lt;code&gt;RENDER&lt;/code&gt; in Bastille:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;HTTP_PORT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;3000
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;POSTGRES_IP&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;SED_PGSQL_IP
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;POSTGRES_USERNAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;SED_PGSQL_USER
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;POSTGRES_PASSWORD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;SED_PGSQL_PASS
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This file has to be stored with the same name as your actual service file, but under &lt;code&gt;/usr/local/etc/rc.conf.d/&lt;/code&gt;. The RC system will auto-detect it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Daemon file
&lt;/h2&gt;

&lt;p&gt;This one is going to be a little bit longer. Let's first take a look at the whole script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/sh&lt;/span&gt;

&lt;span class="c"&gt;# PROVIDE: location_service&lt;/span&gt;
&lt;span class="c"&gt;# REQUIRE: LOGIN DAEMON NETWORKING&lt;/span&gt;
&lt;span class="c"&gt;# BEFORE: some_other_service&lt;/span&gt;
&lt;span class="c"&gt;# KEYWORD: shutdown&lt;/span&gt;

&lt;span class="nb"&gt;.&lt;/span&gt; /etc/rc.subr

&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;location_service
&lt;span class="nv"&gt;rcvar&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;_enable
&lt;span class="nv"&gt;pidfile&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/var/run/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.pid"&lt;/span&gt;
&lt;span class="nv"&gt;pidfile_child&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/var/run/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;_jvm.pid"&lt;/span&gt;
&lt;span class="nv"&gt;logfile&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/var/log/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.log"&lt;/span&gt;
&lt;span class="nv"&gt;location_service_chdir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/usr/local/share/location-service"&lt;/span&gt;

&lt;span class="nb"&gt;command&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/usr/sbin/daemon"&lt;/span&gt;
&lt;span class="nv"&gt;start_cmd&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"location_service_start"&lt;/span&gt;
&lt;span class="nv"&gt;procname&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"daemon"&lt;/span&gt;

load_rc_config &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
: &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;location_service_enable&lt;/span&gt;:&lt;span class="p"&gt;=no&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;

location_service_start&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    /usr/sbin/daemon &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="nt"&gt;-P&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;pidfile&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;pidfile_child&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="nt"&gt;-t&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;logfile&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; /usr/local/bin/java &lt;span class="nt"&gt;-jar&lt;/span&gt; location-service.jar
&lt;span class="o"&gt;}&lt;/span&gt;

run_rc_command &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Main variables
&lt;/h3&gt;

&lt;p&gt;There is some magic going on with the variable names, but that aside, it is a pretty standard shell script file. In this case, we are working with a location service that is to be run by the JVM, but it really doesn't matter - you can run literally anything as a service this way.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;PROVIDE&lt;/code&gt; is the name of the daemon; this is placed here again so potentially other daemons can REQUIRE it.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;REQUIRE&lt;/code&gt; are the daemons/targets that should be loaded before this one. The values should be quite self-explanatory.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;BEFORE&lt;/code&gt; is the inverse of REQUIRE; use it to tell the rc system to start this daemon before the mentioned one(s).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;KEYWORD&lt;/code&gt; can be either &lt;code&gt;nojail&lt;/code&gt; (will be ignored if inside a jail), &lt;code&gt;nostart&lt;/code&gt; (automatic startup procedure will ignore the script. In conjunction with the shutdown keyword, this can be used to write scripts that do something only at system shutdown), and &lt;code&gt;shutdown&lt;/code&gt; (service needs to be stopped before system shutdown).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;. /etc/rc.subr&lt;/code&gt; loads subroutines that enable the "magic" to run the service.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;rcvar&lt;/code&gt; is the flag that you can set to enable or disable your service in the rc.conf file.&lt;/li&gt;
&lt;li&gt;The two pidfiles are holding the process id of the daemon and the actual process, so the system can keep track of it.&lt;/li&gt;
&lt;li&gt;and the &lt;code&gt;location_service_chdir&lt;/code&gt; (or &lt;code&gt;whatever_you_name_it_chdir&lt;/code&gt;) sets the working directory.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The Daemon command
&lt;/h3&gt;

&lt;p&gt;FreeBSD ships with a program aptly called daemon, and we are using it to run our normal program as one. We thus tell the rc system to use /usr/sbin/daemon as the main &lt;code&gt;command&lt;/code&gt;, and tell it that the process started by it - &lt;code&gt;procname&lt;/code&gt; - will be called "daemon". We also tell it to run a custom starting function, &lt;code&gt;start_cmd&lt;/code&gt;, which in this case is called "location_service_start".&lt;/p&gt;

&lt;h3&gt;
  
  
  Configure the &lt;a href="https://www.unix.com/man-page/freebsd/8/daemon/"&gt;daemon&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;We configure the daemon by setting the flags when starting it. We have the following flags:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;-r&lt;/code&gt;: Restarts the process if it dies&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-f&lt;/code&gt;: Redirects standard input/output and standard error to /dev/null&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-p&lt;/code&gt;: the pidfile for the process you want to have daemonized&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-P&lt;/code&gt;: the pidfile of the daemon process itself - that is what the rc system needs&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-o&lt;/code&gt;: the log file to log to&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-t&lt;/code&gt;: gives the process a name (optional)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-u&lt;/code&gt;: (not used here): the user to run the process as&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This service file has to be stored under &lt;code&gt;/usr/local/etc/rc.d&lt;/code&gt; and be made executable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Automatic deployment
&lt;/h2&gt;

&lt;p&gt;We almost have it - the only thing missing are the commands for your CI/CD. It is really simple once you have both files at their respective locations.&lt;/p&gt;

&lt;p&gt;You can set the config variables using &lt;code&gt;sed -i.bak "s/SED_PGSQL_IP/${your_ci_var}/g" /usr/local/etc/rc.conf.d/location_service&lt;/code&gt;. Remember, if your variable contains the "/" character, you can use something else for sed, whatever character follows the "s" will be the separator.&lt;/p&gt;

&lt;p&gt;Enable the service using &lt;code&gt;sysrc -f /etc/rc.conf "location_service_enable=YES"&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;And finally, don't forget to actually (re-)start it using &lt;code&gt;service location_service restart&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Have fun!&lt;/p&gt;

</description>
      <category>devops</category>
      <category>freebsd</category>
      <category>daemon</category>
    </item>
    <item>
      <title>A Must-Read History Lesson For Devs: "The Eternal Mainframe"</title>
      <dc:creator>Daniel Ziltener</dc:creator>
      <pubDate>Mon, 26 Apr 2021 10:01:16 +0000</pubDate>
      <link>https://dev.to/zilti/a-must-read-history-lesson-for-devs-the-eternal-mainframe-18h8</link>
      <guid>https://dev.to/zilti/a-must-read-history-lesson-for-devs-the-eternal-mainframe-18h8</guid>
      <description>&lt;p&gt;Many younger developers run from hype to hype and are completely imprinted on their marketing overlords. The dev community grew too quickly to be contained by its own culture and history, as it - in my opinion - should have been. Because there are important lessons to be learned from the past that spans decades. "The Cloud" isn't a 21st century invention. Neither are "thin clients" and having all your data in said cloud. One of the best articles about this is the essay "The Eternal Mainframe"by Rudolf Winestock.&lt;/p&gt;

&lt;p&gt;I'd love to make dev.to aware of this piece of writing and like to hear your opinions on it!&lt;/p&gt;

&lt;p&gt;You can &lt;a href="http://www.winestockwebdesign.com/Essays/Eternal_Mainframe.html"&gt;find it here&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>history</category>
      <category>watercooler</category>
      <category>cloud</category>
      <category>cloudnative</category>
    </item>
    <item>
      <title>How to share your dev box with others in 5 minutes - Caddy edition</title>
      <dc:creator>Daniel Ziltener</dc:creator>
      <pubDate>Wed, 21 Apr 2021 14:08:23 +0000</pubDate>
      <link>https://dev.to/zilti/how-to-share-your-dev-box-with-others-in-5-minutes-caddy-edition-3me2</link>
      <guid>https://dev.to/zilti/how-to-share-your-dev-box-with-others-in-5-minutes-caddy-edition-3me2</guid>
      <description>&lt;p&gt;Sometimes you want to share what you are working on right now with your coworkers without either calling them over or pushing and waiting until it is deployed on the staging server. Then you take a look and find a bunch of complicated tools, proprietary helpers like ngrok, and a whole lot of similar stuff.&lt;/p&gt;

&lt;p&gt;Yet all you need is a reverse proxy and SSH. And here's how it's done, by example of Caddy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Main Server Configuration
&lt;/h2&gt;

&lt;p&gt;Add something like that to your Caddy file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mymachine.dev.example.com {
  reverse_proxy https://localhost:11010 {
    transport http {
      tls_insecure_skip_verify
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Dev Box Configuration
&lt;/h2&gt;

&lt;p&gt;On the dev box, make sure the webserver either reacts to the domain set up on the main server, or to every request in general. Since this is Caddy, I had to also disable the automatic certificate generation - I generate self-signed certs -, and the HTTPS redirect.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  auto_https off
}
localhost, devbox.local, mymachine.dev.example.com {
  tls /etc/ssl/localcerts/bundle.crt /etc/ssl/localcerts/server.key
  # Rest of your config
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And finally, as the last step, open up the SSH tunnel and reverse-forward the port:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/usr/bin/ssh -N -T -R 11010:localhost:443 user@example.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;N&lt;/code&gt; means "don't execute a remote command", &lt;code&gt;T&lt;/code&gt; means "don't allocate a terminal", and &lt;code&gt;R&lt;/code&gt; means to forward the port in reverse - from the target to the local machine.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;That is all!&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  RC Service File
&lt;/h2&gt;

&lt;p&gt;We're using FreeBSD machines set up using Bastille at work, so I created a simple RC file so the forwarding is done automatically at every devbox start:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/sh&lt;/span&gt;

&lt;span class="c"&gt;# PROVIDE: sompani_tunnel&lt;/span&gt;
&lt;span class="c"&gt;# REQUIRE: LOGIN DAEMON NETWORKING&lt;/span&gt;
&lt;span class="c"&gt;# KEYWORD: shutdown&lt;/span&gt;

&lt;span class="nb"&gt;.&lt;/span&gt; /etc/rc.subr

&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;sompani_tunnel
&lt;span class="nv"&gt;rcvar&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;_enable
&lt;span class="nv"&gt;pidfile&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/var/run/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.pid"&lt;/span&gt;
&lt;span class="nv"&gt;pidfile_child&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/var/run/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;_jvm.pid"&lt;/span&gt;
&lt;span class="nv"&gt;logfile&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/var/log/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.log"&lt;/span&gt;
&lt;span class="nv"&gt;sompani_tunnel_chdir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/usr/local/share/location-service"&lt;/span&gt;

&lt;span class="nb"&gt;command&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/usr/sbin/daemon"&lt;/span&gt;
&lt;span class="nv"&gt;start_cmd&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"sompani_tunnel_start"&lt;/span&gt;
&lt;span class="nv"&gt;procname&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"daemon"&lt;/span&gt;

load_rc_config &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
: &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;sompani_tunnel_enable&lt;/span&gt;:&lt;span class="p"&gt;=no&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;

sompani_tunnel_start&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    /usr/sbin/daemon &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="nt"&gt;-P&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;pidfile&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;pidfile_child&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="nt"&gt;-t&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;logfile&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; /usr/bin/ssh &lt;span class="nt"&gt;-N&lt;/span&gt; &lt;span class="nt"&gt;-T&lt;/span&gt; &lt;span class="nt"&gt;-R&lt;/span&gt; 11005:localhost:443 sompani-live
&lt;span class="o"&gt;}&lt;/span&gt;

run_rc_command &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>tutorial</category>
    </item>
    <item>
      <title>What is Functional Programming?</title>
      <dc:creator>Daniel Ziltener</dc:creator>
      <pubDate>Wed, 20 Jan 2021 22:00:13 +0000</pubDate>
      <link>https://dev.to/zilti/what-is-functional-programming-1ipc</link>
      <guid>https://dev.to/zilti/what-is-functional-programming-1ipc</guid>
      <description>&lt;p&gt;So you are interested in this fancy thing called functional programming. Good! Because that is what I want to teach you. Functional programming has been around for many decades, but only quite recently became the "hot new thing". And due to that, unlike so many other "hot new things" that happen to be bloated, overly complicated solutions to problems nobody really has, it is a quite simple, straightforward approach.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;But why functional programming?&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;Functional programming is a paradigm that emphasizes simplicity. Unlike object oriented programming, it separates data and logic, and in its pure form tries to keep logic and mutable state apart as good as possible, facilitating reasoning about the code, debugging, and testing.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;But today, we won't actually write code yet. Today, we want to get you into the mindset and thinking patterns to make the first lines of code as easy as possible for you!&lt;/p&gt;

&lt;h2&gt;
  
  
  No really, what is it?
&lt;/h2&gt;

&lt;p&gt;Okay, enough with the rambling about the good old days. What actually is functional programming? Well, what the community generally understands as functional programming these days is often synonymous with "pure functional programming". It is a &lt;em&gt;programming paradigm&lt;/em&gt; that takes a lot of ideas from how mathematics work. But don't worry, you don't need any kind of degree or to be especially talented in maths to learn it!&lt;/p&gt;

&lt;p&gt;...Oh, looks like we got a visitor! It's Vodblob McSteele. Vodblob is an absolute expert in multiple areas of programming and got famous through multiple books and courses, and decided to help me out in this one.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9y3IHr6s--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://community.codenewbie.org/remoteimages/i/o13vrfvc2c6llwiyr3ic.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9y3IHr6s--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://community.codenewbie.org/remoteimages/i/o13vrfvc2c6llwiyr3ic.png" alt="Vodblob adjusting its glasses"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The alien adjusts its glasses&lt;/em&gt; Nice to meet you! I'm Vodblob, I dedicated my life to studying all programming paradigms in existence. Some joke there is one for every eye I have, but so far there are still less. But today I am here to teach you functional programming! I can give you a few examples that make you think like a functional programmer in no time - without a single line of code to write! &lt;em&gt;It takes a little slate and a chalk pen out of its pocket and draws two separate circles on it.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Vodblob points at the left circle&lt;/em&gt; The base idea is that you work with functions that take one (or more) argument, give a value back, and do nothing else. We call those &lt;em&gt;pure functions&lt;/em&gt;, and for our explanation, they are all inside that left circle. A real life example for this would be your water heater in the office: you put in a liter of cold water, wait a bit, and get a liter of boiling water to pour into your tea cup. Always the same process. Unless the power is out - then you get nothing. But that applies to programming, too!&lt;/p&gt;

&lt;p&gt;But the problem with that approach is that when you only have pure functions, you get a program that takes an input and produces an output and some hot air - and nothing else. Usually you need more than that, because usually, you want that program to interact with you or with some changing data.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;It points at the right circle&lt;/em&gt; For that, we have &lt;em&gt;impure functions&lt;/em&gt;. Those do more than the pure ones discussed above: they might give you a different result each time, and they might even change the program state, display something on your screen, or other things in the program's environment, like updating file contents! A bit like eating chips: each time you reach into the bag, you get out a slightly different chip, you modify the bag's state, and at some point you might even reach in and find - nothing!&lt;/p&gt;

&lt;p&gt;As you've seen, I drew two distinct, separate circles to represent these groups, and for good reason. We want to keep those two categories separate unless interaction is absolutely necessary, because it is much easier to reason about, test, and debug pure functions and chained-together pure functions.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Vodblob takes a sip of tea out of its cup and pauses for a few seconds. It then takes the chalk pen again and draws a circle that encompasses both other circles.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Lastly, functional programming is &lt;em&gt;data centric&lt;/em&gt;. Your program state tends to be just &lt;em&gt;data structures&lt;/em&gt; - things like numbers, text strings, lists, and key-value maps -, and you use your vast collection of functions to extract, modify, and change the state, and make decisions based on these structures. This is the common denominator between the pure and impure functions, and their way of communicating. It is the background noise of the little universe the pure and impure bubbles live in.&lt;/p&gt;

&lt;p&gt;Functions themselves can be data, too - you can store functions inside these data structures, and pass them as arguments to other functions (which then become &lt;em&gt;higher-order functions&lt;/em&gt;). This last part is what allows you to do elegant data manipulation by simply combining functions you already have, and have them be applied to all kinds of data. This is very powerful!&lt;/p&gt;

&lt;h2&gt;
  
  
  Recap
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Vodblob harrumphs, thinks for a few seconds, and continues.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Alright. I think this is it for today. It might be, purely looking at the number of words, a short lesson, but it is a lot of stuff to digest. To recap:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pure Function:&lt;/strong&gt; A function that, given &lt;code&gt;X&lt;/code&gt;, always returns &lt;code&gt;Y&lt;/code&gt; and does nothing else. Example: 2+2=4.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Impure Function:&lt;/strong&gt; A function that, given &lt;code&gt;X&lt;/code&gt;, might give changing results and changes the program state or the environment. Example: display text, write file, increase counter.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data Structure:&lt;/strong&gt; The way data is kept in memory. This could be text, numbers, lists, key-value-maps, ...&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Program State / Environment:&lt;/strong&gt; The former is mutable data inside your program, the latter is everything from stuff in databases you program can access to what's shown on screen.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data centric:&lt;/strong&gt; your program state is just data structures, and your program uses that data to make decisions and alter said data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Higher-order functions:&lt;/strong&gt; Functions that take other functions as argument to operate on data.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What now?
&lt;/h2&gt;

&lt;p&gt;You might not have 100% understood a few things, but that is fine. You got a first insight, some food for thought, and the rest will come naturally as we progress.&lt;/p&gt;

&lt;p&gt;Next time, we will look at a functional programming language and start writing simple code. Until then, your homework is to look at the recap and let your mind run wild. &lt;strong&gt;What can you imagine doing with the possibilities listed above? What data structures can you imagine existing? Be creative!&lt;/strong&gt; It doesn't have to be realistic, after all you don't know yet what the languages actually work like. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;Vodblob wipes his slate clean, packs his backpack, and shakes your hand.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Oh to be a blank slate again, to learn it all again with fresh eyes... Well, in any case, we'll hopefully see each other again soon!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8IqWu-Py--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://community.codenewbie.org/remoteimages/i/tijxo0lohs610ef5iko4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8IqWu-Py--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://community.codenewbie.org/remoteimages/i/tijxo0lohs610ef5iko4.png" alt="Vodblob driving off into the sunset in its car"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>fundamentals</category>
      <category>beginners</category>
      <category>bootcamps</category>
      <category>clojure</category>
    </item>
    <item>
      <title>The tech to go from zero to shipping in just 3 months</title>
      <dc:creator>Daniel Ziltener</dc:creator>
      <pubDate>Thu, 30 Jul 2020 01:23:44 +0000</pubDate>
      <link>https://dev.to/zilti/the-tech-to-go-from-zero-to-shipping-in-just-3-months-2e1h</link>
      <guid>https://dev.to/zilti/the-tech-to-go-from-zero-to-shipping-in-just-3-months-2e1h</guid>
      <description>&lt;p&gt;As we all know, there are two things no startup ever has enough of: time and money. The constraints are even tighter when you are doing a spin-off as a startup, having to maintain the existing project &lt;em&gt;and&lt;/em&gt; starting a new one. We are a team of three people, with me as the sole developer, and we started three months ago completely from scratch. On the tech side, I could mainly rely on almost a decade of Clojure experience, and on a framework I haven't used before called Fulcro. Here is what we used:&lt;/p&gt;

&lt;h2&gt;
  
  
  Hosting: Google Cloud Services and Cloudinary
&lt;/h2&gt;

&lt;p&gt;I am generally not that much of a fan of clouds, but as a startup, we have a lot of free credits available for Google Cloud, so we opted to just spin up a few machines. I provisioned three &lt;a href="https://www.freebsd.org"&gt;FreeBSD&lt;/a&gt; machines using &lt;a href="https://www.ansible.com"&gt;Ansible&lt;/a&gt;, a build server, a dev server and a production server, and created a managed &lt;a href="https://www.postgresql.org"&gt;PostgreSQL&lt;/a&gt; instance. The deployment from the build to the dev and production servers is being done using the gcloud command line tools, as I didn't want to rely on IP addresses. It was quick and hassle-free to set all this up.&lt;/p&gt;

&lt;p&gt;Apart from that, we use &lt;a href="https://cloudinary.com"&gt;Cloudinary&lt;/a&gt; as our binary storage for PDF and image files used in our product.&lt;/p&gt;

&lt;h2&gt;
  
  
  Database: Datomic on PostgreSQL
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.datomic.com"&gt;Datomic&lt;/a&gt; is a sophisticated database that handles structuring the data with flexible schemas, uses a &lt;a href="http://www.learndatalogtoday.org/"&gt;Datalog&lt;/a&gt; flavour as query language, is tightly coupled with Clojure, and stores the data in time-key-value-action tuples. It marks entries as retracted instead of deleting and keeps track of every change, timestamping it, allowing for "time travel" without any additional software or logic. It is available as a cloud offering on AWS, or as an On-Prem offering for you to self-host. We went with the free single-server license for Datomic Pro for self hosting, using PostgreSQL as storage backend.&lt;/p&gt;

&lt;h2&gt;
  
  
  Programming Language: Clojure
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.clojure.org"&gt;Clojure&lt;/a&gt;, and its sibling ClojureScript, is a modern, functional Lisp. It provides concise code, minimal syntax, and immutable and flexible data structures. The macro system allows for extensibility, and since it compiles to both the JVM and JavaScript, it is possible to write pure-Clojure full-stack programs that even share code between frontend and backend. Dependency handling and compilation is handled using the excellent &lt;a href="https://shadow-cljs.org/"&gt;Shadow-CLJS&lt;/a&gt; tool that also supports NPM packages for the frontend.&lt;/p&gt;

&lt;h2&gt;
  
  
  Framework: Fulcro
&lt;/h2&gt;

&lt;p&gt;If you have spent any amount of time in the Clojure world, you know that Clojurians usually dislike using frameworks, instead insisting on mixing-and-matching libraries to form the application. Frameworks tend to feel constraining and lock you into a cage. But &lt;a href="http://www.fulcrologic.com"&gt;Fulcro&lt;/a&gt; and its &lt;a href="https://github.com/fulcrologic/fulcro-rad"&gt;Rapid Application Development&lt;/a&gt; addon is a quite different beast. While there is a certain core you'll want to use in every project, almost everything about it is optional. For example, you can write your frontend in something completely different. But we went with full-stack Fulcro, which is using React underneath to keep data in sync and allows us to use React components whenever we want to. &lt;/p&gt;

&lt;p&gt;RAD comes with powerful functionalities to validate and even generate the database schema (currently, Datomic and SQL backends are available), and based on that is able to generate reports and forms even with subforms to quickly have a way to manage all the data. &lt;/p&gt;

&lt;p&gt;To top it all off, there is an addon for Chromium called &lt;a href="https://chrome.google.com/webstore/detail/fulcro-inspect/meeijplnfjcihnhkpanepcaffklobaal"&gt;Fulcro Inspect&lt;/a&gt; that allows you to see the entire normalized in-browser database that keeps the program state, the transactions made and even allows you to run queries.&lt;/p&gt;

&lt;h2&gt;
  
  
  Planning: Trello and GitLab Issues
&lt;/h2&gt;

&lt;p&gt;We kept and keep track of what is going on and what we are doing using &lt;a href="https://trello.com"&gt;Trello&lt;/a&gt; and &lt;a href="https://gitlab.com"&gt;GitLab&lt;/a&gt; Issues. &lt;/p&gt;

&lt;p&gt;For that we made two Trello boards: one for the product planning that is mostly for the higher-level picture and groups features the way it makes sense for the business side of things, and a development board using &lt;a href="https://trello.com/templates/engineering/kanban-template-LGHXvZNL"&gt;the Kanban Template&lt;/a&gt; where I create smaller tasks in a way that makes sense to me as a developer, and I link the cards on the development board to the ones on the product board so we don't lose track of each other.&lt;/p&gt;

&lt;p&gt;And finally, we are using GitLab Issues for exactly what you'd expect - to keep track of and fix bugs in features that are already developed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Development: Spacemacs ;)
&lt;/h2&gt;

&lt;p&gt;At least for now, all code so far of this project has been written in Emacs using the cutting-edge branch of &lt;a href="https://develop.spacemacs.org/"&gt;Spacemacs&lt;/a&gt;. It provides an excellent Clojure environment thanks to &lt;a href="https://cider.mx/"&gt;CIDER&lt;/a&gt;, and has ways to integrate GitLab (using the Magit-extension Forge) and Trello (using org-trello). After years of keeping my own Emacs configuration up-to-date I finally made the actually quite small step over to Spacemacs-land, because my config already gravitated towards it anyway, and so far I enjoyed every second with it.&lt;/p&gt;

&lt;p&gt;This last thing probably didn't make it significantly faster, and there are great Clojure addons for Vim (Fireplace), IntelliJ (Cursive-Clojure) and VSCodium (Calva), but you know Emacs people - they just have to mention they're using Emacs. :)&lt;/p&gt;

</description>
      <category>clojure</category>
      <category>fulcro</category>
      <category>react</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Write and auto-deploy daemons on FreeBSD</title>
      <dc:creator>Daniel Ziltener</dc:creator>
      <pubDate>Tue, 14 Jul 2020 19:54:31 +0000</pubDate>
      <link>https://dev.to/zilti/write-and-auto-deploy-daemons-on-freebsd-5m6</link>
      <guid>https://dev.to/zilti/write-and-auto-deploy-daemons-on-freebsd-5m6</guid>
      <description>&lt;h2&gt;
  
  
  Goal
&lt;/h2&gt;

&lt;p&gt;Our goal is to write an rc.d file that allows us to start anything as a daemon, and an accompanying settings file, and to get to know the commands to use for automated deploy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Settings File
&lt;/h2&gt;

&lt;p&gt;We will start with the settings file. &lt;em&gt;Technically&lt;/em&gt; you can do in there whatever you want; if you have any sanity left, you will simply use it to set environment variables. This makes it easy to follow &lt;a href="https://12factor.net/config"&gt;the third rule of the Twelve-Factor App&lt;/a&gt;. And it really is that simple, you just add export statements, and make "dummy values" you will replace in your CI/CD script using sed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;HTTP_PORT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;3000
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;POSTGRES_IP&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;SED_PGSQL_IP
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;POSTGRES_USERNAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;SED_PGSQL_USER
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;POSTGRES_PASSWORD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;SED_PGSQL_PASS
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This file has to be stored with the same name as your actual service file, but under &lt;code&gt;/usr/local/etc/rc.conf.d/&lt;/code&gt;. The RC system will auto-detect it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Daemon file
&lt;/h2&gt;

&lt;p&gt;This one is going to be a little bit longer. Let's first take a look at the whole script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/sh&lt;/span&gt;

&lt;span class="c"&gt;# PROVIDE: location_service&lt;/span&gt;
&lt;span class="c"&gt;# REQUIRE: LOGIN DAEMON NETWORKING&lt;/span&gt;
&lt;span class="c"&gt;# KEYWORD: shutdown&lt;/span&gt;

&lt;span class="nb"&gt;.&lt;/span&gt; /etc/rc.subr

&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;location_service
&lt;span class="nv"&gt;rcvar&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;_enable
&lt;span class="nv"&gt;pidfile&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/var/run/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.pid"&lt;/span&gt;
&lt;span class="nv"&gt;pidfile_child&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/var/run/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;_jvm.pid"&lt;/span&gt;
&lt;span class="nv"&gt;logfile&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/var/log/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.log"&lt;/span&gt;
&lt;span class="nv"&gt;location_service_chdir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/usr/local/share/location-service"&lt;/span&gt;

&lt;span class="nb"&gt;command&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/usr/sbin/daemon"&lt;/span&gt;
&lt;span class="nv"&gt;start_cmd&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"location_service_start"&lt;/span&gt;
&lt;span class="nv"&gt;procname&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"daemon"&lt;/span&gt;

load_rc_config &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
: &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;location_service_enable&lt;/span&gt;:&lt;span class="p"&gt;=no&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;

location_service_start&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    /usr/sbin/daemon &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="nt"&gt;-P&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;pidfile&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;pidfile_child&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="nt"&gt;-t&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;logfile&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; /usr/local/bin/java &lt;span class="nt"&gt;-jar&lt;/span&gt; location-service.jar
&lt;span class="o"&gt;}&lt;/span&gt;

run_rc_command &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Main variables
&lt;/h3&gt;

&lt;p&gt;There is some magic going on with the variable names, but that aside, it is a pretty standard shell script file. In this case, we are working with a location service that is to be run by the JVM, but it really doesn't matter - you can run literally anything as a service this way.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;. /etc/rc.subr&lt;/code&gt; loads subroutines that enable the "magic" to run the service.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;rcvar&lt;/code&gt; is the flag that you can set to enable or disable your service in the rc.conf file.&lt;/li&gt;
&lt;li&gt;The two pidfiles are holding the process id of the daemon and the actual process, so the system can keep track of it.&lt;/li&gt;
&lt;li&gt;and the &lt;code&gt;location_service_chdir&lt;/code&gt; (or &lt;code&gt;whatever_you_name_it_chdir&lt;/code&gt;) sets the working directory.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The Daemon command
&lt;/h3&gt;

&lt;p&gt;FreeBSD ships with a program aptly called daemon, and we are using it to run our normal program as one. We thus tell the rc system to use /usr/sbin/daemon as the main &lt;code&gt;command&lt;/code&gt;, and tell it that the process started by it - &lt;code&gt;procname&lt;/code&gt; - will be called "daemon". We also tell it to run a custom starting function, &lt;code&gt;start_cmd&lt;/code&gt;, which in this case is called "location_service_start".&lt;/p&gt;

&lt;h3&gt;
  
  
  Configure the &lt;a href="https://www.unix.com/man-page/freebsd/8/daemon/"&gt;daemon&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;We configure the daemon by setting the flags when starting it. We have the following flags:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;-r&lt;/code&gt;: Restarts the process if it dies&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-f&lt;/code&gt;: Redirects standard input/output and standard error to /dev/null&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-p&lt;/code&gt;: the pidfile for the process you want to have daemonized&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-P&lt;/code&gt;: the pidfile of the daemon process itself - that is what the rc system needs&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-o&lt;/code&gt;: the log file to log to&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-t&lt;/code&gt;: gives the process a name (optional)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-u&lt;/code&gt;: (not used here): the user to run the process as&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This service file has to be stored under &lt;code&gt;/usr/local/etc/rc.d&lt;/code&gt; and be made executable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Automatic deployment
&lt;/h2&gt;

&lt;p&gt;We almost have it - the only thing missing are the commands for your CI/CD. It is really simple once you have both files at their respective locations.&lt;/p&gt;

&lt;p&gt;You can set the config variables using &lt;code&gt;sed -i.bak "s/SED_PGSQL_IP/${your_ci_var}/g" /usr/local/etc/rc.conf.d/location_service&lt;/code&gt;. Remember, if your variable contains the "/" character, you can use something else for sed, whatever character follows the "s" will be the separator.&lt;/p&gt;

&lt;p&gt;Enable the service using &lt;code&gt;sysrc -f /etc/rc.conf "location_service_enable=YES"&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;And finally, don't forget to actually (re-)start it using &lt;code&gt;service location_service restart&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Have fun!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Adding custom toolbar buttons to Fulcro 3 Workspaces cards</title>
      <dc:creator>Daniel Ziltener</dc:creator>
      <pubDate>Mon, 08 Jun 2020 17:55:32 +0000</pubDate>
      <link>https://dev.to/zilti/adding-custom-toolbar-buttons-to-fulcro-3-workspaces-cards-4306</link>
      <guid>https://dev.to/zilti/adding-custom-toolbar-buttons-to-fulcro-3-workspaces-cards-4306</guid>
      <description>&lt;p&gt;Recently I came across the problem that I wanted to use Workspaces' toolbar functionality - but with Fulcro 3 cards. There is no official documentation of doing this, so I ended up taking the standard Fulcro 3 card as a base and creating this custom card.&lt;br&gt;
I used the following imports:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;ns&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;util&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;:require&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;com.fulcrologic.fulcro.algorithms.merge&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;nubank.workspaces.core&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;nubank.workspaces.model&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;wsm&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;nubank.workspaces.ui&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ui&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;nubank.workspaces.ui.core&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;uc&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;com.fulcrologic.fulcro.dom&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dom&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;nubank.workspaces.card-types.fulcro3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ct.fulcro&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And created this card:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;defn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;custom-toolbar-card&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;fulcro-class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;::keys&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;toolbar-items&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;card-width&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;card-height&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;props&lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;::wsm/card-width&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;card-width&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="no"&gt;::wsm/card-height&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;card-height&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="no"&gt;::wsm/align&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:flex&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="no"&gt;::wsm/init&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;card&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;fulcro-card&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;ct.fulcro/fulcro-card-init&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;card&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;::ct.fulcro/wrap-root?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
                                                         &lt;/span&gt;&lt;span class="no"&gt;::ct.fulcro/root&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="n"&gt;fulcro-class&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="w"&gt;
           &lt;/span&gt;&lt;span class="n"&gt;card-id&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;::wsm/card-id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;card&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
           &lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;::ct.fulcro/app&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fulcro-card&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;assoc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fulcro-card&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="no"&gt;::wsm/render-toolbar&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;dom/div&lt;/span&gt;&lt;span class="w"&gt;
                 &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;mapv&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;uc/button&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:onClick&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="no"&gt;:fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;%&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;:text&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;%&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;toolbar-items&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
                 &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;uc/button&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:onClick&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;ct.fulcro/inspector-set-app&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;card-id&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="w"&gt;
                            &lt;/span&gt;&lt;span class="s"&gt;"Inspector"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
                 &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;uc/button&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:onClick&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;ui/restart-card&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;card-id&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="w"&gt;
                            &lt;/span&gt;&lt;span class="s"&gt;"Restart"&lt;/span&gt;&lt;span class="p"&gt;))))))})&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that I added the standard card-with and card-height parameters as well - you can leave those out - and added the default Fulcro 3 buttons.&lt;/p&gt;

&lt;p&gt;Buttons can now be added in the format &lt;code&gt;{:fn (fn [app-of-the-card] ...) :text "Button Text")}&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You can use it like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;ws/defcard&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;login-card&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;util/custom-toolbar-card&lt;/span&gt;&lt;span class="w"&gt;
             &lt;/span&gt;&lt;span class="n"&gt;account-forms/LoginForm&lt;/span&gt;&lt;span class="w"&gt;
             &lt;/span&gt;&lt;span class="no"&gt;::util/card-width&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="w"&gt;
             &lt;/span&gt;&lt;span class="no"&gt;::util/card-height&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="w"&gt;
             &lt;/span&gt;&lt;span class="no"&gt;::util/toolbar-items&lt;/span&gt;&lt;span class="w"&gt;
             &lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="no"&gt;:fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
                     &lt;/span&gt;&lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;m/merge-component!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;account-forms/LoginForm&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:ui/error&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"The credentials you entered are incorrect."&lt;/span&gt;&lt;span class="p"&gt;}))&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="no"&gt;:text&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"Trigger error"&lt;/span&gt;&lt;span class="p"&gt;}]))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, I made a card for a login form (&lt;code&gt;account-forms/LoginForm&lt;/code&gt;) which is a Fulcro 3 component. I added a toolbar item with the button text "Trigger error" that, when clicked, calls the fn, which is given the fulcro app of the card, updating the LoginForm to set a login error text.&lt;/p&gt;

</description>
      <category>clojure</category>
      <category>fulcro</category>
      <category>workspaces</category>
      <category>react</category>
    </item>
  </channel>
</rss>
