<?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: PNS11</title>
    <description>The latest articles on DEV Community by PNS11 (@cess11).</description>
    <link>https://dev.to/cess11</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%2F52830%2F6befdc7b-7664-465b-8fac-f9faf4725d39.png</url>
      <title>DEV Community: PNS11</title>
      <link>https://dev.to/cess11</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/cess11"/>
    <language>en</language>
    <item>
      <title>Fresh PHP development noIDE adventures</title>
      <dc:creator>PNS11</dc:creator>
      <pubDate>Fri, 24 May 2019 16:19:55 +0000</pubDate>
      <link>https://dev.to/cess11/fresh-php-development-noide-adventures-3nh4</link>
      <guid>https://dev.to/cess11/fresh-php-development-noide-adventures-3nh4</guid>
      <description>&lt;p&gt;Instant interaction response and common interfaces across different development tasks help my productivity immensely. Having started a new job in PHP web development where the host OS on the everyday workhorse is Windows 10 this turned out to be a bit of a challenge. I'll be doing legacy code maintenance in parallel with fresh development of the next, well thought out version of the same application, mainly on a PHP/MySQL/Linux stack. &lt;/p&gt;

&lt;p&gt;As it happens, targeting a Linux server environment from a Windows development box isn't exactly straightforward. If I'm not mistaken it is common in this situation to pay for and run a big IDE and possibly order around a fleet of handcrafted containers and wrestling with undebuggable Services rather than good old daemons. &lt;/p&gt;

&lt;p&gt;I immediately tried out the Windows Subsystem Linux, but it turned out to be somewhat underwhelming. Somehow I had expected more than the lack of GUI and workarounds with MobaXterm being terribly wobbly at best (just don't go there) so I guess I'd been away from Microsoft fairyland long enough to forget the gritty struggles one must endure here. &lt;/p&gt;

&lt;p&gt;However, I'm accustomed to SSH:ing into remote servers and fine with doing work in the terminal, which is basically the experience one gets with the WSL. Quite far from the full unixlike splendour but it is good enough. &lt;/p&gt;

&lt;p&gt;There I mainly do work on the new application, with &lt;a href="https://github.com/tmux/tmux/wiki"&gt;tmux&lt;/a&gt;, &lt;a href="https://vimawesome.com/"&gt;vim+plugins&lt;/a&gt; and &lt;a href="https://github.com/BurntSushi/ripgrep"&gt;ripgrep&lt;/a&gt; as the primary tooling, all of which install and run nicely under WSL. Once upon a time I used tag files but ripgrep chipped away at that and this time I haven't bothered with them at all. It's just too nice to&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;:!rg 'function weirdMethod' -A 5 -B 5 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;from within vim (or command line equivalent in a fresh tmux pane) and instantly get a view of how weirdMethod() is defined and commented and where it is. Especially when working with huge files that mix two browser layout languages, one browser scripting language and two backend languages freely and sometimes erratically it helps a lot to have a consistent, fast and regex capable interface to them. &lt;/p&gt;

&lt;p&gt;Filesharing with the WSL is fairly convenient, instead of using SSH/SFTP for transfer one can reach the host filesystem through a mount point. Other than that it is the regular headless VPS experience for the most part.  &lt;/p&gt;

&lt;p&gt;Since I needed a setup with particular versioning of PHP, web server and so on, I looked into Hyper-V and running a Linux VM as well. I'm just not a container type of monkey. This turned out to be easy at first, a quick reboot to turn on the hardware hypervisor support in BIOS and it was good to go with a well supported Linux image. &lt;/p&gt;

&lt;p&gt;VM:s are usually a bit sluggish but I soon found out that Hyper-V is aimed solely at mid to high end servers running headless guests. The UI was lagging intensely and constantly littered with graphical noise, for example, switching between workspaces in the window manager meant that I also needed to do a quick hop between tmux windows afterwards to render and clear up the screen to see my code. &lt;/p&gt;

&lt;p&gt;So I went looking for a remedy. At first I only came across forum threads patiently describing how this wasn't a technology for virtual desktop computing, but through some search I managed to find some &lt;a href="https://github.com/microsoft/linux-vm-tools"&gt;Linux VM tools from Microsoft&lt;/a&gt; and instructions for enabling XRDP connection to the VM. &lt;/p&gt;

&lt;p&gt;Happily I chugged through it, rebooted, chugged some more, rebooted again, and got the XRDP VNC login greeter form. Great success, or so I thought. &lt;/p&gt;

&lt;p&gt;There was one pretty obvious problem, logging in dumped me into the fairly hideous Ubuntu Unity desktop environment instead of my prefered and tailored i3 setup. &lt;/p&gt;

&lt;p&gt;Panicking and revulsed I fumbled out a terminal and ripped out the line containing 'unity' from the .xsession and promptly entered 'i3wm' instead. &lt;/p&gt;

&lt;p&gt;Quite the mistake. &lt;/p&gt;

&lt;p&gt;What happened after reboot and entering my credentials was a sudden death of the XRDP connection. Over and over. It took me a little bit of patiently retrying while thinking about the issue to realise my mistake. &lt;/p&gt;

&lt;p&gt;The i3 binary isn't named i3wm, hence the .xsession script crashed and burned on login, killing the XRDP connection. &lt;/p&gt;

&lt;p&gt;After some thinking and reading up on &lt;code&gt;help Set-VM&lt;/code&gt; in Powershell I figured out how to turn off XRDP on the Windows end, dropping me into the LightDM greeter instead, and also realised that I could just SSH into the machine to edit the .xsession file. So I did the fixing thing, and a few reboots later it had also been rudely pruned of all the rest of the preinstalled Unity-related calls the .xsession file had been cursed with. &lt;/p&gt;

&lt;p&gt;Compared to the basic Hyper-V VM-connection XRDP is really snappy and almost entirely free from weird graphical artifacts littering the screen every now and then. I had to change the terminal font to make it render better and be more easily read but other than that i3 just worked and pretty good too. &lt;/p&gt;

&lt;p&gt;If you are in a similar situation but haven't found that Github repo yet, go there and try it out. Just make sure your VM boots up to sshd being started (and reachable over your network or virtual switches) so you can &lt;a href="https://www.putty.org/"&gt;PuTTY&lt;/a&gt;-rollback any mistakes while axing the defaults those scripts install for you, just in case you manage to break the LightDM config and get locked out from that one as well. &lt;/p&gt;

&lt;p&gt;The commands for switching connection modes on the Windows end are these, to turn XRDP on first, off second:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PS C:\Windows\system32&amp;gt; Set-VM -VMName your-vm-name-here -EnhancedSessionTransportType HvSocket
PS C:\Windows\system32&amp;gt; Set-VM -VMName your-vm-name-here -EnhancedSessionTransportType VMBus
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Powershell probably needs admin privileges for it to take effect. It should always have, to keep the chance open of bricking one's Windows system and getting an upgrade to something unixlike. &lt;/p&gt;

&lt;p&gt;Other than this we also run some source control and keep remote repos, but that's rarely something one can decide as freely over as whether to suffer under the PHPStorm colossus or integrate oneself neatly and elegantly into a guest operating system with tmux-vim-ripgrep in WSL or Hyper-V. &lt;/p&gt;

&lt;p&gt;Oh, and as a royal grande finale, here's the regedit you need to run to switch Caps and left Ctrl:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;REGEDIT4

          [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layout]
          "Scancode Map"=hex:00,00,00,00,00,00,00,00,03,00,00,00,1d,00,3a,00,3a,00,1d,00,00,00,00,00
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Figuring that out was severely cumbersome and boring and nasty (and if this hex happens to be wrong, comment and I'll share the other I stored which then is sure to be the correct one). Compared to throwing in a xkbdmap or whatever into one's startup scripts RegEdit is a nightmare. And yes, I know there are applications one can soil the system with that supposedly kind of solve it, but I don't like how they dress so they aren't welcome. &lt;/p&gt;

</description>
      <category>php</category>
      <category>linux</category>
      <category>windows</category>
    </item>
    <item>
      <title>Notes on my first PHP job</title>
      <dc:creator>PNS11</dc:creator>
      <pubDate>Thu, 18 Oct 2018 17:14:13 +0000</pubDate>
      <link>https://dev.to/cess11/notes-on-my-first-php-job-7dl</link>
      <guid>https://dev.to/cess11/notes-on-my-first-php-job-7dl</guid>
      <description>

&lt;p&gt;This is kind of long and somewhat repetitive. That's sort of the idea, to show where a few bad decisions or structures will pop up everywhere, over and over. &lt;/p&gt;

&lt;h2&gt;Background&lt;/h2&gt;

&lt;p&gt;As a kid I dabbled in BASIC and Comal80 on a Commodore 64. The next computer was a 23 kilo 286 which managed Win 3.x over DOS and taught me batch scripting, then came others and I picked up some C, HTML and Linux before high school. There I was taught some Java, C++ and more web development, including standard SQL and JavaScript. The impression was that the schooling was abysmally bad and that adults knew nothing about computers, especially since my 'thesis', a project consisting of a small OpenGL engine at the end of high school, was graded solely on the documentation because the teacher didn't manage to get a C++ compiler and run it.&lt;/p&gt;

&lt;p&gt;So I vowed to never make a living as a programmer and only use my interest in computers for evil. Instead I played around with a little cracking and a lot of malicious input into web apps over the next years, in a kind of grey hat not-very-legal manner. &lt;/p&gt;

&lt;p&gt;Fast forward some eighteen years and I have changed my mind. At uni I studied some theology and law but never took a degree, in my spare time I passed through Python, Common Lisp, Clojure and then to the more obscure post-LISP language picolisp. This led to an offer I couldn't refuse, emigrate to the european south and work with modernising legacy PHP in an addiction business. &lt;/p&gt;

&lt;p&gt;Having no ethical issues with profiting from semicompulsory behaviour, I wouldn't turn down Twitter either, and wanting the experience I jumped on the offer and relocated. At the time I had also found that my home country was turning weird and dangerous to leftists so it was attractive to leave and watch from a distance. It turned out to be great fun, absolutely terrifying and a very valuable experience. &lt;/p&gt;

&lt;h2&gt;Organisation&lt;/h2&gt;

&lt;p&gt;When I arrived I found myself in a group of roughly twenty developers including two bosses in one room where managers from elsewhere in the company considered it a virtue to take part in micromanagement of development. The result was an interesting, fragmented development process where specs and UX analysis seemed taboo, more or less replaced by vague instructions like 'port this' and 'add this feature' and a lot of silence following questions and suggestions. &lt;/p&gt;

&lt;p&gt;After watching one boss integrating with a third party API for a couple of days I started getting assignments and worked away on them. Weeks passed without constructive feedback and it turned out that code review was not a part of the regular development work, and also that devs were explicitly forbidden review among peers. &lt;/p&gt;

&lt;p&gt;Instead a kind of code review was implemented after one of the bosses moved to another country and started working remotely. However, it was done by skimming through commit diff snippets and commenting on string concatenation or recommending hands down bad coding practices. Sometimes these practices were implemented instead of the present, more adequate solution as to avoid friction or conflict. &lt;/p&gt;

&lt;p&gt;Since every developer chugged along alone with little contact inbetween bosses also had to repeat themselves quite a bit, telling the same thing to different people, something which appeared to be inconvenient and wasteful to me. &lt;/p&gt;

&lt;p&gt;The lack of structured planning meant deadlines didn't exist, it was rather a culture of quick fix driven development and incremental design. No cohesion in the team parallelled with little cohesion in code output, also this an interesting choice of managerial doctrine. &lt;/p&gt;

&lt;p&gt;A result of this was that the code bases were quite irregular. One person liked warts on variables very much and no one else did. Another thought PHP lacked web templating and invented some in PHP, arguably the worlds most widely adopted web templating language. One had failed at creating REST API:s for years and adopted GraphQL instead, and thus coerced others to do it as well. Some liked Eloquent while others prefered passing in strings to Fluent QB for raw execution, yet others wrote a custom layer on a little of both. &lt;/p&gt;

&lt;p&gt;When there was quitting and laying off ahead it was obvious but not spoken of, it seemed like the bosses thought the rest of us didn't notice anything. It meant quite weird moods among some colleagues and a lot of loose rumour when someone no longer worked there. Perhaps this was the idea, I found that hard to tell.&lt;/p&gt;

&lt;p&gt;It took several months before I was first given a private talk about issues and performance, where I brought up concerns regarding this and some SQLi:s I'd found. I was told something something company policy and that we tend to patch such vulnerabilities when they were found. &lt;/p&gt;

&lt;p&gt;Leadership by fear, anxiety and alienation can be profitable but only in sectors where quality is a non-issue, where machines are the producers and humans are used for pulling levers or something similar. It seems it doesn't translate very well to the art of programming. &lt;/p&gt;

&lt;h2&gt;Lessons learned&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;If your boss is more impressed by LoC output or obedience than code quality and ability to reason about it, start looking for another job because when this becomes an issue you're going to get fired rather than promoted&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If every branch in a repo has a style of its own you'll learn a lot, but it will also slow down bughunting a lot unless it was you who wrote the code&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If there is no constructive feedback on your work you'll have trouble performing well &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A manager has the power of the payslip while you have the power of trust, hence you'll be more likely to be fired if your colleagues start trusting you more than their managers&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Don't work unpaid overtime, and if you did anyway, make sure to tell your superiors you have so they know that they owe you more than they thought&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;When confronted with incoherent code bases consistently write in your own style to the best of your ability and try to make sure the result is good, rather than ask superiors or colleagues about it&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Listen closely to what your colleagues are saying about past employees and what resulted in them no longer working there, this can help avoid sudden changes in your employment&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Code&lt;/h2&gt;

&lt;p&gt;What I thought would be modernising legacy code eventually turned out to be conservation and wrapping of it in more and more projects. The core application was an elderly publishing platform rewritten in the details over the years but never refactored. A term that happened to be used as a synonym to 'changing existing code' rather than the common technical meaning at that workplace. At first this was very confusing.&lt;/p&gt;

&lt;p&gt;This core was written in a procedural style with some OOP on top, ruminated for many years and having a high degree of interconnectivity between files and functions. The resulting complexity turned out as big red circles in PHPmetrics and quite challenging to anyone, regardless of previous experience. What had been described as microservice architecture was rather wrapping of bulky frameworks around new or old instances of this. &lt;/p&gt;

&lt;p&gt;At some point when developing new software one needs to make some strategic decisions about what kind of programmers one wants to write code for. If one is the only one at a company who appreciates higher-order functions and currying as a way to break down problems one should avoid it and make a series of classes and interfaces instead. &lt;/p&gt;

&lt;p&gt;On this issue I found no leadership and struggled quite a bit while figuring out that this was my issue and that I had to try and predict who might read my code later on. Not having a common idea of what kind of software shop the place should become seems to be bad for productivity. Instead the environment was one where old-timey for i &amp;lt; count(input) i++ was a viable pattern even though foreach was introduced in PHP 4 and a code review comment could consist of a demeaning comment about education and a link to the PHP manual on strings. Because apparently the problem with pasting unvalidated input into database queries are whether it is done with single or double quotes. &lt;/p&gt;

&lt;p&gt;While the absence of strategic discussion and peer based code review together with quick fix driven development makes it imperative for a junior to quickly learn new  tools and code patterns it also seems like it has some cost in the long run, since victorious debugging becomes reserved for the ruthless one cannot just assign anyone to a ticket without risking that they'll spend a week in circles. &lt;/p&gt;

&lt;p&gt;Increasingly I got better at quickly judging the code and found more and more serious issues to add to my private bug database. For some reason there was no common one. These findings alarmed me more and more, since I thought it too risky to have some of them in production. When sounding the alarm I was however met with an indifference I had not anticipated, and later I learned that some of these had been known for years and that those who made a fuss consistently had been laid off. &lt;/p&gt;

&lt;h2&gt;Lessons learned&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;When confronted with incoherent code, relax and follow the execution over and over in your mind until you understand it and why the output is as it is&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Thinking in incoherent code is demanding, never skip lunch because you'll get nowhere the last hours of the day&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If you aren't getting good criticism of your code you need to invent it yourself&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The worse the code, the more power is needed in your tooling as well as a solid understanding of command line scripting&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Coding is an art so insensitive comments about it are sure to hurt, use this might wisely and with consideration&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Don't give up bughunting until you have spent a fair bit of time breaking the application in creative ways&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Conclusions&lt;/h2&gt;

&lt;p&gt;I strongly recommend anyone willing to do PHP but lacking work experience to take a job at a place that will hire you on just a few lines crappy code and some talk about knowledge in areas that have nothing to do with the business they're in. &lt;/p&gt;

&lt;p&gt;You'll learn fast, learn a lot and see things that you otherwise would never understand how much you need to avoid until you've done the same mistake yourself and messed up bad. And this is very valuable, impossible to learn on your own (arguably you could pick some up in OSS dev) and will be with you for the rest of your life as a programmer. &lt;/p&gt;

&lt;p&gt;Next I'll be more useful and show the toolchain I got comfy with. &lt;/p&gt;


</description>
      <category>php</category>
      <category>juniordeveloper</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Let's build a picolisp guestbook</title>
      <dc:creator>PNS11</dc:creator>
      <pubDate>Mon, 23 Apr 2018 11:07:11 +0000</pubDate>
      <link>https://dev.to/cess11/lets-build-a-picolisp-guestbook-mkl</link>
      <guid>https://dev.to/cess11/lets-build-a-picolisp-guestbook-mkl</guid>
      <description>

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;This is a short write-up on a guestbook web app I wrote for practice some time ago. &lt;/p&gt;

&lt;p&gt;It renders a form for entering a message and posting it to a guestbook object. &lt;/p&gt;

&lt;p&gt;To run it you install picolisp, save the source code below as 'gub.l', then you do&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ pil gub.l +
: (new! '(+Gbk) 'nm "Your guestbook name here")
-&amp;gt; {2}
:(go)(wait)

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



&lt;p&gt;or replace the last line with &lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;:(bye)
$ pil gub.l -go -wait

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



&lt;p&gt;and now you can point a web browser to localhost:8080. &lt;/p&gt;

&lt;h2&gt;
  
  
  How-to
&lt;/h2&gt;

&lt;p&gt;A good place to start developing a web app is to design your data model. For a guestbook just about anything from loose message objects to a complex schema with users, roles and sub-guestbooks could be thought up in a short time. &lt;/p&gt;

&lt;p&gt;For this example I chose to go about halfway between the simplest possible, loose messages, and a model with an object holding messages in a list in one of its fields, naming them and making it easy to replace a guestbook without deleting all of the messages at once. &lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(class +Msg +Entity)
(rel hdr (+String))
(rel bdy (+String))
(rel sdr (+String))
(rel dor (+String))
(rel book (+Joint) msgs (+Gbk))

(class +Gbk +Entity)
(rel nm (+Ref +String))
(rel msgs (+List +Joint) book (+Msg))

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



&lt;p&gt;With a model like this one we can expose a certain '+Gbk object in the GUI by adjusting this line:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;*Gbk (car (collect 'nm '+Gbk))

# for example, (db 'nm '+Gbk "Certain Name")

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



&lt;p&gt;A more production ready way to do it would be to replace this with a function for browsing and selecting among available guestbooks. &lt;/p&gt;

&lt;p&gt;Fetching data from the GUI form is done by holding values in three global variables and then passing these as method parameters to the object held in '*Gbk. &lt;/p&gt;

&lt;p&gt;The method looks like this:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(dm addM&amp;gt; (Hdr Bdy Sdr) 
    (let  
        D (new! '(+Msg) 
            'hdr Hdr # header
            'bdy Bdy # message body
            'sdr Sdr # sender
            'dor (stamp)
            'book This )
        (put!&amp;gt; This 'msgs D)
    (commit 'upd) ))
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;It is possible to nest 'put!&amp;gt; and 'new! but it would be harder to read and extend, for example, if the newly created object should be added to more places in the database it is usually more convenient to have a 'let scoped symbol for doing so instead of relying on a nest of implicit symbol passing. &lt;/p&gt;

&lt;p&gt;Typically one doesn't use 'ht:Prin directly, it is a fairly low level function used by GUI components, but it is quite useful for experimentation and learning (and, of course, construction of new components). It is more idiomatic and a better practice to use '+Chart with a pilog expression, but it also requires a little more and harder to read code. &lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;            (for X (get *Gbk 'msgs) # one can use 'get 
                (with X # as well as 'with and the shortcuts 
                    (&amp;lt;h3&amp;gt; NIL (ht:Prin (: hdr)) )
                    (&amp;lt;br&amp;gt;)
                    (&amp;lt;p&amp;gt; NIL (ht:Prin (: bdy)) )
                    (&amp;lt;br&amp;gt;)
                    (&amp;lt;p&amp;gt; NIL (ht:Prin (pack (: sdr) " - " (: dor))) )
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;For the next steps in refining this application it could be a good idea to replace this presentation code with 'url&amp;gt; or chart constructs, or perhaps prepend the 'form with another one that lets the user choose among available guestbooks, perhaps giving the choice to create a new one. &lt;/p&gt;

&lt;h2&gt;
  
  
  The entire source code
&lt;/h2&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(load "@lib/http.l" "@lib/xhtml.l" "@lib/form.l")

# in a real application you would use 'allowed to restrict access to 
# certain directories and functions. 
# you would also put httpGate, nginx or somesuch between the Internet 
# and the port where your program is listening.

(class +Msg +Entity)
(rel hdr (+String))
(rel bdy (+String))
(rel sdr (+String))
(rel dor (+String))
(rel book (+Joint) msgs (+Gbk))

# here a TODO could be to write a method that outputs message contents

(class +Gbk +Entity)
(rel nm (+Ref +String))
(rel msgs (+List +Joint) book (+Msg))

(dm addM&amp;gt; (Hdr Bdy Sdr) 
    (let D (new! '(+Msg) 
        'hdr Hdr 
        'bdy Bdy
        'sdr Sdr 
        'dor (stamp)
        'book This )
        (put!&amp;gt; This 'msgs D)
    (commit 'upd) ))

(pool "gb.db")

(setq 
    *Gbk (car (collect 'nm '+Gbk)) # decide which guestbook we'll serve
     )

(de work ()
    (app) # sets up session handling
    (action # says there will be action in some web forms
        (html 0 "Guestbook" "@lib.css" NIL 
            (&amp;lt;h2&amp;gt; NIL "Picolisp guestbook")
            (&amp;lt;hr&amp;gt;)
            (form NIL 
        (&amp;lt;p&amp;gt; NIL "Message header:")
        (gui 'hdr '(+Var +TextField) '*MsgHdr 30)
                (do 2 (&amp;lt;br&amp;gt;))
        (&amp;lt;p&amp;gt; NIL "Message text:")
                (gui 'bdy '(+Var +TextField) '*MsgBdy 30 5)
                (do 2 (&amp;lt;br&amp;gt;))
        (&amp;lt;p&amp;gt; NIL "Your name:")
                (gui 'sdr '(+Var +TextField) '*MsgSdr 30)
                (do 2 (&amp;lt;br&amp;gt;))
                (gui '(+Button) "Send" 
                    '(ask "Post this message?" 
                        (addM&amp;gt; *Gbk *MsgHdr *MsgBdy *MsgSdr) )) )
            (&amp;lt;br&amp;gt;)
        (&amp;lt;hr&amp;gt;)
            (for X (get *Gbk 'msgs) # instead of '+Chart, '+QueryChart or 'url&amp;gt;
                (with X
                    (&amp;lt;h3&amp;gt; NIL (ht:Prin (: hdr)) )
                    (&amp;lt;br&amp;gt;)
                    (&amp;lt;p&amp;gt; NIL (ht:Prin (: bdy)) )
                    (&amp;lt;br&amp;gt;)
                    (&amp;lt;p&amp;gt; NIL (ht:Prin (pack (: sdr) " - " (: dor))) )
            (&amp;lt;br&amp;gt;) )) )))

(de go ()
    (server 8080 "!work") )

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



&lt;h2&gt;
  
  
  The end
&lt;/h2&gt;

&lt;p&gt;If you thought this was worthwhile reading, consider donating a coffee or two, &lt;a href="https://www.patreon.com/Stagling"&gt;Stagling@Patreon&lt;/a&gt;. &lt;/p&gt;


</description>
      <category>picolisp</category>
      <category>guestbook</category>
      <category>basics</category>
      <category>webgui</category>
    </item>
    <item>
      <title>Procrastinating with 'from</title>
      <dc:creator>PNS11</dc:creator>
      <pubDate>Sun, 08 Apr 2018 12:51:25 +0000</pubDate>
      <link>https://dev.to/cess11/procrastinating-with-from-446m</link>
      <guid>https://dev.to/cess11/procrastinating-with-from-446m</guid>
      <description>

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Since I have trouble finding the time to finish that guestbook article I'll keep you bored with some more interactive parsing, this time we'll wring out and save a copy of a subset of a remote database we can access through a browser or similar web client. &lt;/p&gt;

&lt;p&gt;Earlier I've written a little about how one can use the picolisp function 'match for exploring XML or similarly structured data. This is a very powerful pattern matching tool that can be utilised to extract just about any data from any set as long as you have an idea of how its environment looks like. &lt;/p&gt;

&lt;p&gt;Sometimes you want something else and don't know enough for an efficient 'match expression, though. Perhaps you want to exfiltrate every occurrence of a pattern in a repetitive data set but isn't yet sure what the pattern ought to look like. If this is the case one usually applies the pair functions 'from and 'till instead, and in a slightly different manner. &lt;/p&gt;

&lt;p&gt;I have used this technique for all sorts of interactive searching and pattern matching, including real work applications like chugging through gigabytes of web sites hunting for contact information. &lt;/p&gt;

&lt;h2&gt;
  
  
  The model
&lt;/h2&gt;

&lt;p&gt;The other day I was in a pickle, I had some files containing markup and information about swedish metal bands from &lt;a href="https://www.metal-archives.com/lists/SE"&gt;metal-archives.com&lt;/a&gt; and wanted to extract the information and make it searchable. Basically create a subset of their database locally and query it for specifics that I was interested in. &lt;/p&gt;

&lt;p&gt;As you can see in the link it was about nine pages, and if you look at the DOM after the JavaScript has assembled it from the Ajax request and some HTML you'll see that the search result is a one line repetitive tbody-tr-td-construct. This makes it hard to parse out a pattern line by line, for which 'match would have been a perfect fit. &lt;/p&gt;

&lt;p&gt;Instead we get to figure out what we want in sequential pattern fragments instead. &lt;/p&gt;

&lt;p&gt;How to save a copy of a JS-generated, dynamic DOM is a small science in itself, which I will conveniently assume you have already doctored in. As for my setup, I did it with a Chromium instance and quickly got nine HTML files to examine and write a small parser for.&lt;/p&gt;

&lt;p&gt;What we want to do is have the picolisp reader look over that search result line in the HTML files and give us some data structure back that contains band name, location, status, genre and URL. So we start it and tell it what our data model should look like and in what file to keep it persistent. &lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ pil +
: (pool "mase.db") 
-&amp;gt; T
: (class +Band +Entity)
-&amp;gt; +Band
: (rel nm (+Ref +String))
-&amp;gt; +Band
: (rel loc (+Ref +String))
-&amp;gt; +Band
: (rel status (+Ref +String))
-&amp;gt; +Band
: (rel genre (+Ref +String))
-&amp;gt; +Band
: (rel url (+Ref +String))
-&amp;gt; +Band
:
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Or as a snippet in an er.l:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(pool "mase.db") 

(class +Band +Entity)
(rel nm (+Ref +String))
(rel loc (+Ref +String))
(rel status (+Ref +String))
(rel genre (+Ref +String))
(rel url (+Ref +String))
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This can then be loaded with '(load "er.l"). &lt;/p&gt;

&lt;h2&gt;
  
  
  The 'from
&lt;/h2&gt;

&lt;p&gt;Now that you have your model, HTML files and a pooled database it is time to start working on our parser. When doing this with a new set of data it is likely one does some examining from the REPL by reading a file into a variable as a list of transient symbols, or a list of strings, or a list of lines. One could also use a text editor or 'View source' in a browser, whatever works for you when you want to skim through and quickly get an idea about where the valuable information is and how the data is structured there. &lt;/p&gt;

&lt;p&gt;Having looked at 1.html and found the line with ~500 bands and some data on them we can start figuring out how to get it out of there. 'from is like a hook while 'till is a release, so you tell 'from how it looks where the extraction should begin and 'till when to stop. &lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;: (make # we want this to return a list
    (in "1.html" # from this file
        (until (eof) # and keep going until the end
            (link # linking lists into a list of lists
                (make 
                    (from "tr class") # from this pattern, look for
                        (from "href=\"") # this pattern, and then 
                            (link (pack (till "\""))) ] # grab it. 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;If you run this at your REPL and have the HTML files in order you'll get a list of URL:s, something like this but about 500 elements long '(("&lt;a href="https://www.metal-archives.com/bands/Name/ID%22)(%22https://www.metal-archives.com/bands/Another_Name/AnotherID%22)"&gt;https://www.metal-archives.com/bands/Name/ID")("https://www.metal-archives.com/bands/Another_Name/AnotherID")&lt;/a&gt;). &lt;/p&gt;

&lt;p&gt;This is built by the 'make-'link constructs, where the innermost one gets the URL as a transient symbol from 'pack. If we didn't use 'pack we would instead get the URL:s as lists of characters. &lt;/p&gt;

&lt;p&gt;Just getting these links aren't satisfactory, though. We also want the rest of the information, so we'll extend the above like this. &lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;: (make 
    (in "1.html" 
        (until (eof) 
            (link 
                (make 
                    (from "tr class")
                        (from "href=\"")
                            (link (pack (till "\""))) 
                                (from "&amp;gt;") # name is between &amp;gt;
                                    (link (pack (till "&amp;lt;"))) # and &amp;lt;
                                        (from "&amp;gt;&amp;lt;")(from "&amp;gt;&amp;lt;") # after two &amp;gt;&amp;lt; 
                                            (from "&amp;gt;") # then a &amp;gt;
                                                (link (pack (till "&amp;lt;"))) ]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;As you can see, we can be quite ignorant of the details in the data and extract what we want anyway, it is enough to know that there will be two '&amp;gt;&amp;lt;' until there is '&amp;gt;Data&amp;lt;'. This is slightly different from working with 'match, here we are extending our exfiltration incrementally rather than expressing ourselves with a dense list as pattern. &lt;/p&gt;

&lt;p&gt;To get all the interesting information out of this data one would continue adding 'from expressions, the next one would look for a single '&amp;gt;&amp;lt;' before extracting 'from '&amp;gt;' 'till '&amp;lt;', and the last extract would probably be 'from 'span', 'from '&amp;gt;' and 'till '&amp;lt;'. &lt;/p&gt;

&lt;h2&gt;
  
  
  Putting it in objects
&lt;/h2&gt;

&lt;p&gt;Once all of this is in place we get a list where each element is a list '(Url Name Location Genre Status), making it almost trivial to save it as database objects. Assuming you ran it and got the result in the REPL you would probably do something like this, where @ in the regular REPL context is short for 'last on the result stack' and @@ and @@@ dig deeper. &lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;: (for X @ 
    (new! '(+Band)
        'nm (cadr X)
        'loc (caddr X)
        'status (last X)
        'genre (cadddr X)
        'url (car X) ]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Once 'new! has run successfully your data is persistent, browseable and searchable. To be really, really sure it is in your database and will be available next time you open it, run '(commit 'upd) an extra time. &lt;/p&gt;

&lt;p&gt;From here it is easy to put it all together with 'dir supplying a list of arguments for the resulting function. Simplest but somewhat ugly is to replace @ above with the full 'make-'from nest and take the file name from 'dir, so when it has gone through all of the files you end up with a lot of database objects containing a full set of swedish metal bands known to Metal-Archives. &lt;/p&gt;

&lt;p&gt;It is of course better to factor it into a few functions in a file instead, at least if one wants to reuse the basic 'make 'in 'from 'till structure, however, it is as an interactive tool pil really shines and sometimes this means sacrificing a bit of elegance for a more brutish approach to code style. &lt;/p&gt;

&lt;h2&gt;
  
  
  Primitive ad hoc queries
&lt;/h2&gt;

&lt;p&gt;Querying the database can be done in several ways. We used a simple '+Ref index so tolerant and substring searches aren't possible right away, but we can simulate this with our old friend 'match and the 'printsp function, that prints something with a space. &lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;: (for X (collect 'nm '+Band) 
    (with X
        (and 
            (match '("S" "t" "o" "c" "k" "h" "o" "l" @B) (chop (: loc)))
            (printsp (pack (: nm) " - " (: loc))) ]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Using a variable like '@B amounts to a wildcard, this pattern will be true for all location fields that begin with 'Stockhol' (i.e. the next line will fire and 'printsp name and location), also those that look like 'Stockholm/SomeOtherCity'. When doing this in practice it is likely one puts a '@A at the beginning, and in a file one would use 'use to declare these symbols and prevent them from leaking artifacts from other parts of the program. &lt;/p&gt;

&lt;h2&gt;
  
  
  The end
&lt;/h2&gt;

&lt;p&gt;If you would like to see this done quickly by the REPL I saved a ten minute session &lt;a href="https://asciinema.org/a/qJXpTYuE2De6zpd7vNu7yCoFr"&gt;here&lt;/a&gt; that is basically a repetition of the above. &lt;/p&gt;

&lt;p&gt;If you thought this was worthwhile reading, consider donating a coffee or two, &lt;a href="https://www.patreon.com/Stagling"&gt;Stagling@Patreon&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;The data used above might be copyrighted, if so I consider this to be fair use and decent advertisement for an excellent web service, but will of course remove the post if the right people tell me to. While doing this I listened to &lt;a href="https://www.youtube.com/watch?v=Lcj3biWucpU"&gt;Temple of Baal, Verses of Fire&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Addendum: Sorry about the formerly broken links, they are fixed now. Thanks &lt;a href="https://picolisp.a1w.ca/"&gt;aw&lt;/a&gt; for pointing it out.  &lt;/p&gt;


</description>
      <category>picolisp</category>
      <category>functional</category>
      <category>database</category>
      <category>metalarchives</category>
    </item>
    <item>
      <title>Building Factor language without X/GUI</title>
      <dc:creator>PNS11</dc:creator>
      <pubDate>Mon, 02 Apr 2018 11:06:09 +0000</pubDate>
      <link>https://dev.to/cess11/building-factor-language-without-xgui-jda</link>
      <guid>https://dev.to/cess11/building-factor-language-without-xgui-jda</guid>
      <description>&lt;p&gt;Over the last weeks I've procrastinated with stack languages more than usual and dabbled a little in a practical one called Factor. It has a lot of batteries included but no fluff and some edges are as sharp as a you know what, then again, it is very powerful, at least in the way Paul Graham meant in &lt;a href="http://www.paulgraham.com/power.html"&gt;this well known essay&lt;/a&gt; and others. &lt;/p&gt;

&lt;p&gt;Ran into &lt;a href="https://github.com/factor/factor/issues/1520"&gt;this issue&lt;/a&gt; when trying to run the prebuilt binary for the Factor language on a headless Debian server. Basically it expects to find a shared GTK library where there isn't any since neither X nor GTK is installed in this type of environment. One could place a file with the same name in one's PATH as a workaround but it seemed a little too ugly even for my taste. &lt;/p&gt;

&lt;p&gt;Following the recommendation to&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git clone git://factorcode.org/git/factor.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I then added 'NO_UI=1' to './build.sh', basically right after the hashbang. Without any other changes to the script I ran&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;./build.sh update
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and it compiles as well as runs as a CLI interface on the first try. &lt;/p&gt;

&lt;p&gt;After having done some experimenting with this Forth-like tool I'm quite impressed, if you're tired of the sluggishness and ad hoc qualities of Python, come to the dark and stack oriented side where programming is concatenative, strange and powerful. The standard libraries and FFI are quite good and seem to be well enough for exploratory and dynamic programming in almost all the common domains, from systems to applications and web. &lt;/p&gt;

&lt;p&gt;&lt;a href="http://factorcode.org/"&gt;Happy hacking!&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Stagling@Patreon&lt;/p&gt;

</description>
      <category>factor</category>
      <category>stack</category>
      <category>concatenative</category>
      <category>troubleshooting</category>
    </item>
    <item>
      <title>My first asciinema</title>
      <dc:creator>PNS11</dc:creator>
      <pubDate>Mon, 26 Mar 2018 10:32:17 +0000</pubDate>
      <link>https://dev.to/cess11/my-first-asciinema-51im</link>
      <guid>https://dev.to/cess11/my-first-asciinema-51im</guid>
      <description>

&lt;p&gt;Earlier today I found out about an alternative to screen recording, asciinema. &lt;/p&gt;

&lt;p&gt;It was quite easy to install under Debian by grabbing the package python3-pip and and using it for fetching the application. &lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ sudo apt-get install python3-pip
...
$ pip3 install asciinema
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;It's about 20 minutes back and forth in the REPL showing how to reach text files and the shell commands. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://asciinema.org/a/oEnczUEDjkkVRM0z5yzggFIPc"&gt;Here's the recording&lt;/a&gt;. &lt;/p&gt;


</description>
      <category>terminalrecording</category>
      <category>repl</category>
      <category>asciinema</category>
      <category>picolispbasics</category>
    </item>
    <item>
      <title>Let's build: 'load to get faster early web development</title>
      <dc:creator>PNS11</dc:creator>
      <pubDate>Fri, 23 Feb 2018 09:56:30 +0000</pubDate>
      <link>https://dev.to/cess11/lets-build-load-to-get-faster-early-web-development-2pmn</link>
      <guid>https://dev.to/cess11/lets-build-load-to-get-faster-early-web-development-2pmn</guid>
      <description>

&lt;p&gt;When trying stuff out or doing early work on a web site or service it can seem slow and fragmented to restart your application server over and over again. &lt;/p&gt;

&lt;p&gt;Instead of churning out all that Ctrl+C or D and possibly also restarting httpGate or nginx at every adjustment you could use a simple little trick that is suitable when testing app modules or just getting started on a project. &lt;/p&gt;

&lt;p&gt;dev.l&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# libraries for the app server
(load "@lib/http.l" "@lib/xhtml.l" "@lib/form.l") 

(de work () 
    (load "app.l"))

(de go ()
    (server 8080 "!work"))
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Once you have this you run and forget about it:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ pil dev.l -go -wait
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now if you visit localhost:8080 it won't be spectacular. &lt;/p&gt;

&lt;p&gt;Enter some GUI boilerplate into "app.l". &lt;/p&gt;

&lt;p&gt;app.l&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(app) # assuming you want session handling
(action 
    (html 0 "Test bed for savvy gravy" "@lib.css" NIL
        (&amp;lt;h1&amp;gt; NIL "It's alive!")))
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Next visit will then look better, and as you work on and save "app.l" and reload localhost:8080 you'll see changes reflected immediately without restarting "main.l". &lt;/p&gt;

&lt;p&gt;app.l&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(app)
(setq *Awesome T)
(action 
    (html 0 "Test bed for savvy gravy" "@lib.css" NIL
        (if *Awesome
            (&amp;lt;h1&amp;gt; 'awesome "Apparently you're awesome!")
            (&amp;lt;h1&amp;gt; 'notsoawesome "Pretty sure you won't see this!") )))
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Using this technique 'in production' isn't a good idea since file I/O performance is about as bad as it gets, but compared to restarting the same script over and over manually while allowing a separation of your development helper functions and globals in "dev.l" from the app code in "app.l" will feel like super powers. &lt;/p&gt;

&lt;p&gt;There are of course other ways to achieve this or similar results, you could for example use coroutines or background tasks instead, laying ground for a more sophisticated integrated development and production administration environment. Or whatever it's called when you program your servers by pew-pew:ing messages at objects and watching web services grow out of it. &lt;/p&gt;

&lt;p&gt;Next time we'll create a small guestbook application. &lt;/p&gt;

&lt;p&gt;Stagling@Patreon for coffee donations, unless you'd perhaps, y'know, like to hire me or something, then I'm sure we could work something out. &lt;/p&gt;


</description>
      <category>picolisp</category>
      <category>lisp</category>
      <category>functional</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Raw XML exploration with picolisp</title>
      <dc:creator>PNS11</dc:creator>
      <pubDate>Mon, 05 Feb 2018 13:40:01 +0000</pubDate>
      <link>https://dev.to/cess11/raw-xml-exploration-with-picolisp-7hn</link>
      <guid>https://dev.to/cess11/raw-xml-exploration-with-picolisp-7hn</guid>
      <description>

&lt;p&gt;Below is a short tutorial on using the pil VM, DB and OOP for basic data mining in XML structured data. The article assumes some knowledge in programming and the environment to be POSIX or at least unixlike. For information on installing picolisp, &lt;a href=""&gt;visit picolisp.com&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  How to lisp some XML
&lt;/h1&gt;

&lt;p&gt;This year we're having elections in Sweden. To prepare it might be a good idea to read up on the last election cycle back in 2014. &lt;/p&gt;

&lt;p&gt;Luckily the Swedish government supplies us with a full set of voting results. &lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;wget http://www.val.se/val/val2014/slutresultat/slutresultat.zip

unzip slutresultat.zip
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This will unpack a lot of ISO-8859-1 encoded XML files in a new directory, as well as some metadata files about the rest. It is easy to convert them into UTF-8, &lt;a href="https://dev.to/cess11/first-post-picolisp-script-mok"&gt;like this&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Most of them contain voting results from a county, regarding either national parliament, regional or local assembly. The file names are constructed from a numeric county code and a character for each election, R for parliament ("riksdag"), L for region ("landsting"), K for local assembly ("kommun"). &lt;/p&gt;

&lt;p&gt;In the directory with the data we then start pil. &lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ pil +
:
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Not very exciting. Let's take a look at one of the files by attaching it to a symbol and do some simple processing. &lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;:(length 
    (setq A 
        (make 
            (in "slutresultat_1407L.xml" 
                (until (eof)(link (line T]
-&amp;gt; 1832
:(head 10 A)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;As 'head shows this actually is XML data. Since it is we also know that right after every '&amp;lt; there will be interesting information, and we can see that it usually is the first or second character in the data attached to our 'A symbol. &lt;/p&gt;

&lt;p&gt;To extract this we can use an expression like this.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;:(length 
    (setq *Subjects 
        (uniq 
            (make 
                (for X A 
                    (and 
                        (or 
                            (match '("&amp;lt;" @Subject " " @B "&amp;gt;") (chop X))
                            (match '(@C "&amp;lt;" @Subject " " @B "&amp;gt;") (chop X)))
                        (link (pack @Subject]
-&amp;gt; 17
:*Subjects
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In a real mining session one would most likely use 'de and turn this into a function that takes a list (for 'match to use) as argument and has the side effect that the symbol and global variable *Subjects (which would probably have another name) is updated with the results from 'match. When doing interactive work globals can be like post-it notes of arbitrary size, holding anything from millions of text fragments to object references or the emptiness of NIL while the temporary nature of these sessions is resistant to the horrors of globals in production code. &lt;/p&gt;

&lt;p&gt;Here 'length is used to make sure the expression returns something both short and useful, the amount of unique hits in our search. 'setq returns the contents of the symbol which means that it will fill the screen with junk unless our expression is sensible or the data set is very small (and who would want that?). &lt;/p&gt;

&lt;p&gt;Picolisp 'match is often useful where one would otherwise use 'grep' or regexp. Its first argument is a list that it matches against its second argument, and when there's a fit the @Variables get the content that's in the data source at that place in the structure. This means it is extremely well suited for sophisticated exfiltration techniques as well as the basic ones shown here. &lt;/p&gt;

&lt;p&gt;As you can see we now have a set of 17 unique XML tag names. These can be supplied to our earlier expression to extract more information. Let's have a look at what "PARTI" contains. &lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;:(length 
    (setq *PARTI
        (uniq 
            (make 
                (for X A 
                    (and 
                        (or 
                            (match '("&amp;lt;" ~(chop "PARTI") " " @B "&amp;gt;") (chop X))
                            (match '(@C "&amp;lt;" "P" "A" "R" "T" "I" " " @B "&amp;gt;") (chop X)))
                        (link (pack @B]
-&amp;gt; 21
:*PARTI
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The tilde (~) causes the expression to which it is attached to be evaluated as regular lisp, here 'chop turning a transient symbol like "PARTI" into the sequence "P" "A" "R" "T" "I", before matching the result against the list in the next argument. If it is easy to omit 'chop one should, or at least use it to prepare a list for 'match that gets reused, since it brings some overhead that gets very noticable with bigger data sets. &lt;/p&gt;

&lt;p&gt;Apparently 21 parties ("PARTI" means 'party') ran in the regional election in this county (the name of which is in the "NAMN" attribute of the "KOMMUN" tag). &lt;/p&gt;

&lt;p&gt;Let's write out their names. &lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;:(mapcar 
    '((X)
        (and 
            (match '(@A " " @B "\"" @Party "\"" @C) (chop X))
            (printsp (pack @Party)))) 
    *PARTI)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This kind of expression is especially useful, since the first argument to 'mapcar could perform all sorts of side effects while 'mapcar itself will return a list of all successful matches regardless of those side effects. &lt;/p&gt;

&lt;p&gt;One such potential use is saving the exfiltrated data or perhaps entire lines or documents in database objects, by simply putting a 'new! clause at the end and having set up some classes for holding and structuring the data of interest. &lt;/p&gt;

&lt;p&gt;It could look something like this:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;:(class +GeneralContainment +Entity)
-&amp;gt; +GeneralContainment
:(rel tag (+Ref +String))
-&amp;gt; +GeneralContainment
:(rel dta (+List +String))
-&amp;gt; +GeneralContainment
:(mapcar 
    '((X)
        (and 
            (match '(@A "=" "\"" @Short "\"" @B "=" "\"" @Full "\"" @C) (chop X))
            (new! '(+GeneralContainment) 
                'nm "Party names, (abbreviation . name)" 
                'dta (cons 
                    (pack @Short) 
                    (pack @Full))))) 
    *PARTI)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Such class names aren't particularly idiomatic, the point here is that these classes ought to be very generic and kept in a small utility library. Usually the structure above or one with two classes where one can hold many '+Joint relations to objects of the other class (in addition to a name/category field and one for data) is enough to structure most interactive mining. &lt;/p&gt;

&lt;p&gt;Once one gets the hang of the basic list manipulations, text parsing techniques and pilog expressions it can be quite a bit easier to go straight to exfiltration into generic objects instead of dabbling with globals, especially with bigger data sets, but then one should also use some helper methods that do the exfiltration without blocking the REPL since DB operations will probably take some time. &lt;/p&gt;

&lt;p&gt;Thanks for reading, questions and comments are welcome. &lt;/p&gt;

&lt;p&gt;Stagling@Patreon&lt;/p&gt;


</description>
      <category>picolisp</category>
      <category>lisp</category>
      <category>xml</category>
      <category>datamining</category>
    </item>
    <item>
      <title>First post, picolisp script</title>
      <dc:creator>PNS11</dc:creator>
      <pubDate>Sat, 03 Feb 2018 13:39:09 +0000</pubDate>
      <link>https://dev.to/cess11/first-post-picolisp-script-mok</link>
      <guid>https://dev.to/cess11/first-post-picolisp-script-mok</guid>
      <description>&lt;p&gt;Today I made a oneliner for converting a set of ISO-coded XML files in the current directory to UTF-8.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight common_lisp"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;for&lt;/span&gt; &lt;span class="nv"&gt;X&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;dir&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;and&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;match&lt;/span&gt; &lt;span class="o"&gt;'&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;@A&lt;/span&gt; &lt;span class="s"&gt;"."&lt;/span&gt; &lt;span class="s"&gt;"x"&lt;/span&gt; &lt;span class="s"&gt;"m"&lt;/span&gt; &lt;span class="s"&gt;"l"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;chop&lt;/span&gt; &lt;span class="nv"&gt;X&lt;/span&gt;&lt;span class="p"&gt;))(&lt;/span&gt;&lt;span class="nb"&gt;and&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;out&lt;/span&gt; &lt;span class="s"&gt;"sh.sh"&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;prinl&lt;/span&gt; &lt;span class="s"&gt;"#! /bin/sh"&lt;/span&gt;&lt;span class="p"&gt;))(&lt;/span&gt;&lt;span class="nv"&gt;out&lt;/span&gt; &lt;span class="s"&gt;"+sh.sh"&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;prinl&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;pack&lt;/span&gt; &lt;span class="s"&gt;"iconv -f ISO-8859-1 -t UTF-8 "&lt;/span&gt; &lt;span class="nv"&gt;X&lt;/span&gt; &lt;span class="s"&gt;" &amp;gt; utf8_"&lt;/span&gt; &lt;span class="nv"&gt;X&lt;/span&gt;&lt;span class="p"&gt;)))(&lt;/span&gt;&lt;span class="nv"&gt;call&lt;/span&gt; &lt;span class="ss"&gt;'sh&lt;/span&gt; &lt;span class="s"&gt;"sh.sh"&lt;/span&gt;&lt;span class="nv"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A more readable, commented version could look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight common_lisp"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;for&lt;/span&gt; &lt;span class="nv"&gt;X&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;dir&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="nv"&gt;for&lt;/span&gt; &lt;span class="nb"&gt;every&lt;/span&gt; &lt;span class="nv"&gt;file&lt;/span&gt; &lt;span class="nv"&gt;name&lt;/span&gt; &lt;span class="nv"&gt;in&lt;/span&gt; &lt;span class="nv"&gt;this&lt;/span&gt; &lt;span class="nb"&gt;directory&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;and&lt;/span&gt; 
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;match&lt;/span&gt; &lt;span class="o"&gt;'&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;@A&lt;/span&gt; &lt;span class="s"&gt;"."&lt;/span&gt; &lt;span class="s"&gt;"x"&lt;/span&gt; &lt;span class="s"&gt;"m"&lt;/span&gt; &lt;span class="s"&gt;"l"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;chop&lt;/span&gt; &lt;span class="nv"&gt;X&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="nv"&gt;check&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nv"&gt;*.xml&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;and&lt;/span&gt; &lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="nv"&gt;it&lt;/span&gt; &lt;span class="nv"&gt;is&lt;/span&gt; &lt;span class="nb"&gt;or&lt;/span&gt; &lt;span class="nv"&gt;this&lt;/span&gt; &lt;span class="nv"&gt;is&lt;/span&gt; &lt;span class="nv"&gt;skipped,&lt;/span&gt; &lt;span class="nv"&gt;so...&lt;/span&gt;
            &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;out&lt;/span&gt; &lt;span class="s"&gt;"sh.sh"&lt;/span&gt; &lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="nv"&gt;we&lt;/span&gt; &lt;span class="nb"&gt;write&lt;/span&gt; &lt;span class="nv"&gt;a&lt;/span&gt; &lt;span class="nv"&gt;new&lt;/span&gt; &lt;span class="nv"&gt;file&lt;/span&gt;
                &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;prinl&lt;/span&gt; &lt;span class="s"&gt;"#! /bin/sh"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="nv"&gt;with&lt;/span&gt; &lt;span class="nv"&gt;a&lt;/span&gt; &lt;span class="nv"&gt;hashbang&lt;/span&gt; &lt;span class="err"&gt;&lt;/span&gt;
            &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;out&lt;/span&gt; &lt;span class="s"&gt;"+sh.sh"&lt;/span&gt; &lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="nb"&gt;and&lt;/span&gt; &lt;span class="nv"&gt;then&lt;/span&gt; &lt;span class="nv"&gt;add&lt;/span&gt; &lt;span class="nv"&gt;an&lt;/span&gt; &lt;span class="nv"&gt;instruction&lt;/span&gt;
                &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;prinl&lt;/span&gt; 
                    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;pack&lt;/span&gt; &lt;span class="s"&gt;"iconv -f ISO-8859-1 -t UTF-8 "&lt;/span&gt; &lt;span class="nv"&gt;X&lt;/span&gt; &lt;span class="s"&gt;" &amp;gt; utf8_"&lt;/span&gt; &lt;span class="nv"&gt;X&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
            &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;call&lt;/span&gt; &lt;span class="ss"&gt;'sh&lt;/span&gt; &lt;span class="s"&gt;"sh.sh"&lt;/span&gt;&lt;span class="nv"&gt;]&lt;/span&gt; &lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="nb"&gt;and&lt;/span&gt; &lt;span class="nv"&gt;finally&lt;/span&gt; &lt;span class="nv"&gt;run&lt;/span&gt; &lt;span class="nv"&gt;it&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now this isn't very lispy, but it can quickly be turned into a more functional style.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight common_lisp"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;de&lt;/span&gt; &lt;span class="nv"&gt;qconv&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Lst&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="o"&gt;'&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;FromCode&lt;/span&gt; &lt;span class="nv"&gt;ToCode&lt;/span&gt; &lt;span class="nv"&gt;OutPrefix&lt;/span&gt; &lt;span class="nv"&gt;InSuffix&lt;/span&gt; &lt;span class="nv"&gt;FileList&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;for&lt;/span&gt; &lt;span class="nv"&gt;X&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;last&lt;/span&gt; &lt;span class="nv"&gt;Lst&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;and&lt;/span&gt; 
            &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;match&lt;/span&gt; &lt;span class="o"&gt;'&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;@A&lt;/span&gt; &lt;span class="nv"&gt;~&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;chop&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;cadddr&lt;/span&gt; &lt;span class="nv"&gt;Lst&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;chop&lt;/span&gt; &lt;span class="nv"&gt;X&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;and&lt;/span&gt; 
                &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;out&lt;/span&gt; &lt;span class="s"&gt;"sh.sh"&lt;/span&gt; 
                    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;prinl&lt;/span&gt; &lt;span class="s"&gt;"#! /bin/sh"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
                &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;out&lt;/span&gt; &lt;span class="s"&gt;"+sh.sh"&lt;/span&gt; 
                    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;prinl&lt;/span&gt; 
                        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;pack&lt;/span&gt; &lt;span class="s"&gt;"iconv -f "&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;car&lt;/span&gt; &lt;span class="nv"&gt;Lst&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="s"&gt;"-t "&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;cadr&lt;/span&gt; &lt;span class="nv"&gt;Lst&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="s"&gt;" "&lt;/span&gt; &lt;span class="nv"&gt;X&lt;/span&gt; &lt;span class="s"&gt;" &amp;gt; "&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;caddr&lt;/span&gt; &lt;span class="nv"&gt;Lst&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;X&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
                &lt;span class="p"&gt;)))&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;call&lt;/span&gt; &lt;span class="ss"&gt;'rm&lt;/span&gt; &lt;span class="s"&gt;"sh.sh"&lt;/span&gt;&lt;span class="nv"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Still quite ugly though. &lt;/p&gt;

</description>
      <category>picolisp</category>
      <category>lisp</category>
      <category>functional</category>
      <category>interpreted</category>
    </item>
  </channel>
</rss>
