<?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: Lawrence Lagerlof</title>
    <description>The latest articles on DEV Community by Lawrence Lagerlof (@llagerlof).</description>
    <link>https://dev.to/llagerlof</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%2F94985%2Ffc363d35-aa0a-4bc6-acc7-03ee27bb7f1b.jpeg</url>
      <title>DEV Community: Lawrence Lagerlof</title>
      <link>https://dev.to/llagerlof</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/llagerlof"/>
    <language>en</language>
    <item>
      <title>Stop copy-pasting tables from websites: This Firefox and Chrome extension does it better</title>
      <dc:creator>Lawrence Lagerlof</dc:creator>
      <pubDate>Thu, 24 Jul 2025 14:59:03 +0000</pubDate>
      <link>https://dev.to/llagerlof/stop-copy-pasting-tables-from-websites-this-firefox-and-chrome-extension-does-it-better-5h10</link>
      <guid>https://dev.to/llagerlof/stop-copy-pasting-tables-from-websites-this-firefox-and-chrome-extension-does-it-better-5h10</guid>
      <description>&lt;p&gt;How many times have you found yourself manually copying data from a website table, cell by cell, into a spreadsheet or trying to format it for documentation? If you're a developer, researcher, or anyone who works with data, you've definitely been there.&lt;/p&gt;

&lt;p&gt;I built &lt;strong&gt;Website Table Exporter&lt;/strong&gt; to solve this exact problem. It's a Firefox extension that automatically detects HTML tables on any website and adds export buttons right where you need them.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fos0qyrsr39mh7q2vladz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fos0qyrsr39mh7q2vladz.png" alt="Website Table Exporter in action" width="800" height="393"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;Whether you're:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;📊 Analyzing competitor pricing tables&lt;/li&gt;
&lt;li&gt;📝 Documenting API responses in Markdown&lt;/li&gt;
&lt;li&gt;🔍 Researching data from academic databases
&lt;/li&gt;
&lt;li&gt;🧪 Testing with realistic datasets&lt;/li&gt;
&lt;li&gt;📈 Building dashboards with real-world data&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;...you've probably wasted hours manually reformatting table data. Most websites don't provide export functionality, and browser dev tools aren't exactly user-friendly for this.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Solution
&lt;/h2&gt;

&lt;p&gt;Website Table Exporter automatically adds three export buttons to every HTML table you encounter:&lt;/p&gt;

&lt;h3&gt;
  
  
  🗂️ CSV Export
&lt;/h3&gt;

&lt;p&gt;Perfect for spreadsheet analysis. Headers are quoted, numeric data stays numeric:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"Product","Price","Stock"
"Laptop",899,15
"Mouse",25,42
"Keyboard",75,28
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  🔧 JSON Export
&lt;/h3&gt;

&lt;p&gt;Ideal for developers. Maintains proper data types:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Product"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Laptop"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Price"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;899&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Stock"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Product"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Mouse"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; 
    &lt;/span&gt;&lt;span class="nl"&gt;"Price"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Stock"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  📝 Markdown Export
&lt;/h3&gt;

&lt;p&gt;Great for documentation and README files:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;| Product | Price | Stock |
| --- | --- | --- |
| Laptop | 899 | 15 |
| Mouse | 25 | 42 |
| Keyboard | 75 | 28 |
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Smart Features That Actually Matter
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;🧠 Intelligent Data Type Detection&lt;/strong&gt;: The extension analyzes each column to determine if it contains numeric data, preserving data types in JSON and avoiding unnecessary quotes in CSV.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;⚡ Dynamic Table Support&lt;/strong&gt;: Works with JavaScript-generated tables and SPAs. The extension uses a MutationObserver to detect tables added after page load.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🎛️ Toggle Control&lt;/strong&gt;: Hide/show buttons across all pages with the popup. Perfect when you need a clean view.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;⚠️ Merged Cell Warnings&lt;/strong&gt;: Alerts you when tables contain merged cells that might affect export quality.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🔒 Privacy-First&lt;/strong&gt;: Only requires &lt;code&gt;activeTab&lt;/code&gt; and &lt;code&gt;clipboardWrite&lt;/code&gt; permissions. No data collection, everything stays local.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Chrome: Install from source on &lt;a href="https://github.com/llagerlof/websitetableexporter" rel="noopener noreferrer"&gt;GitHub project page&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Firefox: Install from &lt;a href="https://addons.mozilla.org/firefox/addon/website-table-exporter/" rel="noopener noreferrer"&gt;Mozilla Addons website&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>firefox</category>
      <category>productivity</category>
      <category>tools</category>
      <category>chrome</category>
    </item>
    <item>
      <title>AIpim: Ask, copy, done.</title>
      <dc:creator>Lawrence Lagerlof</dc:creator>
      <pubDate>Tue, 01 Jul 2025 17:24:21 +0000</pubDate>
      <link>https://dev.to/llagerlof/aipim-ask-copy-done-6m</link>
      <guid>https://dev.to/llagerlof/aipim-ask-copy-done-6m</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnmdaq5pgw1q3b16yip17.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnmdaq5pgw1q3b16yip17.png" alt="Logo" width="190" height="190"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  🚀 What is AIpim?
&lt;/h2&gt;

&lt;p&gt;AIpim is a minimalist desktop app for super fast OpenAI API responses - no browser, no fluff. &lt;strong&gt;Just prompt, copy, done&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚡ Quick Start
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Clone &amp;amp; install:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   git clone https://github.com/llagerlof/aipim.git
   &lt;span class="nb"&gt;cd &lt;/span&gt;aipim
   npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Run the app:&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;npm start&lt;/code&gt; (any system), &lt;code&gt;./start.sh&lt;/code&gt; (Linux) or &lt;code&gt;start.bat&lt;/code&gt; (Windows) - bind it to a hotkey like &lt;em&gt;Ctrl+Shift+F11&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Configure:&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Go to &lt;strong&gt;File → Configuration&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Add your OpenAI API key&lt;/li&gt;
&lt;li&gt;Choose a model (we recommend &lt;code&gt;gpt‑4.1‑nano&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Save&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🎯 Instant Usage
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Trigger the app (shortcut or CLI)&lt;/li&gt;
&lt;li&gt;Type/paste prompt&lt;/li&gt;
&lt;li&gt;Press &lt;strong&gt;Ctrl+Enter&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Hit &lt;strong&gt;Enter&lt;/strong&gt; twice → answer copied &amp;amp; program closed&lt;/li&gt;
&lt;li&gt;Or press &lt;strong&gt;Esc&lt;/strong&gt; to dismiss the app&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  ✨ Why Use It?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Zero context switching&lt;/strong&gt; - keyboard-only flow.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Speed&lt;/strong&gt; - direct API, no UI overhead.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Simple&lt;/strong&gt; - no chat history, no distractions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Open-source&lt;/strong&gt; &amp;amp; MIT-licensed-hack away&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🖥️ Project page
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/llagerlof/aipim" rel="noopener noreferrer"&gt;https://github.com/llagerlof/aipim&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  🚀 Try AIpim Today
&lt;/h3&gt;

&lt;p&gt;Get instant AI replies with a few keystrokes. Happy prompt &amp;amp; copy!&lt;/p&gt;

</description>
      <category>openai</category>
      <category>productivity</category>
      <category>app</category>
      <category>llm</category>
    </item>
    <item>
      <title>Zombie Infection Simulator</title>
      <dc:creator>Lawrence Lagerlof</dc:creator>
      <pubDate>Sat, 26 Apr 2025 04:48:03 +0000</pubDate>
      <link>https://dev.to/llagerlof/zombie-infection-simulator-1d6a</link>
      <guid>https://dev.to/llagerlof/zombie-infection-simulator-1d6a</guid>
      <description>&lt;p&gt;&lt;a href="https://llagerlof.github.io/games/simzombie" rel="noopener noreferrer"&gt;https://llagerlof.github.io/games/simzombie&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://llagerlof.github.io/games/simzombie" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fro9fjp3zphl2l5xjidjp.png" alt="Screenshot showing blue dots (humans) and red dots (zombies)" width="800" height="612"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>zombie</category>
      <category>game</category>
      <category>simulator</category>
    </item>
    <item>
      <title>Chrome Extension Boilerplate with Popup Interaction (Manifest V3)</title>
      <dc:creator>Lawrence Lagerlof</dc:creator>
      <pubDate>Wed, 04 Sep 2024 19:20:18 +0000</pubDate>
      <link>https://dev.to/llagerlof/chrome-extension-boilerplate-with-popup-interaction-manifest-v3-3ko5</link>
      <guid>https://dev.to/llagerlof/chrome-extension-boilerplate-with-popup-interaction-manifest-v3-3ko5</guid>
      <description>&lt;h2&gt;
  
  
  The goal
&lt;/h2&gt;

&lt;p&gt;This &lt;a href="https://github.com/llagerlof/fresh-chrome-extension" rel="noopener noreferrer"&gt;boilerplate extension&lt;/a&gt; provides developers with a starting point for creating their own Chrome extensions using Manifest V3.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's new
&lt;/h2&gt;

&lt;p&gt;The biggest improvement in this version is the addition of a popup interface. Now, when users click the extension button in the browser's top bar, they're presented with an interactive popup instead of just logging a message to the console.&lt;/p&gt;

&lt;h2&gt;
  
  
  Features
&lt;/h2&gt;

&lt;p&gt;This boilerplate demonstrates three key extension behaviors:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Before page load&lt;/strong&gt;: Print a message to DevTools console before the page loads.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;After page load&lt;/strong&gt;: Print a message to DevTools console before the page loads.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Popup interaction&lt;/strong&gt;: Displays a popup when the user clicks the extension button, allowing for more complex user interactions.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The extension now provides a button within the popup that, when clicked, injects a script into the active tab to modify the DOM and log a message to the console.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Clone or download the files from &lt;a href="https://github.com/llagerlof/fresh-chrome-extension" rel="noopener noreferrer"&gt;github.com/llagerlof/fresh-chrome-extension&lt;/a&gt; and place them in a directory.&lt;/li&gt;
&lt;li&gt;Open your browser's extension page: &lt;strong&gt;chrome://extensions&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Enable "Developer mode" in the top right corner.&lt;/li&gt;
&lt;li&gt;Click &lt;code&gt;Load Unpacked&lt;/code&gt; and select the extension directory.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  How to test it
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Open any website.&lt;/li&gt;
&lt;li&gt;Click the extension button on the browser's top bar. You'll see a popup with a button.&lt;/li&gt;
&lt;li&gt;Click the button in the popup labeled "Click this button to add an orange div to the page".&lt;/li&gt;
&lt;li&gt;Observe the following changes:

&lt;ul&gt;
&lt;li&gt;An orange div appears at the top of the page with the message "DOM modified!"&lt;/li&gt;
&lt;li&gt;Open the developer tools (F12) and look at the console. You'll see the message "Action executed from popup!"&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0szi0nygbd1lx6ktsynz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0szi0nygbd1lx6ktsynz.png" alt="Screenshot of the extension in action"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This boilerplate provides a solid foundation for building more complex Chrome extensions. Feel free to modify and extend it to suit your specific needs.&lt;/p&gt;

&lt;p&gt;Happy coding!&lt;/p&gt;

</description>
      <category>extension</category>
      <category>chrome</category>
      <category>javascript</category>
      <category>boilerplate</category>
    </item>
    <item>
      <title>crtlr.sh - CTRL+r on steroids</title>
      <dc:creator>Lawrence Lagerlof</dc:creator>
      <pubDate>Wed, 05 Apr 2023 12:32:58 +0000</pubDate>
      <link>https://dev.to/llagerlof/crtlrsh-ctrlr-on-steroids-584c</link>
      <guid>https://dev.to/llagerlof/crtlrsh-ctrlr-on-steroids-584c</guid>
      <description>&lt;p&gt;This project is available on GitHub at &lt;a href="http://github.com/llagerlof/ctrlr"&gt;http://github.com/llagerlof/ctrlr&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Usage
&lt;/h3&gt;

&lt;p&gt;Once the script is installed, use the &lt;code&gt;CTRL+r&lt;/code&gt; shortcut in the terminal as you normally would to find past commands. You can use the arrow keys or you can type to search. Find the command you want to execute and press ENTER. The selected command will be inserted into the prompt (but not executed). If you want to execute it you should press ENTER again.&lt;/p&gt;

&lt;p&gt;Beyond that the selected command will be copied to the clipboard, ready to be pasted anywhere (try &lt;code&gt;CTRL+SHIFT+V&lt;/code&gt; in another application).&lt;/p&gt;

&lt;h3&gt;
  
  
  Installation
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Install &lt;code&gt;fzf&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Install &lt;code&gt;xclip&lt;/code&gt; or &lt;code&gt;xsel&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Copy the &lt;code&gt;ctrlr.sh&lt;/code&gt; file to &lt;code&gt;/usr/local/bin/&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Make it executable:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;chmod +x /usr/local/bin/ctrlr.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Override the vanilla &lt;code&gt;CTRL+r&lt;/code&gt; adding the following line to the end of your &lt;code&gt;~/.bashrc&lt;/code&gt;:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bind -x '"\C-r": "source /usr/local/bin/ctrlr.sh"'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Restart the terminal&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>bash</category>
      <category>linux</category>
      <category>tool</category>
      <category>shell</category>
    </item>
    <item>
      <title>Autoleap - automatically leap into any previously visited directory</title>
      <dc:creator>Lawrence Lagerlof</dc:creator>
      <pubDate>Tue, 17 Jan 2023 20:18:00 +0000</pubDate>
      <link>https://dev.to/llagerlof/autoleap-a-very-useful-tool-for-linux-bash-users-1n31</link>
      <guid>https://dev.to/llagerlof/autoleap-a-very-useful-tool-for-linux-bash-users-1n31</guid>
      <description>&lt;p&gt;This script adds an amazing feature to the &lt;code&gt;cd&lt;/code&gt; command. It records (locally) the path of all directories you visit using &lt;code&gt;cd&lt;/code&gt;. When you want to access a previously visited directory, you just need to run &lt;code&gt;cd part_of_directory_name&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The script is very lightweight and fast. The image below shows how simple it is to use:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/llagerlof/autoleap" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqrhepfbzre0mq0a2jemr.png" alt="Image showing how to use the tool" width="768" height="612"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can leap into any directory that exists in the history file, from anywhere.&lt;/p&gt;

&lt;h3&gt;
  
  
  Installation
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Access the GitHub &lt;a href="https://github.com/llagerlof/autoleap" rel="noopener noreferrer"&gt;project page&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Download the script &lt;code&gt;autoleap.sh&lt;/code&gt; anywhere.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;source&lt;/code&gt; the script on your &lt;code&gt;.bashrc&lt;/code&gt; (add the line &lt;code&gt;source /path/to/script/autoleap.sh&lt;/code&gt; to the end of your &lt;code&gt;.bashrc&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Reopen the terminal (or source &lt;code&gt;.bashrc&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Be happy.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>linux</category>
      <category>bash</category>
      <category>shell</category>
      <category>tool</category>
    </item>
    <item>
      <title>Navigator, a fine-tuned tool to quick directory access and navigation</title>
      <dc:creator>Lawrence Lagerlof</dc:creator>
      <pubDate>Fri, 25 Nov 2022 16:14:48 +0000</pubDate>
      <link>https://dev.to/llagerlof/navigator-a-fine-tuned-tool-to-quick-directory-access-and-navigation-487m</link>
      <guid>https://dev.to/llagerlof/navigator-a-fine-tuned-tool-to-quick-directory-access-and-navigation-487m</guid>
      <description>&lt;p&gt;This tiny tool that relies on the shoulder of giants has one single goal: &lt;strong&gt;to allow the user to navigate between directories faster than other tools, even &lt;code&gt;cd&lt;/code&gt; in most cases&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I focused on UX to make it easy and useful. Look these nice features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The last created directories are near the focused cursor for quick access.&lt;/li&gt;
&lt;li&gt;Always focus on directory ".." when changing directory to allow quick exit to the parent directory.&lt;/li&gt;
&lt;li&gt;Files are listed separated from directories.&lt;/li&gt;
&lt;li&gt;Files can be opened with the associated application.&lt;/li&gt;
&lt;li&gt;The path of last directory or file accessed is copied to the clipboard.&lt;/li&gt;
&lt;li&gt;Fuzzy search.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://github.com/llagerlof/navigator"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--T5JdNMqd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d8et60x4mpob4sfr1hkn.png" alt="shell screenshot inside the script navigator showing a list of files and directories" width="639" height="415"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;1)&lt;/strong&gt; Install the following dependencies using your distro's package manager:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;fzf&lt;/li&gt;
&lt;li&gt;xclip&lt;/li&gt;
&lt;li&gt;xgd-open (from package xdg-utils)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;2)&lt;/strong&gt; Download the script &lt;code&gt;navigator&lt;/code&gt; from &lt;a href="https://github.com/llagerlof/navigator"&gt;https://github.com/llagerlof/navigator&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3)&lt;/strong&gt; Copy the script to &lt;code&gt;/usr/local/bin/&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4)&lt;/strong&gt; Make it executable with &lt;code&gt;chmod +x /usr/local/bin/navigator&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5)&lt;/strong&gt; Create an alias in your &lt;code&gt;~/.bashrc&lt;/code&gt;. Add the following line to the end of file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;alias n="source /usr/local/bin/navigator"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;6)&lt;/strong&gt; Reopen the shell to reload the aliases.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Run the script typing &lt;code&gt;n&lt;/code&gt; in bash.&lt;/li&gt;
&lt;li&gt;Navigate with arrow keys.&lt;/li&gt;
&lt;li&gt;Press ENTER key to access a directory.&lt;/li&gt;
&lt;li&gt;Press ENTER key to open a file with the associated application.&lt;/li&gt;
&lt;li&gt;Press ESC key to exit the script. Your new current directory is the last directory visited while using Navigator.&lt;/li&gt;
&lt;li&gt;Start typing to fuzzy search the current list of directories and files.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>bash</category>
      <category>linux</category>
      <category>commandline</category>
      <category>shell</category>
    </item>
    <item>
      <title>mariabak: Making MariaDB and MySQL backups a breeze</title>
      <dc:creator>Lawrence Lagerlof</dc:creator>
      <pubDate>Thu, 11 Aug 2022 15:18:31 +0000</pubDate>
      <link>https://dev.to/llagerlof/mariabak-making-mariadb-and-mysql-backups-a-breeze-37ep</link>
      <guid>https://dev.to/llagerlof/mariabak-making-mariadb-and-mysql-backups-a-breeze-37ep</guid>
      <description>&lt;h2&gt;
  
  
  About
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;mariabak&lt;/strong&gt; is a opensource command-line program frontend for &lt;code&gt;mysqldump&lt;/code&gt; to make MariaDB and MySQL databases backups. Some operations are easier using &lt;code&gt;mariabak&lt;/code&gt; than using &lt;code&gt;mysqldump&lt;/code&gt; directly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Project page
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/llagerlof/mariabak" rel="noopener noreferrer"&gt;https://github.com/llagerlof/mariabak&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Let's see some of the goodies:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;You can opt-out dump data from specific tables. The good news: the tables structure will be preserved (&lt;code&gt;mysqldump&lt;/code&gt; doesn't have this as a native option so you need to execute more than one command to do this).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You can perform backup of all databases at once, or just some chosen databases, creating one dump file for each database (&lt;code&gt;mysqldump&lt;/code&gt; put all databases into one single dump file).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;One directory with a timestamp will be created for each &lt;code&gt;mariabak&lt;/code&gt; execution (more than one file is generated for each backup, so let's keep things organized).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It backups all the user grants, system variables and events to separate files.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Hands-on
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F193798%2F184143085-23380ab9-03da-4d66-8ba8-1aaa1650f3ea.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F193798%2F184143085-23380ab9-03da-4d66-8ba8-1aaa1650f3ea.gif" alt="Demonstration"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Usage examples
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;List databases:&lt;/strong&gt;&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="nv"&gt;$ &lt;/span&gt;mariabak &lt;span class="nt"&gt;-list&lt;/span&gt;     &lt;span class="c"&gt;# default localhost, user root, empty password&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Backup all databases. A directory will be created in current directory:&lt;/strong&gt;&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="nv"&gt;$ &lt;/span&gt;mariabak &lt;span class="nt"&gt;--databases&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;*&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Backup one database, asking for the server password interactively:&lt;/strong&gt;&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="nv"&gt;$ &lt;/span&gt;mariabak &lt;span class="nt"&gt;--databases&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;db1 &lt;span class="nt"&gt;--host&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;localhost &lt;span class="nt"&gt;--user&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;root &lt;span class="nt"&gt;-p&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Backup some databases, ignore some tables data but preserve its structure:&lt;/strong&gt;&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="nv"&gt;$ &lt;/span&gt;mariabak &lt;span class="nt"&gt;--databases&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;db1,db2,db3 &lt;span class="nt"&gt;--ignore-tables&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;db2.table1,db2.table2,db3.table_a &lt;span class="nt"&gt;--user&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;root &lt;span class="nt"&gt;-p&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Backup one database, passing the server password inline:&lt;/strong&gt;&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="nv"&gt;$ &lt;/span&gt;mariabak &lt;span class="nt"&gt;--databases&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;db1 &lt;span class="nt"&gt;--host&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;localhost &lt;span class="nt"&gt;--user&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;root &lt;span class="nt"&gt;--port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;3306 &lt;span class="nt"&gt;--password&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;hunter2  &lt;span class="c"&gt;# Caution with this one. The shell can save command history.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>backup</category>
      <category>mariadb</category>
      <category>mysql</category>
      <category>php</category>
    </item>
    <item>
      <title>Chrome Extension boilerplate (Manifest V3)</title>
      <dc:creator>Lawrence Lagerlof</dc:creator>
      <pubDate>Mon, 09 Aug 2021 15:13:35 +0000</pubDate>
      <link>https://dev.to/llagerlof/chrome-extension-boilerplate-manifest-v3-1mj</link>
      <guid>https://dev.to/llagerlof/chrome-extension-boilerplate-manifest-v3-1mj</guid>
      <description>&lt;h2&gt;
  
  
  The goal
&lt;/h2&gt;

&lt;p&gt;This &lt;a href="https://github.com/llagerlof/fresh-chrome-extension" rel="noopener noreferrer"&gt;boilerplate extension&lt;/a&gt; can be used for devs as a starting point for creating your own extensions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Features
&lt;/h2&gt;

&lt;p&gt;Once installed it observes the 3 most common events: &lt;strong&gt;Before the page load&lt;/strong&gt;, &lt;strong&gt;after page load&lt;/strong&gt;, and &lt;strong&gt;clicking the extension button&lt;/strong&gt; on the browser top bar.&lt;/p&gt;

&lt;p&gt;For each event it writes a message on &lt;em&gt;DevTools&lt;/em&gt; console &lt;em&gt;(press F12 to see it)&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;manifest&lt;/code&gt; is configured to work on every &lt;strong&gt;https&lt;/strong&gt; and &lt;strong&gt;http&lt;/strong&gt; page, but is up to you to define your own.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Get the files from &lt;a href="https://github.com/llagerlof/fresh-chrome-extension" rel="noopener noreferrer"&gt;github.com/llagerlof/fresh-chrome-extension&lt;/a&gt; and put them inside some directory.&lt;/li&gt;
&lt;li&gt;Open the browser extension page: &lt;strong&gt;chrome://extensions&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Check the developer mode on top right.&lt;/li&gt;
&lt;li&gt;Click &lt;code&gt;Load Unpacked&lt;/code&gt; and select the extension directory.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  How to test it
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Open any website.&lt;/li&gt;
&lt;li&gt;Open developer tools and look at the console. You will see 2 messages. One message was written before page load, the other was written after page load.&lt;/li&gt;
&lt;li&gt;Click the extension button on browser top bar and watch the console. A third message will be written &lt;em&gt;(don't forget that new extensions are hidden inside the Chrome "puzzle" button, on top right)&lt;/em&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8w21suncjyg0172f71tk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8w21suncjyg0172f71tk.png" alt="Screenshot do console quando a extensão é usada."&gt;&lt;/a&gt;&lt;/p&gt;

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

</description>
      <category>extension</category>
      <category>chrome</category>
      <category>javascript</category>
      <category>boilerplate</category>
    </item>
    <item>
      <title>Freezer, a tool to help devs discover which records are created when some action is performed on any application that uses MySQL</title>
      <dc:creator>Lawrence Lagerlof</dc:creator>
      <pubDate>Fri, 17 Jul 2020 11:33:35 +0000</pubDate>
      <link>https://dev.to/llagerlof/freezer-a-tool-to-help-devs-discover-which-records-are-created-when-some-action-is-performed-on-any-application-that-uses-mysql-1oca</link>
      <guid>https://dev.to/llagerlof/freezer-a-tool-to-help-devs-discover-which-records-are-created-when-some-action-is-performed-on-any-application-that-uses-mysql-1oca</guid>
      <description>&lt;h2&gt;
  
  
  The goal
&lt;/h2&gt;

&lt;p&gt;The purpose of this tool is to shorten the learning curve necessary to understand the relationships between tables of any MySQL database.&lt;/p&gt;

&lt;h2&gt;
  
  
  How it works?
&lt;/h2&gt;

&lt;p&gt;You are a developer, and sometimes you need to understand third-party applications, either to generate a report or to create a new feature. In theory would be enough to look at relationships, but real life applications tend to create several records in several tables that aren't always clear for the programmer just looking at the structure, and sometimes requiring a lot of research to understand what "that" button does in database. That's where the Freezer comes in.&lt;/p&gt;

&lt;p&gt;Suppose you want to quickly know which tables receives new records, as well as what those records are, when you perform any action in any application installed in your computer (for development purposes). It's very easy:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; With the Freezer application you click on the &lt;strong&gt;Freeze&lt;/strong&gt; button.&lt;br&gt;
&lt;strong&gt;2.&lt;/strong&gt; With the other application you perform one or more operations.&lt;br&gt;
&lt;strong&gt;3.&lt;/strong&gt; Back on the Freezer you click on the &lt;strong&gt;What is New&lt;/strong&gt; button.&lt;/p&gt;

&lt;p&gt;Freezer will show you which records were inserted in all database's tables between the &lt;strong&gt;Freeze&lt;/strong&gt; and &lt;strong&gt;What is New&lt;/strong&gt; commands, and that is an excellent starting point to focus your attention to whatever feature you need to develop for that application, or data you need to extract from that database.&lt;/p&gt;
&lt;h2&gt;
  
  
  Use case
&lt;/h2&gt;

&lt;p&gt;In this example I want to know which records are inserted in Moodle's database when an assignment is created.&lt;/p&gt;

&lt;p&gt;I chose &lt;a href="https://moodle.org"&gt;Moodle&lt;/a&gt; for this demo specifically because the complexity of its database, but you can connect to any MySQL database.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://camo.githubusercontent.com/3a05a0d485f93a6f2b71fc3e08b4b555a3675c4c/68747470733a2f2f692e696d6775722e636f6d2f54674a4f4966642e676966" class="article-body-image-wrapper"&gt;&lt;img src="https://camo.githubusercontent.com/3a05a0d485f93a6f2b71fc3e08b4b555a3675c4c/68747470733a2f2f692e696d6775722e636f6d2f54674a4f4966642e676966" alt="Freezer GIF showcase"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  The project
&lt;/h2&gt;

&lt;p&gt;It's open source, easy to install and use. Just put it in your local web server, configure one or more databases and you are good to go.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vJ70wriM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/github-logo-ba8488d21cd8ee1fee097b8410db9deaa41d0ca30b004c0c63de0a479114156f.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/llagerlof"&gt;
        llagerlof
      &lt;/a&gt; / &lt;a href="https://github.com/llagerlof/freezer"&gt;
        freezer
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Freezer is a tool to help developers to discover which database's records are inserted by other programs.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;h1&gt;
Freezer&lt;/h1&gt;
&lt;p&gt;Freezer is a tool to help developers discover which database records are created by some application's action and which tables received these new records because that action.&lt;/p&gt;
&lt;p&gt;It makes much easier to spot these tables and its new records, understand how the third-party application interacts with the database and also how relationships are made.&lt;/p&gt;
&lt;h2&gt;
Latest version&lt;/h2&gt;
&lt;p&gt;0.16.2&lt;/p&gt;
&lt;p&gt;Currently only MySQL/MariaDB is supported.&lt;/p&gt;
&lt;h2&gt;
Objective&lt;/h2&gt;
&lt;p&gt;The goal of this tool is to shorten the time that developers need to understand the structure of a given database identifying in which tables the third-party application, like &lt;a href="https://moodle.org" rel="nofollow"&gt;&lt;strong&gt;Moodle&lt;/strong&gt;&lt;/a&gt;, &lt;a href="https://www.humhub.com" rel="nofollow"&gt;&lt;strong&gt;HumHub&lt;/strong&gt;&lt;/a&gt; or &lt;a href="https://elgg.org" rel="nofollow"&gt;&lt;strong&gt;Elgg&lt;/strong&gt;&lt;/a&gt; for instance, inserts new records depending on the action the application performed, so the developer can focus directly on the tables that primarily matter for that specific action.&lt;/p&gt;
&lt;p&gt;Or maybe you just want to quickly know which tables are affected by some application's action.&lt;/p&gt;
&lt;p&gt;Freezer can connect to any MySQL/MariaDB database, not…&lt;/p&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/llagerlof/freezer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


</description>
      <category>mysql</category>
      <category>webdev</category>
      <category>productivity</category>
      <category>php</category>
    </item>
    <item>
      <title>MoodleRest, a PHP class to query Moodle REST webservices</title>
      <dc:creator>Lawrence Lagerlof</dc:creator>
      <pubDate>Fri, 20 Dec 2019 14:33:01 +0000</pubDate>
      <link>https://dev.to/llagerlof/moodlerest-a-php-class-to-query-moodle-rest-webservices-4b24</link>
      <guid>https://dev.to/llagerlof/moodlerest-a-php-class-to-query-moodle-rest-webservices-4b24</guid>
      <description>&lt;h2&gt;
  
  
  What it does, exactly?
&lt;/h2&gt;

&lt;p&gt;MoodleRest allow you to easily make GET or POST requests to query or update information from many webservices available on &lt;a href="https://moodle.org"&gt;Moodle&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Moodle is a learning platform designed to provide educators, administrators and learners with a single robust, secure and integrated system to create personalised learning environments".&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This lib can return information from Moodle webservices in one of these formats:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;array&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;json&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;xml&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The GitHub project page
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/llagerlof/MoodleRest"&gt;https://github.com/llagerlof/MoodleRest&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This dev.to article covers the basics. Many more examples and other features on project page.&lt;/p&gt;

&lt;h2&gt;
  
  
  Requirements
&lt;/h2&gt;

&lt;p&gt;Ensure you already have access to a Moodle webservice. To use this class you will need a token (generated by Moodle admin) with the necessary capabilities for the services you want to access.&lt;/p&gt;

&lt;h2&gt;
  
  
  To the code
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;You have 2 options to add this lib to your project:&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Option One
&lt;/h3&gt;

&lt;p&gt;Use Composer to include it in your project.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Inside your project directory create or modify the file &lt;code&gt;composer.json&lt;/code&gt;:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"require"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"llagerlof/moodlerest"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2.3.0"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;In the same directory of the &lt;code&gt;composer.json&lt;/code&gt;, run:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;composer &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;In your project, load the lib using composer autoloader:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;
&lt;span class="k"&gt;require_once&lt;/span&gt; &lt;span class="nb"&gt;dirname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;__FILE__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;'/vendor/autoload.php'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Option Two
&lt;/h3&gt;

&lt;p&gt;Just include the &lt;code&gt;MoodleRest.php&lt;/code&gt; class directly in your script.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;require_once&lt;/span&gt; &lt;span class="nb"&gt;dirname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;__FILE__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;'/MoodleRest.php'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  The &lt;code&gt;MoodleRest&lt;/code&gt; constructor
&lt;/h2&gt;

&lt;p&gt;You can pass 2 parameters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A full url path to the Moodle webserver&lt;/li&gt;
&lt;li&gt;The token generated by Moodle admin.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$MoodleRest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;MoodleRest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s1"&gt;'http://127.0.0.1/moodle/webservice/rest/server.php'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="s1"&gt;'8f12e614dae30735260a045313caa400'&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  The method &lt;code&gt;request()&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;This method needs at least 2 parameters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The webservice functiona name (string).&lt;/li&gt;
&lt;li&gt;The parameters (array) passed to the webservice. The MoodleRest will internally convert this array to a query string. If you need to learn how to build an array compatible to each webservice's function &lt;a href="https://github.com/llagerlof/MoodleRest/wiki/Understanding-the-%24parameters-in-request()-method"&gt;I have you covered&lt;/a&gt;!&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Query example (GET)
&lt;/h2&gt;

&lt;p&gt;Query 2 Moodle groups with IDs 1 and 2, passing the server URL and token in constructor using the &lt;code&gt;request&lt;/code&gt; method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$MoodleRest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;MoodleRest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s1"&gt;'http://127.0.0.1/moodle/webservice/rest/server.php'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="s1"&gt;'8f12e614dae30735260a045313caa400'&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nv"&gt;$groups&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$MoodleRest&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s1"&gt;'core_group_get_groups'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="k"&gt;array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'groupids'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nb"&gt;print_r&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$groups&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Inserting data example (POST)
&lt;/h2&gt;

&lt;p&gt;Set the server and token in constructor and make a request to create a group on Moodle.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$MoodleRest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;MoodleRest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s1"&gt;'http://127.0.0.1/moodle/webservice/rest/server.php'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="s1"&gt;'8f12e614dae30735260a045313caa400'&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nv"&gt;$new_group&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s1"&gt;'groups'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="k"&gt;array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="s1"&gt;'courseid'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
            &lt;span class="s1"&gt;'name'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'Group name'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
            &lt;span class="s1"&gt;'description'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'Group description'&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="cm"&gt;/*
The default request's METHOD is to make a GET request, but you can change it to POST.
This is recommended when inserting and updating data.
*/&lt;/span&gt;

&lt;span class="nv"&gt;$return&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$MoodleRest&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s1"&gt;'core_group_create_groups'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="nv"&gt;$new_group&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="nx"&gt;MoodleRest&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;METHOD_POST&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// If you want the requested URL&lt;/span&gt;
&lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$MoodleRest&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;getUrl&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;That's it! Quick and easy.&lt;/p&gt;

&lt;p&gt;More features and examples on &lt;a href="https://github.com/llagerlof/MoodleRest"&gt;project page&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>moodle</category>
      <category>php</category>
      <category>rest</category>
      <category>lms</category>
    </item>
    <item>
      <title>QuickAuthPHP – One script for web authentication. Multi-user. No database required.</title>
      <dc:creator>Lawrence Lagerlof</dc:creator>
      <pubDate>Tue, 27 Nov 2018 17:11:19 +0000</pubDate>
      <link>https://dev.to/llagerlof/quickauthphp--one-script-for-web-authentication-multi-user-no-database-required-5fa2</link>
      <guid>https://dev.to/llagerlof/quickauthphp--one-script-for-web-authentication-multi-user-no-database-required-5fa2</guid>
      <description>

&lt;h2&gt;
  
  
  Goal
&lt;/h2&gt;

&lt;p&gt;Sometimes you have a small web application that you want to keep private, but don't have time to implement a proper database authentication system, nor &lt;em&gt;.htaccess&lt;/em&gt; is suitable for your needs (or you hate native browser authentication, like me). If this is true for you, QuickAuthPHP is a super fast solution.&lt;/p&gt;

&lt;h2&gt;
  
  
  Project website
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/llagerlof/QuickAuthPHP"&gt;github.com/llagerlof/QuickAuthPHP&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What it does?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Add a single login form to any webpage on your server.&lt;/li&gt;
&lt;li&gt;You can have multiple logins and passwords.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Goodies
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;One single script easy to configure and install.&lt;/li&gt;
&lt;li&gt;Non obstrusive. You only need to require_once() the script in your web pages.&lt;/li&gt;
&lt;li&gt;No dependencies.&lt;/li&gt;
&lt;li&gt;No need to change HTML, Javascript or CSS in your pages.&lt;/li&gt;
&lt;li&gt;Secure.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What will you need?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A working web server with PHP 5.5 or above (preferably 7.x).&lt;/li&gt;
&lt;li&gt;The file &lt;a href="https://github.com/llagerlof/QuickAuthPHP"&gt;auth.php&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;


</description>
      <category>php</category>
      <category>authentication</category>
      <category>opensource</category>
      <category>github</category>
    </item>
  </channel>
</rss>
