Overview



How to build something

[Mostly from POV of a Linux user:]
+/-
  • Before you start building:

    • Ask for advice about how to solve the problem your app would solve. Maybe a solution exists already.

    • Ask about the standard name for the kind of thing you want to do; often that's the key to finding existing things.

    • Search for existing similar apps, ask on forums if anyone knows of a similar app.

    • Search for apps on a variety of platforms and styles: scripts, phone apps, desktop CLI apps, desktop GUI apps, GitHub projects, desktop widgets/extensions, docks/launchers, macroes, bookmarklets, add-ons, web pages, CLI shells.

  • Can you do what you need with existing CLI apps ? Make a shell script.
    To add char-graphical touches, you can use a dialog package, or tput.
    Linux Shell Script

  • Is what you need best done inside an existing GUI app (browser or editor or IDE or image-editor or system file-explorer app) ?

    • Search the Help and menus and buttons of the app; often they have buried features you don't know about.

    • Can you use an existing extension/add-on for the existing app ? If your usual app for that kind of processing doesn't support add-ons, maybe switch to an alternative app that does.

    • Can you use CLI to drive the existing GUI app ? Go to CLI and run the GUI app from there to see options, such as "firefox --help". If the necessary options exist, make a shell script.
      Linux Shell Script

    • Can you use a macro/script engine to drive the existing GUI app ?
      Kantu, iMacro, Greasemonkey, FireMonkey.

    • Can you build a new extension/add-on/scriptlet for the existing app ?
      If your usual app for that kind of processing doesn't support add-ons, maybe switch to an alternative app that does.
      Building a Firefox Extension
      Building a Thunderbird Extension
      Building a VS Code Extension
      Nemo file-explorer actions/scripts
      Dolphin file-explorer actions/scripts

  • Can you do what you need by adding a small feature to an existing app ? Find out where that app's source project lives, what language it's built in. File a feature request, or build the new feature yourself.

  • Do you need a fairly simple app, a step or two up from a shell script ? Maybe make a single-file Python or PHP app.
    PHP program

  • Does your app not need access to the filesystem ? Maybe make a web page, with HTML and CSS and JavaScript. Or a Jupyter Notebook document: Jack Wallen article. Or a spreadsheet. Maybe a simple app based on a spreadsheet or database: Low Code / No Code. Or a web site/app embedded in an Electron app: Ayush Sharma's "Turn any website into a Linux desktop app" (Nativefier).

  • If you want to make a text-processing app, and maybe pipe it with other apps, make a CLI app.
    Probably write it in Rust or Go.
    Prasad, Firshman, Tashian, and Parish's "Command Line Interface Guidelines"
    Manuel Odendahl's "14 great tips to make amazing CLI applications"
    Noaa Barki's "3 steps to create an awesome UX in a CLI application"

  • If you want to make a GUI app:

    • If you want the app to be very cross-platform, maybe use: Electron, Chromium Embedded Framework (CEF), Flutter, Java, C# with Uno. Qt runs on a lot of platforms too.

    • If you want the app to be very Linux-native, maybe use GTK or Qt for the GUI framework/toolkit.

      Then you can use one of many languages for the app logic. With GTK, you can use C, C++, Python, Rust, Vala, Java, or even JavaScript ? With Qt, same ?
      PyQt or pyside2 or similar
      Java

      With GTK, maybe use GNOME Builder ?
      With Qt, maybe use Qt Creator (article) ?

      Make a Linux App

      Don't make your own theme and icons and decorations etc in the app; use the system-wide settings.

      If you do want to take it cross-platform, follow the convention for each OS, for things such as where to put config files, name and location of Settings/Preference menu item, etc.

      See "Desktop Frameworks" section


codecrafters-io / build-your-own-x



GUI app types/architectures

+/-
[Still trying to get my head around these.]


Architectures:
+/-
  • Web app:

    State is kept in a database server. UI is provided by web pages from web server. App-logic may be in an app-server in the middle, with a RESTful API. Scales up to many users. Works for sharing/syncing data among multiple devices. State at any time is sane and persistent.

    Data can change out from under the web page at any time. Data could be saved in one big form-submit, or small field-by-field operations to the database. Data could be read from database once at page load, or constantly in the background via AJAX ?

    Only local client is a browser. Fits well with MVC model. May have to duplicate some logic at multiple levels.

    Less control by the app developer: User could refresh a page or click Back or close the page at any time. Attacker could submit any kind of get/post to the server to try to break in.

    Fireship's "100+ Web Development Things you Should Know" (video)
    Fireship's "I built 10 web apps ... with 10 different languages" (video)

    Progressive web-app (PWA): has a disputed definition. Web app that runs in a browser but has features/feel/UI of a desktop/mobile app. Probably should be able to run from an icon on the desktop, maybe run without browser's menus/toolbars showing, be cached in the browser and have a manifest and run offline and use local storage, have service workers and TLS in the background that handle the data connection, maybe do push notifications. On mobile, not being an app means not having to pay a percentage to the Store.
    Sam Richard's "What are Progressive Web Apps?"
    Anand Mahajan's "What are Progressive Web Apps?"
    Chrome Deveopers' "Chrome Apps"

    Reactive: you write an HTML page, linking fields/buttons to database items and operations. Then things happen sort of automatically, from bottom up: as data in UI or database changes, framework reacts by sending data between UI and database, without you having to write code to do it.
    Honestly Undefined's "Reactive solution" (cartoon)

    Single-page web app (SPA): Browser loads the page once, then code on the page rewrites pieces of the DOM again and again as the user does things, fetching data and HTML fragments from the server or reacting to data pushed from the server. Looks to the user somewhat like a traditional desktop app, because the big "page-and-all-resources fetch-and-parse" only happens once, at the start. Frameworks such as React, Vue, AngularJS support this style. Back-end connection can be via AJAX, WebSockets, Server-Sent Events (SSE), more. The data may be sent in XML, JSON, serialized, HTML formats. There can be various designs where most business logic is done on the client, on server, or both. SPAs create problems in some areas: search engines, portability across browsers, security, server code may track or replicate state of DOM, duplicate code on client and server, user actions can interfere.

    Web App launcher: Icon on the desktop, that launches a browser showing a web page or web app or PWA from a server.
    Brian Burgess's "Install a Website as an App on Your Desktop with Microsoft Edge"
    Techdows article about FirefoxPWA
    Jordan Gloor's "How to Create a Web App in Linux Mint"


  • Desktop app:

    State, UI, app-logic are kept locally and may be mixed together. Single-user, and the app can make lots of assumptions about state. State at any time is sane but may be transient (not saved yet) or persistent.

    Thick client: Local client is a custom application (which may include a browser engine).

    Usually CPU-architecture-specific, OS-specific, maybe DE-specific.

    More control by the app developer: User can be forced to follow a certain path, warned about unsaved data, etc. Attacker has fewer APIs or attack surfaces to work with.


  • Some mixture of the two.

    Maybe the desktop app is custom and complex and has much of the app-logic, but then there is a database server storing the state and having some app-logic, and multiple users of the database.

    Thin-client: Maybe the desktop runs only a browser or remote-desktop app (Citrix, VNC, etc), but the web/app-server is running a large custom, complex app that provides UI and app-logic and has the notion of "sessions" and stores some state. And there is a database server storing the state and having some app-logic, and multiple users of the database.


  • Phone app:

    Have to follow conventions of the device and OS. Often authentication/login is done implicitly, using the ID of the phone. Varying, limited, intermittent, and maybe metered network connection. If applicable, expected to use shared facilities / messages to other apps to do things such as calendar and contacts and notifications. May have to adapt to features being disabled by user, or not available in older OS versions or older API versions, or not available on some devices.

    Android development
    Flutter / Dart



UIs:
+/-
  • Web pages (HTML, CSS, JS):

    Portable across many environments, but less detailed control of the UI. Each view is transient. Each operation is atomic.

    Easy to let the user tweak some UI things simply by editing CSS or changing browser settings.

    Responsive: adapt reasonably to varying screen sizes and touch screens and varying device abilities. Some key ideas here seem to be: design for mobile first, and learn CSS grid and flexbox.


  • Desktop UI (Java, C++, Qt, GTK, etc):

    Often OS-specific or DE-specific, but more detailed control of the UI. Often large, complex pages.


  • Phone app:

    Have to follow conventions of the device and OS. Limited and varying screen size. May have to adapt to features being disabled by user, or not available in older OS versions or older API versions, or not available on some devices.





Cross-platform GUI stacks

+/-
[Still trying to get my head around these.]

Java etc:
+/-
Java
Beans
Swing
Java Kotlin Scala many
more
Java bytecode
JVM (Java Virtual Machine)

.NET:
+/-
C# F# Visual
Basic
Iron
Python
PowerShell C++
(Windows
only)
many
more
IR ? CLI ?
CLR (Common Language Runtime)

C# probably is the main language on .NET.
.NET 5 fully supports Windows, Mac, Linux, iOS, Android.
.NET 5 is the newest version; .NET Framework (Windows-only) and .NET Core (old name) are older.
.NET Standard 2.0 is a library/specification/abstraction layer that works on top of any of them (.NET 5, .NET Framework, .NET Core).
.NET doesn't have a strong cross-platform desktop GUI toolkit; that's being worked on (as of 12/2020). It's very strong for back-end or web apps.
Wikipedia's ".NET Core"
Tim Anderson's "20 years of .NET: Reflecting on Microsoft's not-Java"
Wikipedia's "Universal Windows Platform"
Wikipedia's "LLVM"
Will Fuqua's ".NET and Linux" (video)
Federico Antuna's "Set up a .NET development environment" (on Fedora)
Charles Chen's "6 .NET Myths Dispelled"




Programming styles

+/-
[Still trying to get my head around these.]

"State" is values that can be changed in place; written and rewritten; mutable state.

  • Procedural:

    State is kept in global variables, database, files, devices (UI), etc.

  • Object-oriented:

    State is kept in objects, database, files, devices (UI), etc.

    IMO this can work well if the problem naturally is modeled as a network of objects, or if inheritance and polymorphism are minimized. But it's easy to get into a trap where state is spread all over the place, and code locality is poor (you have to look in many places up and down the hierarchy to figure out what a particular method is doing and what the state is).

    Well-suited languages: C++, C#, Java.

  • Functional:

    State is kept in a database, files, and devices (UI).

    The data flows through sort of a pipeline of functions, with everything (data, configuration, rules, etc) needed by a function passed into it as arguments, and all results come out of the function. Also you can pass functions as arguments to other functions.

    This style is a good fit with VMs and micro-services and cloud, where computing/processing engines are transient, and state is kept in a database.

    It works best if you minimize the state (so you don't have tons of database accesses), concentrate the state (keep it in one place), and defer changes (one commit at the end of processing).

    Well-suited languages: F#.




Shannon's "An Easy README Makeover In 3 Simple Steps"
ddbeck / readme-checklist
readme.so - The easiest way to create a README

TRooTech's "How to Release Great Software Using these 12 Types of Testing"





Build Systems



Wikipedia's "List of build automation software"





App GUI Prototyping



UX Design Institute's "9 best prototyping tools for UI/UX designers"

Jim Nielsen's "User Feedback"



Ended up just hand-writing HTML in a web page to show people what I was talking about: Mockup1


Ravi Makhija's "How to Build a Web Application: An Outline of the Major Steps"





Mobile



If there ever will be a mobile version of your app, probably best to write that version first, and write the desktop version later. Mobile has more limitations and strange events and device variations.

Jared Newman's "Why some developers are avoiding app store headaches by going web-only"

Gergely Orosz's "10 Engineering Challenges Due to the Nature of Mobile Applications"

"Development" section of my Android page





Electron (Simple App)



From someone on reddit:
+/- An Electron application is (basically) a web app packaged with a (slightly old) version of the Chrome browser ...

The Electron application has a copy of the Node.js runtime, which allows you to do many of the things that a native desktop application can do, but which the security model of a web browser doesn't allow you to do, including accessing local files, integrating at a lower level with the Operating System.



Note that Electron has a bit of a fatal flaw: it has a browser engine embedded in it. Security vulns in browsers are found frequently and publicized widely. If the electron app you use has a year-old browser engine in it, your app may be vulnerable.

From someone on Hacker News 8/2022:
"Ironically there is not a single electron app I ended up using in the long term. For all of them the web version ended up being superior: always up to date, running on a properly-secured browser and on which I prevent any external tracking, ads, when I allow or not access to my location, webcam, microphone, etc."



"Electron is a framework that allows developers to wrap web code (JavaScript, HTML, and other bits) in a native coating, giving them access to system-level APIs like notifications, file system, and so on, making it simple to deploy on Windows, macOS, Linux and anything else with one language."
from Owen Williams' "Microsoft Putting Edge on Chromium Will Fundamentally Change the Web"

Electron
Wikipedia's "Electron"
sindresorhus / awesome-electron
reddit's /r/electronjs

Martin Tournoij's "The web as a GUI toolkit"
Niels Leenheer's "Why Electron apps are fine"



A web site/app easily embedded in an Electron wrapper: Ayush Sharma's "Turn any website into a Linux desktop app" (Nativefier).



Electron's "Quick Start"

Electron's "Electron Simple Samples"
hokein / electron-sample-apps
sindresorhus / awesome-electron - Boilerplates



Tricky: "main process" versus "render process"

+/-
JavaScript in the "main" JS file (as specified in package.json) is running in the "main process", and JavaScript in the HTML file is running in the "render process". The syntax for connecting to modules is a bit different between the two.

"The DevTools in an Electron browser window can only debug JavaScript that's executed in that window (i.e. the web pages). To debug JavaScript that's executed in the main process you will need to use an external debugger and launch Electron with the --inspect or --inspect-brk switch."
from Electron's "Debugging the Main Process"

Using console.log() in Electron app

Carlos Delgado's "How to execute a function of the main process inside the renderer process in Electron Framework"



Making a tree-display application

+/-
Carlos Delgado's "Best tree view jQuery and JavaScript plugins"
npm's "electron tree view"
js-treeview"



npm --version
electron --version
sudo npm install -g electron --unsafe-perm=true --allow-root

cd ~/projects
mkdir installproto2
cd installproto2

npm init

npm install js-treeview
npm install load-json-file
npm install systeminformation
Create app.js file:

+/-
const {app, BrowserWindow} = require('electron')
const path = require('path')
const url = require('url')

let window = null

// Wait until the app is ready
app.once('ready', () => {
  // Create a new window
  // https://www.electronjs.org/docs/api/browser-window
  window = new BrowserWindow({
    // Set the initial width to 800px
    width: 800,
    // Set the initial height to 600px
    height: 600,
    // Set the default background color of the window to match the CSS
    // background color of the page, this prevents any white flickering
    backgroundColor: "#D6D8DC",
    // Don't show the window until it's ready, this prevents any white flickering
    show: false,
    webPreferences: { devTools: true, nodeIntegration: true }
  })

  // Load a URL in the window to the local index.html path
  window.loadURL(url.format({
    pathname: path.join(__dirname, 'index.html'),
    protocol: 'file:',
    slashes: true
  }))

  // Show window when page is ready
  window.once('ready-to-show', () => {
    window.show()
  })
})
Create index.html file:

+/-
<!DOCTYPE html>
<html lang="en-US">
<head>
<title>My app name</title>
<meta charset="UTF-8">

<link rel="stylesheet" href="index.css" />
<link rel="stylesheet" href="./node_modules/js-treeview/dist/treeview.min.css" />

<script>
delete module.exports
</script>

<script src="https://code.jquery.com/jquery-3.2.1.js"></script>
<script src="./window.js" charset="utf-8"></script>

</head>

<body>

<label id="t1filename"></label>
<button id="t1expandAll">Expand All</button>
<button id="t1collapseAll">Collapse All</button>
<br /><br />
<div id="t1tree"></div>

</body>

</html>
Create window.js file:

+/-
// "document ready" function:

$(() => {

  const jstreeview = require('js-treeview')
  const loadJsonFile = require('load-json-file')

// https://www.npmjs.com/package/js-treeview
// https://github.com/justinchmura/js-treeview
// https://www.npmjs.com/package/load-json-file


  //
  // Tree Structure
  //

  var t1dataX = [{
    name: 'Vegetables',
    children: []
  }, {
    name: 'Fruits',
    children: [{
      name: 'Apple',
      children: []
    }, {
      name: 'Orange',
      children: []
    }, {
      name: 'Lemon',
      children: []
    }]
  }, {
    name: 'Candy',
    children: [{
      name: 'Gummies',
      children: []
    }, {
      name: 'Chocolate',
      children: [{
        name: 'M & M\'s',
        children: []
      }, {
        name: 'Hershey Bar',
        children: []
      }]
    }, ]
  }, {
    name: 'Bread',
    children: []
  }];

let t1filename = "System-Existing.json";
var t1data = loadJsonFile.sync(t1filename);
$('#t1filename').text(t1filename);

  //
  // Grab expand/collapse buttons
  //
  var t1expandAll = document.getElementById('t1expandAll');
  var t1collapseAll = document.getElementById('t1collapseAll');

  //
  // Create tree
  //

  var t1 = new jstreeview(t1data, 't1tree');
  //$('#t1tree').text("hello");
  //alert("JSON.stringify(t1): " + JSON.stringify(t1));

  //
  // Attach events
  //

  $('#t1expandAll').bind('click', function() {
    //alert("t1expandAll click");
    t1.expandAll();
  });
  $('#t1collapseAll').bind('click', function() {
    //alert("t1collapseAll click");
    t1.collapseAll();
  });


  t1.on('select', function (e) {
    //const text = this.text;
	  //alert('select "' + this.name + '"');
    //alert("select");
    //alert("select: JSON.stringify(e.data): " + JSON.stringify(e.data));
	});
  t1.on('expand', function (e) {
	  // alert('expand');
    //alert("expand: JSON.stringify(e.leaves): " + JSON.stringify(e.leaves));
	  });
  t1.on('collapse', function (e) {
	  // alert('collapse');
    //alert("collapse: JSON.stringify(e.leaves): " + JSON.stringify(e.leaves));
	  });
  t1.on('expandAll', function () {
	  //alert('expand all');
	  });
  t1.on('collapseAll', function () {
	  // alert('collapse all');
	  });

})
Create index.css file:

+/-
td.mytree1 {
	border-style: solid;
	border-width: 1px;
	border-collapse: collapse;
	display:table;
	margin:0 auto;
	min-height: 500px;
	min-width: 300px;
	background-color:lightgreen;
}
Edit package.json file:

+/-
  "main": "app.js",
  "scripts": {
    "start": "/usr/local/lib/nodejs/node-v10.15.3-linux-x64/lib/node_modules/electron/dist/electron app.js"
  },
Run electron desktop-app:

npm start
# see desktop app window appear !

Updating after not running for a while ?

npm --version
electron --version
npm install
npm start
# see desktop app window appear !



To add menus, see:
Tutorialspoint's "Electron - Menus"
Electron's "Menu"

Wanted to modify the js-treeview module. Cloned it from GitHub to js-treeview1, and copied the src CSS and JS files from there to my project. Don't require js-treeview, use class name TreeView instead.



Using node.js:
NodeSchool
Chilkat Node.js Examples
reddit's /r/node
Finding modules to use:
w3schools' "Node.js Built-in Modules"
npm search
reddit's /r/npm



If you ever wipe out the node_modules tree (perhaps when backing up and restoring), in the project directory do "npm install", and then "npm start" or "sudo npm start" to run your app.



Making an installer

+/-
There can be two steps: packaging, and then making an installer.

There are four ways to do packaging and/or making installer: electron-packager, electron-builder, electron-forge, or manually (bad).

So far, I haven't tried electron-forge or manually, and I've found electron-builder is better than electron-packager.

Manually: Electron's "Application Packaging"

Electron-forge might be best ?
Electron's "Boilerplates and CLIs"
Electron Forge
electron-userland / electron-forge


Packaging the app (if you want to do packaging and making installer separately):
+/- Using electron-packager:
+/- Christian Engvall's "Electron packager tutorial"
electron / electron-packager


npm install electron-packager --save-dev
sudo npm install electron-packager -g
# edit package.json to add a "productName" line

#-------------------------
# build for MacOS:
./node_modules/.bin/electron-packager . --overwrite --platform=darwin --arch=x64 --icon=./icon.icns --prune=true --out=release-builds

#-------------------------
# build for Windows:
./node_modules/.bin/electron-packager . YOURPROJECTNAME --overwrite --asar --platform=win32 --arch=ia32 --icon=./icon.ico --prune=true --out=release-builds --version-string.ProductName="YOURPRODUCTNAME"
# requires WINE !!!

#-------------------------
# build for Linux:
./node_modules/.bin/electron-packager . YOURPROJECTNAME --overwrite --asar --platform=linux --arch=x64 --icon=./icon.png --prune=true --out=release-builds


Making an installer for the app

+/- If you used electron-packager:
+/- Christian Engvall's "DMG installer for electron app"
Christian Engvall's "Electron Windows installer tutorial"
Christian Engvall's "Electron installer debian package"


# build for MacOS:

npm install electron-installer-dmg --save-dev
sudo npm install electron-installer-dmg -g

./node_modules/.bin/electron-installer-dmg ./release-builds/YOURPRODUCTNAME-darwin-x64/YOURPRODUCTNAME.app YOURPROJECTNAME
# FAILS !!!:    Error: Must be run on OSX
# creates a file called YOURPROJECTNAME.dmg in the root folder of the application

# build for Windows:

npm install --save-dev electron-winstaller
mkdir installers
cd installers
mkdir windows
cd windows
# make file createinstaller.js as described in
# https://www.christianengvall.se/electron-windows-installer/
cd ../..

node installers/windows/createinstaller.js

# build for Linux:

npm install --save-dev electron-installer-debian
sudo npm install -g electron-installer-debian
# create file debian.json as described in
# https://www.christianengvall.se/electron-installer-debian-package/

./node_modules/.bin/electron-installer-debian --src release-builds/YOURPROJECTNAME-linux-x64/ --arch amd64 --config debian.json

Using electron-builder:
+/- electron-builder
electron-userland / electron-builder
Akash Nimare's "A complete guide to packaging your Electron app"


mkdir build
# copy a background.png and icon files into build directory

npm install electron-builder --save-dev

# had to tweak package.json file a lot
# https://www.electron.build/configuration/configuration
# add following to package.json file:
# "build": {
#  "appId": "YOURAPPID",
#  "mac": {
#    "category": "YOURAPPCATEGORY"
#  },
# "win": {
#   "target": "NSIS"
#  }
# },

#-------------------------
# build for MacOS:
./node_modules/.bin/electron-builder --macos default
# failed because it couldn't spawn hdiutil, which apparently runs only on MacOS

#-------------------------
# build for Windows:
# requires WINE !!!

# If you don't want to install wine through Software Manager:
apt install wine
sudo dpkg --add-architecture i386 && apt update && apt install wine32

# https://www.linuxbabe.com/linux-mint/install-wine-linux-mint-19-1
# Best to install wine-stable from Software Manager (535 MB)
# add /opt/wine-stable/bin to PATH in .profile, log out and in
winecfg
# gave:  0009:err:file:init_redirects cannot open L"C:\\windows" (c000000f)
# but kept going
# wanted to install wine-mono and gecko, but I said cancel to each
# Settings dialog came up, and I chose Windows 10
# Finished, and I ran it again, and Settings dialog came right up, no problems.

./node_modules/.bin/electron-builder --windows nsis
# insisted on an icon at least 256x256

#-------------------------
# build for Linux:
./node_modules/.bin/electron-builder --x64 --linux deb
# insisted on an icon at least 256x256








Electron (Complicated App)



App I want to create: matrix-dashboard (Mockup1),

The technology stack I'm looking at is

+/-
HTML/CSS:Bootstrap or Materialize or Tailwind CSS (article) or Foundation
Library everything else uses:jQuery
UI library or framework:Library: React or Vue. Framework: Angular (AKA "ng")
Electron
electron-builder (packager)
Modules:Node
Database access:SQL.js or Electron-store
Database format:SQLite or MongoDB
OS:Linux.

Wikipedia's "Comparison of JavaScript frameworks"
Oleg Logvin's "Angular 2+ vs ReactJS vs Vue.js - Which JavaScript Framework Used for Web Application Development is the Best"
A lot of them emphasize making a Single-Page Application (SPA) for a smartphone, and adding more stuff for bigger screens (tablet, laptop) as an afterthought.

Wikipedia's "Bootstrap (front-end framework)"
Safwana's "How to Use Bootstrap 4 with Angular"
Bootstrap widgets (ng-bootstrap) (replaces jQuery, Bootstrap's JavaScript, popper)
Techiediaries' "Using Bootstrap 4 with Angular 6|7"
w3schools' "Bootstrap 3 Tutorial"
TutorialRepublic's "Bootstrap 3 Tutorial"
reddit's /r/bootstrap
After playing with Bootstrap a little, I'm a little disappointed. It mostly emphasizes scaling down to handle different screen sizes (a "responsive site").

ng-bootstrap and ngx-bootstrap are modules that extend Bootstrap and replace its JS, integrating it more tightly with jQuery and Angular. They are two different projects by two different project teams.

Wikipedia's "Foundation (framework)"
pzuraq's "Four Eras of JavaScript Frameworks"

Wikipedia's "JQuery"

React is a Facebook/ex-Facebook thing.
Wikipedia's "React (JavaScript library)"
"React can be used as a base in the development of single-page or mobile applications. Complex React applications usually require the use of additional libraries for state management, routing, and interaction with an API."
Shedrack Akintayo's "A beginner's guide to developing with React"
Nick Parsons' "Takeaways on Building a React Based App with Electron"
Jesse Luoto's "What React gets wrong"

Wikipedia's "Vue.js"
Vue's "Comparison with Other Frameworks"

[Alternative to React or Vue: Svelte article]

[Simpler React: Preact article]

Angular is a Google/ex-Google thing.
AngularJS is an older, fairly different thing. Angular (AKA Angular2 or Angular7) is newer.
Wikipedia's "Angular (web framework)"
VS Code's "Using Angular in Visual Studio Code"
NgDevelop's "10 Best VS Code Extensions for Angular Development"
Coding Latte's "Top VS Code Extensions for Angular Developers"
stackoverflow's "How to debug Angular with VS Code?"
Hemant Joshi's "Understanding Routing in Angular"
Hemant Joshi's "Understanding Route Guards in Angular"
Hemant Joshi's "Understanding Observable - A key Concept in Angular"
Seth Gwartney's "Internationalize Your Angular App with ngx-translate"
Holger Schmitz's "Build a Desktop Application with Angular and Electron"
reddit's /r/angular
reddit's /r/Angular2
Angular's "Tutorial: Tour of Heroes"
You can't host an Angular page/site on a normal web-hosting service. You have to have a special Angular-capable hosting package.

Pavels Jelisejevs' "React vs Angular: An In-depth Comparison"
Spec India's "React vs Angular vs Vue.js: A Complete Comparison Guide"
Anatoliy Ulitovskiy's "JavaScript Framework Comparison: Vue, React and Angular (2019)"
From a podcast 9/2020: "For jobs, Angular > React > Vue." and "Vue puts HTML and JS and CSS/SCSS in same file, with control of scoping. So the code is more modular. Some people like this mixing and some people don't."

reddit's /r/electronjs
Christian Engvall's "Electron packager tutorial"

Wikipedia's "MongoDB"

Some possible starter apps:
patrickmoffitt / local-sqlite-example





Bootstrap / Angular / Electron



The technology stack I've chosen is

+/-
HTML/CSS:Bootstrap (CSS and JS), ng-bootstrap (JS)
Library:jQuery from ng-bootstrap (JS)
UI framework:Angular (AKA "ng")
Electron
electron-builder (packager)
Modules:Node
Database access:SQL.js
Database format:SQLite
OS:Linux.
Use yarn instead of npm ?



Getting started on new "matrix-dashboard" app:

Lukas Marx's "Creating Angular Desktop Apps with Electron"
Techiediaries' "Using Bootstrap 4 with Angular 6|7"
beeman's "Tutorial: Styling Angular CLI v6 apps with Bootstrap"
Maybe: Linux4one's "How to Install WebStorm on Linux Mint 19"

Name of app can not have any uppercase letters in it !

  1. Install stuff:

    
    +/-
    # if you don't have Node.js, install that
    
    sudo npm install -g @angular/cli@latest
    # got "skipping optional dependency fsevents"
    # apparently fsevents is for running on OSX
    ng --version
    # 3/2019: I got "Angular CLI: 7.3.5"
    
    sudo npm install -g typescript
    # 3/2019: got "typescript@3.3.3333"
    
    sudo npm install -g electron --unsafe-perm=true --allow-root
    # 3/2019: got "electron@4.0.8"
    
    # Name of new app can not have any uppercase letters in it !
    # cd to place where you want app dir to be created, and:
    ng new matrix-dashboard
    # Asked "Would you like to add Angular routing ?"
    #		This allows user to follow URL links to different parts
    #		of the one page of your single-page application
    #		I answered "no"
    # Asked "Which stylesheet format ?"
    #		I picked the default, CSS.
    
    cd matrix-dashboard
    
    # (I didn't realize that ng-bootstrap and ngx-bootstrap
    # are different things.  Having installed ng-bootstrap,
    # I'll stick with it.)
    ng add @ng-bootstrap/schematics
    # see warnings about peers of jquery and popper not found
    #	ignore the warnings
    #	You don't need jQuery / popper to use ng-bootstrap and
    #	you shouldn't install those manually
    # I also saw warnings about peers of angular/common and
    # /core and /forms not found.  Sounds fatal.  But online,
    # someone says as long as the installed version of Angular
    # is higher than the version in the warning, no problem.
    
    # start development server
    ng serve
    # saw messages that server is up and compile succeeded
    # now app is accessible on http://localhost:4200/
    # go there in browser, see default Angular app
    # back to CLI window, ctrl-C to kill server
    
    # add electron as a dev dependency
    npm i -D electron
    # 3/2019: got electron 4.0.8
    
    npm i -D @types/electron
    
    mkdir dist
    mkdir dist/matrix-dashboard
    
    # edit tsconfig.json file to add first line:
    #		/* angular tsconfig.json */
    
    # edit package.json file to add first component:
    #		"comment": "angular package.json file",
    
    mkdir electron
    cd electron
    mkdir dist
    mkdir dist/matrix-dashboard
    
    Directory structure that resulted:
    +/-
    matrix-dashboard/
    	angular json files
    	do "ng build" when in this dir
    	dist/
    		matrix-dashboard/
    			app's angular HTML, JS files
    	e2e/
    		end-to-end tests
    	node-modules/
    		bootstrap
    			CSS, JS files
    		@ng-bootstrap/
    			JS files
    	src/
    		angular CSS, TS, HTML, JSON files
    		app/
    			app's CSS, TS, HTML files
    	electron/
    		TS, JSON files
    		dist/
    
    So, some trickiness going on here:
    +/-
    • The "top-level" app is an Angular web-app, which uses a local server if you run it.

    • The Angular web-app is using CSS and JS from bootstrap, and JS from @ng-bootstrap.

    • Inside the electron directory is stuff which grabs the Angular code and node_modules, compiles it, and runs it as a desktop app in the electron framework.

    Mosh Hamedani's "Angular 4 Tutorial: Angular 4 in 20 minutes"
    Angular's "Workspace and project file structure"



  2. Build and run Angular web-app:
    
    +/-
    # cd to main matrix-dashboard/ dir
    ng serve
    ng generate service file  # one-time thing to add a service
    ng build
    # go to http://localhost:4200/ to see Angular web app running
    # page HTML source is src/app/app.component.html
    
    # ctrl-C to kill Angular server
    
    Structure of the Angular application:
    +/-
    • Really all that should be in the body of src/index.html is
      
        <app-root>
          <app-yourappsname></app-yourappsname>
        </app-root>"
      


    • In app.component.ts should be the line:
      
        selector: 'app-yourappsname'
      


    • The main page of your app will be in app.component.html.

    • You can't use deprecated HTML in the pages. That means no "center" tags: use CSS "text-align:center" or "margin:0 auto;". Probably also no "font" or "u" tags, and a bunch of deprecated attributes.
      CodeHelp.co.uk's "What's a deprecated tag / attribute?"


    Places errors could be flagged/shown:
    +/-
    • In your source-code editor as you type.

    • In the "ng serve" window when it recompiles.

    • In the page displayed in the browser.

    • In browser's debug-console for the page displayed in the browser.

    Edward Jackson's "Debugging Angular CLI Applications in Visual Studio Code"



  3. Get electron desktop-app going:

    Create electron/index.html file:
    
    +/-
    <html>
    <head>
    <title>Matrix Dashboard</title>
    </head>
    <body>
    Hello
    </body>
    </html>
    
    Create electron/tsconfig.json file:
    
    +/-
    /* electron tsconfig.json */
    {
      "compileOnSave": false,
      "compilerOptions": {
        "baseUrl": "./",
        "outDir": "./dist",
        "sourceMap": true,
        "declaration": false,
        "module": "commonjs",
        "moduleResolution": "node",
        "emitDecoratorMetadata": true,
        "experimentalDecorators": true,
        "target": "es5",
        "typeRoots": ["../node_modules/@types"],
        "lib": ["es2018", "dom"]
      }
    }
    
    Create electron/main.ts file:
    
    +/-
    import { app, BrowserWindow } from "electron";
    //import { Injectable } from "@angular/core";
    //import { ipcMain, IpcRenderer } from "electron";
    import * as path from "path";
    import * as url from "url";
    
    let win: BrowserWindow;
    
    app.on("ready", createWindow);
    
    app.on("activate", () => {
      if (win === null) {
        createWindow();
      }
    });
    
    /*
    ipcMain.on("getFiles", (event, arg) => {
      const files = fs.readdirSync(__dirname);
      win.webContents.send("getFilesResponse", files);
    });
    */
    
    function createWindow() {
      win = new BrowserWindow({ width: 800, height: 600 });
    
      win.loadURL(
        url.format({
          pathname: path.join(__dirname, `/../../dist/matrix-dashboard/index.html`),
          protocol: "file:",
          slashes: true
        })
      );
    
      //win.webContents.openDevTools();
    
      win.on("closed", () => {
        win = null;
      });
    }
    
    Create electron/package.json file (I added the comment):
    
    +/-
    {
      "comment": "electron package.json file",
      "name": "matrix-dashboard",
      "version": "0.0.0",
      "main": "electron/dist/main.js",
      "scripts": {
        "ng": "ng",
        "start": "ng serve",
        "build": "ng build",
        "test": "ng test",
        "lint": "ng lint",
        "e2e": "ng e2e",
        "electron": "ng build --base-href ./ && tsc --p . && electron ."
      }
    }
    
    Build and run electron desktop-app:
    
    +/-
    cd electron/
    npm run electron
    # see desktop app window appear !
    


  4. Now to use Bootstrap:

    Edit Angular's src/styles.css file to add line:
    
    @import "../node_modules/bootstrap/dist/css/bootstrap.css"
    
    Edit src/app/app.component.html file to add:
    
    +/-
    a bootstrap thing:<br />
    <select multiple data-role="tagsinput">
      <option value="Amsterdam">Amsterdam</option>
      <option value="Washington">Washington</option>
      <option value="Sydney">Sydney</option>
      <option value="Beijing">Beijing</option>
      <option value="Cairo">Cairo</option>
    </select>
    
    Build and run Angular web-app:
    
    +/-
    # cd to main matrix-dashboard/ dir
    ng serve
    # go to http://localhost:4200/
    # see Angular web app running with bootstrap-CSS-influenced "select" in page
    

    Build and run electron desktop-app:
    
    +/-
    cd electron/
    npm run electron
    # see new "select" appear in desktop app window
    


  5. Now to use ng-bootstrap:

    Let's try a simple example widget: Rating.

    Edit src/app/app.component.html file to add:
    
    +/-
    an ng-bootstrap thing:<br />
    <ngb-rating rate="2"></ngb-rating>
    
    Edit src/app/app.module.ts file to add lines:
    
    +/-
    import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
    
    // in imports, after BrowserModule:
        NgbModule.forRoot()
    
    Build and run Angular web-app:
    
    +/-
    # cd to main matrix-dashboard/ dir
    ng serve
    # go to http://localhost:4200/
    # see Angular web app running with new widget in page
    
    # ctrl-C to kill Angular server
    
    Edward Jackson's "Debugging Angular CLI Applications in Visual Studio Code"

    Build and run electron desktop-app:
    
    +/-
    cd electron/
    npm run electron
    # see new widget appear in desktop app window
    


  6. Add a new app component that uses ng-bootstrap:

    Create src/app/rating-basic.html file containing:
    
    +/-
    <ngb-rating [(rate)]="currentRate"></ngb-rating>
    <br />
    <pre>Rate: <b>{{currentRate}}</b></pre>
    
    Create src/app/rating-basic.ts file containing:
    
    +/-
    import {Component} from '@angular/core';
    
    @Component({
      selector: 'ngbd-rating-basic',
      templateUrl: './rating-basic.html'
    })
    export class NgbdRatingBasic {
      currentRate = 8;
    }
    
    Edit src/app/app.component.html file to add:
    
    +/-
    app component that references an ng-bootstrap thing:<br />
    <ngbd-rating-basic></ngbd-rating-basic>
    
    Edit src/app/app.module.ts file to add lines:
    
    +/-
    import { NgbdRatingBasic } from './rating-basic';
    
    // in declarations:
        NgbdRatingBasic
    
    Build and run Angular web-app:
    
    +/-
    # cd to main matrix-dashboard/ dir
    ng serve
    # go to http://localhost:4200/
    # see Angular web app running with new widget in page
    
    # ctrl-C to kill Angular server
    
    Edward Jackson's "Debugging Angular CLI Applications in Visual Studio Code"

    Build and run electron desktop-app:
    
    +/-
    cd electron/
    npm run electron
    # see new widget appear in desktop app window
    




VS Code extensions:
+/-
  • vscode-angular-html

  • vscode-typescript-angular-plugin

  • People report problems with vscode-ng-language-service, say it causes a huge performance hit.




  1. Add a new app component that is the main window of my application:

    Bootstrap - Layout - Overview

    +/-
    Ran into a nasty problem involving tables and Angular. I had one big table, with a header row generated in one page/component (mdmainwindow), then next rows generated by N calls to a sub-component (mdrow). But Angular passes the tags <sub-component-name> ... </sub-component-name> through to the browser, and since they are encapsulating each row, they made the browser place the whole row (for rows 2-N) into the first column in the bigger table, not what I wanted. Ended up with an L-shaped table ! I'll have to generate the whole table structure in one page, and then call sub-components to fill the contents of each cell in the table.

    HTML looked like:
    
    <table>
      <tr><td>colheader1</td><td>colheader2</td></tr>
      <mdrow>
        <tr><td>data</td><td>data</td></tr>
      </mdrow>
      <mdrow>
        <tr><td>data</td><td>data</td></tr>
      </mdrow>
      <mdrow>
        <tr><td>data</td><td>data</td></tr>
      </mdrow>
    </table>
    

    Fixed it by making mdrow into a TypeScript class, not an Angular class, and never putting <mdrow> in HTML.

    Later, someone told me I could have fixed it by invoking ("selecting") MDRow via an attribute on another tag (e.g. <tr mdrow>), instead of via an <mdrow> tag:
    "In @Component you've a 'selector' property. It's pretty much a CSS selector. Normally it's like 'mdrow', but it can be also a class selector ".mdrow" or attribute '[mdrow]'."

    Got the code working.

    Code is too big to show here. But src/app/mdmainwindow.html file contains:
    
    +/-
    <table class="table-striped table-bordered table-hover table-sm">
    
    <thead class="thead-light">
    <tr>
    <td> </td>
    <td *ngFor="let colname of appareas[ncurrentapparea].columnnames; index as ncolumn" id="{{colname}}">
      {{colname}}
    </td>
    </tr>
    </thead>
    
    <tr *ngFor="let row of rows; index as nrow" id="{{row.name}}">
      <td>{{row.name}}</td>
      <td *ngFor="let colname of appareas[ncurrentapparea].columnnames; index as ncolumn"
            id="cell{{nrow}}-{{ncolumn}}">
        <mdcell [nrow]="nrow" [ncolumn]="ncolumn"></mdcell>
      </td>
    </tr>
    
    </table>
    
    And src/app/mdmainwindow.ts file contains:
    
    +/-
    export class MDMainWindow implements OnInit {
      @Input() nrows = 0;
      @Input() ncolumns = 0;
    
      rows: Array<MDRow>;
    
      appareas: Array<MDAppArea>;
      ncurrentapparea = 0;
    
      constructor() {
      }
      ngOnInit() {
        this.rows = new Array();
        for (let r = 0; r < this.nrows; r++) {
          var newrow = new MDRow(r,this.ncolumns);
          this.rows.push(newrow);
        }
    
        this.appareas = new Array();
        var aa = new MDAppArea("Standard",this.ncolumns);
        this.appareas.push(aa);
        aa = new MDAppArea("Custom1",this.ncolumns);
        this.appareas.push(aa);
        aa = new MDAppArea("Custom2",this.ncolumns);
        this.appareas.push(aa);
      }
    }
    




"Components shouldn't fetch or save data directly and they certainly shouldn't knowingly present fake data. They should focus on presenting data and delegate data access to a service."

"Don't fetch data in a component constructor. An ngOnInit() is a good place for a component to fetch its initial data."

In Angular HTML files, "Angular removes <script> tags from templates on purpose as you shouldn't use those to load code on demand."

Mihovil Rister's "Angular 2+ exception handling made simple with logging"


In VS Code editor, HTMLHint complains that every one of the HTML files for Angular components should start with a doctype declaration, but they can't. And it complains about Bootstrap attributes that use uppercase, such as "ngbDropdown".



  1. Add database connection:

    Angular can do HTTP requests, and SQL databases can provide RESTful APIs, where they accept HTTP requests to do operations.

    I wanted to use Node's sql.js module and a local SQLite database, following patrickmoffitt / local-sqlite-example. But Angular is in a browser client with no access to filesystem. And the sql.js module throws errors when added to a TypeScript project.

    There used to be an Angular "http" module, but it's been replaced by an "HttpClient" module.

    Started looking into client/server components:
    Then someone said just use IndexedDB, a database inside the browser.
    +/-
    A complication for me: often there will be two browser profiles, one for daily use and one for web-app testing use. Probably this app will have to "live" in the testing profile.
    MDN's "IndexedDB API
    MDN's "Browser storage limits and eviction criteria
    Wikipedia's "Web storage"
    Works on Firefox, Chrome, Opera.
    Data-size limits not a problem for my app.
    How to backup or copy to another machine ? On Firefox, the DB is under "<profile>/storage/permanent". Or I could create export and import features into my app.

    But I see some statements:
    "IndexedDB is a document-oriented database while SQL is relational database ... Avoid using multiple tables in IndexedDB and trying to create joins."
    "SQL is relational database. IndexedDB is an indexed key/value store similar to a document-oriented database."

    Wrapper libraries, or DB engines that use IndexdDB for storage:
    SQL-like interface:
    AlaSQL (SQL-like interface)
    Object interface:
    JsStore
    Dexie.js
    NanoSQL
    Lovefield

    Firefox uses SQLite to store IndexedDB data, and there's an API directly to SQLite ? Confusing.
    Mozilla's "Performance/Avoid SQLite In Your Next Firefox Feature"

    Decided to use AlaSQL.
    The AlaSQL Wiki


    Whoops, better design my database schema first:
    +/-
    Table Name Row Fields Example
    projects: project_id, project_name Project1
    appareas: apparea_id, project_id, apparea_name Standard
    appfunctions: appfunction_id, project_id, apparea_id, appfunction_name Login
    activities: activity_id, project_id, activity_name, role_id, client_id Learn app
    cells: cell_id, project_id, appfunction_id, activity_id Learn app / Login
    tools: tool_id, tool_name, tool_path_type, tool_path Burp Suite
    cellpaths: cellpath_id, cell_id, cellpath_type, path_name, path_type, path, toolid, args app.com/login.html or docs/doc1.md
    roles: role_id, role_name Admin
    clients: client_id, client_name, devicetype_id, browsertype_id, ostype_id PFL
    devicetypes: devicetype_id, devicetype_name PC
    browsertypes: browsertype_id, browsertype_name Firefox
    ostypes: ostype_id, ostype_name Windows

    Before I changed to AlaSQL, I started to do:
    +/-
    SQLite Home Page
    Create a new file mdschema.sql:
    
    CREATE TABLE "projects" (
    	 "project_id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
    	 "project_name" TEXT(255,0) NOT NULL
    );
    CREATE INDEX "project_name_index" ON projects ("project_name" COLLATE NOCASE ASC);
    INSERT INTO `projects` VALUES
    	(NULL, "Default");
    
    CREATE TABLE "appareas" (
    	 "apparea_id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
    	 "project_id" INTEGER NOT NULL,
    	FOREIGN KEY(project_id) REFERENCES projects(project_id),
    	 "apparea_name" TEXT(255,0) NOT NULL
    );
    CREATE INDEX "apparea_name_index" ON appareas ("apparea_name" COLLATE NOCASE ASC);
    INSERT INTO `appareas` VALUES
    	(NULL, (SELECT project_id FROM projects WHERE project_name = "Default"), "Standard");
    

    
    npm install alasql
    # gave "3 vulnerabilities found"
    
    Create a new file mdsql.ts (only partial code shown):
    
    import alasql from 'alasql';
    
    ...
    
      alasql("SET AUTOCOMMIT ON");
      alasql("DROP localStorage DATABASE matrixdashboard");
      alasql("CREATE localStorage DATABASE matrixdashboard");
      alasql("ATTACH localStorage DATABASE matrixdashboard AS matrixdashboard");
      alasql("USE matrixdashboard");
    
    ...
    
      var res = alasql('CREATE TABLE projects ( \
                      project_id INT NOT NULL PRIMARY KEY AUTOINCREMENT, \
                      project_name  TEXT(255,0) NOT NULL \
                      )');
    
    ...
    
      var res = alasql('INSERT INTO projects (?,?)',[0,new_project_name]);
    
    ...
    
      var res = alasql("SELECT * FROM projects WHERE project_id=" + project_id);
    
    ...
    
      var res = alasql('CREATE TABLE appareas ( \
                      apparea_id INT NOT NULL PRIMARY KEY AUTOINCREMENT, \
                      project_id INT REFERENCES projects(project_id), \
                      apparea_name  TEXT(255,0) NOT NULL \
                      )');
    
    Every time I start up "ng serve", the very first compile fails with "alasql no default export". Change the source in some tiny way, recompiles, the compile sucseeds, while STILL saying "alasql no default export".

    Got things working, creating a database, using it, closing it, opening it. But when I quit out of Firefox and launched it again, the database was gone.

    Messed around in FF's storage settings, ended up clearing all storage, and that destroyed everything ! Anything I do in alasql gives "There is no any AlaSQL databases in localStorage" error message. Restarted "ng serve" and FF, tried loads of code combinations, always get that error. Gave up and filed a bug report on GitHub.

    An hour later, situation on my machine is fixed. Maybe I forgot to try just starting with a CREATE after it got into this state ? I quit everything, did "npm remove alasql", then "npm install alasql", DROP still gave the error if it was the first operation, but CREATE as first operation worked. And now the database is persistent across quit/relaunch of Firefox, too. I must have gotten the storage into some weird state or something.

    Tried building in Electron, and that "alasql no default export" error made the build fail every time. Back to Angular, and tried to eliminate it. Tried all kinds of variations of the import statement in mdsql.ts and the declare/export statements in node_modules/alasql/dist/alasql.d.ts, but no luck.

    Then started looking at compiler options, and found something. Added
    
    "allowSyntheticDefaultImports": true
    
    to src/tsconfig.app.json, and that killed the error, but caused uses of "alasql.databases.*" to fail (can import using either "import alasql from 'alasql';" or "import * as alaSQLSpace from 'alasql';", same behavior with either). I can do without "alasql.databases.*", I think. Holding my breath to see if anything else breaks. Build and run in Electron works.

    Started wiring the database further into my app. Reached a point where I was beating my head against a problem for half an hour, finally noticed compile-time errors from "ng serve", and realized it was using an old copy of one of the source files. Restarted it and app worked. Also, if you change a JSON config file, best to kill "ng serve" and restart it.

    Built in electron, and app fails with "alasql.min.js: It looks like you are using the browser version of AlaSQL. Please use the alasql.fs.js file instead.".

    Tried adding following to electron/package.json file, later (without "../") in angular.json file, but no change:
    
      "fileReplacements": [
        {
          "replace": "../node_modules/alasql/dist/alasql.min.js",
          "with": "../node_modules/alasql/dist/alasql.fs.js"
        }
      ],
    
    In the app under electron, select View/ToggleDeveloperTools menu item (or ctrl-shift-I) to see console log and errors.

    Got the app to run, despite the "alasql.fs.js" error message. And got another message in the console: "This window has node integration enabled by default. In Electron 5.0.0, node integration will be disabled by default. To prepare for this change, set {nodeIntegration: true} in the webPreferences for this window ...". Fixed it; in electron/main.ts, change:
    
      win = new BrowserWindow({ width: 800, height: 600 });
    
    to:
    
      win = new BrowserWindow({ width: 800, height: 600, webPreferences: {nodeIntegration: true} });
    

    Hey, the database is persistent under Electron ! I was trying to get to that point. I don't see where it's being stored, though; no new files have popped up in the development tree, that I can see. I thought it would not be persistent, because Electron provides a fresh copy of Chromium engine every time it starts ?

    Later, found out my database keys are not auto-incrementing. Strange. Looking in Github, found this issue was reported over 3 years ago and still not fixed. Bummer. And still seeing occasional hiccups where AlaSQL gives errors opening the database or a table of it.

    Decided to switch from AlaSQL to Dexie.
    
    npm remove alasql
    
    Later was told "Please remember that any interaction with localstorage is async, so you risk running into problems if you don't handle the async behaviour. I recommend the promise notation from Async" So probably I was doing that wrong.

  2. Switch to Dexie:

    
    npm install dexie --save
    npm install webpack -g
    
    Took a few hours to get things to compile, had to rework various constructors and such. And then started the battle with Promises; I like synchronous code, but for this I have to use asynchronous.

    Took a while just to get opening the database to work properly. Then I had to rework the code a couple of times to get Promises working and data going in and out. Then I still ended up with startup not working: NgInit() requests all the data, but then the HTML code executes before the data has arrived, blowing up everything. Consulting with people online, and they're saying I have to learn about more Angular things, resolvers and services and such. Beginning to think I shouldn't use Angular.

    Yes, the more they explain "reactive programming" to me, the more I think I want nothing to do with it. I'll have to try a different approach.



Java



IDE's:
Eclipse
IntelliJ IDEA
NetBeans
Java in Visual Studio Code
Ayush's "5 Best IDE for Java Programmers and Developers"
Mindfire's "Best Java IDEs 2018"
Samia Alam's "IntelliJ vs. Eclipse: Which is Better for Beginners?"

Swing (NetBeans GUI-builder)
JavaFX

NetBeans' "General Java Development Learning Trail"
Laxman's "Build Desktop application software using Java Tutorial" (using JavaFx)

SQLite Tutorial's "SQLite Java: Connect To The SQLite Database Using SQLite JDBC Driver"

Kevin Degeling's "Java development on Fedora Linux"
altexsoft's "The Good and the Bad of Java Programming"



  1. Starting, with NetBeans and Swing:

    Downloaded incubating-netbeans-10.0-bin.zip
    Extracted it to /usr/local/share
    apt install ant
    At CLI, run /usr/local/share/netbeans/bin/netbeans

    Followed Saleem Gul and Tomas Pavek's "Introduction to GUI Building":
    Created new project of type Java / Java Application, unchecking "Create Main Class".
    IDE downloaded and installed an extension manager.
    IDE activated Java SE.

    Created a quick GUI in Swing and ran it:
    In Projects window, right-click on main project's node and choose New / Other.
    In the New File dialog box, choose the Swing GUI Forms category and the JFrame Form file type.
    Set <projectname>UI as the class name.
    Enter my.<projectname> as the package.
    Files are created and GUI builder opens.
    Drag and drop GUI items, when done select Run / Run Project menu item.


  2. Get SQLite and JDBC driver:

    (There also is "Java DB / Derby", but it seems more complicated than SQLite. Apache Derby)

    Followed SQLite Tutorial's "Getting started with SQLite":
    Download Linux binary version of SQLite from https://www.sqlite.org/download.html (it's only about 2 MB)
    Extracted it to /usr/local/share
    cd /usr/local/share/sqlite-tools-linux-x86-3270200
    sqlite3
    type ".quit" to quit

    Download SQLite Studio from https://sqlitestudio.pl/index.rvt
    Set Execute permission on the file
    Double-click it to run it
    Installed in /opt/SQLStudio
    Tried it, decided it's better to create database from inside the IDE.

    Followed SQLite Tutorial's "SQLite Java: Connect To The SQLite Database Using SQLite JDBC Driver":
    Went to https://bitbucket.org/xerial/sqlite-jdbc/downloads/ and downloaded sqlite-jdbc-3.27.2.1.jar
    Moved JAR file into my project folder
    In NetBean IDE with your project open:
    Select main project node and click on Services tab
    Right-click on Drivers and select New Driver ...
    Specify JAR file

    Set up for app to connect through JDBC to database:
    In Services tab, right-click on SQLite driver and select Connect Using ...
    For "JDBC URL" use connection string jdbc:sqlite:matrixdashboard.sqlite3
    Click Finish
    See database appear in next area below Drivers.
    "KDE Wallet" dialog opens up; NetBeans IDE wants to store database login credentials in a secure way (even though there are no credentials).
    Click Cancel two or three times to get rid of dialog.


  3. Connect app through JDBC to database:

    tutorialspoint's "JDBC - Sample, Example Code"
    mkyong's "Java JDBC Tutorials"

    Created table definitions: under Services / JDBC, right-click on Tables and select Create Table ...
    But there seems to be no way to write those definitions into the database, they're just used by the IDE.

    In NetBeans IDE, tried right-clicking on main project node and selecting New / Entity classes from database ...
    Interesting code got created, but not quite useful.

    Telosys does automatic code-generation from an existing database.
    Laurent Guerin's "Telosys : the concept of lightweight model for code-generation"
    After installing the CLI version, have to edit CFG file to set editor.
    But the documentation is incredibly cryptic, apparently you need a .dbcfg file which I have no idea how to get.
    Gave up on it.

    Finally started copying/writing code to connect to database. Took a bit of trial-and-error to get the connect working, key steps were:
    • In NetBeans IDE, right-click on Libraries, select Add JAR/Folder, add sqlite JAR.
    • In code, use driver class name "org.sqlite.JDBC".
    • In code, use connection URL "jdbc:sqlite:matrixdashboard.sqlite3".
    Got the code working, database to table etc.

    Some quirks of NetBeans IDE:

    • Somehow, the main "form" file disappears from the project, so the "Design" button disappears. File still was on disk, so just did an Open File on it, and Design button came back.

    • In Design mode, can't do GUI design of components that are not top-level ? Found the answer: have to right-click on your main package icon, select New... For modal dialog, select JPanel Form.

    • But Design mode imposes some restriction: one source file for each UI element (form) you design. So if you have four dialogs which are very similar, figure out a way to design it once, in one class, and use code to hide/reveal/enable/disable elements in the form.

    • Javadocs: Go to Tools / Java Platforms, for JDK 10 select Javadoc tab. Click on Add URL button, add url "http://docs.oracle.com/javase/10/docs/api/". Now you can right-click on Java classes and see the docs for it.

    • To generate a Javadocs file for your new classes, go to Run / Generate javadoc (yourprojectname).

    Put the code into GitHub: BillDietrich / MatrixDashboard



Later, I had a bad experience with the project management. Went around in circles trying to add and remove libraries, and a delete operation removed most of my source files without warning me. Restored them from backups, but found the UI very unclear about when you're unlinking something from the project and when you're deleting something from disk.



Future:
- import description of apps pages or functions in some standard language ?
- add section for server config, server file discovery
https://laconicwolf.com/2018/08/27/exploring-the-burp-suite-api/



Beginners Heap's "Create and use Java Table in NetBeans"
NetBeans Plugin Portal
plugins to get: dataclassg


To deploy outside IDE:

"jps -v" to get a ps-like view of Java processes.



From /u/ScottContini on reddit:
+/- > Why do you think Java is a bad choice?

Lots of reasons.

Java is an old language. It has many problems with it that are never fixed, especially with respect to security. They just let the problems continue from one version to the next.

Java was not designed with security in mind: many parts of it are not secure by default (examples: all the XML parsers are vulnerable to XXE by default, the deserialization vulnerabilities, the crypto, etc). The Java Cryptography Architecture is a disaster. Very few developers can write Java crypto code securely because the architecture assumes the developer is expert in crypto (none are) and warns that it is the developer's responsibility to achieve such expertise before using it (the exact opposite approach of NaCl). The Java documentation is generally poor quality. You get a vague, half-useful explanation of many API methods in the sunny day case, with no explanation of what explanation of what happens if not-so-friendly data is sent in. There are so many little gotchas in the language that are not explained, and are left for the developer or security-reviewer to figure out on their own. For example, Google the dangers of seeding SecureRandom or specifying a default SecureRandom provider, and really there are many, many obscure examples like this.

There are lots of other problems with Java other than security. For example it did not support unsigned ints because one of the people who created it thought it was too complicated (ironically, signed ints are more complicated than unsigned). Java generally takes a lot more code to do simple things than modern languages do. Worst of all, they are now trying to get people to pay for Java SE. And don't forget that fight with Google for Google using the APIs in Android -- Java was originally free for everybody, and then Oracle tried to find a way to get money for it by changing the rules.

Back in the 1990s, Java was wonderful. It gave us an escape from the horrible crap that Microsoft was trying to force on everybody else. It was free. It had functionality built into it that other languages did not support. It had the elegance of C with added features, yet avoided the complexities of C++. That was good for back then, but the bar for software language expectations today is much higher than it was back then in the 20th century.

Since then, times have changed enormously. Nowadays Microsoft is giving us great software (.Net core) that we can use anywhere to escape the horrible mess of Java. Microsoft languages now tend to be secure by default, well documented, and easy to use. Microsoft has gone forward, whereas Java in general (especially Oracle Java) is going backwards if anywhere.

So we don't just complain about Java because it is the cool thing to do. We complain because we have lived through the torture for too many years.

I myself whose career largely involves secure code review and guidance know that I will always be in demand as long as languages like Java are around. But if I were to write production software today, Java is one of the last languages I would consider using. It's just awful.





C#



You probably want to install .NET and do cross-platform development.
MS's "Install .NET on Linux"



Uno Platform (C# and WinUI to make cross-platform apps)





C++



Linux Shell Tips' "How to Create a Simple (.deb) Debian Package" (simple C++ program)
The GNU C++ Library
C++ Language





Flutter / Dart



Google's framework/toolkit (Flutter) and language (Dart) for building cross-platform apps for mobile and desktop.



Get started on Linux desktop app

+/-
Linux Shell Tips' "Getting Started with Flutter on Linux Desktop"
Joey Sneddon's "Google & Ubuntu Team Up to Bring Flutter Apps to Linux"
Daniel Llewellyn's "Getting started with Flutter on Ubuntu"


snap install flutter

# to build Linux desktop apps:
flutter channel dev
flutter upgrade
flutter config --no-analytics
flutter config --enable-linux-desktop
flutter config
# now have 924 MB installed under ~/snap/flutter

snap install flutter-gallery
Install Flutter extension in editor such as VS Code (search for "Flutter" extension, install, restart editor, then run "Flutter Doctor").

cd ~/projects
flutter create flutt2
In VS Code, open folder flutt2.
Open file lib/main.dart, see code.
F5 to run.
Select environment "Dart & Flutter".
App may take 30 seconds or longer to appear.
App window may not paint until you move the mouse.

Code looks like this:

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        title: 'Flutter Demo',
        theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

Get started on Android app

+/-
Vitaly Kuprenko's "Create a mobile app with Flutter"
Mikhail Alfa's "Creating and Releasing an App with Flutter: Part I"
Mikhail Alfa's "Creating and Releasing an App with Flutter: Part II"


# install Android studio
# https://developer.android.com/studio
# download .tar.gz file
cd                # to home
tar xf FILENAME   # creates ~/android-studio
cd ~/android-studio/bin
./studio.sh
# see dialog, choose "do not import settings"
# see data-sharing dialog, make a choice
# see welcome dialog, click Next
# see Install Type dialog, choose Standard
# eventually get to Finish, and see components downloaded
# get welcome dialog, click X to quit
# This has created ~/Android
# config is in ~/.config/Google/AndroidStudioNNN

# Edit ~/.profile to add:
export JAVA_HOME="$HOME/android-studio/jre"
export PATH="$PATH:$JAVA_HOME/bin"

sudo snap install --classic flutter
# or
# follow https://flutter.dev/docs/get-started/install/linux :
# download .tar.xz file
cd                 # to home
tar xf FILENAME    # makes ~/flutter

# Edit ~/.profile
# add:
export PATH="$PATH:~/flutter/bin"
# or:
# export PATH="$PATH:~/snap/bin/flutter"

# Edit ~/.profile
# add:
export CHROME_EXECUTABLE="???"

# log out and back in

flutter config --no-analytics
flutter channel dev
flutter upgrade
flutter doctor --android-licenses
# If you get a Java exception:
# In Android Studio, click "Configure", then
# "SDK Manager", then tab "SDK Tools", then
# enable "Command-line Tools".

# optional:
snap install flutter-gallery

flutter doctor -v
# get to point where everything passes
# can leave "chrome - to develop for web" as fail

# Run Studio:
~/android-studio/bin/studio.sh

VS Code:
+/-
Install Flutter extension in editor such as VS Code (search for "Flutter" extension, install, restart editor, then Ctrl+Shift+P and run "Flutter Doctor").

cd ~/projects
flutter create flutt2
In VS Code, open folder flutt2.
Open file lib/main.dart, see code.
Run / Open Configurations / Add Configuration "Flutter: Attach to Device".
F5 to run.
Select environment "Dart & Flutter".
App may take 30 seconds or longer to appear.
App window may not paint until you move the mouse.

Code looks like this:

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        title: 'Flutter Demo',
        theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

Android Studio / IntelliJ:
+/-
Vitaly Kuprenko's "Create a mobile app with Flutter"
Souvik Biswas' "Flutter: Getting Started"

Install Flutter plugin, which will install Dart plugin. Restart Android Studio.
Create flutter application.
Attach phone in developer mode through USB cable.
Phone has to be logged-in for app to appear.
To use an emulator instead of a phone, select Tools / AVD Manager, do Create Virtual Device, install a system image on it, in list of devices click Run icon nextt to it, see emulated phone, click power button on it.
Run / Edit Configurations, select main.dart, see message at bottom about SDK not configured, click Fix. Path to Flutter SDK is something like /home/USERNAME/snap/flutter/common/flutter (on CLI do "flutter sdk-path").
Run / Flutter Run 'main.dart' in Release Mode
Very first time, wait 5+ minutes for everything to happen. See some warnings about deprecated things in libraries.
Subsequent time, wait 30 seconds or so for everything to happen.
If see packages not resolved, add references to them in pubspec.yaml, then do "flutter pub get".
Demo app will pop up on whole screen; no need to launch it from phone.
Use demo app.
Run / stop 'main.dart' to close the app.

If your app needs permissions, it's not enough to list them in manifest.xml; you also have to go into Settings on the phone and grant the permissions. If you see an "invalid envelope" error, it probably is a permission violation.

Vitaly Kuprenko's "Create a list in a Flutter mobile app"

My first Flutter phone-app: BillDietrich / fake_contacts

Path to Flutter SDK is stored in app's android/local.properties file. Have to change it if you switch between Snap and native forms of Flutter SDK.

Key files:
+/-
  • android / app / src / main / AndroidManifest.xml (package name, permissions, for Android)
  • lib / main.dart
  • ios / Runner / Info.plist (permissions description, for iOS)
  • pubspec.yaml (name, version number, dependencies)
  • build/app/outputs/flutter-apk/app-profile.apk
  • build/app/outputs/flutter-apk/app.apk (executable app, for Android)
  • .ipa is executable for iOS, but I don't see one produced.
  • android/app/src/main/res/*/ic_launcher.png (app icon ?)
  • ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-*.png (app icon ?)
  • ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage*.png (app icon ?)
iOS sizes: https://jigarm.medium.com/ios-app-icon-and-launch-image-sizes-e8d5990cb72b
For LaunchImage, I picked 320x320, and 2x that, and 3x that

Wasn't able to build for iOS; I think you have to do that on a Mac.

How to publish an app:
+/-
Publish to F-Droid ? Google Play Store ? APKMirror (for beta versions of Play Store apps, or new apps from devs already established on Play Store) ? https://apkpure.com/ ? Huawei AppGallery ? Apple App Store ? Cydia (for Apple) ?

Submitting an app to Google Play Store is free, but you have to be a registered Google developer/publisher, which costs $25 one-time ? Starting 8/2021, Google Play Store will accept only AAB format, not APK format.

Submitting an app to Apple Store is free, but you have to be a registered Apple developer, which costs $99/year ?

Flutter's "Build and release an Android app"
Instabug's "How to Release Your Flutter App for iOS and Android"
Anmol Gupta's "Publishing Flutter App To PlayStore"
Gary Sims' "Publishing your first app in the Play Store" (2014)

How to publish to F-Droid:
+/-
F-Droid's "Contributing to F-Droid"
F-Droid's "Signing Process"
reddit's /r/fdroid
Wonder's Lab's "F-Droid: how is it weakening the Android security model?"


# Takes a long time and 1 GB of disk space.
# It even updates initramfs !
# Which failed, leaving an unbootable system, and a learning experience:
#   have enough free space in /boot to be able to rebuild.
sudo apt install fdroidserver

# I did this in my project home dir:
mkdir metadata
wget -O metadata/app.id.yml https://gitlab.com/fdroid/fdroiddata/raw/master/templates/app-full
cd metadata
mv app.id.yml YOURAPPID.yml
# Edit the file to fill in fields.
# see https://f-droid.org/docs/Build_Metadata_Reference/
cd ..
fdroid readmeta
# Fix errors.
fdroid lint
# Fix errors.

# Create an account on GitLab
# Create SSH keys for it.
# Fork https://gitlab.com/fdroid/fdroiddata
# Clone the fork to local disk:
cd ~/projects
git clone https://gitlab.com/BillDietrich/fdroiddata.git
# takes a couple of minutes, 500+ MB of disk

cd fdroiddata

# copy YOURAPPID.yml to the  metadata dir, and:
fdroid readmeta   # takes a couple of minutes

git remote rm origin && git remote add origin 'git@gitlab.com:BillDietrich/fdroiddata.git'
git add .
git status      # should be only your file staged
git commit -m "APP new version NNN"
git push -u origin master
Go to your GitLab repo in browser.
On left side, click on Merge Requests.
Click on button New Merge Request.

Set Source Branch to your master branch.
Click button "Compare branches and continue".
Really should set "Description / Choose a Template" to "App Inclusion", but 2/3 of stuff in it didn't seem to apply.

Submit the merge request, see it appear in main repo.
https://gitlab.com/fdroid/fdroiddata/-/merge_requests/8246
https://gitlab.com/fdroid/fdroiddata/-/merge_requests/8483

See "pipeline running".
Probably lots of errors.
Get email about progress.

I'm told I should use Fastlane and remove the Summary and Description variables from YML file. Also remove the commented strings in your metadata, and any "(use those which apply)".

Created a Fastlane (https://gitlab.com/snippets/1895688) directory in top of my source tree, with appropriate files (fastlane/metadata/android/en-US/*) underneath.

Also have to make a tag "v1.0" in source repo.
https://git-scm.com/book/en/v2/Git-Basics-Tagging
git tag -a v1.0 -m "my version 1.0.0"
git tag
git push origin --tags

The lint you run locally is not the same as the "lint" (really rewritemeta) run by the build process. The latter wants to see blank lines in certain places, and certain order of some lines. Tweak your YML until the build process is happy (no more diffs shown).

Thought I was finished, but then told something else (build CI) is failing. Error message "Gradle task 'assembleFdroidRelease' not found".

Eventually got closer.

Every time you change something:
- update README to list new version and description
- update metadata/APP.yml to have new "versionName" value
- update "versionCode" to new value
- update "commit" value to "v" plus "versionName" value
- update "CurrentVersion" to match "versionName"
- update "CurrentVersionCode" to match "versionCode"
- update pubspec.yaml "version" to "versionName" plus "+" plus "versionCode"
- in APP top dir, do "fdroid lint"
- in APP top dir, do "git add .", "git commit", "git push"
- in APP top dir, do "git tag -a vTAGVALUE -m 'message'""
- in APP top dir, do "git push origin --tags"
- NO: copy APP.yaml file to fdroiddata/metadata directory
- NO: in fdroiddata dir, do "git add .", "git commit", "git push"
- if did the initial merge request, get email with results
- if just an update, instead see https://f-droid.org/wiki/page/me.billdietrich.fake_contacts/lastbuild
(also see https://gitlab.com/-/snippets/1896503)

App appeared in store on phone another 1-2 weeks after merge request succeeded. I think F-Droid was having some general build problems at the time.
Fake Contacts app in store

App is set to auto-update in F-Droid, so for subsequent updates, after committing new version to GitHub, just wait for F-Droid to pick it up automatically.


Second app: single-page like the first one:
+/-
BillDietrich / fake_contacts_2

Tried to duplicate existing project and modify it, but that failed. Instead, create new project and copy old code across.
Do "git init".

Third app: multiple activities and a service worker:



Calling an asynchronous method of a plugin:

Future<void> _myfunc() async {
  log("_myfunc: about to call ContactsService.addContact");
  // defined as: static Future addContact(Contact contact)
  await ContactsService.addContact(newContact);
  log("_myfunc: about to return");
}


From someone on reddit 9/2020:
+/-
My First App using Flutter Framework

I made Android app using Flutter framework in 20 days. This is related to Telegram channels, groups, stickers and Bots.

...

I have 4 years experience in programming (php) but 0% experience in app or Java. I was able to learn flutter and dart in one week from YouTube videos. Just check 2 or 3 videos from below playlist, you will find if it is easy or not.
The Net Ninja's "Flutter Tutorial for Beginners"

This is the easiest framework i found to make an app. One of the advantages is same source code will work for both Android and iOS.



Flutter / Get Started / Install
/r/FlutterDev
Flutter web is beta 12/2020, and web debugging only works on Chrome browser, not any other chromium-based browser ?
Garrit Franke's "Flutter Web - the Good, the Bad and the Ugly"



Flutter / Get Started / Write your first Flutter app
Flutter Samples
flutter-examples
Flutter - material library
JB Lorenzo's "Data Persistence on Flutter"
Denyse's "Flutter state management"
Find plugins/packages to use: pub.dev
nepaul's "Awesome Flutter"
Minas Giannekas' "Using Flutter to build a native-looking desktop app for macOS and Windows"

Getting started with dart
Tutorialspoint's "Dart Programming Tutorial"

Dart's "Asynchronous programming: futures, async, await"
Flutter Fix's "Flutter Future, Await, and Async - All You Need To Know"
reddit's /r/dartlang

I want to make an app to add Contacts:
pub.dev's "contacts_service 0.4.6"
Flutter Awesome's "A Flutter plugin to retrieve and manage contacts"
permission_handler plugin
shared_preferences plugin (note: no permission needed)

Android Developers' "Manifest.permission"



Richard MacManus's "Google's Flutter Beefs up Web Support, So How Does It Compare to React Native Now?"
Hackernoon's "React Native Vs. Flutter: The Ultimate Comparison"
Hugo Tunius's "Flutter Web: A Fractal of Bad Design"
Georg von der Howen's "Flutter Failed To Solve the Biggest Challenge for Our Cross-Platform App"





PyQt



From Wikipedia's "PyQt":
"PyQt is one of Python's options for GUI programming. Popular alternatives are PySide (the Qt binding with official support and a more liberal license), PyGTK, wxPython, Kivy and Tkinter (which is bundled with Python)."

Python and Qt are cross-platform: Linux, Windows, Mac.

Michael Herrmann's "PyQt5 tutorial"
Shantnu Tiwari's "Using Qt creator to create a simple GUI"
ZetCode's "PyQt5 tutorial"


# use app "Qt 4 Designer" to edit JSONitor.ui file to manage UI
designer JSONitor.ui

# process JSONitor.ui file to create JSONitorUI.py file
pyuic5 JSONitor.ui -o JSONitorUI.py

# run application
python3 JSONitor.py
Useful snippets (indentation matters in Python):

for ind, filename in enumerate(["System-Existing.json", "System-New.json"]):
    logger.debug('initUI: ind {}'.format(ind))
    logger.debug('initUI: filename {}'.format(filename))
    if filename and os.path.isfile(filename):
        self.currentTextPane = ind


import Utilities.JSONTools as jst
jsc = jst.JSONConverter(logger)
sampleJSON = jsc.getDict(text)

itemModel = StandardItemModel()
if sampleJSON:
    itemModel.populateTree(sampleJSON, itemModel.invisibleRootItem())
I tried to prototype a "two-JSON-tree edit app" by stripping down AaronAikman / JSONitor, but it turned out to be too complex, with tree-models, background threads, undo/redo, bookmarks, tabs, etc.



Qt5 Cadaques - A Book about Qt5
Mike Royal's "Qt Guide"





C++ and Qt



Re: "Starting with KDE/Qt development",
from /u/Tereius on reddit 3/2022:
+/- I think it is a long way to go before you are able to implement a QML app from scratch, especially if it should run cross-platform (Linux, Windows, MaxOS, iOS, Android). With C/C++ there are additional difficulties that do not exist with higher-level programming languages such as: missing garbage collection (memory leaks), build/deploy management (makefiles), pointer arithmetic.

First of all, I would read the first page of the following CMake tutorial. CMake is a portable makefile-generator for all operating systems and is also used by KDE. Unfortunately, CMake is very complex and the learning curve is very steep (but there is no way around). After you have worked through the first page of the tutorial, you should have an executable program that you can compile with "cmake --build".

Now I would install an IDE. KDevelop or VS Code (with the CMake plugin) or CLion (costs money or use EAP build). Now try to get the CMake tutorial program to work within the IDE. All three IDEs mentioned can handle CMake. If you can start the program via the IDE and see the program output, you have a good starting point for further learning.

Next, I would work through the following tutorial: LearnCpp.com. Since you already have an IDE, you can skip chapters 0.9 - 0.12. Depending on how much experience you already have with Python, you can also skip further chapters. However, you should not skip chapter "9.6 Introduction to pointers". You should skip the chapter "20 Exceptions".

While you are working through the C++ tutorial, you should also continue reading the CMake tutorial.

Now that you have mastered C++ and CMake :-) you should get to grips with Qt. Qt uses a preprocessor process (called MOC) to enrich C++ with reflections and signals/slots. So you need to learn the MOC-specific macros and the behavior of the event-loop. See CleanQt. After that you could start with QML. QML uses JavaScript (ECMAScript 6 standard) for the logic, so you need to learn some basic JavaScript as well.

Now you can look at the KDE Tier 1 frameworks especially Kirigami2. Try to get a Kirigami example to work and build your app from there on.



From someone new on kde-devel mailing list:
"the KDE stack is quite daunting: first you have C++, then Qt, then QML, then KDE Frameworks, then Kirigami, and finally somewhere on top of the stack my code is supposed to reside."



Qt's "Creating a Qt Widget Based Application"
Qt5 Cadaques - A Book about Qt5
Mike Royal's "Qt Guide"
stackoverflow - Qt

nmariusp's "KDE Frameworks 5 tutorial" (video)
nmariusp's "Create KDE neon VM and set up kdesrc-build tutorial" (video)
nmariusp's "What to do after a module builds with kdesrc-build" (video)
nmariusp's "Start programming for KDE tutorial for beginners" (video)


sudo apt install qtcreator
qtcreator -version

# tried to follow https://doc.qt.io/qtcreator/creator-writing-program.html
# stuck at "no kits installed"

# tried again following https://web.stanford.edu/dept/cs_edu/resources/qt/install-linux
sudo apt-get -y install build-essential openssl libssl-dev libssl1.0 libgl1-mesa-dev libqt5x11extras5
# download installer .run file from https://www.qt.io/download-qt-installer
chmod +x qt*.run.
./qt*.run
# launch qtcreator, create project
# select both kits: Desktop, and Desktop Qt n.n.n GCC 64bit
# got it working

In QtCreator 8, to open a project, select the project's "CMakeLists.txt" file.



In QtCreator 8, to run app as root:
Edit - Preferences - Environment - System tab - Terminal == add "sudo" after "-e"
Edit - Preferences - Build & Run - General tab - Default for "Run in terminal" == enabled.



Current directory while running your app may not be:
.../PROJECTDIRNAME
but instead:
.../build-PROJECTDIRNAME-Desktop-Debug



To display a Markdown file:

QFile inputFile("/home/user1/.../FILENAME.md");
inputFile.open(QIODevice::ReadOnly);

QTextStream in(&inputFile);
QString lines = in.readAll();
inputFile.close();

//ui->textEdit1->setText("hello");

ui->textEdit1->setMarkdown(lines);

//ui->textEdit1->setText(lines);
//ui->textEdit1->toMarkdown(QTextDocument::MarkdownDialectCommonMark);

ui->textEdit1->setReadOnly(true);



To run a sub-process (blocking; bad):

QProcess process;
process.startCommand("/bin/pwd");
process.waitForFinished(5000);
int code = process.exitCode();
QString lines = process.readAllStandardOutput() + " " + QString::number(code);

To run a sub-process (non-blocking; good) [DIDN'T WORK]:

/* all inside a class */

QProcess process;

connect(&process, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
    [=](int exitCode, QProcess::ExitStatus exitStatus){
      /* called when process is finished */
      QString lines = process.readAllStandardOutput() + " " + QString::number(exitCode);
    });

process.startCommand("/bin/pwd");
return;
https://doc.qt.io/qt-5/qprocess.html#finished
Didn't work for me; that "[=]" gives a "calling a deleted constructor" syntax error, and trying to understand it gets into "lambda functors" and all kinds of crazy.

To run a sub-process (non-blocking; good) [WORKED]:

/* define global vars, not inside a class */

QProcess process;

void procdone(int exitCode, QProcess::ExitStatus exitStatus) {
      QString lines = process->readAllStandardOutput() + " " + QString::number(exitCode);
}

/* following parts inside a class */

connect(
    &process,
    QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
    procdone
    );

process.startCommand("/bin/pwd");





Node.js



Build server-side and networking applications written in JavaScript.
Write the (server) app in Node, use browser as GUI.

From /u/KnackeBrot on reddit:
+/- JavaScript traditionally only runs in internet browser as a client application.

Node is basically just a so-called runtime environment which allows JavaScript to be executed outside of the browser. Additionally it provides tools for filesystem access and other low-level stuff that doesn't exist in normal "browser" JavaScript as well as a package manager, which ends up making JavaScript a pretty powerful and versatile programming language.

Aaron Kili's "How to Write Your First Node.js App in Linux"
Node.js
Gergely Nemeth's "Node Hero - Getting Started With Node.js Tutorial"
Paul Brown's "How to Get Started Writing Web Applications with Node.js"
Paul Brown's "Get Started Writing Web Apps with Node.js: Using the All Powerful NPM"

npm's "Downloading and installing Node.js and npm"
Installing Node.js via package manager

nvm: node version manager that can maintain multiple versions of node on your system.
npm: node package manager.
node: do operations in a project using config files and a tree of modules.



Finding node modules to use:
w3schools' "Node.js Built-in Modules"
Ashish's "A to Z List of Useful Node.js Modules"
Philip Ackermann's "20 Node.js modules you need to know"
aravindnc / A-to-Z-List-of-Useful-Node.js-Modules
npm's "most depended upon packages"

Nikola Duza's "Ride Down Into JavaScript Dependency Hell"

Snyk Security (VS Code extension to show security vulns in npm packages)



To see if Node is installed, run "node --version".
In Mint 19, it's installed by default.
"npm" is the package manager. "npm --global ls" to see what is installed on your system.

Somehow, it got removed from my PATH at some point, not sure what happened. I was unsure if more of it was damaged, and I saw it was an old version anyway. So I uninstalled the version 8.something through Software Manager, and installed version 10.15.3:

# went to https://nodejs.org/en/download/
# downloaded "Linux Binaries (x64)" tar.xz file

# followed instructions at https://github.com/nodejs/help/wiki/Installation
VERSION=v10.15.3
DISTRO=linux-x64
sudo mkdir -p /usr/local/lib/nodejs
sudo mv node-$VERSION-$DISTRO.tar.xz /usr/local/lib/nodejs
cd /usr/local/lib/nodejs
sudo tar -xJvf node-$VERSION-$DISTRO.tar.xz
sudo rm node-$VERSION-$DISTRO.tar.xz

# added following to .bash_profile and .zshrc
# Nodejs
VERSION=v10.15.3
DISTRO=linux-x64
export PATH=/usr/local/lib/nodejs/node-$VERSION-$DISTRO/bin:$PATH

sudo ln -s /usr/local/lib/nodejs/node-$VERSION-$DISTRO/bin/node /usr/bin/node
sudo ln -s /usr/local/lib/nodejs/node-$VERSION-$DISTRO/bin/npm /usr/bin/npm
sudo ln -s /usr/local/lib/nodejs/node-$VERSION-$DISTRO/bin/npx /usr/bin/npx

# tested installation using
cd ~
node -v
npm version
npx -v
3/2020 ripped out version 10.15.3 and installed version 13.11.0:

sudo npm uninstall npm -g
sudo rm -fr /usr/local/lib/nodejs
sudo rm -rf /usr/local/{lib/node{,/.npm,_modules},bin,share/man}/npm*
cd ~
grep -s nodejs ~/.*
# edit matched files to remove *nodejs* from PATH

# went to https://nodejs.org/en/download/current/
# downloaded "Linux Binaries (x64)" tar.xz file

# followed instructions at https://github.com/nodejs/help/wiki/Installation
# But I'm not sure why the version number in the instruction is old
NODEVERSION=v13.11.0
NODEDISTRO=linux-x64
sudo mkdir -p /usr/local/lib/nodejs
sudo mv node-$NODEVERSION-$NODEDISTRO.tar.xz /usr/local/lib/nodejs
cd /usr/local/lib/nodejs
sudo tar -xJvf node-$NODEVERSION-$NODEDISTRO.tar.xz
sudo rm node-$NODEVERSION-$NODEDISTRO.tar.xz


# Added following to user's .profile and ALSO to /root/.profile
# Nodejs
NODEVERSION=v13.11.0
NODEDISTRO=linux-x64
export PATH=/usr/local/lib/nodejs/node-$NODEVERSION-$NODEDISTRO/bin:$PATH

# log out and back in, or
. ~/.profile

# tested installation using
cd ~
node -v
npm version
npx -v

# install web-ext so can develop Firefox extensions
sudo su - root
npm install -g npm
npm install --global web-ext
ctrl-D to get out of SU shell
web-ext --version

https://nodejs.org/dist/latest-v13.x/docs/api/


Check dependencies in a project:

npm audit
npm prune --dry-run

# ???
depcheck
npm-check
# double-check before removing anything listed as "not used"


Riya Thomas's "Developing An App with NodeJS: Best Practices to Follow"



Lea Verou's "Today's JavaScript, from an outsider's perspective" (really about node.js)
Hagen Hubel's "Web-Development is running into the wrong direction"
Kailash Nadh's "The JavaScript 'ecosystem' is a hot mess and so is software development in general"
Overreacted's "npm audit: Broken by Design"





Deno



Naruhodo's "Introducing Deno: A JavaScript and TypeScript Runtime Build in Rust"





Ruby



Ruby alone

+/-
Ruby is comparable to Python, although maybe more object-oriented, and slower ?
"Ruby isn't compiled so ruby developers have to give away their source code for desktop apps."

Tutorials Point's "Ruby Tutorial"
GeeksforGeeks' "Ruby For Beginners"

Using a text-editor, create a file mytest.rb:

# comment here
n = 100
puts "Hello World #{n}"


ruby mytest.rb

"WxRuby: cross-platform GUI toolkit that is native-looking on whatever platform you are on."

"The standard graphical user interface (GUI) for Ruby is Tk." from Tutorials Point's "Ruby - Tk Guide"



David Eastman's "Ruby Devs: Try Sinatra before Moving up to Ruby on Rails"



Ruby on Rails

+/-
Rails is a MVC web application framework running on the Ruby programming language.
I think Rails is for database-centric web apps: you have a database and the web app lets users read and modify it, using app logic etc.
Rails Guides' "Getting Started with Rails"
Mehdi Farsi's "Learn Ruby on Rails"



When installing Ruby on Rails, there are some choices: RVM or rbenv or from source or from Ubuntu repos, and sqlite3 or MySQL or PostgreSQL or MariaDB database.

RVM and PostgreSQL on Ubuntu:
HowtoForge's "How to Install Ruby on Rails on Ubuntu 20.04 LTS"

Multiple choices:
Go Rails' "Install Ruby On Rails on Ubuntu 20.04 Focal Fossa"
Raj's "How To Install Ruby On Rails On Ubuntu 20.04"



I installed rbenv / MariaDB on Ubuntu 20.04 following Raj's "How To Install Ruby On Rails On Ubuntu 20.04":
+/-

sudo apt update

sudo apt install -y curl gnupg2 dirmngr git-core zlib1g-dev build-essential libssl-dev libreadline-dev libyaml-dev libsqlite3-dev sqlite3 libxml2-dev libxslt1-dev libcurl4-openssl-dev software-properties-common libffi-dev

wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.35.3/install.sh | bash
# close terminal and re-open it
nvm install node
node -v   # get 14.n.n
npm -v    # get 6.14.n

curl -sL https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
sudo apt update && sudo apt install -y  yarn

cd
git clone https://github.com/rbenv/rbenv.git ~/.rbenv
echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bashrc
echo 'eval "$(rbenv init -)"' >> ~/.bashrc
exec $SHELL

git clone https://github.com/rbenv/ruby-build.git ~/.rbenv/plugins/ruby-build
echo 'export PATH="$HOME/.rbenv/plugins/ruby-build/bin:$PATH"' >> ~/.bashrc
exec $SHELL
du -sh .rbenv

rbenv install 2.7.1
du -sh .rbenv
rbenv global 2.7.1
ruby -v   # get 2.7.1

gem install bundler
du -sh .rbenv

gem install rails
du -sh .rbenv     # 270M
rails -v

sudo apt install -y mariadb-server mariadb-client
sudo apt install -y libmariadb-dev

sudo mysql -u root -p
# At MariaDB prompt:
CREATE USER 'myuser'@'localhost' IDENTIFIED BY 'mypassword';
GRANT ALL PRIVILEGES ON *.* TO 'myuser'@'localhost';
exit

gem install mysql2

# Create new application:
cd ~/projects
rails new myrailsapp1 -d mysql
du -sh myrailsapp1    # 132M
cd myrailsapp1

# Edit config/database.yml to change username and password to values you chose:
default: &default
  adapter: mysql2
  encoding: utf8mb4
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: myuser
  password: mypassword
  socket: /var/run/mysqld/mysqld.sock

rake db:create

# Start the application:
rails server -b 0.0.0.0

# Open in browser:
http://localhost:3000
# See app's web page.
# Close page in browser.
ctrl+C to stop app running

# Main HTML page of app seems to be app/views/layouts/application.html.erb
https://www.tutorialspoint.com/ruby-on-rails/rails-directory-structure.htm
https://dev-yakuza.github.io/en/ruby-on-rails/folder-structure/

# Too complicated for me.
cd ~/projects
rm -fr myrailsapp1
gem uninstall mysql2
sudo apt remove libmariadb-dev
sudo apt remove mariadb-server mariadb-client
gem uninstall rails







Django



Web-app back-end framework based on Python.
Jahid Onik's "How to Install and Configure Django on Linux System"
Vladyslav Nykoliuk's "Django Tutorials: Building a Web App from Scratch"
Ankush Singla's "Django vs Laravel: An In-Depth Comparison"





Go



"Go is a general-purpose language with an emphasis on concurrency. ...
Go is more like a very powerful and fast Python. ...
Go is quite good for quick prototyping. It does asynchronous execution quite well.
It's really good for building web services or API-driven software."



Vivek Gite's "How to install Go [golang] on Ubuntu Linux"
SoByte's "Getting Started with Golang in 10 Minutes"

Chris Hodapp's "Go programming language: my totally unprompted opinions"
Ten Reasons Why I Don't Like Golang
Will Yager's "Why Go Is Not Good"
Amos's "I want off Mr. Golang's Wild Ride"
Martin Tournoij's "Go is not an easy language"

Gaurav Kamathe's "Find security issues in Go code using gosec"

From post by jchw:
"I love Go but the Go runtime is a pretty big snowflake, it's one of the few non-libc users of the Linux syscall interface."





Rust



"Rust is a systems-programming language that operates close to the metal like C but with some safety paradigms enforced at compile-time. ... Rust is more of a safe C++. ... Because Rust memory-ownership is just a compile-time concept and it has zero cost in runtime, it is very good language where performance matters. Especially if you can't afford inconsistent performance caused by garbage collection."

You will hear a lot of security people liking Rust because it is very easy to call from C. So replacing a vulnerable old C module with a safer equivalent written in Rust is easy.



Intended to replace C, and maybe follow-ons such as C++.
Ed Jones's "Why and how to use Rust on Ubuntu"
Tour of Rust
Rust
Wikipedia's "Rust (programming language)"
/r/rust

boringcactus's "A Survey of Rust GUI Libraries (21 Aug 2020)"
Paul Biggar's "Why Dark didn't choose Rust"
Matt Welsh's "Using Rust at a startup: A cautionary tale"

Package manager/publisher is "Cargo"; "Rustup" is getting toward EOL.




sudo apt install rustc
rustc --version


Using a text-editor, create a file mytest.rs:

fn main() {
    println!("Hello, world!");
}

rustc mytest.rs 
./mytest




JavaScript

Bender Fine, I'm gonna make my own app

Nimisha Mukherjee's "4 reasons why JavaScript is so popular"
Zell Liew's "The Flavors of Object-Oriented Programming (in JavaScript)"
The Modern JavaScript Tutorial
Adrian Mejia's "The JavaScript Promise Tutorial"
leonardomso's "33 Concepts Every JavaScript Developer Should Know"
Ana's "Top Mistakes JavaScript Developers Make"

Tapajyoti Bose's "7 Console Methods Used by Pros"
Christian Heilmann's "Dear Console, ..."

Shedrack Akintayo's "6 predictions for JavaScript build tools"

Gjs: JavaScript Bindings for GNOME

Ctrl blog's "Deploy your JavaScript source maps"

If you want to grab or examine code from another site, but it's all on one line, process it with: Prettier.





TypeScript



TypeScript docs home

Gary Bernhardt's "Problems With TypeScript in 2020"





Linux Shell Script



"the shell is not a general-purpose language, it's a special-purpose language for running commands"



Using a text-editor, create a file mytest.sh:

#!/usr/bin/env sh

set -o errexit    # exit on error
set -o nounset    # unset variables are an error

# this is a comment

echo "hello"

read -p 'OK? ' dummyvar
[First line matters because different shells have slightly different syntax, and different users may use different login shells. Also, bash has a nasty behavior where it ignores ctrl+C if that is caught by a sub-process; see Unable to stop a bash script with Ctrl+C]

In a Terminal window (CLI), run:

chmod a+x mytest.sh
./mytest.sh

If you really want to use bash, create a file mytest.sh:

#!/usr/bin/env bash

set -Eeuo pipefail
trap cleanup SIGINT SIGTERM ERR EXIT

cleanup() {
  trap - SIGINT SIGTERM ERR EXIT
  # script cleanup here
}

# this is a comment

echo "hello"

read -p 'OK? ' dummyvar

(Note: edge case with pipefail)



To pop up a GTK dialog, add this to mytest.sh file:

zenity --info --title="mytest.sh running" --text="the mytest.sh script is running"

To pop up a KDE dialog, add this to mytest.sh file:

kdialog --title "mytest.sh running" --msgbox "the mytest.sh script is running"

To pop up a char-type dialog, add this to mytest.sh file:

whiptail --title "mytest.sh running" --msgbox "the mytest.sh script is running" 10 60
# or:
dialog --title "mytest.sh running" --msgbox "the mytest.sh script is running" 10 60

To send an OS notification when done, add this to mytest.sh file ?

trap '(( $? )) && notify-send "error happened" || notify-send "all good"' EXIT
# or:
trap 'notify-send "$FINISHED_MESSAGE"' EXIT

tput/terminfo/ncurses ?
charmbracelet / gum
rofi
dmenu (display lines from a file as a menu, return one that user selects)
xclip (data to/from clipboard)
Kyle E. Mitchell's "Pick-From-a-List Tools"



Ryan Chadwick's "Bash Scripting Tutorial"
BashGuide
BashFAQ
kvz's "Best Practices for Writing Bash Scripts"
The Sharat's "Shell Script Best Practices"
Evan Slatis's "Fix bugs in Bash scripts by printing a stack trace"
Mendel Cooper's "Advanced Bash-Scripting Guide"
dylanaraps / pure-bash-bible
Karthick Sudhakar's "How to Use Declare Command in Linux Bash Shell"
Carl Tashian's "How to Handle Secrets on the Command Line"
/r/bash



ShellCheck - A shell script static analysis tool
Or use it online



explainshell (get help text to explain a line of script)



Witness the power of this bash script



Python



Apparently there are a couple of important differences between Python 2 and Python 3, such as some string-handling changes. If code has stmts such as "print x", it's Python 2; has to be "print(x)" in Python 3.



Using a text-editor, create a file mytest.py:

#!/usr/bin/env python3

# this is a comment

if __name__ == '__main__':
  print('hello')

In a Terminal window (CLI), run:

chmod a+x mytest.py
./mytest.py

Example of a "docstring" comment which will appear in Help output:

#!/usr/bin/env python3

def func1 (str1):
  """
  docstring comment is here
  """
  print(str1)

if __name__ == '__main__':
  func1('hello again')

In a Terminal window (CLI), run:

python3
# get '>>> ' prompt (Python interactive mode)

>>> import mytest
>>> help('mytest')
>>> help('mytest.func1')
>>> import math
>>> help('math')
# q to get out of help

# ctrl+d to get out of Python interactive mode



From someone on reddit:
"Always use virtualenv or docker. Never install pip packages system-wide. If you do so then system is bound to break."



Useful modules:
To do OS-type stuff: https://github.com/kivy/plyer/ (to install do "pip3 install plyer")

Differences between Linux and Windows:
Module syslog is Linux-only; use win32evtlog and win32evtlogutil on Windows.
Different sets of signal functions and constants are available.



To display GUI dialogs or notifications (Zenity):

+/-
# for Linux Mint, no installation needed, Zenity is installed by default. # For Win10, https://github.com/maravento/winzenity # Download https://github.com/maravento/winzenity/raw/master/zenity.zip # and copy the EXE file inside it to the same folder where ipwatch.py is located.. # https://www.linux.org/threads/zenity-gui-for-shell-scripts.9802/ # https://en.wikipedia.org/wiki/Zenity import subprocess # in Linux, do a (non-modal) notification, so no wait for user action subprocess.call(['zenity','--notification','--text',sMsg]) # on Linux, see output as notifications in system tray # in Win10, only modal-dialog choices are available with WinZenity # open a modal dialog, so no more checking until user sees the dialog and closes it subprocess.call(['zenity','--info','--text',sMsg])
Another way to display GUI dialogs or notifications (plyer):

+/-
# https://plyer.readthedocs.io/en/latest/# # https://github.com/kivy/plyer # no way to have notification remain permanently # do "pip3 install plyer" or "pip install plyer" from plyer import notification # in Linux, notifications appear both on desktop (briefly) and in tray notification.notify(title='SOMETITLE', message=sMsg, app_name='SOMEAPPNAME', timeout=8*60*60)
Logging to system journal (Linux):

+/-
# https://docs.python.org/2/library/syslog.html import syslog syslog.syslog(sMsg) # to see output: # sudo journalctl --pager-end # or # sudo journalctl | grep ipwatch
Logging to system event log (Windows):

+/-
# https://stackoverflow.com/questions/51385195/writing-to-windows-event-log-using-win32evtlog-from-pywin32-library # https://www.programcreek.com/python/example/96660/win32evtlogutil.ReportEvent # https://docs.microsoft.com/en-us/windows/win32/eventlog/event-logging-elements # https://rosettacode.org/wiki/Write_to_Windows_event_log#Python # do "pip install pywin32" import win32evtlogutil import win32evtlog win32evtlogutil.ReportEvent( "APPNAME", #7040, # event ID # https://www.rapidtables.com/convert/number/decimal-to-binary.html 1610612737, # event ID # https://www.rapidtables.com/convert/number/decimal-to-binary.html eventCategory=1, eventType=win32evtlog.EVENTLOG_INFORMATION_TYPE, strings=[sMsg], data=b"") # to see output: run Event Viewer application.
Linux signals:

+/-
import signal # https://docs.python.org/3/library/signal.html # Not sure why this is needed, but it is, otherwise signal will make process exit. # And sometimes this is not called, even though the signal came in to the main loop. def handler(signum, frame): #print('Signal handler called with signal', signum) return # Not sure why this is needed, but it is, otherwise signal will make process exit. signal.signal(signal.SIGUSR1, handler) # Create file to tell sender that it can send signals to us now. # If we allowed it to send signal before this point, a signal would make this app exit. gsAliveFilename = "/tmp/serverisup" fileAlive = open(gsAliveFilename, 'w+') # SIGUSR1 == 10 in major archs # send does: pkill --signal SIGUSR1 -f server.py objSignal = signal.sigtimedwait({signal.SIGUSR1}, gnSleep) if objSignal == None: print('sleep timed out') else: print('received signal '+str(objSignal.si_signo)) fileAlive.close() try: os.remove(gsAliveFilename) except: i = 1 # placeholder
To get command-line arguments given to app: sys.argv



GNU/Linux.guru's "Python"
James Quick's "How To Get Started With Python in Visual Studio Code"
Martin Heinz's "Ultimate Guide to Python Debugging"
/r/Python
PyPA's "Packaging Python applications"
Sumantro Mukherjee's "Run Python applications in virtual environments"
John Mathews' "Virtual environments and python versions"



"sudo pip install SOMEPKG" installs package system-wide.
"pip install --user SOMEPKG" installs package only for you (current user).

From someone on reddit 4/2021:
+/-
General tips for Python [to avoid dependency-hell on Linux]:
  • Never, ever use "pip" to modify the system python installation. "sudo pip" is right out.

  • Don't try to remove the system python. It's probably used by either distribution system management tools, or by applications installed through the distribution's tools.

  • Use a new venv for each application, and you'll never need to resolve conflicts.
    
    python3 -m venv myapp1
    . myapp1/bin/activate
    pip3 install dep
    # or
    pip3 install -r requirements.txt
    

Working with python on GNU/Linux systems shouldn't be any more difficult than other operating systems, providing that you're working with venvs and not trying to share one big set of libraries among multiple apps with conflicting requirements.

There is a new thing "pipx" that is an easier way to use venvs ?



mypy (static type checker for Python):

+/-
python3 -m pip install mypy
mypy yourprogram.py
Then modify your code to add type hints (from installing-and-running-mypy):

+/-
# change:
def greeting(name):
# to:
def greeting(name: str) -> str:

# change:
def greet_all(names):
# to:
from typing import List
def greet_all(names: List[str]):

# change:
my_global_dict = {}
# to:
my_global_dict: Dict[int, float] = {}   # Python 3.6+
or:
my_global_dict = {}  # type: Dict[int, float]   # any version of Python




Place to copy some example code from: HPI article



PySimpleGUI
Have to do "sudo apt install python3-tk" and "pip3 install pysimplegui".



Make a GUI desktop HTML app that uses Python (a bit like Electron with JavaScript): Eel



Make a Python/Flask web-app in a local web server running on your Android phone: Phani Adabala's "Create and run Python apps on your Android phone"



Bas Steins' "A Gentle Introduction to Testing with PyTest"



Make a call-graph of your application: Python Call Graph





PHP program



PHP Manual

Using a text-editor, create a file mytest.php:

#!/usr/bin/env php
<?php

/*
  this is a comment
*/

echo "hello";

?>
In a Terminal window (CLI), run:

php -r 'phpinfo();' | less

# if that fails, do:
sudo apt install php-cli

chmod a+x mytest.php
./mytest.php

# if you remove the "#!/usr/bin/env php" line and don't do the chmod:
php -f mytest.php



If your program uses functions from any extension libraries, you need to install something listed in PHP Manual / Extension List / Alphabetical (which is not quite alphabetical). I had to do:

sudo apt install php-gd


[Heard on a podcast 1/2020: don't use PHP for anything serious, many heavily-used functions in it are marked "deprecated", the language should die.]





Perl program



Perl Docs

Using a text-editor, create a file mytest.pl:

#!/usr/bin/env perl -w

# this is a comment

print "hello\n";
In a Terminal window (CLI), run:

perl -v

# if that fails, do:
sudo apt install perl

chmod a+x mytest.pl
./mytest.pl

# if you remove the "#!/usr/bin/env perl" line and don't do the chmod:
perl mytest.pl

# to install a needed module:
# https://www.ostechnix.com/how-to-install-perl-modules-on-linux/
make -v
sudo cpan
install MODULENAME
# Expect a TON of operations and output the first time you do this.
# Installing XML::RSS set off half an hour of building on my machine,
# and created 260M of stuff under ~/.local/share/.cpan, maybe more elsewhere.
# Tried to install XML::Atom::Entry, which set off another 5-10 minutes and then failed.
exit


Apparently the emerging Perl 6 was so different from previous versions that it is a new language. There is Perl 5, and there is Raku (formerly Perl 6). Perl will continue to evolve, from Perl 5.





Low Code / No Code



Some make phone-apps, some make web-apps, some make web-sites ?

Google AppSheet
Thunkable
Bubble
Swing2App
MobinCube
Composer Pro
AppsMoment





Building a Firefox Extension



[Note: If you plan to have same extension work on both Firefox and Chrome, it might be best to develop on Chrome first. Chrome does not support Promises, so if you develop first on FF and use Promises, when you try to go to Chrome you're stuck.]

MDN's "Browser Extensions"
Mozilla's "Extension Workshop"
Egidio Docile's "How to create, package and sign a Firefox web extension"
Mozilla's "Getting started with web-ext"
Mozilla's "Implement a settings page"

Mozilla's "Add-ons" forum (disable VPN to do new-acct registration)
/r/FirefoxAddons

I want to contribute to the Containers area

+/-
https://github.com/mozilla/multi-account-containers and related/derived extensions.

Original project was called "test pilot".

Some resources:

https://discourse.mozilla.org/c/test-pilot/containers (but most recent activity is 8 months ago)

https://wiki.mozilla.org/Security/Contextual_Identity_Project/Containers (but seems outdated/proposal)

https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/contextualIdentities is the missing piece.

Import/export config: issues 1427, 1409, 1420, 1282 in https://github.com/mozilla/multi-account-containers

I want to make an extension that has no UI other than a Settings page.
Started with https://github.com/mdn/webextensions-examples/tree/master/favourite-colour
https://github.com/mdn/webextensions-examples/tree/master/contextual-identities
https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/downloads/download

Did:
Copied example code from github.
Changed names etc in code.

sudo bash
npm install --global web-ext
ctrl-D to get out of SU shell
/usr/local/lib/nodejs/node-v10.15.3-linux-x64/bin/web-ext --version
Created repo https://github.com/BillDietrich/ContainersExportImport

In extension project directory:

/usr/local/lib/nodejs/node-v10.15.3-linux-x64/bin/web-ext run --pref privacy.userContext.enabled=true --pref privacy.firstparty.isolate=false --pref privacy.firstparty.isolate.restrict_opener_access=false
In browser running add-on, to see console.log() messages, you don't want web console, you want add-on debugging console. Type about:debugging in the address bar. See your add-on listed. Click the "debug" link for it. A separate window/process will open, showing the output. Click on "console" and enable "persist logs". Then manipulate your add-on. https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Debugging

Got the code working (I think) in debug environment.

To sign the extension for permanent but private (unlisted) use, went to Developer Hub - API Credentials. Logged in with Firefox account. Clicked on the "Generate new credentials" button to get API keys. Copied the keys.

Then in CLI, in add-on project directory:

/usr/local/lib/nodejs/node-v10.15.3-linux-x64/bin/web-ext sign --api-key=<JWT issuer> --api-secret=<JWT secret>
Got success, it returned a validation ID, and created a .web-extension-id file and a web-ext-artifacts directory. Inside that directory is the .xpi file.

In Firefox, type "about:addons" in address bar (or do alt-T, a) (or do ctrl-shft-a), see add-ons page. Click on "gear" pull-down menu, select "Install add-on from file" menu item. Navigate to web-ext-artifacts directory and select your add-on's .xpi file.

Go to Developer Hub - My Add-ons and log in to see list of your add-ons.

alert() works in debug mode but is a bit broken in "real mode" ? The text and button appear, but no box around them, and they're a bit separated. Supposed to use Notifications, not alert(), in "real mode".

Type "about:profiles" in the address bar to manage profiles or choose a profile. Click on "Launch profile in new browser" button for new/test profile.

To publish to the world:
Tweak descriptions and settings and versions:
Start at https://addons.mozilla.org/en-US/firefox/
Log in.
Go to https://addons.mozilla.org/en-US/developers/
Locate your add-on and click on its "Edit Product Page".
Click on "Manage Status & Versions"
Publish:
https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/Distribution/Submitting_an_add-on
https://addons.mozilla.org/en-US/developers/addons

Was confused about how to change from self-distributed to AMO (public to world). Got this info: "When you submit a new version on the website, the top of the first page in the submission flow is labeled 'Where to Host'. You should see a button or link there that allows you to change the setting to hosted on the site. You can change that setting every time you submit, depending on what you need."

So, make changes and commit and push them.
Do NOT sign the extension to make XPI file.
Add files to a ZIP file: icons, manifest, package, README, LICENSE, source files:

zip archivename.zip file1 file2 ...
zip containersexportimportVERSION.zip background.js icon*.png LICENSE.md manifest.json options.* package.json README.md
zip decentraleyessimpler1.3.zip background.js icon*.png LICENSE.md manifest.json options.* package.json README.md
Login at https://addons.mozilla.org/en-US/firefox/
Go to https://addons.mozilla.org/en-US/developers/addons
Click on link for the add-on
Do NOT click on "upload new version", instead click on "View All".
Click on "Upload a New Version" button.
Click on "Upload a New Version" button.
Under "Where to Host Version", click on "change" link.
Upload ZIP file.
Click on "Sign add-on" button.
Icon did not get picked up, had to edit that setting later.

If there are errors/warnings about the content of your add-on when you try to publish, you can see same list of errors/warnings by running "web-ext lint" locally.



How to make a desktop-Firefox extension work in Android-Firefox

+/-
MDN's "Developing extensions for Firefox for Android"

To just quickly try your extension in an Android phone:
  1. On computer, create .xpi file.
  2. On phone, enable Developer Options.
  3. On phone, enable Android USB Debugging.
  4. Connect computer to phone via USB cable.
  5. On computer CLI, do "adb devices" to see that connection is good.
  6. On computer CLI, do "adb push filename.xpi /mnt/sdcard/" to copy file to phone.
  7. On phone, launch Firefox for Android browser.
  8. In Firefox, browse to file:///mnt/sdcard
  9. You may have to Allow access to files by Firefox.
  10. See list of filenames.
  11. Tap on filename.xpi link.
  12. In Firefox, click Allow on warnings.




How to make a Firefox extension work in Chrome

+/-
David Rousset's "Creating One Browser Extension For All Browsers: Edge, Chrome, Firefox, Opera, Brave And Vivaldi"
MDN's "Porting a Google Chrome extension"
MDN's "Building a cross-browser extension"
MDN's "Chrome incompatibilities"
mozilla / webextension-polyfill

To just quickly try your extension in Chrome:
  1. In Chrome, type "chrome://extensions" in address bar.
  2. Enable "Developer Mode" (button in upper-right).
  3. Click on "Load unpacked", and choose the extension's project folder.
  4. See a box for your extension in the Extensions page.
  5. If there is a red "Errors" button for your extension, click it.

Useful snippet to allow use of "browser" in Chrome:

window.browser = (function () {
  return window.msBrowser ||
    window.browser ||
    window.chrome;
})();
But, for me, there are too many differences between Firefox and Chrome, I gave up:
  • Various manifest.json differences; requires two separate files.
  • Permission "browser_specific_settings" not supported in Chrome.
  • Chrome doesn't support Promises (maybe use mozilla / webextension-polyfill).




I like to put this at top of the README.md of a just-started add-on:

![Do not use](https://www.billdietrich.me/AbnormalBrain.jpg "Do not use")





Building a Chrome Extension



Chris Bongers' "Browser extensions - our first extension"
Chris Bongers' "Types of browser extensions"
Chris Bongers' "Browser extensions - our first theme"
Chrome's "Getting Started"
John Sonmez's "How to Create a Chrome Extension in 10 Minutes Flat"
Thomas Peham's "How to develop a chrome extension in 2018"
Matt Frisbie's "10 Things Every Chrome Extension Needs"
Chrome's "API Reference"

Chris Bongers' "Publishing a Chrome browser extension"





Building a Thunderbird Extension



About Thunderbird (Development)
cleidigh / ThunderStorm
thundernest / sample-extensions

Thunderbird Add-on Developers mailing list



Did:
Copied example code from github.
Changed names etc in code.

In Thunderbird, go to hamburger icon / Add-Ons / Add-ons.
Select Extensions in left side.
Click on gear icon / Debug Add-ons.
Click on Load Temporary Add-on button.
Select add-on's manifest.json file.
See new add-on listed in Add-ons tab.
Click Debug, see Debug window appear, click on Console and Persist Logs.
Go back to main tab, see button for new add-on has appeared in toolbar.
Click button, see action of the add-on.



My add-on

+/-
https://addons.thunderbird.net/en-US/thunderbird/addon/new-account-types/
https://addons.thunderbird.net/en-US/thunderbird/addon/teclib/
https://github.com/gooselinux/thunderbird
I want to add WhatsApp integration into TB. Chat accounts (e.g. Twitter) seem to be formatted as one integrated timeline from all users, which is not how WhatsApp works. Maybe I want to model it after a newsgroup integration ?

https://developer.mozilla.org/en-US/docs/Mozilla/Thunderbird/MailNews_fakeserver
http://test.xennanews.com/
https://www.ngprovider.com/free-newsgroup-server.php

Or maybe I could just have WhatsApp appear as a button on the top, like "Chat", and open as an HTML window in the main pane ?

Thunderbrowse
https://bitbucket.org/alta8888/browseintab/wiki/Home

Config setting general.useragent.override lets you set user-agent string ?
Boolean compatMode.firefox should work too, but doesn't work with WhatsApp parsing for some reason.





Building a VS Code Extension



VS Code's "Extension API"

Installing environment

+/-
  1. Install VS Code.
    See "VS Code" section of my "Using Linux" page

  2. Install Node.
    "sudo apt install nodejs"
    "sudo apt install npm"
    "sudo npm install -g vsce" or "sudo npm install -g @vscode/vsce"
    "sudo npm install -g typescript"
    "sudo npm install --save-dev esbuild"


Generating initial code

+/-
Use the Yeoman generator:
James Quick's "How To Create Your First Visual Studio Code Extension"
OR:

  1. Find an example extension you like from Microsoft / vscode-extension-samples

  2. Copy the code to a directory on your disk.

  3. In VS Code, open the project folder and press F5 to run it. If it runs okay, go to next step.

  4. Delete example directory from project dir.

  5. Copy the code again to a directory on your disk.

  6. Rename project dir from old name to MYPROJNAME.

  7. Change filenames and edit files to use MYPROJNAME instead of old name.

  8. In VS Code, open the project folder and press F5 to run it. [Best to have cursor in your extension.ts file when you press F5 ?]

VS Code Extension Samples
Sample code illustrating the VS Code extension API

Running code in debug mode

+/-
  1. Launch VS Code, choose File / Open Folder and pick the folder that you generated.
  2. Press F5 or click on the Debug icon and click Start.
  3. Your extension will be compiled and run.
  4. A new instance of VS Code will start in a special mode (Extension Development Host) and this new instance is now aware of your extension.
  5. If the extension operates on the document in the editor window, have the cursor in that window when you run your extension, don't have the cursor in the debug output window.


Problems

+/-
Project is failing to compile. Typescript not installed ?
VS Code's "Editing TypeScript"
Run "tsc --version" to check.
Run "sudo npm install -g typescript" to install.


If you ever wipe out the node_modules tree (perhaps when backing up and restoring), in the project directory do "sudo npm install". Then maybe "sudo npm audit fix".

Bundling

+/-
Visual Studio Code's "Bundling Extensions"
Rob O'Leary's "Why you should always bundle a VS Code extension, and prefer esbuild"

Use esbuild.

Ian't find exported function: "command extension.FUNC not found": in package.json, change to: "main": "./out/main.js"

Have to disable minification ?

The .vscodeignore file is important; it affects execution in debug mode, not just editing mode.

Running code in normal mode

+/-
  1. Did the stuff in Git - Getting Started.
  2. To run the extension in normal VS Code, not debug:
    1. Make a ~/.vscode/extensions/linkcheckerhtml directory.
    2. Copy files from linkcheckerhtml development directory to that new directory. Files/trees to copy are: linkcheckerhtmlicon.jpeg, LICENSE.md, node_modules, out, package.json, README.md
  3. sudo npm install -g vsce
  4. To package the extension into a .vsix file, without publishing it to the store, do "sudo npm install -g vsce" and then "vsce package". If you want to share your extension with others privately, you can send them your packaged extension .vsix file.
  5. To install an extension from .vsix file, either:
    • "code --install-extension FILENAME.vsix", or
    • In VS Code GUI, in the Extensions view command drop-down, select the "Install from VSIX" command.

Publish to the extension Marketplace

+/-
  1. You have to have an Azure DevOps organization.
  2. Create a publisher in the Marketplace publisher management page.
  3. Have to have a VSIX file.
  4. In Marketplace publisher management page, do "add an extension", upload the VSIX file.

Update the extension in the Marketplace

+/-
  1. Have to have a VSIX file.
  2. Log in to your Azure account.
  3. Use this link to go to Marketplace publisher management page.
  4. In Marketplace "Manage Publishers & Extensions", right-click on your extension's icon, select "Update", upload the VSIX file, click Upload button.
  5. See message "It's live !" and status "Verifying", but still see old version number.
  6. Log out of your Azure account, if you wish.
  7. Get an email when verification is complete.
  8. Quit VS Code and re-launch. Check that new version is being used (may have to do a Reload). Test.

Publish to open-vsx.org so available to VSCodium and Code-OSS

+/-
Uses your GitHub account. Need Eclipse Foundation account to sign publisher agreement.

Login to Open VSX Registry using GitHub creds.
It will ask to add "EclipseFdn" as an OAuth user of your creds.
Go to https://www.eclipse.org/legal/open-vsx-registry-faq/#faq-4
Click on link for publisher agreement, and read PDF.
Go to https://www.eclipse.org/legal/open-vsx-registry-faq/#faq-6
Go to https://accounts.eclipse.org/
Create an account.
Click "Edit my account" and add GitHub name to profile.
Need to sign two agreements ? "Eclipse Contributor Agreement (ECA)" and "Eclipse Foundation Open VSX Publisher Agreement".

Then to publish, go to https://www.eclipse.org/legal/open-vsx-registry-faq/#faq-11

Go to https://open-vsx.org/user-settings/tokens
I created a token named "Open VSX"; copy the token value and save it.

Get namespace value from "publisher" field of your package.json file.

Run "npx ovsx create-namespace NAMESPACEVALUE -p TOKENVALUE"

Follow instructions to claim ownership of the namespace (involves creating an Issue on https://github.com/EclipseFdn/open-vsx.org/issues/).
Issue will be resolved very quickly, but you will not receive any notification, you have to keep checking the issue status.

Run "npx ovsx publish VSIXFILENAME -p TOKENVALUE"





After many struggles and much learning, finally got it working and announced it as a VSIX file for people to try. On GitHub, the project is linkcheckerhtml. On Visual Studio Marketplace, the extension is HTML / XML / RSS link checker.

If you ever wipe out the node_modules tree (perhaps when backing up and restoring), in the project directory do "sudo npm install".

Tomasz Smykowski's "How to test Visual Studio Code extension"



Automated testing of your extension ?




To see all key-shortcuts: ctrl+k ctrl+s.
To see what key-shortcuts map to what extensions: ctrl+k ctrl+s then search on "@source:extension".





Bash script to run via cron



"Cron" section of my Using Linux page

devhints.io's "Bash scripting cheatsheet"



Script idea, for

monitoring security changes

:
+/-
script to generate system status into a file:
- list of browser profiles and extensions and certs
- default browser
- browser home page
- microcode checksum
- BIOS checksum
- /etc/passwd checksum
- /etc/groups checksum
- kernel version
- active network listeners
- VPN status
- IP address
- DNS settings
- MAC address of router (Arpwatch ?)
- dir list of /bin, /usr/bin, ...
- filesystem dirty bits
- list of PCI devices: lspci
- list of SCSI/SATA devices: lsscsi
- dmidecode
- env has changed
- who is logged on right now (w)
- iptables rules
- list of cron jobs
- shell profiles for users
- file explorer extensions
- source editor extensions
- home/.ssh/known_hosts
- /etc/init/*

script to call that script, then diff results with previous results

send alerts to:
- pushbullet (https://unix.stackexchange.com/questions/381821/how-can-i-send-notifications-alerts-using-the-linux-terminal)
- journal (logger -p user.info this is the message")
- email

Started building it.

Then someone pointed me to SysConfCollect (SCC). Which is complicated and missing a lot of desktop stuff and reports some false-positives, but works.





systemd Service



"man systemd.service"
"man systemd.unit"
"man systemd"
ArchWiki's "Writing user units"
my "Linux systemd" page



Simple script to run when system boots

+/-
Best if your script file /FULLPATH/SCRIPTNAME.sh is NOT under /home, because if user's home directory is encrypted or not mounted, script will be inaccessible.

Create file /etc/systemd/system/YOURSERVICENAME.service:

[Unit]
Description=MY DESCRIPTION HERE
#After=network.target
After=network-online.target
Before=graphical.target
Before=multi-user.target

[Service]
Type=simple
ExecStart=/FULLPATH/SCRIPTNAME.sh

[Install]
WantedBy=multi-user.target
Create file /home/FULLPATH/SCRIPTNAME.sh:

# whatever it's supposed to do, maybe just something like:
touch /tmp/laststartup
Set permission and enable the service:

chmod a+x /FULLPATH/SCRIPTNAME.sh
sudo systemctl enable YOURSERVICENAME
sudo systemctl status YOURSERVICENAME --full --lines 1000
sudo systemctl start YOURSERVICENAME
sudo systemctl status YOURSERVICENAME --full --lines 1000
After system boot:

sudo journalctl | grep YOURSERVICENAME



Michael Maclean's "Avoiding complexity with systemd"





Nemo file-explorer actions/scripts



Create a file test1.sh in ~/.local/share/nemo/scripts

#!/usr/bin/env bash

echo "script test1.sh executed" `date` >~/test1.log.txt
echo "arguments " $* >>~/test1.log.txt
echo "env:" >>~/test1.log.txt
printenv >>~/test1.log.txt

zenity --info --title="test1.sh running" --text="the test1.sh script is running"
Set permission:

chmod a+x ~/.local/share/nemo/scripts/test1.sh

In Nemo, Edit / Plugins and see test1.sh in the Scripts pane. Make sure it is enabled.

In Nemo, right-click on any file or folder and choose Scripts / test1.sh



Nemo is a fork of GNOME Files (formerly named Nautilus).

https://github.com/thioshp/nemo_scripts
https://unix.stackexchange.com/questions/197098/custom-nemo-actions-bash-script
https://askubuntu.com/questions/419532/nemo-custom-action-sh-script-does-not-execute
https://github.com/Alfcx/linux-mint-nemo-actions
https://github.com/linuxmint/nemo-extensions
https://wiki.archlinux.org/title/Nemo





Dolphin file-explorer actions/scripts



I created a new "Service Menu" to handle LUKS container files: lukscontainerfile and BillDietrich / lukscontainerfile.



KDE Store's "Dolphin Service Menus"
Creating Dolphin Service Menus
Adding an entry to the Create New menu
Kai Yuan's "Introduction to File MIME Types"
Shell Scripting with KDE Dialogs
From KDE / kdialog: "the width and height attributes have been removed for most dialogs - Qt/KDE have layouts"

Took N tries to get uninstallation to work. It doesn't seem to be documented. Maybe Dolphin silently calls script deinstall.sh or uninstall.sh ?





Thunar file-explorer custom actions



Thunar - Custom Actions
Ubuntu's "Thunar Custom Actions"

"Custom actions" basically are small snippets of shell code. There also are "plugins", which are written in C and GTK and call the thunarx API.

Nautilus can use same "custom actions". article





KDE Settings Module



[I want to make Troubleshooter and Scanner App. I want them to be pretty distro- and DE-agnostic; i.e. portable.]



KDeveloper's "Settings module (KCM) development"
KDE TechBase's "Development/Tutorials/KCM HowTo" (OLD, probably don't use)

Examples:
https://invent.kde.org/plasma/plasma-workspace/-/tree/master/kcms/nightcolor
https://github.com/KDE/sddm-kcm

"A KCM consists of a KPackage holding the QML UI and a C++ library holding the logic."

There seems not to be a good sample KCM anywhere, e.g. on GitHub. Maybe copy the code out of the KDeveloper article linked above.

Don't develop on a native distro, unless you're running KDE Neon. Instead: KDE development in a VM

If you're going to install Qt Creator on a distro other than KDE Neon, install the Flatpak version, to get latest release.

Info about setting up development environment: KDeveloper's "Getting Started with KDE Frameworks"




ktraderclient5 --servicetype KCModule | grep '^Name :' | sort
ktraderclient5 --servicetype KCModule | less
ktraderclient5 --servicetype KCModule | grep Parent-Category | sort | uniq
ktraderclient5 --servicetype KCModule | grep '^Library' | grep security



Test-run via "kcmshell5 MODULENAME" ("kcmshell5 --list")

"ls /usr/lib/x86_64-linux-gnu/plugins/"
"ls /usr/lib/x86_64-linux-gnu/qt5/plugins/"



Maybe first create a user-base page (similar to KDE UserBase Wiki's "System Settings / Icons" ) for the module, and submit a forum post (KDE Community Forums) or get on Telegram VDG, and submit an issue (KDE Bugtracking System) and a pull-request (to plasma / systemsettings) to create that.

System settings KCMs in bugzilla: product=systemsettings



Display Markdown:
Qt: "if you want to use markdown in Text or TextEdit then you must set TextEdit.MarkdownText in the textFormat property"
GTK: https://gjs.guide/guides/gtk/3/06-text.html#gtk-label

Run a shell script:
Qt: process.startDetached("/bin/bash", QStringList() << "path to file.sh");
GTK: Posix.system("bash -c scriptfile.sh");





Miscellaneous



SoloLearn



Joel Spolsky's "The Joel Test: 12 Steps to Better Code"



Alligator.io's "Awesome Free Tools For New Developers"
Ari Noman's "Use this command-line tool to find security flaws in your code" (Graudit)



Putting an interpreter specification in first line of a script file:

#!/usr/bin/php
#!/usr/bin/env php
# second form is more portable than the first form
Wikipedia's "Shebang (Unix)"



GNOME Shell Extensions
Argos (write GNOME Shell extension in Bash script)
Just Perfection's "How To Create A GNOME Extension"
GNOME Wiki's "Extensions / Writing / Overview"
GNOME Wiki's "Step by step tutorial to create extensions"



NW.js (an alternative to Electron)


Tauri (an alternative to Electron)




Why Linux is best OS for development

[Some claim the CLI makes Linux best for development]

I think Linux people are firmly off-base on this view that the CLI is so important. (BTW, I use Linux, I first used CLI on Unix in 1980, I'm not hostile to Linux or the CLI.)

I'd say Linux is better for development because the OS internals are so much more open than those on Windows or MacOS. If you need to see some detail of how an OS service or feature or system call works, the code is available and probably documented. And probably several articles have been written about how it works.

And that openness carries over to many of the apps. If you want to develop a new widget, the code of dozens of somewhat-related widgets is freely available. Less likely to be true on Windows or MacOS.

A big factor: on Linux/FOSS, you can see the bug-tracking databases, file bugs, get responses.

Yes, the CLI is best for some operations, especially manipulating text files.



Young Coder's "An Illustrated Guide to Server-Side and Client-Side Code"
Turnkey Linux (server/stack images, easy to install)

Web development:
Silvestar Bistrovic's "Tips On Learning Web Development"
Developer Roadmaps
kamranahmedse / developer-roadmap
Christian Heilmann's "[Browser] Developer Tools secrets that shouldn't be secrets"



Cloud services:
Sudeep Chauhan's "We Burnt $72K testing Firebase + Cloud Run and almost went Bankrupt"



Callum Kilby's "How to build better digital experiences with UX writing principles"



Divio's "The documentation system"
Katie Nickels' "How to Make Better Infosec Presentation Slides"



Run a script when some event occurs (such as attaching a USB drive)

+/-
Put a file "autorun.sh" on a USB stick that is EXT4 format (MS-DOS format does not work). Set execute permission on the file. When attach the drive, get a prompt asking if want to run the file, click Run.

Trickier, more flexible ways:

From Ask Ubuntu question:
Find the *.mount name for your drive:

systemctl list-units -t mount | grep media
# insert your device
systemctl list-units -t mount | grep media
# find the added name
Create file /etc/systemd/system/YOURSERVICENAME.service:

[Unit]
Description=MY SCRIPT TRIGGERED WHEN DRIVE XXX INSERTED
Requires=media-YOURMEDIALABEL.mount
After=media-YOURMEDIALABEL.mount

[Service]
ExecStart=/home/FULLPATH/SCRIPTNAME.sh

[Install]
WantedBy=media-YOURMEDIALABEL.mount
Create file /home/FULLPATH/SCRIPTNAME.sh:

Set permission and enable the service:

chmod a+x /home/FULLPATH/SCRIPTNAME.sh
sudo systemctl enable YOURSERVICENAME.service
"If the service is failed somehow (for example, the script is not executable), your mount point will change to OLDMOUNTPOINTNAME1 next time you mount the USB device. To fix this issue, execute 'sudo systemctl reset-failed'".

Another way: using udevadm and creating a file in /etc/udev/rules.d/. But using systemd (above) is better because the systemd service won't trigger until after the filesystem is mounted.

Another way: Nemo file-explorer in Mint has Edit / Preferences / Behavior / Media Handling / "Prompt or autorun/autostart programs when media are inserted" check-box. But I don't see how to specify a program. If I turn off that option, no Nemo window is opened when I attach a USB drive, even though the "automatically open a folder" option still is checked. See Nemo file-explorer actions/scripts

In Nautilus file-explorer under Edit / Preferences / Media you can choose "other action" and then "custom command". https://github.com/Alfcx/linux-mint-nemo-actions https://linuxconfig.org/how-to-extend-the-gnome-nautilus-file-manager-with-custom-scripts

In Ubuntu, Activities / Details: https://help.ubuntu.com/stable/ubuntu-help/files-autorun.html



Regular expressions 101
RegExr



Search for example code snippets: searchcode

Public APIs



Julia Evans' "A debugging manifesto"

Debuggers for binary apps:
gdb
Stephan Avenwedde's "A hands-on tutorial for using the GNU Project Debugger"
rr
Rubaiat Hossain's "20 Best Linux Debuggers for Modern Software Engineers"
Sergio Durigan Junior's "A debuginfod service for Debian"
Run app that core-dumps, do "coredumpctl gdb", then "backtrace full"

Moy Blog's "Linux Core Dumps"



C programming language

+/-
An important point made by some people: we really should stop using the C language (created in 1972-3). It is not memory-safe and type-safe, doesn't have the concepts of exceptions (it always just does something and keeps going), heap, strings. Unfortunately, the Linux kernel and much of the user-space code is written in it. This leads to tens of thousands of bugs in Linux today, including security vulnerabilities. Maybe C is appropriate for very low-level system programming, as an alternative to assembly language. But for apps and services and modules, not.
John Regehr's "A Guide to Undefined Behavior in C and C++"
Alex Gaynor's "Modern C++ Won't Save Us"
Ian Barland's "Why C and C++ are Awful Programming Languages"
Quora thread "Is C that bad of a programming language?"
Catalin Cimpanu's "Chrome: 70% of all security bugs are memory safety issues"

What is better, and a reasonable evolution from C ? Probably Rust
But: Drew DeVault's "Rust is not a good C replacement"

Cross-compiler that runs on Linux and makes an EXE for Windows: MinGW ("sudo apt install mingw-w64").

meain's "Ehh, WebAssembly?"
SoByte's "Knowledge about WebAssembly"
Example of embedding WASM inside an offline single html page
Robert Kimani's "Demystifying WebAssembly: What Beginners Need to Know"
WebAssembly



Drew DeVault's "How I decide between many programming languages"
Hillel Wayne's "The Hard Part of Learning a Language"

Martin Heller's "How to choose the right database for your application"



Heather Booker's "im not a programmer"
Jan Schaumann's "Falsehoods CS Students (Still) Believe Upon Graduating"

Gergely Orosz's "Advice to Myself When Starting Out as a Software Developer"
mtlynch.io's "How to Make Your Code Reviewer Fall in Love with You"



Choose a License
Joinup Licensing Assistant (JLA)
GNU's "Various Licenses and Comments about Them"
MIT, BSD, others say you can take and use OSS for any purpose you want; GPL also says any changes you make have to be made public and freely available ?
I prefer the MIT license.
/dev/lawyer's "Switching Open Software Terms"



Linux has two main compiler stacks (there are others):
GNU Compiler Collection (GCC), and
LLVM (a framework centered around a language-independent intermediate representation (IR)) / Clang (a front end for C-type languages, usually used with LLVM).

Linux has two main libc implementations (there are others):
musl (cautionary tale), and
glibc.



Jacob Davis-Hansson's "Your Makefiles are wrong"



Open Build Service



RESTful API:
"Representational State Transfer"
Client-server, stateless, uniform interface.
Usually uses CRUD operations: Create, Read, Update, Delete.
Fatunbi David Oluwakayode's "What is a RESTful API - A beginner's guide"



Delivering software:
Signing so identity is verified: TLS certificate, sigstore.
Audit / code review (maybe light and automated): F-Droid, Apple Store, VS Code extension.
Open / uncontrolled store: Mozilla store, Dockerhub, Snap store ?



xkcd's "Success"
Toggl's "Git the Princess"