hatching-chick Overview
Using GitHub
App GUI Prototyping
Electron (Simple App)
Electron (Complicated App)
Bootstrap / Angular / Electron
Java
PyQt
Node.js
Ruby
Django
Building a Firefox Extension
Building a Thunderbird Extension
Linux Shell Script
PHP program
Bash script to run via cron
Miscellaneous







Overview



How to build something:
[Mostly from POV of a Linux user:]

ddbeck / readme-checklist





Using GitHub



GitHub Guides' "Hello World"
Meghan Nelson's "An Intro to Git and GitHub for Beginners (Tutorial)"
Adam Dachis' "How the Heck Do I Use GitHub?"
Lauren Orsini's "GitHub For Beginners: Don’t Get Scared, Get Started"
Aayushi Johari's "How To Use GitHub - Developers Collaboration Using GitHub"
Matthew Setter's "A Beginner's Git and GitHub Tutorial"
Aaron Kili's "How to Use Git Version Control System in Linux"
GitHub's "Resources to learn Git"
GitHub Help's "Set up git"
Rapid7's "Git cheatsheet"
GitHub Extension for Visual Studio
Aaron Kili's "11 Best Graphical Git Clients and Git Repository Viewers for Linux"
reddit's /r/github
WhiteSource's "Top 5 Git Security Mistakes"



On Linux Mint, I did:

  1. [Tried Gitg GUI app, didn't understand it.]
  2. [Downloaded and tried to install GitHub extension into VSCode, it failed.]


  3. sudo apt-get install git
  4. git config --global user.name "Your Name Here"
  5. git config --global user.email "your_email@youremail.com"


  6. In browser, logged in to GitHub, went to a project I wanted to copy (Microsoft / linkcheckermd), cloned it to my home directory.


  7. Renamed "linkcheckermd" directory to "linkcheckerhtml".
  8. Deleted the .git stuff under linkcheckerhtml.
  9. Edited the source files.


  10. On GitHub web page, created new repository in my account named linkcheckerhtml.
  11. Set description.
  12. Turned off Wiki and Projects. Turned on "Restrict editing to collaborators only", but I think it only applies to the Wiki ?


  13. Went to CLI, into linkcheckerhtml directory, and did:
    1. git init
    2. git add README.md
    3. git commit -m "first commit"
    4. git remote add origin https://github.com/BillDietrich/linkcheckerhtml.git
    5. git push -u origin master
      (Had to turn off 2FA for login to work.)
  14. From now on, cycle is:
    1. Edit source files.
    2. git add filename (for each file edited)
    3. git commit -m "first commit"
    4. git push -u origin master
    When you operate this way, there is only one branch ("master").

    To delete a file, do "git rm filename", then commit and push.

    To see status at any time, do "git status".

    Starting a new repository from scratch (the wrong way, probably):
    • Created app source code on my disk.
    • Backed it up.
    • In browser, logged into GitHub and created new repo.
    • Went to home directory of project on disk, and did "git init".
    • Edited .git/config to point to new repo on GitHub.
    • Did git adds, commit, push. Had to add "--force" to the push.



In a bigger, multi-person project:

  1. Clone the (master branch) files to disk: login to GitHub web site, go to repo, click big green "Clone or download" button near upper-right. Easiest to click on "Download ZIP".
  2. Build the project on disk, test.
  3. Create a branch (on project's main page in GitHub, click "Branch: Master" pull-down, and type new branch's name).
  4. Edit files on disk, test, repeat.
  5. Commit changed files to the branch as you go along, or after it's all working.
  6. Get whole thing into a finished state.
  7. When all changes are done and committed to the branch, open a pull request for the branch.
  8. Get approval of the pull request (the changes).
  9. Merge branch into master branch.



Picking a package to use from GitHub:



2FA in GitHub:
When I turned on 2FA (TOTP) on my GitHub account, I could no longer log in through the CLI.

Found out later: log in to GitHub web page, go to Settings / Security and enable 2FA. Back to Settings, go to Developer settings, then Personal access tokens. Click on Generate new token button. Check only the "repo" item, to do just that stuff through the CLI; do all other stuff through the web UI. Click Generate new token button. Copy the token value and save it.

Then when you do operations through the CLI, use the value of your personal access token instead of your account password.



Count lines in files in git project on disk:
# cd into project directory
git ls-files | xargs wc -l
# or:
git ls-files | grep -P ".*(js|html)$" | xargs wc -l
# or:
git ls-files | grep -vE ".*(png|jpg|ico)$" | xargs wc -l
# or:
sudo apt install cloc
cloc $(git ls-files)
#or:
cloc --vcs git

Count lines in files from git repository:
# clone latest commit of project to disk, count, then remove it from disk
git clone --depth 1 https://github.com/OWNERNAME/PROJECTNAME.git
cd PROJECTNAME
cloc --vcs git
cd ..
rm -fr PROJECTNAME
Or use Chrome extension "GLOC" ? Shows only files in current directory, no recursion ?





App GUI Prototyping



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




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.

"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



Electron's "Writing Your First Electron App"

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"

Electron's "remote"
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"


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://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 !



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.





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 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)"

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."
Nick Parsons' "Takeaways on Building a React Based App with Electron"

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

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)"
VSCode's "Using Angular in Visual Studio Code"
NgDevelop's "10 Best VSCode Extensions for Angular Development"
Coding Latte's "Top VSCode Extensions for Angular Developers"
stackoverflow's "How to debug Angular with VSCode?"
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"
Toby Rogers' "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)"

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
    



VSCode extensions:



  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 VSCode 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 behavour. 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"

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"



  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 "JDBC Tutorial"

    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: Got the code working, database to table etc.

    Some quirks of NetBeans IDE:

    Put the code into GitHub: BillDietrich / MatrixDashboard



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:



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.





Node.js



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

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



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"



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




Ruby





Django



Web-app framework using Python.



Building a Firefox Extension



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 wth 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:
https://addons.mozilla.org/en-US/firefox/
log in
https://addons.mozilla.org/en-US/developers/
Click on "Edit Product Page" for your add-on
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:




I like to put this at top of the README.md of a just-started add-on:
![Do not use](http://4.bp.blogspot.com/-1lTbJMSPZaE/Tyu0eri0bOI/AAAAAAAAEP0/L6yk8jqGUwI/s1600/abnormal%2Bbrain.jpg "Do not use")





Building a Thunderbird Extension



About Thunderbird (Development)
cleidigh / ThunderStorm
thundernest / sample-extensions
MDN's "Thunderbird extensions" (pre-version-60)

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.





Linux Shell Script



Using a text-editor, create a file mytest.sh:
#!/bin/bash

# this is a comment

echo "hello"

read -p 'OK?'
[First line matters because different shells have slightly different syntax, and different users may use different shells.]

In a Terminal window (CLI), run:
chmod a+x mytest.sh
./mytest.sh




PHP program



PHP Manual

Using a text-editor, create a file mytest.php:
#!/usr/bin/php
<?php

/*
  this is a comment
*/

echo "hello";

?>
In a Terminal window (CLI), run:
php -r 'phpinfo();' | more

# if that fails, do:
sudo apt-get install php7.2-cli

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

# if you remove the "#!/usr/bin/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-get install php7.2-gd




Bash script to run via cron



"Cron" section of my Using Linux page

devhints.io's "Bash scripting cheatsheet"



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)





Miscellaneous



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)"



Develop a VSCode extension: see "Building a new extension for VSCode" section of my Using Linux page



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 Mint 19, 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.

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"





Search my site: