Javascript
Introduction
External Links
- The size of the World Wide Web (The Internet)
@[https://www.worldwidewebsize.com/]
- HTML Spec:
@[https://html.spec.whatwg.org/]
- State Of JS:
@[https://stateofjs.com/]
  Check out our results to find out which libraries developers want to learn
  next, which have the best satisfaction ratings, and much more.
-@[https://developer.mozilla.org/en-US/]
-@[https://eloquentjavascript.net/]
-@[https://www.infoq.com/articles/javascript-web-development-trends]
  how well does your browser support HTML5?
@[http://html5test.com/]
- webplatform. Your Web, Documented.
-@[https://webplatform.github.io/]
  The latest information on how to use the technology
  that runs the web — HTML, CSS, JavaScript and more.  WebPlatform.org is a
  work in progress. We could use your help in making it better. Join us.
- Great blog about CSS design and  HTML5
@[http://www.smashingmagazine.com/]
@[https://jvns.ca/blog/2018/11/01/tailwind--write-css-without-the-css/]

- Browser Built-in objects:
@[http://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects]
- @[https://css-tricks.com/learning-to-learn/]
JS 101
•BºIMMUTABLE JS CODEº                                                      [qa]
  • const doesn't make an object inmutable.
    It just avoid re-referencing or adding atributes. Ej:
    const a = [1,2,3]
    a[0] = 3 ; // Mutable

  • Object.freeze(objInstance)

  •ºInmutable JSº
    @[https://facebook.github.io/immutable-js/]                           [TODO]


•BºArrays/listsº                                                     [data_structure]
  const list01 = [1,2,3,4,1]
  const list02 = list01.map(n =˃ n * 2);                             [functional_code]
  list01.length         // 5
  1 in l                // true
  list01.indexOf(1)     // ← 0 (-1 if not found)
  list01.lastIndexOf(1) // ← 4
  list01.join()         // ← "1,2,3,4,1" string
  list01.pop(2/*index*/)// ← returns 3.       list01 after:[1,2,4,1]
  list01.pop()          // ← returns 1.       list01 after:[1,2,4]
  list01.push(5)        // ← add to current a.list01 after:[1,2,4,5]
  list03 = 
       list01.concat(5) // ← add object to new array                  [immutable_code]
                             do NOT modify original one
  list01.reverse()      //                     l = [5,4,2,1]
  list01.  shift()      // ← 5 (1st element)   l =   [4,2,1]
  list01.unshift(5)     // ← 4 (new length)    l = [5,4,2,1]
  list01.slice()        // ← return part of the array as new array.
  list01.sort()         //                     l = [1,2,4,5]
                   //ºA sort function can be providedº

  list01.splice()       // Adds/removes elements from array.
                      splice accepts two lists of elements: the
                      elements to remove and the ones to be added.
  list01.toString()
  list01.valueOf()      // TODO:  Returns the primitive value of the array.

•BºWalking over arraysº 
   const list01 = [1,2,3,...]
   for (var idx = 0; idx ˂ list01.length; idx++) {
      const elementI = list01[idx];
      ...
   }
   for (const elementI of list01) { ... }       // Doesn't look to work properly
   list01.forEach((elementI, idx) =˃ console.log(elementI)); 

•BºLet vs Varº
  let var1 = ...;  // ← Preferred. Variable scope limited to block/statement/expression
  var var2 = ...;  // ← Discouraged. Variable global to function (even if defined inside block)

• BºDATE AND TIMEº @[https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date] const date1 = new Date('December 17, 1995 03:24:00') ← ºGMTº const date2 = new Date('1995-12-17T03:24:00') ← ºGMTº console.log(date1 === date2) ← false console.log(date1 - date2) ← 0 const date3 = Date.now()
BºStringsº • String object are immutable. • methods do NOT alter the original String, but return new ones. s = "1234" s.length // 4 s.charAt(1) // 2 s.charCodeAt(index) // 49 (Unicode Code for "1") String.concat(s1,..)// Joins Strings, returns copy of result. s.indexOf(2) // 2 (1st occurrence) , -1 if doesn't exists s.lastIndexOf(2) // 2 " s.match(/^1/) // ["1"] (returns matching array) s.replace(/^./,"A") // "A234" s.search(/2.4/) // 1 position of 1st match. slice(startPos, endPos): Extract the part of the String split(token) Splits String into string[], using the specified token as the delimiter. TODO substr(startPos, numChars): Extracts a subString from the String, beginning at the start position through the specified number of characters. subString(startPos, endPos): Extracts a subString from the String, between the specified start position and end position. toLowerCase(): Returns the String in all lowercase characters. toUpperCase(): Returns the String in all uppercase characters. trim(): Returns the String without any of the whitespace at either end. valueOf(): Returns the primitive value of the String. String.fromCharCode() // Converts Unicode → characters. ECMAScript 6.0: Template strings support string interpolation. Example: let a="A" let t = `a: ${a}` console.log(t) "a: A" • ES6 in depth [TODO] @[https://hacks.mozilla.org/category/es6-in-depth/] • es6 design Patterns [TODO] @[https://github.com/loredanacirstea/js-design-patterns] !!! @[http://loredanacirstea.github.io/es6-design-patterns/]
Introduction++
JS "OOP"
    function Message (subject, recipient, content){
      this.subject = subject;
      this.recipient = recipient;
      this.content = content;
    }
    Now that we have created a Message function we define its ".prototype" to complete the "Class":
    Message.prototype = {
      constructor: Message,   ← !!

      sendMessage: function(){
        console.log('Sending message to ' + this.recipient);
      },

      show : function(){
        console.log('To:' + this.recipient + 'Subject: ' + this.subject + 'Message:' + this.content);
      }
    };

    The complete definition of the Message object is now in one place, and the same methods are available to all
    instances of Message we create. Each message created can have its own instance properties that are passed through to
    the constructor.

    var workMessage = new Message('Work complete'', 'boss@mycorp.com', 'My work is done here');
    var socialMessage = new Message('Time to go out', 'friend@gmail.com', 'Finished work now.');
    workMessage.send();
    socialMessage.send();
    ________________________
    var F = function() {};// This is a function object.
    var p = F.prototype; // prototype object associated.
    var c = p.constructor; // function associated with pro.

    c === F
    true: F.prototype.constructor==F for any function
    ________________________
    Method overide:

    Dog.prototype.talk = function(){
     console.log('The dog says');
     Animal.prototype.talk.call(this);
    }

    When calling the parent object method earlier, we needed to know that the
    parent was Animal.prototype. We can make the code more elegant by keeping a
    record of what the parent object is.

    Dog.prototype = new Animal();
    Dog.prototype.constructor = Dog;
    //define the parent property
    Dog.prototype.parent = Animal.prototype;
    Dog.prototype.talk = function(){
    console.log('The dog says'); //use the parent property to invoke the method
    this.parent.talk.call(this);
    }
    __________________
    Namespaces:
    var com = com || {};
    com.apress = com.apress || {};
    com.apress.chapterone = com.apress.chapterone || {};
    com.apress.chapterone.Message = function Message(...) {...}

    The usage of a Message object will now need to respect the namespace as follows:

    var myMessage = new com.apress.chapterone.Message(...);
JS Package bundlers
Bº###############################º
Bº# Rollup vs Webpack vs Parcel #º
Bº###############################º
 • Package bundler "==" assets bundle +  runtime module "loader" 

  REF: https://x-team.com/blog/rollup-webpack-parcel-comparison/
  •ºWebpackº: Most user/project base
  •ºRollupº: Best option and similar to webpack
            out-of-the-box features likes source maps, 
            not config-dependencies on .babelrc
  •ºParcelº: zero-conf option.
  • Gulp, Grunt, and Browserify: Old options, still in use in some projects.
  •  SPEED COMPARATIVE: (Time in seconds)
   
                   DEV BUILD          |        PRO BUILD
             ─────────────────────────┼─────────────────────────
               1st run     2nd run    │    1st run     2nd run
             ─────────     ─────────  │  ─────────     ─────────
   RºParcel    14.92        5.22  º   │   738.50       35.36  º
   BºRollup     0.57        0.48  º   │     0.71        0.66  º
     Webpack    3.60        3.32      │     3.63        3.80  

  PRE-SETUP: 
  1) Adding Babel (ES6 to ES7) to package.json (using presets, polyfills and shims).
    "babel-loader": "=7.1.4",
    "babel-plugin-external-helpers": "=6.22.0",
    "babel-preset-env": "=1.6.1",
    "babel-preset-react": "=6.24.1",
    "babel-preset-stage-0": "=6.24.1"
  1) add $prj_root/.babelrc:
     { "presets": ["env", "react", "stage-0"] }

Bº##################º
Bº# PARCEL SUMMARY #º
Bº##################º
  • PRE-SETUP: Add next dependency to package.json:
    "parcel-bundler": "=1.7.1"   (or install OS wide $º$ npm i parcel-bundler:1.7.1 -Dº)
  • main diff with webpack: 
    parcel  sets index.js file into       │ webpack sets index.js file into 
    script.scr @ index.html               │ compiled bundle
    ˂script                               │ ˂script src="built/vendor.min.js"˃˂/script˃
        src="../reactAppSrc/index.js"˃    │ ˂script src="built/built.min.js"˃˂/script˃
    ˂/script˃
  • Ussage: BºNo human (zero-conf) configuration neededº

    $ parcel index.html                      ← transpile dependencies
    $ parcel build public/parcel.index.html  ← production builds
                                               1) builds dependency tree + script 
                                               2) transpile, minify, and bundle 
                                               (built cached. very Fast re-builds)
                                               Optionally add next flags to tune build:
                                                 -d dist/ 
                                                 --public-url '.'
Bº##################º
Bº# ROLLUP SUMMARY #º
Bº##################º
  • PRE-SETUP: Add next dependencis to package.json:
    "rollup": "=0.58.2",                 [TODO]: Update (2019) version
    "rollup-plugin-babel": "=3.0.4",
    "rollup-plugin-uglify": "=3.0.0"

  • PROJECT CONFIG:
    DEVELOPMENT                                    PRODUCTION
  $º$ rollup \                          º        $º$ rollup \                          º
  $º  -c rollup/rollup.dev.config.js \  º        $º  -c rollup/rollup.prod.config.js \ º
  $º  --external all                    º        $º  --external all                    º

    import babel from 'rollup-plugin-babel'        import babel from 'rollup-plugin-babel';
                                                   import uglify from 'rollup-plugin-uglify'
                                                   
    export default {                               export default {
      entry: 'reactAppSrc/rollup.index.js',          entry: 'reactAppSrc/rollup.index.js',
      dest: 'public/built/main.min.js',              dest: 'public/built/main.min.js',
      format: 'iife',                                format: 'iife',
                                                     sourceMap: 'inline',
      plugins: [                                     plugins: [
        babel({                                        babel({
          babelrc: false,                                babelrc: false,
          exclude: 'node_modules/**',                    exclude: 'node_modules/**',
          presets: [                                     presets: [
            "react",                                       "react",
              [ "es2015", { "modules": false } ]             [ "es2015", { "modules": false } ]  
          ],                                             ], 
          "plugins": [ "external-helpers" ]              "plugins": [ "external-helpers" ]
        })                                             }),
                                                       uglify()
      ],                                               ],
    }                                                }

Bº###################º
Bº# WEBPACK SUMMARY #º
Bº###################º
  • PRE-SETUP: 
    GLOBAL INSTALL             LOCAL INSTALL
    $ npm install -g webpack   $ npm init                       
                               $ npm install --save webpack
                                 ^^^^^^^^^^
                                 alt: manually add dependencies to package.json:
                                      "webpack": "=4.6.0"
                                      "webpack-cli": "=2.0.15" 

  • PROJECT CONFIG: edit ºwebpack.config.jsº lik :
    'use strict'

    const debug = process.env.NODE_ENV !== "production"   
    const path = require('path'),
       webpack = require('webpack')
    
    module.exports = {
      mode: 'production',
      context: __dirname,
      devtool: debug ? 'inline-sourcemap' : null,
      entry: './reactAppSrc/index.js',  // or './js/scripts.js', ..
      output: {
        path: path.resolve(__dirname, '../public/built/'),
        filename: '[name].min.js',
      },
      resolve: {
        extensions: ['.js', '.jsx'],
      },
      module: {
        rules: [
          {
            test: /\.jsx$/,
            exclude: /node_modules/,
            loader: 'babel-loader'
          },
          {
            test: /\.js$/,
            exclude: /node_modules/,
            loader: 'babel-loader'
          }
        ]
      },
      plugins: debug ? [] : [
          new webpack.optimize.DedupePlugin(),
          new webpack.optimize.OccurenceOrderPlugin(),
          new webpack.optimize.UglifyJsPlugin({
              mangle: false, sourcemap: false
          })
        ],
    }

  • Run/package: generate scripts.min.js
  $º$ export NODE_ENV=development #  production     º
  $º$ webpack --config webpack/webpack.config.js  \ º
  $º          --progress --profile --colors         º


Bº#################º
Bº# Vite  SUMMARY #º
Bº#################º
• BºModern alterantive to WebPack, Rollup and Parcel,ºdesigned with ES modules
  in mind from the scratch, completely removing the need for "old bundling".
• Vite divides modules into:
  ·ºDependencies:ºwith little/no-change during development, shipped in various
    module formats (e.g. ESM or CommonJS). 
  ·ºSource code:ºoften non-plain standard (JSX/Vue/Svelte components) that needs
    transforming, and edited very often.

  • Depends onºesbuildºfor fast packaging:
  @[https://www.infoq.com/news/2020/06/esbuild-faster-go-js-bundler/]
    •ºwritten in go and multi-coreº
    • seeks to bring order-of-magnitude speed improvements in 
      JS bundling+minification. (10x-100x)
    Bº0.37 secs vs 63 secs pf webpack 5!!!!º
      Major features:
      ✓ Extreme speed without caching ✓ TypeScript and JSX syntax
      ✓ ES6 and CommonJS modules      ✓ Source maps
      ✓ Tree shaking of ES6 modules   ✓ Minification
      ✓ An API for JavaScript and Go  ✓ Plugins

WebPack What's new @[https://www.infoq.com/news/2020/10/webpack-5/] • Webpack 5.0: rethinks some core architectural decisions focusing on: ✓ Improved performance (persistent and long-term) caching ✓ Improved algorithm defaults ✓ Improved bundle sizes (better Tree Shaking and Code generation) ✓ Improved compatibility with web platforms ✓ clean up internal structures inRº"weird state" while implementing features in v4º ✓ Preparing for LTS (no breaking changes after 5) • two key changes have caught the attention of JS community: · Module Federation · change in default behavior for the Node.js API polyfills.
Async Programming
callback to Promise
   function setPromiseTimeout() {       ← Returns promise:
       return new Promise(                modern JS can invoke it with await
         function(callbackOK,             invoking async code with sync syntax
                  callbackError) {
           setTimeout(callbackOK, 500)
         });
   }

   async function start() {
      for (idx=0; idx˂3; idx++) {  
         await setPromiseTimeout()     ← call sequentially async funct. inside loop
         console.log(idx)                 very-difficult/impossible with Callbacks
      }
   }
   start();

  RºWARN!!!º: Promise can not throw since that would force
              client code calling the promise to use both 
              try-catch and ".catch(...). 

async/await explained @[https://2ality.com/2016/10/asynchronous-iteration.html] by Domenic Denicola and Kevin Smith. • async/await serve for "Asynchronous Iteration" • ECMAScript 6 ECMAScript 2018 ✓ support for sync ✓ support for async iteration over data iteration over incomming data (in RAM memory) (from remote HTTP/AJAX/... response) const iterable const asyncIterable = ['1', '2']; = createAsyncIterable(['1', '2']); const iterator = const asyncIterator = iterable[Symbol.iterator](); asyncIterable[Symbol.asyncIterator](); iterator.next() asyncIterator.next() └──────┬──────┘ .then(iterResult1 =˃ { return {value:..., done:...} /* ↖ { value: '1', ... } */ ^{ value: '1', done: false } return asyncIterator.next(); }) iterator.next() asyncIterator.next() └──────┬──────┘ .then(iterResult1 =˃ { ^{ value: '2', done: false } /* ↖ { value: '2', ... } */ return asyncIterator.next(); }) iterator.next() asyncIterator.next() └──────┬──────┘ .then(iterResult1 =˃ { { value: undefined,ºdone: trueº} /* ↖ { ...,ºdone: trueº } */ return asyncIterator.next(); ^ next() doesn't work async }) └─────────────┬──────────────────┘ ┌─────────────┴──────────────────┐ Within async functions syntax for managing Promise results can be simplified as: async function f() { const asyncIterable = createAsyncIterable(['1', '2']); const asyncIterator = asyncIterable[Symbol.asyncIterator](); console.log(await asyncIterator.next()); // { value: '1', done: false } console.log(await asyncIterator.next()); // { value: '2', done: false } console.log(await asyncIterator.next()); // { value: undefined,ºdone: trueº} } Bº#################################º Bº# ECMAScript 2018 for-await-of #º Bº#################################º • Syntax converts each iterated value via Promise.resolve() to a Promise, which it then awaits. • Can be used with sync/async iterables. e.g: async function f() { for await (const x of createAsyncIterable(['a', 'b'])) { ← long explicit syntax // for await (const x of ['a', 'b'] ) { ← short syntax console.log(x); } } • for-await-of and rejections Similarly to how await works in async functions, the loop throws an exception if next() returns a rejection: MOCKED asyncIterator Mocked code capturing returning an exception Promise error ============================== ====================== function createIterableMock() { Qº(ºasync function () { // (A) returnº{º ºtry {º [Symbol.asyncIterator]() { for await (const x of return this; createIterableMock()) { }, console.log(x); next() { } return Promise.reject( ··········→ º} catch (e) {º new Error('Problem!')) console.error(e);// ← Error: Problem! },// ^ º}º º}º // async code can not throw }Qº)º() } // exceptions. Promise.reject Qº^º: wrap code: async doesn't work // used as replacement. at script|module top level Bº####################º Bº# Async generators #º Bº####################º async function* // ← '*' turns fun. into (a)sync generator createAsyncIterable(syncIterable) { // ← Converts for (const elem of syncIterable) { // ← sync iterable to yield elem; // ← async " . next(...) will } return Promise for {value:,done:} } Calling the generator does NOT return a value but a generator object that can be invoqued with .next(...). Then .next(...) returns {value:...,done:} In Each invocation genObj.next() returns a Promise for an object {value,done} that wraps a yielded value. In the async version JS automatically will queue invocations to next() (think of next(...) are async request to a remote serve). JS will call the generator once it becomes ready. There is no need to wait for the Promise before invoquing next(..) again (in the same way that there is no need to wait for a server TCP-ACK to send another TCP-connection). In many/most occasion code needs to wait for the Promise and the Promise resolution, and then the for-wait-of takes care of it transparently. Still Promise.all() can be use to "send" next in parallel, then wait for "all" completion like: const [{value:v1},{value:v2}] = await Promise.all( [ asyncGenObj.next(), asyncGenObj.next(),..] ); (See original source @[https://2ality.com/2016/10/asynchronous-iteration.html] for more details and complex examples) Bºcaolan/asyncº [qa][TODO] @[https://github.com/caolan/async] @[http://caolan.github.io/async/v3/] • Async provides around 70 functions that include the usual 'functional' suspects (map, reduce, filter, each…) as well as some common patterns for asynchronous control flow (parallel, series, waterfall…). • It works on browsers and (NodeJS) server code.
Concurrency
Service Workers 
• Not to be confuse with web workers:                 [comparative]
  ·ºService-Workersº handle net.requests/cache/push notifications,...
  ·ºWeb-Workerº: Mimics multithreading, allowing intensive scripts 
    to be run in the background.
• See also Service Workers in Angular #[angular_service_worker]

• JS module providing web apps reliability and performance on par
  with natively-installed code. 
• Service workers function as a network proxy managing cache.
• intercept outgoing HTTP requests (data, HTML, even index.html),
  and choose how to respond to them:
  • If properly designed, it can completely satisfy the app load
    without the need for the network.
• S.Workersºdo NOT rely on server-specified caching headersº.
• preserved after closing the tab/window.
• When a browser loads the web page/app, service workers loads first.
  •@[https://serviceworke.rs/]
    Service Worker Cookbook:collection of working, practical examples       [qa]
    of using service workers in modern web apps.
    - Network or cache: try fetch from network, fallback to cache.
    - Cache only:
    - Cache and update: fetch from cache, update cache then.
    - Cache, update and refresh UI.
    - server embedded content on missing resources.
    - Push notification, Retrieve Payload on received notification
    - Push notification with Payload (string, ArrayBuffer, Blob, JSON).
    - Push Rich, defining notification language, vibration pattern, image
    - Push Simple: (even when page is not open).
    - Push Tag: (replace old notifications).
    - Push Quota (experiment with browser limits)
    - Push control-Clients: focus re-open tab
    - Push Subscription: 
    - Immediate Claim: take control of page without waiting for avigation event
    - Cache from ZIP recipe: cache contents from zipfile
    - Message Relay, Fetch Remote Resources, Live Flowchart,
      Offline Fallback, Offline Status, JSON Cache, Local Download,
      Virtual Server, API Analytics, Load balancer, Dependency Injection,
      Request Deferrer, Cache then Network, Render Store
  • @[https://www.infoq.com/news/2019/08/postMessage-performance-study/]
      Surma, Web Advocate at Google, recently published a study on the 
    performance of postMessage, the method used by web workers to 
    communicate. Surma concludes that while postMessage comes with some 
    overhead, provided the payload is below a given budget, moving non-UI 
    tasks off the main thread may result in increased overall 
    user-perceived performance.

BºSUMMARYº                                                                [TODO]
  • probably the most powerful API added to the web platform recently.
  • allows to do anything with each request/response received by a browser. 
    (cancel requests, re-route, modify/cache responses, ...)
BºWorkbox libraryº                                                    [low_code]
@[https://developers.google.com/web/tools/workbox/]
  • rapidly integrate common Service Worker functionality like 
    precaching, runtime caching, request routing, background sync, and more.
  • Fully async, compatible with XHR and localStorage.

• External resources:
  • @[https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API]    [TODO]
  • @[https://developers.google.com/web/fundamentals/primers/service-workers/]TODO]
Web Workers
• See also #[service_workers]
Debugging
Bº#################º
Bº# DEBUGGING 101 #º
Bº#################º
• Play with ajax requests (Firefox only?)º
  → Go to inspector → network tab → RightClick on request
    → choose Edit and Resend: Now you can change anything
      you want: header, params, ... and resend.

• "debugger" keyword: pause in code just when console is open

• dump object to string: ºJSON.stringify(myJS_object)º
  To avoid cicular dependencies problems redefine stringify like:
  REF: @[https://stackoverflow.com/questions/11616630/how-can-i-print-a-circular-structure-in-a-json-like-format]
  JSON.stringifySec = function (circ) {
    cache = []
    result = JSON.stringify(circ, function(key, value) {
        if (typeof value === 'object' ⅋⅋ value !== null) {
            if (cache.indexOf(value) !== -1) {
                return         // Duplicate reference found, discard key
            }
            cache.push(value)  // Store value in our collection
        }
        return value
    })
    cache = null
    return result
  }
  var circ = {};
  circ.circ = circ;
  JSON.stringifySec (circ)    // ← Ussage

• Print the calling function in the called function:
  var f1 = function(...){
     console.warn( "Called from:" +
      ºarguments.callee.caller.toString()º);
      ...
  }
• Quickly access elements in the console:
   $('css-selector’) ← return first match of CSS selector
  $$(‘css-selector’) ← return all   matches

Bº########################º
Bº# debugging async code #º
Bº########################º
OºNodeJS Dump async function chain ("async stack-trace")º         [async]
@[https://stackoverflow.com/questions/40300996/nodejs-is-is-possible-to-show-the-stack-trace-of-a-calling-async-function]
@[https://gist.github.com/lll000111/3d6a53da4d53beb909189793c7631ba6]

  • Context:  fnThrowingError is call asynchronously
    const RºfnThrowingErrorº= async () =˃ {
        await ...
       ºthrow new Errorº(                 ← Some deeply nested (in the actual call hierarchy)
          'Houston we have a problem!');    asynchronous function that throws an error.
    }


  • Alternative 1: Node.js 12+. (2019-08-04+)
    Async Stack Traces come out of the box  using flag '--async-stack-traces'
  @[https://medium.com/@nodejs/introducing-node-js-12-76c41a1b3f3f]
  

  • Alternative 2:
    const fn2 = async () =˃ {
      try {
          return awaitRºfnThrowingErrorº()
      } catch(err) {                         // ← STEP 1: try-catch all errors. 
                                                          (DON'T return promise directly)
          err.stack +=                       // ← STEP 2: Add a locally generated stack trace 
             º(new Error()).stackº                        to the one already existing on 
          throw err                                       the error object                                     
      }
      ...
      return result
    }

  • Alternative 3: (Syntax alternative)
       const result =RºfnThrowingErrorº()
         º.catchº(err =˃ {                  // ← STEP 1: replace try-catch → promiseº.catch(..)º
                                                         main advantage: allows assignment to "const"
          err.stack +=                      // ← STEP 2: Same as Alt. 2
             º(new Error()).stackº
             throw err
           }
       )

BºDumping "async" stack-trace fn0 → fn1 (async call) → fn2:    [async]
  constºfn1º= async () =˃ {       ← STACK "LEVEL 1"
      try {
          return awaitºfn2º()     ← RºWARNº:if something more complex than just 
                                    retuning is executed then err can be different
                                    to the fn1 async err and the async stack trace
                                    will be "false"
      } catch(err) {
          err.stack += 
            (new Error())º.stackº ← Add locally generated stack trace to existing one 
         ºthrow errº
      }
  }
  
  constºfn0º= async () =˃ {       ← STACK "LEVEL 0"
      try {
          return await fn1()
      } catch(err) {
          err.stack += 
            (new Error())º.stackº ← Add locally generated stack trace to existing one
          throw err
      }
  };
  
  fn0().catch(console.error)      ←ºDump stack here !!!º     

Bº###################º
Bº# advanced tricks #º
Bº###################º
• REF:@[https://raygun.io/blog/2015/06/useful-javascript-debugging-tips-you-didnt-know/]
  console.table(animals);      ← Display object as tables in the console: (Chrome only?)
  
  this.funcZ = function(){     
    console.trace('trace car') ← Dump stack trace for function funcZ
  }
  
  debug(car.functY)            ← Quick find a function to debug:  (Chrome only?)
                                 (not the same that console.debug)
  
  monitor(funct1)              ← Every time the function is called values pased in will be logged 

  debug(car.functY)            ← Quick find a function to debug.
                                 (not to be confused with console.debug)

• Ignore (black list) Script while debugging
  CHROME:                                                      FIREFOX:
  · Alt 1. inspector → source → Right click                    Inspector → Debugger → Mark scriptto black list →
    the file to black list and choose black box script.        Click on the eye in the very bottom left corner.
  · Alt 2. Open up settings view → Click                       https://hacks.mozilla.org/2013/08/
    "manage framework black boxing" → write a regexp in          new-features-of-firefox-developer-tools-episode-25/
    popup to blackbox, for example, the entire vendor folder.
    https://developer.chrome.com/devtools/docs/blackboxing

• SOURCE MAPPING
  REF: @[http://blog.getsentry.com/2015/10/29/debuggable-javascript-with-source-maps.html]
  • source maps : JS's version of debug symbols: 
  • Include with:
    //# sourceMappingURL=/path/to/app.min.js.map
  • Generated by modern JS transpilers
  • Ex source map:
    source map example:
    {
      version : 3,  // version of source map spec (should be 3)
      file: "app.min.js", // generated filename associated to
      sourceRoot : "",    // all sources are relative to it (opt)
      sources: ["foo.js", "bar.js"], // URLs to original  files
      names: ["src", "maps", "are"], // variable/method names found in your code
      mappings: "AAgBC,SAAQ,CAAEA"   // base64Enc VLQ values source code mappings
    }

Fiddler Proxy @[www.telerik.com/fiddler] [tool] • Allows to replace remote html/css/AJAX responses with local/mocked ones.[troubleshooting] Very useful when deploying to remote server can be "slow" due to CI constrains. • Allows to see the "total page weight" HTTP caching and compression at a glance • Tutorial: http://www.youtube.com/watch?v=TP_5JYatlNQ [Video]

Prog.WApps Summary
@[https://developer.mozilla.org/en-US/Apps]
• apps built using standard Web technologies, working in any modern Web browser.
• Compared to standard web apps/sites: 
  · Apps are installed by a user, they are self-contained and don't always
    require the chrome of a browser window.
  · can be built to run offline.
• Example of Progressive web apps include Gmail, Twitter or Etherpad.
• Integrate within desktop and mobiles OSes, by allowing to access them through
  "start" or desktop icons and run in background pooling/pushing data from/to 
  remote servers while the browser is "closed".

Bº######################º
Bº# "Hello World!" PWA #º
Bº######################º
  SUMMARY FROM
@[https://medium.com/james-johnson/a-simple-progressive-web-app-tutorial-f9708e5f2605]
  by James Johnson
• PWA layout: 
  Hello-PWA/
  ├─ index.html    ← ✓ Hard code initial content to avoid empty-page when offline 
  │                    or using old / non-PWA compliant browsers.
  │                ← ✓ PWA UI must display properly on mobile/desktop:
  │                    Add viewport meta tag to index.html like:
  │                    ˂meta name="viewport"
  │                       content="width=device-width, initial-scale=1.0"˃
  │
  ├─ sw.js         ← ✓ Service Worker running in background in charge of
  │                    non-user-interactive tasks (cache dynamic data, ...)
  │                  
  ├─ manifest.json ← ✓ json file specifying look and behavior on 
  │                    different devices. (orientation, theme color,...)
  ├─ css/        
  │  └─ style.css
  │
  ├─ js/    
  │  └─ main.js  ← ✓ Register service worker here.
  │
  │  favicon.ico   ← 16x16 px
  └─ images/ 
     └─ ...      ← ✓ At least image resolution of 128x128px, 144x144 px,
                     152x152 px, 192x192 px, 256x256 px and 512x512px needed
                     for compliance with Windows, Mac, iPhone and Android.

• ┌─ e.g. Hellow-PWA/index.html:───────────────────
  │ ˂!doctype html˃
  │ ˂html lang="en"˃
  │ ˂head˃
  │   ˂meta charset="utf-8"˃
  │   ˂title˃Hello World˂/title˃
  │   ˂link rel="stylesheet" href="css/style.css" ˃
  │   ˂link rel="manifest"   href="/manifest.json"˃
  │   ˂meta name="viewport" 
  │      content=
  │        "width=device-width, initial-scale=1.0"˃
  │
  │ ˂!-- app icon related stuff {{{ ˃  
  │ ˂link rel="icon" href="favicon.ico" type="image/x-icon" /˃  
  │ ˂meta name="theme-color" content="white"/˃  
  │ ˂link rel="apple-touch-icon"                       href="images/app-icon-152.png"˃   
  │ ˂meta name="msapplication-TileImage"            content="images/app-icon-144.png"˃  
  │ ˂!-- }}} ˃
  │
  │ ˂!-- apple mobile custom config {{{ ˃  
  │ ˂meta name="apple-mobile-web-app-capable"          content="yes"˃  
  │ ˂meta name="apple-mobile-web-app-status-bar-style" content="black"˃ 
  │ ˂meta name="apple-mobile-web-app-title"            content="Hello World"˃ 
  │ ˂!-- }}} ˃
  │
  │ ˂body class="fullscreen"˃
  │   ˂div class="container"˃
  │     ˂h1 class="title"˃Hello World!˂/h1˃
  │   ˂/div˃
  │ ˂script src="js/main.js"˃˂/script˃       ← Load at the bottom of page.  
  │ ˂/body˃                                    Really needed?
  │ ˂/html˃
  └────────────────────────────────────────────────
• ┌─ e.g. Hellow-PWA/css/style.css:────────────────
  │ body { font-family: sans-serif; }
  │ 
  │ html,
  │ .fullscreen {
  │    display: flex;
  │    height: 100%;   ┐ Make content area fill 
  │    width: 100%;    ├ entire browser window
  │    margin: 0;      │
  │    padding: 0;     ┘
  │ }
  │ 
  │ .container {
  │   margin: auto;       ┐ Center the content
  │   text-align: center; ┘ in browser window
  │ }
  │ 
  │ .title { font-size: 3rem; }
  └────────────────────────────────────────────────
  • TIP: Periodically audit tests over the app using some tool 
         like (OOSS) Google’s Lighthouse.


• ┌─ e.g. Hellow-PWA/sw.js:    ────────────────
  │ const cacheName = 'hello-pwa';
  │ const filesToCache = [
  │   '/'             ,
  │   '/index.html'   ,
  │   '/css/style.css',
  │   '/js/main.js'
  │ ];
  │ 
  │ self.addEventListener(              
  │   'install', function(e) {               ← PWA standard life-cycle callback
  │     e.waitUntil(                           called automatically when installing
  │       caches                               for the first time.
  │         .open(cacheName)
  │         .then(function(cache) {
  │           return
  │             cache.addAll(filesToCache)
  │       })
  │     );
  │ });
  │ 
  │ self.addEventListener(
  │   'fetch', function(e) {                  ← bind "fetch" event to serve 
  │     e.respondWith(                          cached content when possible
  │       caches                                
  │         .match(e.request)                   
  │         .then(function(response) {          
  │           return response                 ← Return cached content if available
  │               || fetch(e.request);        ← try online fetch.
  │         })                            WARN: demo code will fail if just 
  │     );                                      one of the file fetches fails.
  │ });                                         retry strategies needed.
  └────────────────────────────────────────────


• ┌─ e.g. Hellow-PWA/js/main.js ────────────────
  │ window.onload = () =˃ {
  │   'use strict';
  │     if (! 'serviceWorker' in navigator) {
  │       alert("Browser not supported. PWA needed")
  │       throw "PWA not available"
  │     }
  │     navigator
  │       .serviceWorker                      ← Register service worker
  │       .register('./sw.js');
  │ }
  └─────────────────────────────────────────────


• ┌─ e.g. Hellow-PWA/manifest.json ─────────────
  │ {
  │   "name": "Hello World",                 ← Used at install time
  │   "short_name": "Hello",                 ← Used in app icon
  │   "lang": "en-US",
  │   "start_url": "/index.html",
  │   "display": "standalone",               ← Treat as standalone without 
  │   "background_color": "white",             browser chrome
  │   "theme_color": "white"                 ← Must match 
  │ }                                          ˂meta name="theme-color" content="white"/˃
  └─────────────────────────────────────────────
Functional Testing
Mocha
@[https://mochajs.org/]
• Easy testing of async services / REST APIs / ...
  better than Jasmine                                  [comparative]
• JS based, runs in browser and NodeJS.
• tests run async service serially, allowing for
  accurate reporting, mapping uncaught exceptions
  to the correct test
• install:
  $ npm install -g mocha
• Commonly used withº"Chai" library as assertion libraryº
  (assert, expect, should), installed per project like:
  $ npm install --save-dev chai
• Commonly used withº"Supertest" SuperAgent extension library asº
 ºHTTP AJAX test library.º, installed per project like:
  $ npm install --save-dev supertest
• Ussage summary:
  $ mocha ← execute tests with default conf. (defaults + mocha.opts)
  $ mocha directory_with_tests ← Run tests at location
  $ mocha --grep {{^regex$}}   ← Run tests matching pattern
  $ mocha --watch              ← Run tests once, the on JS file change
  $ mocha --reporter $reporter ← Run tests with specific reporter
• Test how-to summary:
  · mkdir test 
  · vim test/test01.js
    iconst request = require('supertest');
    const app = require('../server/app.js');
    
    describe('GET /users', function() {
      it('return list of users', function() {
        return request(app)
          .get('/users')
          .expect(200)
          .expect('Content-Type',/json/)
          .expect('[{"name":"ej","age":26},{"name":"jh","age":28}]')
      })
    })
• See official doc for info about hooks (before, after, afterEach)
  Retry Tests, Timeouts, Diffs, ...
• Official examples at:
@[https://github.com/mochajs/mocha-examples/tree/master/packages]
  selenium, rxjs, react-webpack,programmatic-usage
Selenium (Web test Automation)
• External Resources:
  ·@[http://docs.seleniumhq.org/]
  ·@[http://docs.seleniumhq.org/projects/ide/]
  ·@[http://code.tutsplus.com/tutorials/headless-functional-testing-with-selenium-and-phantomjs--net-30545]
  ·@[http://stackoverflow.com/search?q=selenium]

• Automate browser execution applying test on expected elements,
  URL, events ....
• Oldest and most widely adopted End-to-End automation framework.
• Can orchestrate tests in any major browser.
• Example test: 
  const {Builder, By, Key, until} = require('selenium-webdriver');       [code_snippet]
  
  (async function example() {
      let driver = await new
          Builder().forBrowser('firefox').build();
          try {
      await driver.get('https://www.google.com'); // ← Navigate to Url
  
      await driver
            .findElement(By.name('q')             // *1 
          ).sendKeys('cheese', Key.ENTER);   // ← Enter "cheese", then "Enter"
  
      let firstResult = await driver.wait(
                until.elementLocated(
                   By.css('h3')),                 // *1
                10000);
  
      console.log(await firstResult.getAttribute('textContent'));
          } finally{
      driver.quit();
          }
  })();

  *1 The crux of Selenium is the element locator.
     ✓ id                  ✓ tag name
     ✓ name                ✓ class name
     ✓ link text           ✓ css
     ✓ partial link text   ✓ xpath
    
• Selenium IDE: Firefox/Chrome extension to automatically record/save/replay tests
  @[https://examples.javacodegeeks.com/enterprise-java/selenium/selenium-ide-commands-example/]
  @[https://www.youtube.com/watch?v=ZG3VFDMaAlk]

•ºAlternatives to Seleniumºinclude:
  ✓ºCypressº:  JS centric framework, probably more friendly to web developers. [TODO]
    · No need for "wait" commands in test scripts.
      Cypress waits automatically for commands and assertions.
    · Tests can make use of Spies, Stubs, and Clocks to verify
      and control the behavior of responses, functions and timers.
    · Automatic scrolling ensures that elements are visible 
      before performing (testing) any action.

  ✓ºPlaywrightº: JS centric
    · Focused on web-scraping (headless browser)
    · Ex: 
      const playwright = require('playwright');                           [code_snippet]
      async function main() {
         const browser = await 
            playwright.chromium.launch({                   ← Use choromium
             headless: false                               ← Disable headless mode (enable view)
         });
         const page = await browser.newPage();
         await page.goto('https://.../testPage');
         const scraped_data_list = await page.
                  $eval('#someID', headerElm =˃ {
           const data_list = [];
           const li_list = headerElm.getElementsByTagName('li');
           li_list.forEach(domObject =˃ {
               data_list.push(domObject.innerText.split('\n'));
           });
           return data_list;
         });
         console.log('scraped_data_list:', scraped_data_list);
         await page.waitForTimeout(5000);                  ← wait for 5 seconds
         await browser.close();
     } 
    
    main();   
Mock Service Worker MSW (REST/GraphQL Testing)
@[https://www.infoq.com/news/2020/11/msw-mocking-graphql-rest-api/]
• test UI components webapps without actual back-end, setting up mock server,
  or stubbing native http/https/fetch implementations.
• test  as much as possible in the same conditions and in the same way
  as a real user would.
• User actions are exercised on an actual rendered component,
  they may trigger real effects (e.g., remote data fetching, API calls)
  that need to be mocked or stubbed.
• having tests passing against an altered version of a native fetch
  browser method does not completely guarantee that the same tests
  will pass against the unaltered version of fetch.
• MSW allows developers to mock Rest and GraphQL APIs without having to
  modify the component code or stubbing native http/https/fetch implementations.
Testing
Google Lighthouse
@[https://developers.google.com/web/tools/lighthouse/]
• OOSS Automated tool, searching to improve quality of web pages.
• Can test any site (public or requiring authentication).
• Audits performance, accesibility, PWA, SEO, ...
• Can be roon on Chrome Devtools, command line, or Node module.

  E.g. ussage extracted from
  https://medium.com/james-johnson/a-simple-progressive-web-app-tutorial-f9708e5f2605
  """... Make sure "Progressive Web App" option is checked. You can 
  uncheck the others for now. Then click on the “run tests” button. 
  After a minute or two Lighthouse should give you a score and list of 
  audits that the app passed or failed. The app should score around 45 
  at this point. If everything was coded properly, you’ll notice that 
  most of the tests it passes are related to the requirements we 
  outlined at the beginning..."
StoryBook.js
https://storybook.js.org/ !!!!
robust UIs: sandbox to build UI components in isolation so you can
develop hard-to-reach states and edge cases.
for React, Angular, Vue, ...
Profiling
YSlow Profiler
• home page: @[http://yslow.org]
• YSlow analyzes web pages and why they're slow
  based on Yahoo!'s rules for high performance web sites
• Feature highlights:
  ✓ Grades web page based on one of three predefined ruleset
    or a user-defined ruleset
  ✓ It offers suggestions for improving the page's performance
  ✓ Summarizes the page's components
  ✓ Displays statistics about the page;
  ✓ Provides tools for performance analysis, including Smush.it™
    and JSLint.
• Check for nextºbest-patterns/rulesº:
  ✓ Minimize HTTP Requests
  ✓ Use a Content Delivery Network
  ✓ Add an Expires or a Cache-Control Header
  ✓ Gzip Components
  ✓ Put StyleSheets at the Top
  ✓ Put Scripts at the Bottom
  ✓ Make JavaScript and CSS External
  ✓ Reduce DNS Lookups
  ✓ Minify JavaScript and CSS
  ✓ Remove Duplicate Scripts
  ✓ Configure ETags
  ✓ Make AJAX Cacheable
  ✓ Use GET for AJAX Requests
  ✓ Reduce the Number of DOM Elements
  ✓ Reduce Cookie Size
  ✓ Use Cookie-Free Domains for Components
  ✓ Make favicon.ico Small and Cacheable
  ❌ Avoid empty src or href
  ❌ Avoid CSS Expressions
  ❌ Avoid Redirects
  ❌ No 404s
  ❌ Avoid Filters
  ❌ Do Not Scale Images in HTML

Mozilla Perf.Tool • REF: @[https://developer.mozilla.org/en-US/docs/Tools/Performance] • Performance tool gives insights into a site's general responsiveness, JS and layout performance. • It allows to create a recording(profile), of a site over a period of time. The tool then shows you an overview of the things the browser was doing to render the page/s and a graph of the frame rate over the profile.
JS Alternatives
Typescript
• JS with types.  @[https://www.typescriptlang.org/]
• Quick tutorial:
 @[https://learnxinyminutes.com/docs/typescript/]
• Debugging TS in Firefox DevTools:    [TODO]
@[https://hacks.mozilla.org/2019/09/debugging-typescript-in-firefox-devtools/]
• BºSyntax summaryº
@[https://learnxinyminutes.com/docs/typescript/]
  let isDone: boolean = false   ← 3 basic types
  let lines : number  = 42 
  let name  : string = "Anders" 
  let   var1 = false            ← Type inference if type ommited
  
  let name  : any = jsObject    ← any: Compatibility with non-typed JS
  const CON1 = false            ← Make constant/immutable (prefered) [qa][billion_dolar_mistake]
  
  
  let   typedArray01: number[]      = [1, 2, 3]
  let genericArray02: Array˂number˃ = [1, 2, 3]
  
  enum Color { Red, Green, Blue }
  let c: Color = Color.Green
  
  BºFunctionsº
    let f1 = function (i: number): number {
      return i * i;                └─┬──┘
    }                              Return type (or void)
                                   (It can also be inferred)
  
    let f2 = (i: number): number =˃  ← Arrow syntax (used also in anonoymous
       { return i * i; }               lamdas)
  
    let f5 = (i: number) =˃ i * i;   ← braceless means void/none return
  
  BºInterfacesº
    interface Person {                 ← Interface declaration
      name: string;
      age?: number;                      ← Optional type               [qa][billion_dolar_mistake]
      move(): void;
    }
    let p: Person = {                  ← Interface implementation
     name: "Bobby",
     move: () =˃ { } 
    };
    
    interface SearchFn {               ← Interface describing a function type
      (source: string,                   Only param's types are important, names are not
       subString: string): boolean;
    }
    let fnSearch: SearchFn = function  ← Function implementing the interface
        (src: string, sub: string) {
          return src.search(sub) != -1
        }
  
  BºClassesº
  class Point {                      ← class definition
    x: number;                       ← Properties public by default
    static origin = new Point(0, 0); ← Static member
    readonly name: string;           ← read-only, only allowed to be                [qa]
                                       writen in constructor.(Typescript 3.1+)
    constructor(
      _x: number, 
      private y: number = 0          ← syntax shortcut 'y' defined as class property as 'x'
      _name : string ) {
      this.x = _x;                     
      this.name ) 
    }
    
    fn01(): number {  ... }
  
  }
  
  class PointPerson 
    implements IPerson { ... }       ← Class implementing interface
  
  class Child
    extends ParentClass { ... }      ← Class inheriting from parent class .
                                       RºWARN:º Discouraged. Better use composition
  
  BºModulesº
    module Geometry {                  ← Modules, "." can be used as separator for sub modules
      export class Square { ... }
    }
    import G = Geometry;                 ← Local alias for referencing a module
    let s1 = new Geometry.Square(5);       ← Or just new G.Square(5);
  
  BºGenericsº
    class Tuple˂T1, T2˃ {            | interface Pair˂T˃ { | function ˂T˃(p: Pair˂T˃) {
      constructor(                   |   item1: T;         |   return 
          public item1: T1,          |   item2: T;         |     new
          public item2: T2) { ... }  | }                   |      Tuple(p.item1, p.item2);
      ...                            |                     | };
    }                                |                     |
  
  BºTemplate Stringsº
  let greeting  = `Hi ${name}, how are you?`
  let multiline = `This is an example
  of a multiline string`;
  
  BºInmutable Collectionsº
    const         number_array: Array˂number˃ = [0, 1, 2, 3, 4];    ←          number_array can not be reasigned to other
                                                                      array (const), but current array can be modified
    const inmutable_number_array: ReadonlyArray˂number˃ = numbers;  ← inmutable_number_array can not be reasigned to other
                                                                      array (const), and no modifications allowed either.
  
  BºTagged Union Typesº (model state-machine states easely)        [qa]
    DECLARATION                                USSAGE
    type State =                               declare const state: State;
      | { type: "loading" }                           if (state.type === "success") {
      | { type: "success", value: number }      ... state.value  ...
      | { type: "error", message: string };    } else if (state.type === "error") {  
                                                ... state.message ...
                                               }
  
  BºIterators and Generatorsº
    let arrayOfAnyType = [...];                ← Array or list
    for (const val of arrayOfAnyType) { .... } ← Iterate overºvalues in listº
    let object = { ... }
    for (const key in list) { ... }              Iterate overºkeys in objectº
Elm
•BºNo Runtime Exceptionsº
    Elm uses type inference to detect corner cases and give friendly
    hints.
     NoRedInk switched to Elm about two years ago, and 250k+ lines
    later, they still have not had to scramble to fix a confusing runtime
    exception in production.
    Ex:
      -- TYPE MISMATCH ---------------------------- Main.elm
      The 1st argument to `drop` is not what I expect:
      8|   List.drop (String.toInt userInput) [1,2,3,4,5,6]
                      ^^^^^^^^^^^^^^^^^^^^^^
                 This `toInt` call produces:
                 Maybe Int
                 But `drop` needs the 1st argument to be:
                 Int
      Hint: Use Maybe.BºwithDefaultº to handle possible errors.

•BºGreat Performanceº

•BºEnforced Semantic Versioningº
   ✓ Breaking APIs force new major version automatically.
     thanks to its "ML" type system:
   BºNo surprises in PATCH releasesº

   $ Bºelm diffº Microsoft/elm-json-tree-view 1.0.0 2.0.0
   This is a MAJOR change.
   ---- JsonTree - MAJOR ----
       Changed:
         - parseString : String → Result String Node
         + parseString : String → Result Error Node

         - parseValue : Value → Result String Node
         + parseValue : Value → Result Error Node

•BºSmall Assetsº (faster page loads)
   Use --optimize flag, compiler do the rest. (no config needed)

•BºJavaScript Interoperabilityº

Reason @[https://reasonml.github.io/] • By Facebook • " Reason lets you write simple, fast and quality type safe code while leveraging both the JavaScript and OCaml ecosystems." • See (excellent) comparative Elm vs Reason @[https://stackoverflow.com/questions/51015850/reasonml-vs-elm] • See also: ReasonReact
Security
Trusted Web Code
@[https://www.infoq.com/articles/encryption-defense-native-browser-apps/]
• Trusted code: first-line-of-defense for browser security.
  Reusing libraries makes web development faster at the cost
  of increasing the risk of introducing malicious code.
• There are also under-used code-delivery settings that instruct the
  browser to take extra precautions since they reduce the flexibility
  of the development and integration process.
Bºthe security they provide is worth the work, whether your applicationº
Bºdoes encryption or not.º

BºHTTP Strict Transport Security (HSTS):º
- Instructs the browser to always load this page over HTTPS. This
  prevents downgrade attacks, for instance, if the attacker can
  redirect your DNS to a malicious service they can't downgrade the
  connection to unencrypted HTTP.

BºStrict Content Security Policies (CSP):º
  Whitelist safe sources for loading code, preventing apps to
  dynamically load code from unknown remote resource.

BºSubresource Integrity (SRI):º
  Only load trusted scripts, using cryptographic hashes to mark
  trusted scripts.

BºWebCrypto API:º
  "relatively" new browser API helping efficient and secure delivery
  of cryptographic primitives.
  - low-level ciphers.
  - hashes
  - "other" encryption components.

• Being directly implemented into (trusted) browser and taking
  advantage of local native execution (and even hardware acceleration)
Gºthey are much safer than js code.º
  RºWARN:º They do NOT prevent certain attacks, like
  just sending an unencrypted copy of the data to the "bad guys".
AAA
External Links
• @[/Architecture/architecture_map.html?topics=oauth]
• @[/Architecture/architecture_map.html?topics=aaa]
Web Authentication API
• This API enables users toºavoid text-based passwords for websitesº
  and insteadºuses a local device with a biometric check or private PINº
  to generate a secure cryptographic identifier. 
• Firefox adopted in in 2018
@[https://www.infoq.com/news/2018/05/firefox-web-authentication-api]
W3C DIDs
• SPEC: @[https://www.w3.org/TR/did-core/]
• DID stands for Decentralized IDentifier representing any type of subject
  (person, organization, thing, data model, abstract entity, etc.) 
  decoupled from any centralized registries (Active Directory, ..),
  identity providers (Facebook, Google, ...) or certificate authorities.  Eg: 

  did:ether:21tDAKCERh95uGgKbJNHYp;foo:bar=high 
                                       ───┬────   
  ┌───────────────────────────────────────┘
  generic DID parameter names.
  · hl             resource hash of DID document (integrity protection)
  · service (id)   Identifies a service from the DID document 
  · version-id     Identifies a specific version of DID document 
                   (sequential number, UUID, ...).
                   (optional in implementations)
  · version-time   Identifies a certain version timestamp of DID document
                   (optional in implementations)

• DIDs are URIs linking the DID subject to a DID document. The DID
  document in practice will be:
   ✓ cryptographic material        (public keys, revoked pub.keys,...)
   ✓ verification methods/services (signature schemas, ...)
   ? other public credentials as
     desired by the owner/controller
  · Non-normative (self-managed) minimal DID-document example:
    {
      "@context": "https://www.w3.org/ns/did/v1",
      "id": "did:id_of_DID_method:DIDI_method_specific_id",
      "authentication": [{
        "id": "did:id_of_DID_method:DIDI_method_specific_id#keys-1",
        "type": "RsaVerificationKey2018",
        "controller": "did:id_of_DID_method:DIDI_method_specific_id",
        "publicKeyPem": "-----BEGIN PUBLIC KEY...END PUBLIC KEY-----\r\n"
      }],
      "service": [{
        "id":"did:id_of_DID_method:123456789abcdefghi#vcs",
        "type": "VerifiableCredentialService",
        "serviceEndpoint": "https://example.com/vc/"
      }]
    }
BºNOTE:º A single DID document could be related to N DIDs in 1-to-N
  relationship, allowing the same "identity" be represented by different
  implementations/methods (e.g., one DID on top Ethereum , and another
  one on top of github+gpg).
• DID controller refers to the subject that can prove "ownership" or 
  "control" of the DID (in practice through private/pub crypto signature)
  whithout the intervention of permissions of third parties.
  More formaly, it represents the entity/ies authorized to make changes
  to the associated DID Document.
  · Authorization and Delegation of DID Document's controller is contemplated.
• Designed to provide Global unique identifier world-wide.
• DID registries are in charge of storing or recording the DID documents.
  Such registries can be and many times are virtual ones: 
  - from the DID the DID Document can be generated using an algorithm.
    E.g.: a DID based on a public key contains all the information needed
          to recreate the DID Document.
          On the other side, a DID can require some sort of existing 
          database to recreate the DID Document. In such case this database
          will be the DID registry.
• Technology neutral but most implementations works on top of public/
  permissioned blockchains.
•ºPart of a bigger echosystem.º W3C models identity as a graph, where nodes
  are globally unique IDs and directed edges are claims that neighbors nodes
  make towards it:
  
• DID BºMethod Registryº:
  more than 80 implementations (methods) currently available
  @[https://w3c-ccg.github.io/did-method-registry/]
• Public Keys in DID documents are expressed in either
  · JSON Web Key (JWK) format using the publicKeyJwk property
  · JWK or Privacy Enhanced Mail (PEM) encoding Base58
  · Ed25519           public key encoded as JWK or raw 32─byte Base58 Bitcoin format
  · Secp256k1 Koblitz "      "    "       "  "   "  "  33 "     "     "        "
  · Secp256r1         "      "    "       "  "   "  "  32 "     "     "        "
  · Curve25519        "      "    "       "  "   "  "  32 "     "     "        "
    ("X25519")
• RºWARN:º Caching and expiration of the keys in a DID document is entirely the
            responsibility of DID resolvers and other clients.
did-jwt
@[https://github.com/decentralized-identity/did-jwt]

• The did-JWT library allows you to sign and verify JSON Web Tokens
  (JWT) using ES256K, ES256K-R and Ed25519 algorithms.

• Public keys are resolved using the Decentralized ID (DID) of the
  signing identity of the claim, which is passed as the iss attribute
  of the encoded JWT.

• Supported methods: ethr | uport | https | nacl | muport
W3C Credentials API
@[https://w3c-ccg.github.io/credential-handler-api/]
• Credential Management Level 1 describes an imperative API enabling
  a website to request a user's credentials from a user agent, and to
  help the user agent correctly store user credentials for future use.
• User agents implementing that API prompt the user to select a way to
  handle a credential request, after which the user agent returns a
  credential to the originating site. This specification defines
  capabilities that enable third-party Web applications to handle
  credential requests and storage.
Solid
@[https://solidproject.org/for-developers/]
• Standard proposed by Teem Berners Lee (Web inventor).
• Solid is an extension (vs replacement) of current Webs,
  working on any modern browser.
• The objective is to centralize all "scattered data" around
  on the Internet like Social Networks, Online-Shops (Amazon,...),
  digital services  (online banks, ...) and keep that data under
  the control on final users (vs Facebook, Google, Amazon,...).
  User's "Pods" are in charge of storing all our personal data:
  Pods can be self-hosted or provided by Pod's service provider.
• Compares to W3C DID/VC. WebID is the equivalent to W3C DID.    [comparative]
  As with DIDs, different WebID's can be owned by the same person,
  e.g., one WebID issued by governments, another self-issued WebID for 
  personal uses, ...
• "Vocabularies" help to interpret Pod's data to any independent
  service/application/company that has been granted access.  
• Helps to buildºapplication decoupled from dataº, avoiding to   [low-code]
  maintain a separate back-end.
• Data is requested directly to users (vs provider's custom API).


Styling
CSS
CSS Selectors
•ºBY COORDINATE:º
  selector           Example          Example description
  --------           -------          ------- -----------
  .class             .intro           match 1+ element/s by class="intro"
  #id                #firstname       match element by id
  º                  º                match all elements
  html_tag           p                match all ˂p˃ elements
  sel1,sel2,...      div, p           match ˂div˃ + ˂p˃ elements
  element element    div p            match ˂p˃ elements inside ˂div˃ elements
  element˃element    div ˃ p          match ˂p˃ elements with parent ˂div˃ 
  element+element    div + p          match ˂p˃ elements placed immediately
                                      after ˂div˃ elements
  element1~element2  p ~ ul           match every ˂ul˃ element when preceded by ˂p˃s
  [attribute]        [target]         match elements having a "target" attribute
  [attribute=value]  [title=flower]   match all elements when title is     flower
  [attribute~=value] [title~=flower]  match all elements when title is not flower 
  [attribute*=value] [title*=flower]  match all elements when title val. contains "flower"
  [attribute|=value] [lang|=en]       match all elements when lang  val. starts with en
  [attribute^=value] a[href^="http"]  match ˂a˃ elements when href  val. starts with http
  [attribute$=value] a[href$="pdf"]   match ˂a˃ elements when href  val. ends   with .pdf
  :active            a:active         Selects the active link

•ºBY RELATIVE COORDINATE:º
  selector           Example          Example description
  --------           -------          ------- -----------
  :first-of-type     p:first-of-type  match ˂p˃ element  when ˂p˃ is 1st  element of parent
  :last-of-type      p:last-of-type   match ˂p˃ element  when ˂p˃ is last element of parent
  :not(selector)     :not(p)          match all elements except ˂p˃s
  :first-child       p:first-child    match ˂p˃ element  when ˂p˃ is 1st  child of its parent
  :last-child        p:last-child     match ˂p˃ element  when ˂p˃ is last child of its parent
  :nth-child(n)      p:nth-child(2)   match ˂p˃ element  when ˂p˃ is 2nd  child of its parent
  :nth-last-child(n)                  match ˂p˃ element  when ˂p˃ is "-2" child of its parent
                     p:nth-last-child(2)  
  :nth-last-of-type(n)                match ˂p˃ element  when ˂p˃ is last-but-2 of ˂p˃'s parent
                     p:nth-last-of-type(2) 
  :nth-of-type(n)    p:nth-of-type(2) match ˂p˃ element  when ˂p˃ is nth of ˂p˃'s parent
 º:only-of-type      p:only-of-type   match ˂p˃ element  when it's the only ˂p˃ of its parentº
 º:only-child        p:only-child     match ˂p˃ element when it's the only child of its parentº
  :root              :root            match document's root element
  ::after            p::after         Insert content after  every ˂p˃ element
  ::before           p::before        Insert content before every ˂p˃ element
 º:empty             p:empty          match ˂p˃ elements when it has no children and no textº
  ::first-letter     p::first-letter  match first-letter of ˂p˃ elements
  ::first-line       p::first-line    match first-line   of ˂p˃ elements

•ºBY STATUS:º (INPUT ELEMENTS)
  selector           Example          Example description
  --------           -------          ------- -----------
  :checked           input:checked    match checked ˂input˃ element
  :disabled          input:disabled   match disabled ˂input˃ element
  :enabled           input:enabled    match enabled ˂input˃ element
  :valid             input:valid      match input elements with a    valid value
  :invalid           input:invalid    match input elements with an invalid value
  :read-only         input:read-only  match input elements with "readonly" attribute     specified
  :read-write        input:read-write match input elements with "readonly" attribute NOT specified
  :required          input:required   match input elements with    "required" attribute  specified
  :optional          input:optional   match input elements with no "required" attribute
  :in-range          input:in-range   match input elements with a value within  a specified range
  :out-of-range    input:out-of-range match input elements with a value outside a specified range
  :focus             input:focus      match the input element which has focus

•ºLINKS:º
  ::selection        ::selection     match portion of an element selected by a user
  :target            #news:target    match current active #news element 
                                     (clicked on a URL containing that anchor name)
  :visited           a:visited       match all visited links
  :link              a:link          match all unvisited links

•ºOTHERS:º
  :hover             a:hover         match links on mouse over
  :lang(language)    p:lang(it)      match every ˂p˃ element with lang attribute "it"


CSS variables • CSS variables (also called CSS custom properties) let express dynamic relations among CSS properties. · Declared by prefixing their names with --. e.g. --background · Its value can be reused in other CSS declarations using the var() function. ·ºThe variable can be updated either via CSS or JavaScriptº, ºautomatically updating all dependent variables reactivelyº and allowing developers to express custom algorithms ºcloser to a Turing-complete languageºlike JavaScript. · They are scoped to the element(s) they are declared on. • CSS becomesºmore maintainable,ºeasier to understand, paremeterize and change. • Can also be used with 'calc'. E.g.: width: calc(var(--variable-width) + 20px); • Ex: :root { --first-color: #16f; --second-color: #ff7; } #firstParagraph { background-color: var(--first-color); color: var(--second-color); } #secondParagraph { background-color: var(--second-color); color: var(--first-color); } #container { --first-color: #290; } #thirdParagraph { background-color: var(--first-color); color: var(--second-color); } • Extracted from REF:@[https://www.infoq.com/news/2020/06/css-variables-design-systems/] """ Tolinski concluded with the following advice: RºFrameworks require overhead of both kb and onboarding.º ... Write only what you need, use variables as the backbone. """
calc(ulated) • RºWARNº: css calc(ulated) can slow down rendering according to some sources. • E.g. extracted from @[https://developer.mozilla.org/en-US/docs/Web/CSS/calc()] width: calc(10px + 100px); width: calc(2em * 5); width: calc(var(--variable-width) + 20px); • box-sizing asºpotential alternative to css calcº: @[http://stackoverflow.com/questions/16034397/css-calc-alternative] box-sizing Description related Prop. ------------- ----------------------------------------------------- • content-box · Default width and height (and min/max) includes only the content. · Border/padding/margin not included • border-box · width and height properties (and min/max properties) includes content, padding and border, but not the margin • initial · Set property to default value. (Read about initial) • inherit · Inherits property from parent element.
CSS Layout • Layout mode: algorithm that determines position+size of boxes based on how they interact with sibling and ancestor boxes: @[https://developer.mozilla.org/en-US/docs/Web/CSS/Layout_mode] · Normal flow : (default) includes: · block layout: lay out boxes (paragraphs,...) · inline layout: lay out inline items (text,...). · Table layout: · Float layout: cause item to position left|right with the rest of the content. · Positioned layout: position elements without much interaction with other elements. · Multi-column layout: lay out content in columns. · Flexible box layout: lay out complex pages that can be resized smoothly. · Grid layout: lay out elements relative to a fixed grid. →ºStep 1:ºDefine "display" property · @[https://developer.mozilla.org/en-US/docs/Web/CSS/display] · sets · - outer layout respect siblings (block or inline) · - inner layout of children (flow-root,flow,flex,grid,table) · · none: Turns off display of an element · RºWARNº: use visibility:hidden to replace element with transparent box · contents: don't produce a specific box by themselves. · Place inner content on parent container. · · - CSS3 value syntax Legacy CSS2 · ------------------ ----------- · block flow-root · block flow · block flex · block grid · block table · inline flow-root inline-block · inline flow · inline flex inline-flex · inline grid inline-grid · inline table inline-table · └·→ºStep 2:ºDefine float:= left | right | none | inline-start | inline-end · @[https://developer.mozilla.org/en-US/docs/Web/CSS/float] · It implies theºuse of a block layoutº, modifying if needed the · computed value of display values if needed. · It defines element's placementºrelative to parent containerº. · └·→ºStep 3:ºDefine clear:= left | right | both | none @[https://developer.mozilla.org/en-US/docs/Web/CSS/clear] It allows to control vertical placement relative to ºsibling floating elementsº. It defines whether current element must be moved below (cleared) sibling floating elements to its right/left. (the element itself can be or not floating).
Responsive 101
There are two main aspects to consider when adapting a web "page"
to be used on mobiles and desktops (and TVs, ...)
•º#################################º
 º# ASPECT 1) USER INPUT HARDWARE #º
 º#################################º
  · This is the main difference between mobiles and desktops. 
  · Desktop users can profit from a mouse with accurate movement
    over the screen, while mobile users must use coarse finger "touchs".
  · ✓ CSS 4 (º2018+º, support by all major browsers) @media allows to 
    show/hide/modify (input) elements according to the accuracy of
    system's pointer ("mouse").
    It also allows to show/hide/modify elements according to the
    possibility to detect mouse hovering (flying above) above them.

    PRIMARY INPUT                         POINTER TYPE       DEVICE TYPE
    ==========================            =================  ===============
    @media (pointer  : coarse)  { ... }   limited accuracy   mobiles
    @media (pointer  : fine  )  { ... }   high    accuracy   laptops,desktops
    @media (pointer  : none  )  { ... }   no pointer         embedded info-pannels,...

    PRIMARY INPUT                PRI/SECONDARY INPUT/S          HOVER TYPE
    ==========================   ==========================     ===========================
    @media (hover    : hover )   @media (any-hover    : hover ) easy   hover over elements
    @media (hover    : none  )   @media (any-hover    : none  ) limited/none hover 
    └───────────┬────────────┘
    Complementary to those @media filters we can 
    dynamically use Javascript to detect the 
    mouse/hover properties and react accordingly
   ºJavascript Media queryº:
    if ( window.matchMedia("(any-hover: none)".matches ) {      [code-snippet]
      ...
    }

  · Ussually input elements requiring high accuracy, tooltips "on Hover", ...
    will need to be replaced by ("simpler") alternatives on mobile phones.
     
  · mobile "multi-touch" (zoom-in/out) effects probably will require input sliders 
    (˂input type="range" ...˃) on desktops.
     
•º#########################º
 º# ASPECT 2) SCREEN SIZE #º
 º#########################º
  The styling to apply depending on the screen size is more subject to interpretations.
  • meta-header viewport (mobile only):
    ˂meta name="viewport"
       content="user-scalable=no, 
                width=device-width, º*1º
                initial-scale=1" /˃

    º*1º (emulated) width. If physical mobile screen is 6"-diagonal and has a native 1920px
                        screen resolution, then an 192px-diagonal image will display in
                        just ~0.6" by default. 
                        By setting viewport width to 192px virtual pixels, it will display
                        
    Initial-scale:1 
    Minimum-scale: 
    Maximum-scale: 
    User-scalable: yes / no

  • Vision angles (vs screen size and resolution) is the key point to consider.
    There is always an important Rºmissing parameterºto choose the right layout: 
    "Distance-from eye-to-screen".
    This implies that we must make assumptions covering standard scenarios:
      · For mobiles eye-to-screen is about   20- 40 cms.
      · For laptops eye-to-screen is about   70-100 cms.
      · For TV      eye-to-screen is about  300-500 cms.
    with that arbirary assumption different @media can be applied:

    @media only screen and
               (pointer  : coarse)          ← probably mobile at 20-40 cms distance
           and (min-device-width : 320px)   ← low (mobile) resolution
           and (max-device-width : 800px) {
               (max-width: 800px) {         
      body { font-size: 1.3em }             ← Increase font-size
      ... 1 column  layout ...              ← e.g.: Render just 1 column of "payload" info
    }

    @media only screen and
               (pointer  : coarse)          ← probably mobile at 20-40 cms distance
           and (min-device-width : 801px)   ← medium (mobile) screen resolution
           and (max-device-width :1024px) {
      body { font-size: 1.2em }             ← Increase font-size
      ... 1 column  layout ...              ← e.g.: Render just 1 column of "payload" info
    }

    @media only screen and
               (pointer  : coarse)          ← probably mobile at 20-40 cms distance
           and (min-device-width :1025px)   ← high (mobile) screen resolution
    {
      body { font-size: 1.2em }             ← Increase font-size
      ... 2 column  layout ...              ← e.g.: Render 2 columns of "payload" info
    }

    @media only screen and
               (pointer  : fine ) and       ← probably desktop at 70-100 cms distance
                                              probably high-screen resolution
               (max-width: 960px) {         ← probably browser windows right/left of
                                              desktop with a 1920+px screen resolution
      body { font-size: 10px }              ← Increase font-size
      ... 1 column  layout ...              ← e.g.: Render just 1 column of "payload" info
    }
    @media only screen and
               (pointer  : fine ) and       ← probably desktop at 70-100 cms distance
                                              probably high-screen resolution
               (max-width: 960px) {         ← probably maximized windows filling 
                                              desktop with a 1920+px screen resolution
      body { font-size: 10px }              ← Increase font-size
      ... 2 column  layout ...              ← e.g.: Render 2 columns of "payload" info
    }
CSS Flex/Grid
REF: @[http://flexbox.malven.co/] by @[https://malven.co/]
BºELEMENT FLEX PROPERTIES RELATIVE TO ***PARENT CONTAINER***º

  • display:= how current element behaves with ºsiblingsº
     · flex       : As box (paragraph,...) 
     · inline-flex: As line(text     ,...) 
    
  • flex-direction:=  establishes the main axis for children
      row    row-reverse    column  column-reverse:
      |||⇒      ⇐|||          -         ⇑
                              ⇓         -
  
  • flex-wrap:= What to do when items don't fit in a line/column
      nowrap       wrap         wrap-reverse
      ┌───────┐    ┌───────┐    ┌───────┐
      │|||||||│    │|||||||│    │|||    │
      │       │    │|||    │    │|||||||│
      └───────┘    └───────┘    └───────┘
     
  • justify-content: who to (attempt to) distribute extra space on main axis
  
      flex-start       flex-end       center     
      ┌───────┐        ┌───────┐      ┌───────┐  
      │|||    │        │    |||│      │  |||  │  
    
      space-between    space-around   space-evenly
      ┌───────┐        ┌───────┐      ┌───────┐ 
      │|  |  |│        │ | | | │      │ | | | │  
  
  • align-items: Determines how items are laid out on cross (vs main) axis
     flex-start  flex-end   center     baseline   stretch
     ┌───────┐   ┌───────┐  ┌───────┐  ┌───────┐  ┌───────┐
     │·······│   │       │  │       │  │·······│  │1º2º...│
     │       │   │       │  │·······│  │       │  │1º2º...│
     │       │   │·······│  │       │  │       │  │1º2º...│
     └───────┘   └───────┘  └───────┘  └───────┘  └───────┘
     
     
  • align-content: Only aplies with 2+ content lines (Ex using flex-wrap)
      flex-start  flex-end   center     space-     space-     stretch
                                        between    around
      ┌───────┐   ┌───────┐  ┌───────┐  ┌───────┐  ┌───────┐  ┌───────┐
      │1 2 3 4│   │       │  │       │  │1 2 3 4│  │       │  │1 2 3 4│
      │5 6 ...│   │       │  │1 2 3 4│  │       │  │1 2 3 4│  │1 2 3 4│
      │       │   │1 2 3 4│  │5 6 ...│  │       │  │5 6 ...│  │5 6 ...│
      │       │   │5 6 ···│  │       │  │5 6 ...│  │       │  │5 6 ...│
      └───────┘   └───────┘  └───────┘  └───────┘  └───────┘  └───────┘

BºFLEX PROPERTIES OF ELEMENT's CHILDRENº

  • order: Allows to explictly set children's order: 
    := integer

  • flex-grow: determine how each child is allowed to grow as a part of a whole
      flex-grow: 1                flex-grow 
      ┌────────────┐            ┌────────────┐
      │┌──┐┌──┐┌──┐│            │┌┐┌──┐┌────┐│
      ││  ││  ││  ││            ││││  ││    ││
      ││  ││  ││  ││            ││││  ││    ││
      (applied to all)          (1, 2, and 3)

  • flex-basis: Defines size of children before remaining space is distributed
      ┌────────────┐ ← first item 20%,
      │┌┐┌──┐┌────┐│   second item 40%
      ││││  ││    ││
      ││││  ││    ││  

  • flex-shrink: shrink childrens if necessary. Only really useful with
                 a set size or flex-basis
      ┌──────────┐  
      │┌──┐┌────┐│← Ex: both want to be 100% wide
      ││  ││    ││  2nd item has flex-shrink: 2
      ││  ││    ││
    
  • align-self: Sets alignment for individual item.
      ┌───────┐
      │·· ····│← Ex: 3rd item has align-self:flex-end
      │       │    
      │  ·    │    
      └───────┘
- http://grid.malven.co/     [TODO]
CSS Grid
REF: @[http://grid.malven.co/] by @[https://malven.co/]

• CSSgrid generator: online visual Grid design tool.
 @[https://cssgrid-generator.netlify.app/]

   [TODO] beatify with ascii-art visual hints (like original page)  [TODO]
BºELEMENT GRID PROPERTIES RELATIVE TO ***PARENT CONTAINER***º

  • display := grid  |  inline-grid | subgrid

  • grid-template: Defines the rows and columns of the grid.

    Ex. 3x3 matrix:
    grid-template-columns: 12px 12px 12px;
    grid-template-rows: 12px 12px 12px;

    Ex. 3x3 matrix:
    grid-template-columns: repeat(3, 12px);
    grid-template-rows: repeat(3, auto);

    Ex. 3x3 matrix:
    grid-template-columns: 8px auto 8px;
    grid-template-rows: 8px auto 12px;

    Ex. 3x3 matrix:
    grid-template-columns: 22% 22% auto;
    grid-template-rows: 22% auto 22%;

  • grid-gap: set  size of column and row gutters.
    Ex. 1:                  Ex.2:               Ex.3:
    grid-row-gap   : 1px;   grid-gap: 1px 9px;  grid-gap: 6px;
    grid-column-gap: 9px;

  • justify-items: Aligns content in grid along row axis.
    :=  start | end | center | stretch (default)

  • align-items: Aligns content in grid along column axis.
    start | end | center | stretch (default)

  • justify-content: Justifies ALL grid content on row axis 
                     when total grid size is smaller than container.
    align-content  : Justifies ALL grid content on column axis
                     when total grid size is smaller than container.
    := start |  end |  center |  stretch |  space-around | 
       space-between |  space-evenly 

  • grid-auto-flow: Algorithm used to automatically place grid items
                    not explictly placed.
    := row | column | dense

BºFLEX PROPERTIES OF ELEMENT's CHILDRENº

  • grid-column: Determines an items column-based location within the grid.
    grid-column-start: 1;
    grid-column-end  : 3;

    grid-column-start: span 3;

    grid-column-start: 2;
    grid-column-end  : 4;


    grid-column      : 2 / 3
    grid-column      : 2 / span 2

  • grid-row: Determines an items row-based location within the grid.
    grid-row-start: 1;
    grid-row-end: 3;

    grid-row-start: span 3;

    grid-row-start: 2;
    grid-row-end: 4;

    grid-row: 1 / 3;
    grid-row: 1 / span 3;

  • grid-row + grid-column: Combining grid rows with grid columns.
    grid-row: 1 / span 2;
    grid-column: 1 / span 2;

    grid-row: 2 / span 2;
    grid-column: 2 / span 2;

 • justify-self: Aligns content for a specific grid item along the row axis.
   justify-self: start;

   justify-self: end;

   justify-self: center;

   justify-self: stretch; (default)

 • align-self: Aligns content for a specific grid item along the column axis.
   align-self: start;

   align-self: end;

   align-self: center;

   align-self: stretch; (default)
CSS Cont.
CSS3 Animations
• Animations allows to gradually change an element's CSS properties from
  initial style/value to final one.

@keyframesºanimation01º{            ← STEP 1) Define key frames describing 
                                              element/s styles at certain "times"

  from   {color: red;  left:   0; }   ← from ==   "0%" 
  10%,90%{color: #AAA; left: 10%; }           
  30%,70%{color: blue; left: 20%; }
  to     {color: green;left: 30%; }   ←   to == "100%"
}

div {                               ← Animation will apply to all div's
  ...
  color              : red;
 ºanimation-name     : animation01;º← STEP 2) Animation ussage

  animation-duration : 4s;            ← (non-Opt) Set transition time 

  animation-delay    : 2s;            ← Opt. If negative anim. starts as 
                                             if running for "-N" secs.

  animation-direction: normal         ← Opt. normal* | reverse 
                                                | alternate | alternate-reverse 

  animation-iteration-count: 3;       ← Opt. Repeat N times (vs infinite)

  animation-timing-function: linear;  ← Opt. :=   linear | ease | ease-in
                                             | ease-out | ease-in-out

  animation-fill-mode: forwards;      ← Opt. Effect CSS before-1st/after-lst.frame 
                                        none*    : Keep original CSS
                                        forwards : retain  last keyframe style
                                        backwards: retain first keyframe style
                                        both     : retain 1st keyframe before start
                                                          lst.keyframe after  end
}

• External references:
  · Advanced CCS3 animations using SVG can be 
  @[http://css3.bradshawenterprises.com/cfimg/]

Profiling •ºProblem Contextº: Performance issue when adding CSS-based animation (dropped frames) ºQº: Are there any tools to debug/profile the issue? ºAº: • Chrome : Timeline tab Display stats about restyles, reflows, paint, compositing operations as time goes. Will be available in Firefox in a future (2014-08) • Firefox: FirefoxDevTools → "performance" tab → profiler STEP 1) Create JS calls record. STEP 2) Inspect ºframerate graphº along with a bar graph showing the types of activities occurred on each recorded sample (network, JIT, GC, events, styles, graphics, storage). └──────┬───────┘ CSS animation related ones Optional: Enable "Gecko platform data" for extra information It works overºremote devtools-protocolº allowing for mobile profile / debug.
CSS Logical Props.
@[https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Logical_Properties]
• CSS Logical Properties and Values CSS modules introduces
  logical properties and values that provide the ability to
  control layout through logical, rather than physical,
  direction and dimension mappings.
• The module also defines logical properties and values for properties
  previously defined in CSS 2.1. Logical properties define
  direction‐relative equivalents of their corresponding physical
  properties.
CSS Background
• background-color: red;

• Image background attributes:
  background-image   : url(image);
  background-repeat  : repeat | no-repeat | repeat-x  | repeat-y
  background-position: top | center | bottom
  background-size    : 100px | 90% | cover | contains

• Gradient:
  p1: coordinates gradient start
      TODO: Firefox(top|left|right|down)
      Webkit: % horizontal/vertical
  p2: coodinates gradinet end
  1: color start
  c2: color end
  (-webkit|moz)-gradient(linear, p1, p2, from(c1), to(c2));
  linear-gradient(p1, c1, c2) no-repeat;

• Gradient Vertical:
  background: -moz-linear-gradient(top, red, blue);
  background: -webkit-gradient(linear, 0%, 0%, 0%, 100%, from(red), to(blue));
• Gradient Horizontal
  background: -moz-linear-gradient(left, red, blue);
  background: -webkit-gradient(linear, 0%, 0%, 100%, 0%, from(red), to(blue));
• Gradient Radial
  background: -webkit-gradient(radial, p1, r1, p2, r2, from(c1), to(c2));
Fonts/Art Gallery
fontsquirrel
Declaring external font:
@font-face
{
   font-family: MyFontFamilyName; /* "id" to be used in CSS for this font*/
   src: url('my_font.ttf');
   src: url('my_font.eot');
   src: url('my_font.svg');
   src: url('my_font.woff');
}

use:
h1 { font-family: 'MyFontFamilyName'; }
- https://www.fontsquirrel.com/
    Free fonts have met their match. We know how hard it is to find quality
    freeware that is licensed for commercial work. We've done the hard work, hand-
    selecting these typefaces and presenting them in an easy-to-use format. Here
    are some of our favorites:
   http://christ-offer.blogspot.com.es/2011/05/html5css3-fonts-with-font-face.html

- Embedding specific fonts on a web page, traditionally, has been
  accomplished using images.  Though IE 5.0+ allowed you to embed fonts on your
  web page, they needed to be in EOT (Embedded OpenType) format.  Other
  browsers supported TTF (TrueType) and OTF (OpenType) fonts.  IE9 now supports
  TTF, OTF and also WOFF (Web Open Font).  To accomplish the task of embedded
  real fonts into your web pages, use the CSS3 @font-face rule.

- Where to get quality FREE fonts for use in web pages?  FontSquirrel is a
  great place with hundreds of free fonts, including kits that demonstrate how
  to embed and use them into a web page, plus a generator to create your own.
  With the kit, you get the font in all the formats so that you can craft your
  web pages to support all the major
"fonts for pros"
https://type-scale.com/
CSS :
From: @[https://www.infoq.com/news/2020/06/css-variables-design-systems/]
Typography-wise, Tolinski recommended leveraging existing tools to 
visualize fonts and their scale ratio. An example of code 
auto-generated for copy-pasting purposes by type-scale.com is as 
follows:
@import url('https://fonts.googleapis.com/css?family=Poppins:400|Poppins:400');

html {font-size: 100%;} /*16px*/

body {
  font-family: 'Poppins', sans-serif;
  ...
}kkkkkkkkk

h1, h2, h3, h4, h5 {
  font-family: 'Poppins', sans-serif;
  ...
}
Extra typography resources include
• modularscale
  https://www.modularscale.com/
• Figma typography recommendations
  https://www.figma.com/best-practices/typography-systems-in-figma/
• vertical-rhythm-reset
  http://jhildenbiddle.github.io/vertical-rhythm-reset/sassdoc/
Art Gallery
Icon Gallery:
@[https://github.com/NitruxSA/nitrux-icons]
@[http://tiheum.deviantart.com/art/Faience-icon-theme-255099649]
@[http://tiheum.deviantart.com/art/Faenza-Icons-173323228]
@[http://0rax0.deviantart.com/art/Uniform-Icon-Theme-453054609]
@[http://gnome-look.org/content/show.php/Dalisha?content=166286]
Others
Colors-for-all
@[https://github.com/AmadeusITGroup/Colors-for-All]
• Tool enabling to easily check color contrasts and WCAG 
  compliance (AA or AAA levels as defined by W3C) between specific 
  colors in one shot ! 
• online application available for UX/UI designers or any other
  people involved in digital accessibility.
Resize_Observer_API
@[https://developer.mozilla.org/en-US/docs/Web/API/Resize_Observer_API]
• The Resize Observer API provides a performant mechanism by which code
  can monitor an element for changes to its size, with notifications
  being delivered to the observer each time the size changes.
Apply Masks to images
@[http://www.html5rocks.com/en/tutorials/masking/adobe/]

• Clipping an image: 

  ˂svg˃                           ← STEP 1: Define SVG clip
    ˂defs˃
      ˂/clipPathº id="clipping01"º˃
        ˂circle 
          cx=284 cy=213 r=213 /˃
      ˂/clipPath˃
    ˂/defs˃
  ˂/svg˃

  img#img01 {                    ← STEP 2:  Add css to img dom
    clip-path: url(#clipping01º);  ← with a clip-path property
  }
  
  
• Animated Clipping:
  @keyframes animation01 {       ← STEP 1: Define animation
    0% {
      clip-path: polygon(...);
    },
    100% {
      clip-path: polygon(...);
    }
  }
  img#img01:hover {              ← STEP 2: Apply clip to image. 
    clip-path:
      polygon(0px 208px, 146.5px 207px,... ...);
    animate: animation01 3s;     ← STEP 3: Apply animation to CSS
  }
gRPC
Summary
@[https://grpc.io/]
@[https://en.wikipedia.org/wiki/GRPC]
- Cloud Native Foundation project (initial develop:Google)
- High performance, cross-platform/language RPC framework.
-ºHTTP/2 for transport and Protocol Buffers for interface º
 ºdescription languageº.
  - pluggable support for load balancing, tracing, health
    checking and authentication.
- bidirectional streaming and flow control                        [async]
- blocking or nonblocking bindings, and cancellation and timeouts.[async]
- binary encoding on the wire (protocol buffers, or "protobufs" for short).
- Cross-language Proxy objects auto-generated with
  safe type checking (when supported language)                    [qa]


BºPROTOC + gRPC INSTALLATION STEPSº
  STEP 1) install protobuf + protoc  commands
  STEP 2) Install Node/Python/Go/... tools:

Bºgrpcurlº:
@[https://github.com/fullstorydev/grpcurl]
  • cURL for gRPC!!!!.  CLI tool for interacting with gRPC servers.
  • accept JSON encoding as input, much more friendly (than binary)
    for humans/scripts.
  • bi-directional streaming methods supported
  • TLS supported, including mutual TLS.
  • Docker support:
  $º$ docker run fullstorydev/grpcurl api.grpc.me:443 list º
  • Go quick install:
  $º$ go get github.com/fullstorydev/grpcurl/...             º
  $º$ go install github.com/fullstorydev/grpcurl/cmd/grpcurl º

$º$ grpcurl {{grpc.server.com:443}} list \º ← List all services exposed
$º          {{my.custom.server.Service}}  º   ← Optional. Filter by service
                                              using server supporting reflection or
                                              reading proto source files         or
                                              by loading in compiled "protoset"
                                              files (containiing encoded file
                                              descriptor protos).

$º$ grpcurl {{grpc.server.com:443}} \    º  ← Send an empty request
$º  {{my.custom.server.Service/Method}}  º

$º$ grpcurl -H                         \ º ← Send request with
$º  "{{Authorization: Bearer $token}}" \ º   ← header and
$º  -d {{'{"foo": "bar"}'}} \            º   ← body
$º  {{grpc.server.com:443}} \            º
$º {{my.custom.server.Service/Method}}   º

BºCOMPILING NODEJS SCRIPT EXAMPLEº

  #!/bin/sh
  set -e                           # ← Abort on first error.
  PROTOC=/opt/protoc_v3/bin/protoc # ← PATH to protoc compiler executable
  OUT_DIR="./src/lib/protobuf"

  if [ ! -d ${OUT_DIR} ]; then mkdir -p ${OUT_DIR} ; fi

  # protoc fails if relative path is provided. (2017-01)
  GRPC_NODE_PLUGIN=/usr/local/lib/node_modules/grpc-tools/bin/grpc_node_plugin

  ${PROTOC} \
   --proto_path=../project_proto_definition/   # ← Path to search *proto for
   --js_out=import_style=commonjs,\
                            binary:${OUT_DIR} \# ← JS protobuf output path
  \
   --grpc_out=${OUT_DIR} \                     # ← gRPC(services) output path
   --plugin=protoc-gen-grpc=\                  # ← gRPC service related
            ${GRPC_NODE_PLUGIN} \
   file1.proto

BºCOMPILING JAVA SCRIPT EXAMPLEº
@[https://github.com/grpc/grpc-java/blob/master/README.md]
  - Gradle protobuf conf:
    apply plugin: 'java'
    apply plugin: 'com.google.protobuf'

    buildscript {
      repositories { mavenCentral() }
      dependencies {
        classpath
          'com.google.protobuf:protobuf-gradle-plugin:0.8.0'
      }
    }

  - Gradle+grpc conf:
    compile 'io.grpc:grpc-netty:1.0.1'        ┐
    compile 'io.grpc:grpc-protobuf:1.0.1'     ├non-Android
    compile 'io.grpc:grpc-stub:1.0.1'         ┘
    compile 'io.grpc:grpc-okhttp:1.0.1'       ┐
    compile 'io.grpc:grpc-protobuf-lite:1.0.1'├Android
    compile 'io.grpc:grpc-stub:1.0.1'         ┘
    ...
    protobuf {
      protoc { artifact = "com.google.protobuf:protoc:3.1.0" }
      plugins {
        grpc { artifact = 'io.grpc:protoc-gen-grpc-java:1.0.1' }
      }
      generateProtoTasks { all()*.plugins { grpc {} } }
    }

BºgRPC PROTOBUF EXCEPTION HANDLINGº            [qa]
C⅋P FROM @[http://stackoverflow.com/questions/38810657/exception-handling-in-grpc]
Context: server written in Java, client written in PHP.
Q: How can client catch exceptions from server?
A: For handled exceptions, call responseObserver.onError().
   If you pass in a StatusRuntimeException or StatusException
   (generally created via status.asRuntimeException()) the status
   code and description will be communicated to the client.
 RºUnhandled exceptionsº within a callback will cancel
   the RPC and will continue propagating the exception
   (generally leading in an UncaughtExceptionHandler being
   called for the executor).


grpc ecosystem @[https://github.com/grpc-ecosystem] RPC Ecosystem that complements gRPC · grpc-gateway : gRPC to JSON proxy generator following the gRPC HTTP spec · go-grpc-prometheus: Prometheus monitoring for your gRPC Go servers. · grpc-health-probe : cli tool to perform health-checks for gRPC apps · ...
gRPC JAVA Summary

GºJAVA SERVER IMPEMENTATION SUMMARYº
  service RouteGuide {
    rpc GetFeature(Point)           returns (       Feature)    {} ← ºgRPC DEFINITIONSº
    rpc ListFeatures(Rectangle)     returns (stream Feature)    {}
    rpc RecordRoute(stream Point)   returns (     RouteSummary) {}
    rpc RouteChat(stream RouteNote) returns (stream RouteNote ) {}
  }


  public class RouteGuideServer                                    ← Server implementation
    ... initialization code ...
     private static class RouteGuideService
       ºextends RouteGuideGrpc.RouteGuideImplBaseº
         ...
           ┌──────────────────────────────────────────────┬────────────────────────────────────────────┐
           │ºSINGLE RESPONSEº                             │ºSTREAM RESPONSEº                           │
 ┌─────────┼──────────────────────────────────────────────┼────────────────────────────────────────────┤
 │ºSINGLE º│  @Override                                   │  @Override                                 │
 │ºREQUESTº│  public void getFeature(                     │  public void listFeatures(                 │
 │         │      Point request,                          │       Rectangle request,                   │
 │         │      StreamObserver responseObserver)        │       StreamObserver responseObserver) {   │
 │         │  {                                           │    for (Feature feature : features)        │
 │         │    // Single onNext iteration                │    {                                       │
 │         │    responseObserver.onNext(                  │      ...                                   │
 │         │      _checkFeature(request));                │      responseObserver.onNext(feature);     │
 │         │    responseObserver.onCompleted();           │                 Oº   ^^^^^^^º              │
 │         │  //^ ends inmediatelly  ^                    │                 Oºfor each feature foundº  │
 │         │  }                                           │    }                                       │
 │         │                                              │     //*streaming response*                 │
 │         │                                              │   responseObserver.onCompleted();          │
 │         │                                              │  }                                         │
 ├─────────┼──────────────────────────────────────────────┼────────────────────────────────────────────┼
 │ºSTREAM º│  @Override                                   │  @Override                                 │
 │ºREQUESTº│  public StreamObserver recordRoute(          │  public StreamObserver routeChat(          │
 │         │      final StreamObserver responseObserver)  │      final StreamObserver responseObserver)│
 │         │  {                                           │  {                                         │
 │         │    return new StreamObserver() {             │    return new StreamObserver() {           │
 │         │      @Override                               │      @Override                             │
 │         │      public void onNext(Point point) {       │      public void onNext(RouteNote note)    │
 │         │       ...                                    │      {                                     │
 │         │      }                                       │        for (RouteNote prevNote :           │
 │         │                                              │            notes.toArray(new RouteNote[0]))│
 │         │      @Override                               │        {                                   │
 │         │      public void onError(Throwable t) {      │          responseObserver.onNext(prevNote);│
 │         │          logger.... "recordRoute cancelled");│        }                                   │
 │         │      }                                       │        ...                                 │
 │         │                                              │      }                                     │
 │         │      @Override                               │                                            │
 │         │      public void onCompleted() {             │      @Override                             │
 │         │        long seconds =                        │      public void onError(Throwable t) {    │
 │         │            NANOSECONDS.toSeconds(            │          logger.... "routeChat cancelled");│
 │         │          System.nanoTime() - startTime);     │      }                                     │
 │         │        responseObserver                      │                                            │
 │         │        Oº.onNext(º                           │      //*Do not complete until receivedº    │
 │         │           RouteSummary.newBuilder()          │      //*onCompleted for peerº              │
 │         │            .setPointCount(pointCount)        │      @Override                             │
 │         │            .setFeatureCount(featureCount)    │      public voidºonCompleted()º{           │
 │         │            .setDistance(distance)            │         responseObserver.onCompleted();    │
 │         │            .setElapsedTime((int) seconds)    │      }                                     │
 │         │            .build()                          │    };                                      │
 │         │         Oº)º;                                │  }                                         │
 │         │        responseObserver.onCompleted();       │                                            │
 │         │                        ^^^^^^^^^^^^^^        │                                            │
 │         │                        end stream            │                                            │
 │         │      }                                       │                                            │
 │         │    };                                        │                                            │
 │         │  }                                           │                                            │
 └─────────┴──────────────────────────────────────────────┴────────────────────────────────────────────┴


GºJAVA CLIENT IMPEMENTATION SUMMARYº
 
            ºInitialization codeº
             function getServer() {                             │  if (require.main === module) {
               var server = new grpc.Server();                  │    var routeServer = getServer();
               server.addService(services.RouteGuideService, {  │    routeServer.bind('0.0.0.0:50051',
                 getFeature: getFeature,                        │        grpc.ServerCredentials.createInsecure());
                 listFeatures: listFeatures,                    │    ...
                 recordRoute: recordRoute,                      │    routeServer.start();
                 routeChat: routeChat                           │  });
               });                                              │  exports.getServer = getServer;
               return server;                                   │
             }
           ┌───────────────────────────────────────────────────┬──────────────────────────────────────────
           │ºSINGLE RESPONSEº                                  │ºSTREAM RESPONSEº
 ┌─────────┼───────────────────────────────────────────────────┼──────────────────────────────────────────
 │ºSINGLE º│ feature = blockingStub.                           │ Rectangle request =
 │ºREQUESTº│             getFeature(                           │      Rectangle.newBuilder()
 │         │              Point.newBuilder()                   │        .setXXX
 │         │               .setXXX()                           │        ...
 │         │               ....                                │        .build();
 │         │              .build());                           │ Iterator˂Feature˃ features
 │         │                                                   │     = blockingStub
 │         │                                                   │       .listFeatures(request);
 ├─────────┼───────────────────────────────────────────────────┼───────────────────────────────────────────
 │ºSTREAM º│ public void recordRoute(                          │  public void routeChat()
 │ºREQUESTº│     List˂Feature˃ features, int numPoints)        │    throws InterruptedException
 │         │      throws InterruptedException                  │  {
 │         │   // NOTE: java.util.concurrent.CountDownLatch    │  //
 │         │      details removed                              │  // rpc RouteChat(stream RouteNote)
 │         │                                                   │  //     returns (stream RouteNote) {}
 │         │   // STEP 1. SETUP RESPONSE OBSERVER              │  //
 │         │   StreamObserver˂RouteSummary˃ responseObserver = │
 │         │       new StreamObserver˂RouteSummary˃() {        │  //*STEP 1. SETUP RESPONSE OBSERVER*
 │         │     @Override                                     │    final CountDownLatch finishLatch
 │         │     public void onNext(RouteSummary summary) {    │       = new CountDownLatch(1);
 │         │         info... summary.get*());                  │    StreamObserver˂RouteNote˃
 │         │     }                                             │       requestObserver =
 │         │     @Override                                     │        asyncStub.routeChatBº(º
 │         │     public void onError(Throwable t) {            │          new StreamObserver˂RouteNote˃()Oº{º
 │         │         //    Rº^^^^^^^   º                       │            @Override
 │         │         //    RºRPC Failedº                       │            public void onNext(RouteNote note)
 │         │         log ... Status.fromThrowable(t););        │            {
 │         │     }                                             │                info"Got message ... ";
 │         │     @Override                                     │            }
 │         │     public void onCompleted(){                    │            @Override
 │         │         finishLatch.countDown();                  │            public void onError(Throwable t)
 │         │     }                                             │            {
 │         │   };                                              │                warn ... Status.fromThrowable(t);
 │         │                                                   │            }
 │         │   // STEP 2. SETUP REQUEST OBSERVER               │            @Override
 │         │   StreamObserver˂Point˃ requestObserver =         │            public void onCompleted()
 │         │       asyncStub.recordRoute(responseObserver);    │            {
 │         │                                                   │                finishLatch.countDown();
 │         │   try {                                           │            }
 │         │     for (int i = 0; i ˂ numPoints; ++i) {         │         º}*
 │         │       // push point to req.stream                 │    Bº)*;
 │         │       requestObserver.onNext(point);              │
 │         │       if (finishLatch.getCount() == 0 ) {         │  //*STEP 2: SETUP REQUEST OBSERVER*
 │         │         /* RPC completed|failed before end of     │        try {
 │         │          * request stream                         │    RouteNote[] requests =
 │         │          * Sending further requests won't error,  │      {newNote(...), newNote .. };
 │         │          * but they will just be thrown away.     │    for (RouteNote request : requests)
 │         │          */                                       │    {
 │         │         //                                        │      requestObserver.onNext(request);
 │         │         return;                                   │      //             ^^^^^^^
 │         │       }                                           │      //             Send Message
 │         │     }                                             │    }
 │         │   } catch (RuntimeException e) {                  │        } catch (RuntimeException e) {
 │         │       requestObserver.onError(e) /  Cancel RPC  /;│    requestObserver.onError(e); throw e;
 │         │       throw e;                                    │                 Rº^^^^^^^^^^^º
 │         │   }                                               │                 RºCancel RPC º
 │         │   requestObserver.onCompleted();                  │    requestObserver.onCompleted();
 │         │                  º^^^^^^^^^^^^^ º                 │                   ^^^^^^^^^^^^^^
 │         │                  ºMark the end of requestsº       │                // Mark the end of requests
 │         │                                                   │    finishLatch.await(1, TimeUnit.MINUTES);
 │         │   // Receiving happens asynchronously             │    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 │         │   finishLatch.await(1, TimeUnit.MINUTES);         │    // Receiving happens asynchronously
 │         │                        ^^^^^^^^^^^^^^^^           │  }
 │         │                        java.util.concurrent.      │
 └─────────┴───────────────────────────────────────────────────┴────────────────────────────────────────────
                                                                                
BºgRPC ecosystemº:                                                              [TODO]
-@[https://github.com/grpc-ecosystem]



GºNODEJS SERVER IMPLEMENTATION SUMMARYº

- ºSERVER INITIALIZATIONº
@[https://github.com/grpc/grpc/blob/master/examples/node/static_codegen/route_guide/]

  var routeServer = new grpc.Server();
  routeServer.addService(services.RouteGuideService, {
    getFeature: getFeature,
    listFeatures: listFeatures,
    recordRoute: recordRoute,
     routeChat: routeChat
  });
  routeServer.bind('0.0.0.0:50051',
                   grpc.ServerCredentials.createInsecure());
  ... "any other initialization"...
  routeServer.start();
            ┌────────────────────────────────────┬──────────────────────────────────────────
            │ ºSINGLE RESPONSEº                  │ºSTREAM RESPONSEº
  ┌─────────┼────────────────────────────────────┼──────────────────────────────────────────
  │ºSINGLE º│ function getFeature(               │ function listFeatures(
  │ºREQUESTº│    call, responseCallback )        │   call) { // ← where call.request is
  │         │ {                                  │                     Rectangle(lo, hi)
  │         │   responseCallback(null, feature); │   _.eachBº(ºfeature_list, feature =˃ Oº{º
  │         │   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ │     if ("feature OK") {
  │         │        write response              │       call.write(feature)
  │         │ }                                  │       ^^^^^^^^^^^^^^^^^^^
  │         │                                    │       write to response stream
  │         │                                    │     }
  │         │                                    │ Oº}º
  │         │                                    │ Bº)º
  │         │                                    │   call.end();
  │         │                                    │   ^^^^^^^^^^^
  │         │                                    │   end stream
  │         │                                    │ }
  ├─────────┼────────────────────────────────────┼──────────────────────────────────────────
  │ºSTREAM º│ function recordRoute (             │ function routeChat (
  │ºREQUESTº│     call // ← stream, callback)    │    call // ← stream. NOTE: no callback )
  │         │ {                                  │ {
  │         │   call.on('data',                  │   call.on('data',
  │         │     (point) =˃ { ... }             │     (note) =˃ {
  │         │   )                                │     _.each(internal_data,
  │         │   call.on('end',                   │     (note) =˃ {
  │         │     () =˃ {                        │       call.write(note)
  │         │       var summary = new            │            ^^^^^^^^^^^
  │         │         messages                   │           write to resp.stream
  │         │        .RouteSummary().set...      │     })
  │         │       callback(null, summary);     │   })
  │         │     })                             │   call.on('end',
  │         │ }                                  │     () =˃ { call.end(); }
  │         │                                    │  )
  │         │                                    │ }
  └─────────┴────────────────────────────────────┴──────────────────────────────────────────

GºNODE.JS CLIENT IMPLEMENTATION SUMMARYº

  messages = require('...._pb')
  services = require('...._grpc_pb')
  grpc = require('grpc')

  client = new services
             .RouteGuideClient(
      'localhost:50051',
      grpc
        .credentials
        .createInsecure())

            ┌────────────────────────────────┬───────────────────────────────────
            │ºSINGLE RESPONSEº               │ºSTREAM RESPONSEº
 ┌──────────┼────────────────────────────────┼───────────────────────────────────
 │ºSINGLE º │ function featureCallback(      │ function runListFeatures(callback)
 │ºREQUESTº │       error, feature)          │ {
 │          │ {                              │   call = client
 │          │   if (error) {                 │            .listFeatures(rect);
 │          │      ....                      │   call.on(
 │          │      return                    │      'data',
 │          │   }                            │      (feature) =˃ {
 │          │   var latitude = feature.get.. │       //  process feature 'event'
 │          │   ...                          │   })
 │          │   next();                      │   call.on('end', callback);
 │          │ }                              │ }
 │          │ client                         │
 │          │   .getFeature(                 │
 │          │      point1,                   │
 │          │      featureCallback);         │
 ├──────────┼────────────────────────────────┼───────────────────────────────────
 │ºSTREAM º │ //* a) Create call.write(able)*│ function runRouteChat(callback)
 │ºREQUESTº │ //*    object*                 │ {
 │          │ var call = client.recordRoute( │   //*1) create call.write(able)*
 │          │   function(                    │   //*   object with onData notifier*
 │          │     error,                     │   var call = client.routeChat()
 │          │     stats // ← server response │   call.on(
 │          │   )                            │     'data',
 │          │   {                            │     (note)=˃ { // ← response from stream /
 │          │     if (error) {               │       //*2) callback for stream response*
 │          │       ...                      │       //*   object received*
 │          │       return                   │       .. do whatever with note response
 │          │     }                          │     }
 │          │     // process stats response  │   )
 │          │   }                            │   //*3) Setup onEnd*
 │          │ );                             │   call.on('end', callback)
 │          │ //* b) Write to stream*        │
 │          │ for ("location in ddbb") {     │   //*4) Write to request stream*
 │          │    call.write(location);       │   for ("note in note_ddbb") {
 │          │ }                              │     var noteMsg = new messages
 │          │                                │           .RouteNote().setXXX..;
 │          │                                │     call.write(noteMsg);
 │          │                                │   }
 │          │                                │   call.end();
 │          │                                │ }
 └──────────┴────────────────────────────────┴───────────────────────────────────
Rsocket (gRPC alt)
Rsocket authors claim that it's better than gRPC:
- @[https://github.com/rsocket/rsocket/blob/master/Motivations.md]
- @[https://medium.com/netifi/rpc-thunder-dome-3103e2449957]
Data Visualization
Perspective
@[https://github.com/jpmorganchase/perspective]
@[https://perspective.finos.org/]
• interactive visualization forºlarge, real-time datasetsº
  and customizable analytics.
• JS engine, runs on any modern browser.
• Integrates withºPython and JupyterLabº.
• fast, memory efficient streaming query engine,
 ºwritten in C++ and compiled for both WebAssembly and Python,º
 ºwith read/write/stream/virtual support for Apache Arrow.º
D3.js
• External resouces:
@[https://d3js.org/]
@[https://github.com/d3/d3]
@[https://www.youtube.com/watch?v=_8V5o2UHG0E&t=894s]
• White-paper summary:
 @[http://idl.cs.washington.edu/files/2011-D3-InfoVis.pdf]
  · ...based on CSS these libraries (jQuery) share the concept
    of a selection:
    identify a set ofe lements using simple predicates, then
    apply a series of operators that mutate the selected elements.
  · For data visualization, document transformers must handle the 
    cre-ation and deletion of elements, not just the styling of existing 
    nodes.This is impossible with CSS, and tedious with jQuery.
  · D3 alternatives, like Processing and Raphaël are tedious for     [comparative]
    complex tasks (no convenient abstractions).
  •ºselection º: D3's atomic operand:  filter over document's elements.
  •ºOperators º: Act on selections, modifying content.
  •ºData joinsº: bind input data to elements, enabling functional
                operators that depend on data, and producing 
                enter and exit subselections for the creation and
                destruction of elements in correspondence with data.
  •ºevent     º: Special operators responding to user input and
   ºhandlers  º  enable interaction.
  •ºhelper    º: simplify common tasks:
   ºmodules   º  ✓ data-processing utilities such as next/cross operators, 
                   CSV parser, date/number formating, ...                   
                 ✓ layouts:                                         
                 ✓ ...                                              
                 

  const x = (d, i) =˃ { return i*25 },  ← scale fun. for position encoding
        y = (d, i) =˃ { return 10 -d }      

  const svg = d3                              
        .select("body")                 ← Add SVG container to body
        .append("svg:svg")                  
        .data([[1, 2, 3, 2, 1, 0.5]])     ← bind data (array of arbitrary values) 
                                            Data is then passed to functional operators 
                                           ºas first argument by conventionºalong with
                                            numeric index (i). By default Nth element
                                            is binded to Nth data (ordered by index).
                                            Aº"key" functionºcan override the def.behaviour.
                                           º*1º
                                           data can also be used to reorder(ºsortº)and/or
                                           cull (ºfilterº) DOM elements.
                                            
  svg.append("svg:path")                ← Add path element for the area
     .attr("class", "area")
     .attr("d",                             
           d3.svg                           
             .area().x(x).y0(14).y1(y))     

  svg.append("svg:path")                ← Add path element to emphasize
     .attr("class", "line")                the top line.
     .attr("d" ,
           d3.svg.line().x(x).y(y))
                                            
  const g = svg.selectAll("g")          ← Add containers for reference values.
        .data(d3.range(0,2, .5))          select || selectAll accept CSS selector
        .enter()                          syntax?.
                                          selects can be chained, 
                                            ex: selectAll("p").select("b")
        .append("svg:g")                ← insert(),append() ops. add new elements to   DOM
                                          remove            ops. del.    elements from DOM
                                          transition(..)  same syntax than style/attr but
                                             interpolating from current to final value 
                                             gradually over time.

  g.append("svg:line")                  ← Add reference lines. 
   .attr("class", (d) =˃ {"rule"})        ← operator acting on selection and
   .attr("x2",160)                          wrapping W3C DOM API,
   .attr("y1", y)                           := .attr(...) | .style(...) | .property(...)
   .attr("y2", y)                              .html(...) | .text(...)  |
                                               .each(...) (general extension point operator)
                                            and expressed either as constants or functions.

  g.append("svg:text")                  ← (g) Add reference labels. 
   .attr("x",164)
   .attr("y",y)
   .attr("dy", ".3em")
   .text(d3.format(",.1"))

 º*1º                   ┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐  NOTE: Data is sticky: Once bound
       e  e  e  e  e  e │u││u││u││u││u││ ││ ││ ││ ││ │        to nodes, it is available
                        └─┘└─┘└─┘└─┘└─┘└─┘└─┘└─┘└─┘└─┘        in next re-selection with
       └───────┬──────┘ └──────┬──────┘└──────┬──────┘        no need for .data(...) operator
       entering data    updated data    exit nodes with
       data with no     bounded to      no matching data
       matching nodes.  matching nodes  allowed to be 
       insert will bind                 removed.
       new nodes to the
       data.

                       
• used as "kernel" library for other high level ones 
  e.g.: @[#vega_lite_summary]
    
• Extracted from @[https://observablehq.com/@d3/learn-d3]
 • D3 stands for "Data Driven Documents".
 • D3 allows to bind arbitrary data to a Document Object Model (DOM),
   and then apply data-driven transformations to the document.
   e.g:
    INPUT        BIND TO
    ========     =======
    number[] --→ D3.js ─┬→ Interactive SVG chart
                        ├→ HTML table
                        ├·····→

  •RºStep learning pathº: 30+ modules , 1000s of methods.
Vega Lite!!! 
@[https://vega.github.io/vega-lite/]
@[https://vega.github.io/vega-lite/examples/]
•ºHIGH-LEVEL GRAMMAR OF INTERACTIVE GRAPHICSºwith declarative JSON syntax.
  by University of Washington Interactive Data Lab
• visualizations for data analysis and presentation. 
• Used by:
  Tableau , Google, Microsoft, Airbnb, Los Angeles Times, CERN,
  Carnegie Mellon University, Berkeley University, ...
• Extracted from: https://vega.github.io/vega/about/vega-and-d3/
  ... D3 is intentionally a lower-level library (than Vega) ...
  a "visualization kernel" rather than a "toolkit" or "framework"
  ... intended as a supporting layer for higher-level visualization 
  tools. Vega is one such tool, and Vega uses D3 heavily within its
  implementation: vega lite → vega → d3.js

•ºHOWTO: STEP 1) HTML SETUPº
@[https://vega.github.io/vega-lite/tutorials/getting_started.html]
 ┌──────────────────────────────────────────────────────────────────────────┐
 │ ˂!DOCTYPE html˃                                                          │
 │ ˂html˃                                                                   │
 │ ˂head˃                                                                   │
 │   ...                                                                    │
 │   ˂script src="https://cdn.jsdelivr.net/npm/vega@5.20.2"      ˃˂/script˃ │
 │   ˂script src="https://cdn.jsdelivr.net/npm/vega-lite@5.1.0"  ˃˂/script˃ │
 │   ˂script src="https://cdn.jsdelivr.net/npm/vega-embed@6.17.0"˃˂/script˃ │
 │                                                                          │
 │   ˂style media="screen"˃                                                 │
 │     .vega-actions a {       /* Add space between Vega-Embed links */     │
 │       margin-right: 5px;                                                 │
 │     }                                                                    │
 │   ˂/style˃                                                               │
 │ ˂/head˃                                                                  │
 │ ˂body˃                                                                   │
 │   ...                                                                    │
 │   ˂divºid="vis"º˃˂/div˃     ˂!-- visualization container --˃             │
 │                                                                          │
 │   ˂script˃                                                               │
 │     var vlSpec = {                                                       │
 │       $schema: 'https://vega.github.io/schema/vega-lite/v5.json',        │
 │      ºdata    º: { values: [ ... ] },                                    │
 │      ºmark    º: 'bar',                                                  │
 │      ºencodingº: { ... }                                                 │
 │     }                                                                    │
 │                                                                          │
 │     vegaEmbed(º'#vis'º, vlSpec); // Embed visualization in "div"         │
 │   ˂/script˃                                                              │
 │ ˂/body˃                                                                  │
 │ ˂/html˃                                                                  │
 └──────────────────────────────────────────────────────────────────────────┘

•ºHOWTO: STEP 2) DATA and Visualization SETUPº
@[https://vega.github.io/vega-lite/tutorials/getting_started.html]
  TABULAR DATA SET │ EQUIVALENT VEGA-LITE
                   │ JSON ARRAY + RENDER PROP
  ================ │ ========================
 var. a    var. b  │ {
  cate- vs nume-   │  º"data"º: {          ← "data" prop defines data source for chart
gorical    rical   │     "values" : [         Other data sources type supported
      C ←→ 2  · · ·│· · · {"a": "C", "b": 2}, ┐  e.g: "data": {"url": ".../data/myData.csv"}
      C ←→ 7  · · ·│· · · {"a": "C", "b": 7}, ┤  ← each value (row) will be rendered 
      C ←→ 4  · · ·│· · · {"a": "C", "b": 4}, ┤    as a1visual markº
      D ←→ 1  · · ·│· · · {"a": "D", "b": 1}, ┤
      ...
      E ←→ 7  · · ·│· · · {"a": "E", "b": 7}  ┘
                   │           ]
                   │   },
      vega-lite  ┌ →  º"mark":º"point",    ← mark key indicates how to render data
          chart  │ │                         mark properties := position, size, color
  visualization ─┤ │                         vega-lite will render one point per "data" object 
     properties  │ │  
                 └ →  º"encoding":º{       ← Without encoding output marks will overlap. 
                   │      "x": {               ← encode "x-channel" to ("row") data fields.
     vega-lite     │        "field": "a",        ("a" in this case) 
     chart         │        "type" : "nominal"   := "quantitative" | "temporal" | "ordinal" | "nominal" º*1º
  visualization    │      },                   
                   │      "y": {           ← "x" alone will already render "a" distribution. 
                   │        "field": "b",    "y" to compare "var a" vs "var b"
                   │        "type" : "quantitative"  
                   │        "title": "b's average"   ← optional.
                   │        "aggregate": "average"   ← optional := "aggregate" | "average"
                   │      }                                           ^
                   │   }                                          "mark" : "bar"
                   │ }                       
                    º*1º@[https://vega.github.io/vega-lite/docs/encoding.html#type]
                    TIP: Vega-Lite will auto. add axis-with-labels for different-categories + axis title.

•ºEXPLORING DATA EXAMPLESº
@[https://vega.github.io/vega-lite/tutorials/explore.html]

  QUANTITATIVE CONTINUOUS            SAME QUANTITATIVE VAR DISCRETIZED
  VAR DISTRIBUTION ALONG X AXIS      AS BAR HISTOGRAM ALONG X/Y AXES
  =============================      ===============================
  
  {                                  {
    "data": ...                        "data": ...
    "mark": "tick",                    "mark": "bar",
    "encoding": {                      "encoding": {
      "x": {                             "x": {
         "field": "precipitation",         "field": "precipitation"
         "type" : "quantitative"          º"bin"  : true,º ← bin == discretize cont.var.
      }                                  },                 (bin quantitative by default) 
                                         "y": {
                                          º"aggregate": "count"º
                                         }
    }                                  }
  }                                  }

  MEAN PRECIPITATION VS (month) DATE                  
  ==================================         
  {                             
    "data": ...                 
    "mark": "line",             
    "encoding": {               
      "x": {                    
        "field"    : "date"     
       º"timeUnit" : "month",º ← : yearmonth will compare same month
      },                           in different years
      "y": {                   
        "field"    : "precipitation"
       º"aggregate": "mean",º  
      }                       
    }                         
  }                           

  WEATHER TYPE OVER MONTH STACKED (aggregate) BAR 
  ==============================================         
  {
    "data": ...
   º"mark": "bar"º,
    "encoding": {
      "x": {
        "timeUnit"  : "month",
        "field"     : "date",
        "type"      : "ordinal"
      },
      "y": {
       º"aggregate": "count",   ←···· we need to add "color" prop. 
        "type"     : "quantitative"   to indicate stack visualization 
      },                                ·
      "color": {                        ·
        "field": "weather",     ←······─┘
        "type": "nominal",
        "scale": {   ← Optional. Customize default category colors
          "domain": ["sun", "fog" , "drizzle", "rain", "snow"],
          "range":  ["#ea2","#c77", "#aec7e8", "#1b4", "#946"]
        }
      }
    }
  }


•ºCALCULATED FIELD HOW-TOº
  =======================         
  {
    "data": ...
    "transform": [ 
      {
        "calculate" : "datum.temp_max - datum.temp_min", 
        "as"        :º"temp_range"º
      }
    ],
    "mark": ...
    "encoding": {
      ...
      "y": {
        "field":º"temp_range"º
        ...
      }
    }
  }
Visx
• @[https://www.infoq.com/news/2020/12/airbnb-visx-data-visualization/]
  Airbnb Releases Visx, a Set of Low-Level Primitives for Interactive
  Visualizations with React components that can be composed into interactive
  visualizations.
• Builds on D3 primitives, React component model, DOM handling.
• data visualization solution Bºeasy to learnºwithout sacrificing
  expressiveness.
  " ...  After 3 years of development, 2.5 years of production use 
    at Airbnb, and a rewrite in TypeScript we are excited to announce
    the official 1.0 release of visx (formerly vx). ..."
JointJS
@[http://www.jointjs.com/tutorial]
@[http://www.jointjs.com/demos/umlcd]
• JointJS 

  INPUT                        PROCESSING              OUTPUT
  =====                        ==========              ======
  GRAPH MODEL:          ···→   attach graph to   ···→   rendered view
  · N joint.dia.Element's      joint.dia.Paper
      (or descendants)
  · M joint.dia.Link's
      ^^^^^^^^^^^^^^^^
      cell := Element or Link 

- Joint.JS  "Hello World!:
  ˂script src="joint.js"˃˂/script˃
  ˂script˃
    const graph01 = new joint.dia.Graph()    ← Represent a diagram.

    const paper      = new joint.dia.Paper({
        el: $('#myholder'),                  ← paper container
        width: 600, height: 200, gridSize: 1 ← CSS data
        model: graph01,                      ← attached graph
    })
    paper.scale(.5);
    paper.$el.css('pointer-events', 'none');

    graph01.on('all',                        ← .on(...) D3 operator reacting to input events
                                               On D3, callback receives data and index as
                                               1st arg.RºTODO:Q:ºIs the same for vega-lite?
      function(eventName, cell)              ← Event handling based on the Backbone MVC
      { ... })                                 See all events triggered by any model in the
                                               graph.
                                               


    const rect01 =                           ← Basic shapes in JointJS: 
      new joint.shapes.basic.Rect({            ✓ joint.shapes.basic.Rect
        position: { x: 100, y: 30 })           ✓ joint.shapes.basic.Circle
                                               ✓ joint.shapes.basic.Text
                                               ✓ joint.shapes.basic.Image

    rect01.attr({                            ← Shape styling
      rect: { rx: 5, ry: 5,
              fill      : '#2C3E50',
              'stroke-width': 2,
              stroke    : 'black' },
      text: { text      : 'my label',
              fill      : ...,
              'font-size': 18, ... }
    })

    rect01.on('change:position',             ← bind event to shape 
      (element) =˃ {
        ... element.id
        ... element.get('position')
      })

    link.set('vertices',                     ← Set vertices on a link
      [ { x: 300, y: 60 },
        { x: 400, y: 60 },
        { x: 400, y: 20 }
      ])
  link.set('smooth', true)                   ← Avoid sharp break at vertice 
                                               (Use interpolated curve)
JS Pivot Tables
See also Vega-Lite pivot charts @[#vega_lite_summary]
@[https://github.com/search?q=pivot+table]
@[https://pivottable.js.org/examples/]
@[https://github.com/nicolaskruchten/pivottable]
@[https://www.flexmonster.com/demos/pivot-table-js/]
Complex Model Real Time Render
https://www.infoq.com/presentations/autodesk-forge-viewer/
Shwetha Nagaraja & Federico Rocha explore in detail some of the most
interesting heavily-optimized techniques and strategies that Autodesk
Forge Viewer introduces for viewing extremely large 2D and 3D models
in the browser in real-time. These include progressive rendering to
reduce time to first pixel, geometry consolidation to reduce draw
overhead.
Multimedia
- http://www.w3.org/2010/05/video/mediaevents.html

- http://stackoverflow.com/questions/14317179/display-a-video-from-a-blob-javascript
  var reader = new FileReader();
  reader.readAsDataURL(vid);

  function display(vid){
      var video = document.getElementById("video");
      video.src = window.URL.createObjectURL(vid);

  }

- http://html5doctor.com/video-canvas-magic/
  http://html5doctor.com/demos/video-canvas-magic/demo2.html
  https://developer.mozilla.org/en-US/docs/Web/HTML/Manipulating_video_using_canvas

- Video & MediaSource:
  https://dvcs.w3.org/hg/html-media/raw-file/tip/media-source/media-source.html
 During playback, the media element pulls segment data out of the source
buffers, demultiplexes it if necessary, and enqueues it into track buffers so
it will get decoded and displayed. buffered describes the time ranges that
are covered by media segments in the source buffer.
  Once a new SourceBuffer has been created, it expects an initialization
segment to be appended first. This first segment indicates the number and
type of streams contained in the media segments that follow. This allows the
media element to configure the necessary decoders and output devices

  A MediaSource object can be attached to a media element by assigning a
MediaSource object URL to the media element src  attribute or the src
attribute of a ˂source˃ inside a media  element. MediaSource object URLs are
created by passing a MediaSource  object to window.URL.createObjectURL().
Initialization segments are an optimization. They allow a byte stream format
to avoid duplication of information in Media Segments that is the same for
many Media Segments. Byte stream format specifications need not specify
Initialization Segment formats, however. They may instead  require that such
information is duplicated in every Media Segment.


   | http://updates.html5rocks.com/2011/11/Stream-video-using-the-MediaSource-API
   |*//SUMMARY:
   | video.src = video.webkitMediaSourceURL;
   | ...
   | video.webkitSourceAppend(new Uint8Array(...));
   | if (endOfStreamDetected) {
   |     video.webkitSourceEndOfStream(HTMLMediaElement.EOS_NO_ERROR);
   | }
   |
   |*//FULL CODE:*
   | const chunkSize = Math.ceil(file.size / 5 /*number of Chunks */); // file is a video file
   | var video = document.querySelector('video');
   |     video.src = video.webkitMediaSourceURL;
   |     video.addEventListener('webkitsourceopen', function(e) {
   |         for (var i = 0; i ˂ NUM_CHUNKS; ++i) {
   |             var startByte = chunkSize * i;
   |             var chunk = file.slice(startByte, startByte + chunkSize); // get slice
   |             var reader = new FileReader();
   |             reader.onload = (function(idx) {
   |                 return function(e) {
   |                     video.webkitSourceAppend(new Uint8Array(e.target.result)); // appending chunk:
   |                     if (idx == NUM_CHUNKS - 1) {
   |                       video.webkitSourceEndOfStream(HTMLMediaElement.EOS_NO_ERROR);
   |                     // appending chunk:
   |                     }
   |                 };
   |             })(i);
   |             reader.readAsArrayBuffer(chunk);
   |         }
   |     }, false);
   |
   | splits video into chunks, then "stream" to a ˂video˃ tag by appending each chunk to the element using the MediaSource API.
   |
   | If you're interested in learning more about the API, see the specification.
   |
   | Support: Currently, the MediaSource API is only available in Chrome Dev Channel 17+ with the
   |  --enable-media-source flag set or enabled via about:flags.
   |
   | CONST chunkSize = Math.ceil(file.size / 5 /*number of Chunks */); // file is a video file


Web-Audio Components [TODO]
@[https://github.com/web-audio-components]

• External Resources:
· JS Oscillator:
@[https://tonejs.github.io/examples/oscillator]
WebRTC: Peer-to-peer media streaming
@[http://www.html5rocks.com/en/tutorials/getusermedia/intro/]
@[http://gingertech.net/2014/01/08/use-deck-js-as-a-remote-presentation-tool/]
Kurento Media Server (KMS)
@[https://doc-kurento.readthedocs.io/en/latest/]
• multimedia server  to develop advanced video applications 
  for WebRTC platforms.
• FaceOverlayFilter is a simple Computer Vision example that 
  detects people's faces on the video streams, to add an overlay 
  image on top of them.
shaka-player
@[https://github.com/google/shaka-player]
• JS media player library with support for adaptative video streams
  (video resolution and bandwith adapted on "real-time" to the available
  network and client/resources) supporting DASH and HLS protocols.
  and MSE-EME player.
Binary Data
@[https://github.com/jDataView]
- jBinary High-level API for working with binary data.
- jDataView. DataView. Extended. Anywhere.
@[https://github.com/jDataView/jBinary/wiki/jBinary-Constructor]
@[https://github.com/jDataView/jDataView]
@[http://www.khronos.org/registry/typedarray/specs/latest/]
  | "* BufferArray: Array of Bytes. Constructor BufferArray(byte length)
  | * TypedArray: Type view of the Buffer Array (Ui|i)nt(8|16|32)Array , Float(32|64)Array
  |     Constructors:
  |       +- TypedArray(byte length) ← Creates new BufferArray
  |       +- TypedArray(TypedArray (existing)array) ← Creates new BufferArray duplicated of array
  |       +- TypedArray(sequence array) ← Creates new BufferArray from Javascript array
  |       +- TypedArray((existing)buffer[, byteOffset, length]) ← Creates new view from existing buffer
  |     Methods:
  |       +- void set( TypedArray array[, offset]) ← copy values from TypedArray
  |       +- void set( type[] array[, offset])     ← copy values from JS array
  |       +- TypedArray subarray(offsetFirstElement [, offsetLastElement=""last one""]) ← Creates a view, not a new buffer!!
  |
  | * DataView: Low level endianess aware view of the Buffer (use for file/hardware/network access with a defined endianess defined ""outside"" our computer)
  |     Contructor:
  |       +- DataView(ArrayBuffer buffer[, byteOffset, byteLength])
  |     Methods (Read):
  |       +- get(Ui|I)nt(8|16|32)(byteOffset[, littleEndian])
  |       +- getFloat(32|64)(byteOffset[, littleEndian])
  |     Methods (Write):
  |       +- set(Ui|I)nt(8|16|32)(byteOffset, value[, littleEndian] )
  |       +- setFloat(32|64)(byteOffset, value[, littleEndian] )
  | Note: Detecting endianness:
  |   var littleEndian = function() {
  |     var buffer = new ArrayBuffer(2);
  |     new DataView(buffer).setInt16(0, 256, true);
  |     return new Int16Array(buffer)[0] === 256; /* true | false */
  | };

- Creating a simple array of 128 32-bit floats and filling with 8 consecutive floats:

  var f32s = new Float32Array(128);

  var groupLength = 8;
  for (var i = 0; i ˂ 128/groupLength; ++i) {
    var sub_f32s = f32s.subarray(i, i+groupLength);
    for (var j = 0; j ˂ 8; ++j) {
       sub_f32s[j] = j;
    }
  }

- Representing a point with 3xFloat32 coordinates values plus 4xUint8 color data values:

  var elementSize = 3 º Float32Array.BYTES_PER_ELEMENT + 4 º Uint8Array.BYTES_PER_ELEMENT;
  var buffer = new ArrayBuffer(4 * elementSize);
  var coords = new Float32Array(buffer, 0);
  var colors = new Uint8Array(buffer, 3 * Float32Array.BYTES_PER_ELEMENT);

- Slicing a large array into multiple regions:
  var buffer = new ArrayBuffer(1024);
  var floats = new Float32Array(buffer,   0 /*     0 offset*/, 128); (128*4 = 512 bytes)
  var shorts = new Uint16Array (buffer, 512 /*floats offset*/, 128); (12*2  = 256 bytes)
  var bytes = new Uint8Array   (buffer, shorts.byteOffset + shorts.byteLength);

- JBinary
  ref: https://github.com/jDataView/jBinary

  - Typical scenario:
  - Create your custom types using jBinary.Type (if needed).
  - Describe type set with JavaScript-compatible declarative syntax.
  - Create jBinary instance from jDataView (or any underlying type) and your type set.

- Constructors:
  +- new jBinary(jDataView data[, typeSet])
  +- new jBinary(javascript Byte array[, typeSet])
  Read Methods:
  +- read(type[, offset = binary.tell()]) ← If offset is provided internal pointer doesn't moves
  Pointer Methods:
  +- tell(): Return the current position. Ex: var currentPos = binary.tell();
  +- seek(position[, callback]): Go to position; if callback → execute it and reset position.
  +- skip(count[, callback]): Advance by count bytes; same callback behavior as seek
  Instance helpers
  +- slice(start, end[, forceCopy = false]): Returns sliced version of current binary with same type set.
  +- as(typeSet[, modifyOriginal = false]): Casts instance to typeSet
  Loading Data
  +- jBinary.loadData(source, callback(error, data)) (static method)
  |     source := Blob/File | HTTP(S)_URL | Data-URI (simple|base64-encoded) | Node.js (local file path|stream)

  var b1 = new jBinary([0x05, 0x03, 0x7F, 0x1E]); // with default typeset
  var b2 = new jBinary(new jDataView(data, 5, 10, true), { MetaName: ['string', 30]}); // typeset with custom type MetaName.
  var firstInt = b1.read('uint32');           // uint32 value at offset 0 → Pointer moves 4 bytes
  var byteAtOffset100 = b2.read('uint8', 100);// uint8 value at custom position → Pointer unchanged(offset provided)
  var intAt200 = binary.seek(200, function () { return this.binary.read('int32') });
  var intAfter8 = binary.skip(8, function () { return this.binary.read('int32') });
  var binary = someExternalBinary.as(TAR); // casting
  fileInput.addEventListener('change', function () {
    jBinary.loadData(fileInput.files[0], function (error, data) {
      if (error) { return console.log(error); }
      ...
    });
  });

  jBinary.load('sample.tar', function (error, binary) {
    if (error) { return console.log(error); }
    var tar = binary.read('File'); // TAR format auto-detected (using jBinary.Repo)
  });

  - Typesets normally are object dictionaries
    { typeName1 : type1 , ← types that can refer to each other but they may also contain special config
      typeName2 : type2 , values that set some global options or modes for entire typeset. Options are:
      typeName3 : type3 ,
      typeName4 : type4 ,
      typeName5 : type5 ,
      typeName6 : type6 ,
       ...
    }
    - jBinary.all - reference to general type that represents entire data; required for enabling user to read/write entire file at once.
    - jBinary.mimeType - sets mime-type which should be used for saving data from this typeset (i.e., when calling toURI without argument).
    - jBinary.littleEndian - sets endianness for this format.

  - __________ Integers ______________
      uint8 (byte) / int8 - one-byte integer.
      uint16 / int16 - word.
      uint32 / int32 - dword (double-word).
      uint64 / int64 - qword - please see warning about precision loss in jDataView documentation.
    ___________ Floats  ______________
      float32 (float) - classic 32-bit float used in languages like C.
      float64 (double) - 64-bit float with double precision (double in C), default for JavaScript number representation.
    ___________ Strings ______________
      char - one-byte binary character.
      string(@length, encoding = 'binary') - string of given length in binary or 'utf8' encoding, reads/writes to the end of binary if length is not given.
      string0(@length, encoding = 'binary') - null-terminated string stored in given number of bytes; treated as dynamic null-terminated string if length is not given.
    _________ Complex types __________
      const(baseType, value, strict = false) - treats type as constant; if read value does not match expected and strict mode is enabled, calls strict(readValue) if it is function or simply throws TypeError if not.
      array(baseType, @length) - array of given type and length, reads/writes to the end of binary if length is not given.
      object(structure, proto = Object.prototype) - complex object of given structure (name → type), creates new context while processing inner properties; object may also contain functions instead of types for calculating some values during read/write for internal purposes.
      extend(...object structures...) - extends one structure with others; merges data into one object when reading and passing entire object when writing.
      enum(baseType, matches) - enumeration type with given key <=> value map (if value not found in the map, it's used "as-is").
    _________ Binary types __________
      bitfield(length) - unsigned integer of given bit length (supports up to 32 bits, wraps around 2^32).
      blob(@length) - byte array represented in most native type for current engine; reads/writes to the end of binary if length is not given.
      binary(@length, typeSet = {}) - jBinary instance on part of original one with given length and optional custom typeset (useful for container formats); accepts also raw binary data when writing.
    _____ Control statements   ______
      if(@condition, trueType, falseType) - conditional statement.
      if_not(@condition, falseType, trueType) - same but inverted.
      skip(@length) - simply skips given length on read/write.
    ______About @  __________________

    All the arguments marked with @(references) can be passed not only as direct values, but also as getter functions callback(context) or string property names inside current context chain.

  - Usage (in Browser): Include scripts for jDataView and jBinary like that:
    ˂script src="//jdataview.github.io/dist/jbinary.js"˃˂/script˃
    ˂script˃
      var typeSet = { magic: ['array', 'uint8', 4] };
      jBinary.load('file.bin', typeSet, function (err, binary) {   console.log(binary.read('magic')); } );
    ˂/script˃
  - HLS player using JBinary
    http://rreverser.github.io/mpegts/

  - Ex1: Audio Data Transport Stream (ADTS):
    (function (exports) {
    var ADTS = {
    /* :
     * Structure: AAAAAAAA AAAABCCD EEFFFFGH HHIJKLMM MMMMMMMM MMMOOOOO OOOOOOPP (QQQQQQQQ QQQQQQQQ)
     *            ^bit (not byte)
     * Header consists of 7 or 9 bytes (without or with CRC).
     * Usage in MPEG-TS
     * - ADTS packet must be a content of PES packet. Pack AAC data inside ADTS frame, than pack inside PES packet, then mux by TS packetizer.
     * - ADTS frames goes one by one in TCP stream. Look for syncword, parse header and look for next syncword after.
    */
        ADTSPacket: {
    /*bits Letter*/  _start            : function () { return this.binary.tell() },
    /*12       A */  _syncWord         : ['const', 12, 0xfff, true],           // syncword 0xFFF, all bits must be 1
    /* 1       B */  version           : ['enum',   1, ['mpeg-4', 'mpeg-2']],  // MPEG Version: 0 for MPEG-4, 1 for MPEG-2
    /* 2       C */  layer             : ['const',  2, 0],                     // Layer: always 0
    /* 1       D */  isProtectionAbsent: 1,                                    // protection absent, Warning, 1 → no CRC, 0 → CRC
    /* 2       E */  profileMinusOne   : 2,                                    // Audio_Object_Types
    /* 4       F */  samplingFreq      : ['enum',   4, [96000,88200,64000,48000,44100,32000,24000,22050,16000,12000,11025,8000,7350]],// MPEG4 Sampl.FrequencyIndex
    /* 1       G */  _privateStream    : 1,                                    // private stream, set to 0 when encoding, ignore when decoding
    /* 3       H */  channelConfig     : 3,                                    // MPEG4 Audio Channel_Configurations(if 0, configuration is sent via an inband PCE)
    /* 4    IJKL */  _reserved         : 4,                                    // originality, home, copyrighted, copyright start bits
    /*13       M */  frameLength       : 13,                                   // frame length value. Must include 7 or 9 bytes of header length: = (ProtectionAbsent == 1 ? 7 : 9) + size(AACFrame)
    /*11       O */  bufferFullness    : 11,                                   // Buffer fullness
    /* 2       P */  aacFramesCountMinusOne: 2,                                 // # of AAC frames(RDBs) in ADTS frame minus 1, for maximum compatibility always use 1 AAC frame per ADTS frame
    /*16       Q */  data              : ['blob', function (context) { return context.frameLength - (this.binary.tell() - context._start) }] // CRC if protection absent is 0
        }
    };

    if (typeof module !== 'undefined' && exports === module.exports) {
        module.exports = ADTS;
    } else {
        exports.ADTS = ADTS;
    }

    })(this);

   - Ex2: MPEG-TS Packet:
   MPEG-TS Packet:
   Name                          |#bits|Description
   _______________________________________________________________________________________________
   sync byte                     |8    |Bit pattern from bit 7 to 0 as 0x47 or ASCII char 'G"
   Transport Error Indicator(TEI)|1    |Set by demodulator if can't correct errors in the stream, to tell the demultiplexer that the packet has an uncorrectable error
   Payload Unit Start Indicator  |1    |Boolean flag with a value of true meaning the start of PES data or PSI otherwise zero only.
   Transport Priority            |1    |Boolean flag with a value of true meaning the current packet has a higher priority than other packets with the same PID.
   PID                           |13   |Packet Identifier
   Scrambling control            |2    |'00' = Not scrambled. For DVB-CSA only→'01':Reserved,'10':Scrambled with even key,'11':Scrambled with odd key
   Adaptation field exist        |1    |Boolean flag
   Contains payload              |1    |Boolean flag
   Continuity counter            |4    |Sequence number of payload packets.  Incremented only when a payload is present (i.e., payload value is true)
   Note: the total number of bits above is 32 and is called the transport stream 4-byte prefix or Transport Stream Header.
   Adaptation field              |0+   |If adaption field exist value is true
   Payload Data                  |0+   |If contains payload value is true

   jBinary Packet Representation: {
       _startof: function () { return this.binary.tell() },

       _syncByte: ['const', 'uint8', 0x47, true],
       transportError: 1,
       payloadStart: 1,
       transportPriority: 1,
       pid: 13,
       scramblingControl: 2,
       _hasAdaptationField: ['Flag', 'adaptationField'],
       _hasPayload: ['Flag', 'payload'],
       contCounter: 4,
       adaptationField: ['FlagDependent', '_hasAdaptationField', 'AdaptationField'],
       payload: ['FlagDependent', '_hasPayload', jBinary.Template({
           getBaseType: function (context) {
               var pid = context.pid, file = this.binary.getContext(1);
               if (pid ˂ 2 || pid in file.pat) {


ANGULAR [Official Doc]
Ext.Links
- Angular API:
@[https://angular.io/api?type=package]
- Github Repo:
@[https://github.com/angular/angular]

What's new •BºAngular 11º @[https://www.infoq.com/news/2020/11/angular-11/] @[https://blog.angular.io/version-11-of-angular-now-available-74721b7952f7] - Hot Module Replacement implementation: $º$ ng serve --hmr º ← It can be initialized with --hmr flag. NG app will not need full page refresh on code changes: Instead, latest changes to code/style/templates will be updated directly while preserving the current state of the application. - Build process speed boost by upgrading to TypeScript 4.0 and through improving the ngcc update process. - developers can now opt-in to the experimental Webpack 5 support (faster builds with persistent disk caching and smaller bundle sizes using improved tree-shaking). To enable it: "resolutions": { "webpack": "5.4.0" } ← Add to package.json - NG language service (popular add-on offers autocomplete, type checking, etc...) is being transitioned to the new Ivy engine, offering improved support for generic types. - For simple upgrade of projects: $º$ ng update @angular/cli @angular/coreº RºWARNº: for more complex updates, use the interactive update guide provided by the Angular team. •BºAngular 9º @[https://www.infoq.com/news/2020/02/angular-9-ivy-rendering-engine/] • Ivy Compiler: Smaller bundle sizes, improved build times, and better debugging thanks to the release of the much anticipated Ivy rendering engine that has been in development by Google since 2018. Ivy uses tree shaking, allowing it to include only the parts of Angular needed for the current application. •BºAngular 5º Service worker implementation shipping by default.
Architecture
@[https://angular.io/guide/architecture]
 ºVIEWº: "screen element" on browser, mobile, ...

 ºCOMPOMENTº: $º $ ng generate component "compName" º
  • Typescript Class with ng-decorator.

  • Defines N views, arranged hierarchically.
    The (optional) ºRouter serviceº defines navigation paths
    among them.

  • At least one ºroot componentº is needed by App, connecting a
    component hierarchy with the page document object model (DOM).

  • ºServiceº (providers) are injected (@Injectable() decorator) to provide
    needed non-visual functionality.

  • When a component is instantiated, it's associated directly with
    the (root) host view.

                        Bº DATA  º
  ºTEMPLATEº == HTML +  BºBINDINGº  + DIRECTIVES
                        BºMARKUP º  @[https://angular.io/guide/built-in-directives]
                          └─┬──┘      └───┬────┘
               ┌────────────┘             └ There can be:
               │                   ANGULAR  ├─ Component directives (the most common)
    DOM        │                  COMPONENT │
    └┬┘ ┌──────┴─────────────────┐└───┬───┘ ├─ Attribute Directives:
     │                                │     │  - [ngClass]="JS expression"
 (output)·············Bº{{value}}º·· ←┤     │  - [ngStyle]="JS expression"
     │                                │     │  - NgModel two way data binding:
 (output)····Bº[property]="value"º·· ←┤     │    PRE-SETUP: add FormsModule to @"X".module.ts
     │                                │     │    imports:[...,FormsModule]
 ( input)→·Bº(event)="handler"º·······→     │    ˂input [(ngModel)]="model.field01" id="field01"˃
     │                                │     │
 ( input)←·Bº[(ng-model)]="property"º·→     └─ Structural directives: add/remove elements
           -----------------------             NgIf, NgFor, NgSwitch:
      Two way binding (forms mainly). Ex:      ˂app-item *ngIf="isActive" [item]="item"˃...
      ˂input [(ngModel)]="hero.name"˃
                                               ˂div *ngFor="let I of items"˃{{I.name}}˂/div˃
 ☞GºAll data bindings are processed once º
  Gºfor each JS event cycle from appº          ˂div [ngSwitch]="e.index"˃
  Gºroot component through tree children.º       ˂comp1 *ngSwitchCase="'1'" [item]="ddbb[1]"˃˂/comp1˃
                                                 ...
                                                 ˂comp1 *ngSwitchDefault    [item]="ddbb[0]"˃˂/comp1˃
                                               ˂/div˃

   ºTEMPLATEº   : template → evaluate   → resolve  → modify
   ºEVALUATIONº   input      directives   binding    HTML DOM
                                          syntax


   ºTEMPLATE PIPESº (data transformation)
    • Ex: date data → pipe → locale-date
    • Predefined Pipes (@[https://angular.io/api?type=pipe]):
      Async , Currency , Date , Decimal, I18n(Plural|Select), JSON,
      KeyValue, (Lower|Upper)Case , Percent , Slice , TitleCase

User click → (intercepted by) → Router  → (reacts by) → showing/hiding view hierarchies.
                                                        (ºlazy loadº   └───────┬──────┘
                                                         of related modules)   │
       ┌····································Bºhierarchical structureºis key ···┘
       │                                      to how Angular detects/reacts
       │                                      to changes in the DOM|app data.
   ┌───┴─────┐
┌→ view root   ←→ NgModule1.rootComponent ┐ ←ºboostrapping moduleº (ex. app.module.ts)
·   └- view1   ←→ NgModule1.component1    ├ A view hierarchy can include
·   └- view2   ←→ NgModule2.rootComponent │ views from components in the
·     └- view3 ←→ NgModule2.component3    ┘ same or different NgModule
·                 └───┬───┘ └───┬───┘
·                     |     @[https://angular.io/guide/architecture-components]
·                     |     - (typescript) app logic controling a view
·                     |       through an properties+methods API.
·                     |     -
·  @[https://angular.io/guide/architecture-modules]
·  -  container|scope for a set of (component list, Service list, ...)
·  -Bºcompilation contextº for components:
·  -  orthogonal app-domain|workflow|capabilities set.
·  -  can depend on other (imported) NgModules
·
└→ Ex Module: app.module.ts:
   import {OºNgModuleº }      from '@angular/core';             ← JS input
   import {BºBrowserModuleº } from '@angular/platform-browser'; ← JS input
  º@NgModuleº({                         ← Decorator function.
    ºimportsº:     [ BºBrowserModuleº ],
    ºprovidersº:   [ Logger ],         ← Creators of services that this NgModule
                                         contributes to.  (providers at component
                                         level can also be specified , which is
                                         often preferred).
                                         A service declared here also ensures that it
                                         will be available as a singleton instance to
                                         any other component/service.

     declarations: [ AppComponent ],   ← components|directives|pipes declared

     exports:      [ AppComponent ],   ← (opt) Subset of declarations accesible
                                         by templates in other NgModules

     bootstrap:    [ AppComponent ]    ← (Only root module): main app view
   })
   export class AppModule { }          ← JS export (vs NgModule export)



 → Ex Component: src/app/hero-list.component.ts
  º@Componentº({
     selector   : 'app-hero-list',               ← associated html tag name
┌→   templateUrl: './hero-list.component.html',  ← seteable property programatically
·┌   providers:  Bº[HeroService]º                ← required Service prov. array
·· })                                             ºSize must match constructor arg. sizeº
··
·· export class HeroListComponent implements ºOnInitº {
·· Oºheroesº     : Hero[]; ← data app property. Note: Many components wrap all
··   selectedHero: Hero;   ← data app property        data in a model dict to make code
··                                                    more readable.
·└   constructor Bº(private service:HeroService)º ← service will be injected
·    { ...}                                        ºMust match @Component.providers
·
·   Qº@Input()ºhero : Hero;   // ← @Input() marks field as input, bounding it
·   Qº@Input()ºpower: string; //   to template DOM prop. Used to comunicate data
·                             //   among parent←→children components.
·                                @[https://angular.io/guide/inputs-outputs]
·     ...
·   QºngOnChanges(change_map: SimpleChanges)º{ // @[https://angular.io/api/core/OnChanges]
·                 └───────────┬───────────┘
·     /*  lifecycle hook called when data-bound properties change.
·      *  Implemented by NgModel, FormControl*, Max/MinLenghtValidator, ...
·      *  maps each changed property to a SimpleChange
·      *  instance with (current,previous) values. */
·       for (let key in change_map) {
·         let chng = change_map[key];
·         let cur  = JSON.stringify(chng. currentValue);
·         let prev = JSON.stringify(chng.previousValue);
·         .log('PropName: ${key}: Val: ${cur}, previous ${prev}');
·       }
·     }
·
·
·   ºngOnInit()º {                               ←·lifeCycle hook
·      this.Oºheroesº = this.service.getHeroes();  See also detailed examples at:
·    }                                       @[https://angular.io/guide/lifecycle-hooks]
·    selectHero(hero: Hero) { this.selectedHero = hero; }              │
·  } └─────────┬──────────┘                                            │
·              └─────────────────────────────────────────┐             │
·                                                        │             │
└→ Ex template: src/app/hero─list.component.html         │             │
   ˂h2˃Hero List˂/h2˃                                    │             │
   Pick a hero from list:                                │             │
   ˂ul˃                                          ┌───────┴──────┐      │
     ˂li º*ngForº="let hero of Oºheroesº" º(click)º="selectHero(hero)"˃│
       Oº{{hero.name | UpperCase}}º                                    │
     ˂/li˃                                                             │
   ˂/ul˃                                                               │
                                                                       │
    ˂app-hero-detail            ← another component                    │
     º*ngIfº="selectedHero"                                            │
     º[hero]º="selectedHero"˃                                          │
    ˂/app-hero-detail˃                                                 │
  Qº˂on-changes [hero]="hero" [power]="power"˃˂/on-changes˃º           │
                                                                       │
           ┌───────────────────────────────────────────────────────────┘
   ┌───────┴───────────┐
  ºMain Life-cycle Hooksº for Component(or Directive in general):
   HOOK                                 PURPOSE AND TIMING
   ────                                 ──────────────────
   ngOnChanges(changes: SimpleChanges)  (re)sets data-bound input properties.
   ngOnInit()                           Initialize component after first display
                                        with data-bound properties and sets the
                                        directive/component's input properties.
   ngDoCheck()                          Detect and act upon changes that Angular
                                        can't or won't detect on its own.
   ngAfterContentInit()                 Respond after Angular projects external content
                                        into the component's view
   ngAfterContentChecked()              ...
   ngAfterViewInit()                    ...
   ngAfterViewChecked()                 ...
   ngOnDestroy()                        tap into Cleanup just before Angular destroy
                                        Use it to Unsubscribe Observables and detach
   Other hooks:                         event handlers to avoid memory leaks.
   - Angular sub-systems
   - 3rd party libraries may add new hooks.


└→ Ex Service: src/app/logger.service.ts
 $º$ ng generate service ...º
 BºService:  "Do one thing and do it right" (root/module/component)singletonº.
   - Injected in components through constructors.
   @Injectable()
   export class Logger {
     log  (msg: any) { console.log  (msg); }
     error(msg: any) { console.error(msg); }
     warn (msg: any) { console.warn (msg); }
   }

   Note on Services injection procedure:
   Angular will create 1+providers for each service(or function|value).
   - The provider can be part of the service's own metadata, to make
     it available everywhere, or it can be registered with an specific
     module|component using the respective decorator
     (@Injectable(), @NgModule() or @Component())
     NOTE: If the providers is in @Injectable() decorator, Angular
          will optimize the app by removing it, if it's not used.

   -ºService SCOPE:º
     ┌──────────┬─────────────────────────────────┬──────────────────────────────
     │ LEVEL    │ Scope                           │ Declaration
     ├──────────┼─────────────────────────────────┼──────────────────────────────
     │ ROOT     │ single instance injected in all │ @Injectable(
     │ (app)    │ app─components (Default)        │    {providedIn: 'root'})
     │          │                                 │ (@ service01.service.ts)
     ├──────────┼─────────────────────────────────┼──────────────────────────────
     │ NgModule │ single instance injected in all │ @NgModule( ...
     │          │ module─components               │ { providers:
     │          │                                 │     [ service01, service02 ]
     │          │                                 │ })
     ├──────────┼─────────────────────────────────┼──────────────────────────────
     │ Component│ new service instance created for│ @Component({
     │          │ each new component              │   selector   : '...'
     │          │                                 │  ,templateUrl: '...component.html'
     │          │                                 │  ,providers  : [ service01 ]
     │          │                                 │ })
     └──────────┴─────────────────────────────────┴──────────────────────────────
Responsive App
BºObservables and event processingº
@[https://angular.io/guide/observables]

- similar (but not identical) to the publish/subscribe
  design pattern. In the observer pattern:
  "subject" object  maintains a list o its dependents (observers)
  "subject" automatically notifies dependent observers of state
            changes.

  Component01 →  +Observable: Observable is a function that
                  function    executes only when a consumer subscribes


  Component02 → Component02 : create Component02.Observer01
  Component02 →  Observable : subscribe (Component02.Observer01)
                 function

  Observable function
  execution "loop":
     Observable  → Observer01: event (keystroke, HTTP response,
     function                         timer,  ...)

-BºSetup and teardown logic is handled by the observable functionº.
 Bºapplication code in Component02 only needs to worry about  º
 Bºsubscribing to consume values, and when done, unsubscribingº
 BºIt doesn't change whether the code was sync or async.      º

 - Unicast example:
   const Oºobservable01º =
       new Observable(
     /*
      * This code creates a new independent execution for each
      * subscribed observer creating a relation
      *      Execution 1 ←→ 1 Subscriber
      * (vs) Execution 1 ←→ N Subscriber  ("Multicast")
      */
       Bº(observer) {º ← function to execute at ".subscribe(...)
         const {nextCallback, errorCallback} = observer;
         let watchId = navigator.geolocation
              .watchPosition(nextCallback, errorCallback);
         return {
           unsubscribe() {       // ← ☞ Freing resources is
             navigator.geolocation.   responsability of Observable
               clearWatch(watchId);
           }
         };
     Bº}º);

    const Bºsubscription01º = Oºobservable01º.subscribe(
    {
      next(position) { console.log(position);       },
      error(msg)     { console.log('Error: ', msg); },
    });
    ...
    setTimeout(() => {
      observable01.unsubscribe();
    }, 10000);

 - Multicast example:
   ☞TIP: multicasting tools simplify next code by allowing
         to convert any existing observable to "multicast".

    // Emit one value/second until end-of-array.
┌·→ function executor(observer, arr, idx) { ←┐
|     return setTimeout(() => {              |
|       observer.next(arr[idx]);             |
|       if (idx === arr.length - 1) {        |
|         observer.complete();               |
|       } else {                             |
|         executor(observer, arr, ++idx); ···┘
|       }
|     }, 1000);
|   }
|
|   /*
|    * multicastSequenceSubscriber wraps the executor
|    * keeping state of subcribers.
|    */
|   function multicastSequenceSubscriber() {
|     const seq = [1, 2, 3];
|     const Bºobserversº = [];  // ← Keep track o subscribers
|     // Still a single timeoutId because there will only ever be one
|     // set of values being generated, multicasted to each subscriber
|     let timeoutId;
|
|     // Return the subscriber function (runs when subscribe()
|     // function is invoked)
|     return (observer) => {
|     Bºobserversº.push(observer);
|       if (Bºobserversº.length === 1) {
|       //  ^^^^^^^^^^^^^^^^^^^^^^
|       // start executor at 1st subcription only
└··       timeoutId = executor({
            next(val) {
              Bºobserversº.forEach(obs => obs.next(val));
            },
            complete() {
              Bºobserversº.forEach(obs => obs.complete());
            }
          }, seq, 0);
        }

        return {
          unsubscribe() {
            observers.splice(observers.indexOf(observer), 1);
            if (observers.length === 0) {
              clearTimeout(timeoutId);
            }
          }
        };
      };
    }

    const mcastObservble01 = new Observable(multicastSequenceSubscriber());

    setTimeout(() => {
      multicastSequenceº.subscribeº({
        next (num) { console.log('1st subscribe: ' + num);  },
        complete() { console.log('1st sequence finished.'); }
      });
    },º   0 /*← Subscribe "now"*/º);

    setTimeout(() => {
      multicastSequenceº.subscribeº({
        next (num) { console.log('2nd subscribe: ' + num); },
        complete() { console.log('2nd sequence finished.'); }
      });
    },º1500 /*← Subscribe after 1st event */º);

    Console will show:
    (second 1) → 1st subscribe: 1
    (second 2) → 1st subscribe: 2
      "        → 2nd subscribe: 2
    (second 3) → 1st subscribe: 3
      "        → 1st sequence finished
      "        → 2nd subscribe: 3
      "        → 2nd sequence finished

PrimeNG Library
@[https://www.primefaces.org/primeng/#/]
• See also other "top" Frameworks:
@[https://www.ngdevelop.tech/best-angular-ui-component-libraries/]

•BºPRE-SETUPº
 $º$ npm install primeng --save             º
 $º$ npm install primeicons --save          º
 $º$ npm install @angular/animations --save º (opt)
         ^
    Or manually add dependencies to 
    package.json add like :
    ...
    "dependencies": {
        ...
  +     "primeng": "^10.0.0",
  +     "primeicons": "^4.0.0"
        ...
    }
•º95% of code is native with no 3rd party dependenciesº
•ºUI component library configured as ng-modules. e.g:
  import {AccordionModule} from 'primeng/accordion'; //accordion and accordion tab
  import {MenuItem}        from 'primeng/api';       //api
• Lot of free themes out-of-the-box.

• Ex. config. for required styles:
    "styles": [
      "node_modules/primeng/resources/themes/saga-blue/theme.css",
      "node_modules/primeng/resources/primeng.min.css",
      "node_modules/primeicons/primeicons.css",
      ...
    ],
    ...
• See also: PrimeNG Video Tutorial:
@[https://www.youtube.com/watch?v=4Wk4RgYN9ZQ&list=PLEXcOZ7ShIgAnxrnPgiOpIz1uPKZNQ9ZJ]
Service Workers  
@[https://angular.io/guide/service-worker-intro]
• See general introduction to Service workers at #[service_workers_summary]
• The Angular service worker's (v5.0+) design goal:
  • Caching app as one unit. The running app will use the               [devops]
    same version of all files (vs randomnly receiving cached
    files from a newer incompatible version).
  • Refreshing will show latest fully cached version.                   [devops]
    with updates executing in background.
  • NG service will load the PWA manifest file from the server
    describing the resource to cache.  When an update to the
    PWA is deployed, manifest data changes triggering the 
    background update.
  • TheBºmanifest is generated from "ngsw-config.json"º.                [devops]

• NG Service how-to:
  • Include  NgModule ????                                                [TODO]
  • Registering NG Service Worker with the browser:
    •RºWARN:º PWApp must be accessed over HTTPS, not HTTP.
              Otherwise, registration will fail to avoid
              tampering. (security meassure since Service Workers
              are "quite powerful").
              Exception: localhost is allowed for developers.

  • See Service Worker config at:                                         [TODO]
  @[https://angular.io/guide/service-worker-config]
  • See Service Worker production ready at:                       [TODO][devops]
  @[https://angular.io/guide/service-worker-devops]
Interactive Forms
@[https://angular.io/guide/forms]
Support complex data entry scenarios with HTML-based validation and dirty checking.

- template-driven interactive form how-to

  - Requested features:
  - from with control elements bound to data properties
  - input data integrity validation with two-way data binding


- design approaches:
  -GºAlt 1: write templates using:º
           - NG template syntax
           - form-specific directives
           - "best-pattern".
    - suitable for small or simple forms

  -GºAll 2: Use reactive(==model-driven) approachº
    - lay out the controls creatively, binding to the data in your object model.
    - Set input validation rules and output display validation errors.
    - conditionally enable controls.
    - trigger built-in visual feedback,
    - ...
_________________________________________________________
GºAlt 1: template-driven formº
  - Next directives defined in ºFormsModuleº are used:.
    -ºNgModelº: reconcilites "form element"  ←→ data model value changes
                - used also to respond to user input (input validation, error handling).

    -ºNgFormº: - creates top-level ºFormGroupº instance bined to ˂form˃ DOM.
               - track aggregated form value and validation status.
               - active by default on all ˂form˃ tags at "FormsModule" import
                 (it has a selector matching the ˂form˃ element).

    -ºNgModelGroupº: create+bind ºFormGroupº instance  ←→ DOM element.

  - STEPS:
    - Define a sample data model.
    - Include FormsModule,... "stuff".

    - Bind form-controls ←→ data properties with ºngModelº
      - Examine how ngModel reports control states using CSS classes.
      - Name controls to make them accessible to ngModel.

    - Track input validity/control status with ºngModelº
      - Add custom CSS to provide visual feedback on the status.
      - Show and hide validation-error messages.

    - Respond to a native HTML button-click event by adding to the model data.

    - Handle form submission using form ºngSubmitº output property.
      - Disable the Submit button until the form is valid.
      - After submit, swap out the finished form for different content on the page.


Ex: two required fields (css:left border when OK, red otherwise)
     with initial default values.

    - src/app/hero.ts: (Model)

      export class Hero {
        constructor(
          public id: number,
          public name: string,
          public power: string,
          public alterEgo?: string
        ) {  }
      }

    - src/app/hero-form/hero-form.component.ts: (v1) (layout, details)

      import { Component } from '@angular/core';
      import { Hero } from '../hero';

      @Component({
        selector: 'app-hero-form', ·············· ← drop form in parent template using  ˂app-hero-form˃
        templateUrl: './hero-form.component.html',
        styleUrls: ['./hero-form.component.css']
      })
      export class HeroFormComponent {

        powers = ['Really Smart', 'Super Flexible',
                  'Super Hot', 'Weather Changer'];

        model = new Hero(18, 'Dr IQ', this.powers[0], 'Chuck Overstreet');

        submitted = false;

        onSubmit() { this.submitted = true; }

        // TODO: Remove this when we're done
        get diagnostic() { return JSON.stringify(this.model); }
      }


    - src/app/app.module.ts:
      import { NgModule } from '@angular/core';
      import { BrowserModule } from '@angular/platform-browser';
      import { FormsModule } from '@angular/forms';              ← enable Forms feature

      import { AppComponent } from './app.component';
      import { HeroFormComponent } from './hero-form/hero-form.component';

      @NgModule({
        imports     : [ BrowserModule, FormsModule ],
        declarations: [ AppComponent, HeroFormComponent ],
        providers   : [],
        bootstrap   : [ AppComponent ]
      })
      export class AppModule { }

    - src/app/app.component.html:
      ˂app-hero-form˃˂/app-hero-form˃  ← display at root component's template.

    - src/styles.css:
      (Twitter Bootstrap style classes: container/form-group/form-control/btn)
      @import url('https://unpkg.com/bootstrap@3.3.7/dist/css/bootstrap.min.css');

    - src/app/hero-form/hero-form.component.html
      ˂style˃ .no-style .ng-valid   { border-left: 1px  solid #CCC } ; ...  ˂/style˃

      ˂div class="container"˃
        ˂div [hidden]="submitted"˃  ←  main form visible by default since submitted init to  false

          ˂form (ngSubmit)="onSubmit()" #heroForm="ngForm"˃
                                        └───┬────────────┘
                                            └──── Access overall form status
                                                  #heroForm : tpl ref.var is now a ref. to
                                                              NgForm directive inst.governing form
                                                              as a whole.
            ˂div class="form-group"˃
              ˂label for="name"˃Name˂/label˃
              ˂input type="text" class="form-control" id="name"
                                                      └───┬──┘
                                                          └──────────── (standard HTML). used by ˂label˃ to match
                     required
                     [(ngModel)]="model.name"
                     └──────────┬───────────┘
                                └──────────── two-way data binding. model.name server to display and debug that
                                              model is really being updated when user changes input.
                                              NG sets special CSS classes on (NgModel) control elements to
                                              reflect the state.
                                              ┌─────────────────────────────────┬────────────┬─────────────┐
                                              │State                            │ Class      │ Class       │
                                              │                                 │ if true    │ if false    │
                                              ├─────────────────────────────────┼────────────┼─────────────┤
                                              │The control has been visited.    │ ng─touched │ ng─untouched│
                                              ├─────────────────────────────────┼────────────┼─────────────┤
                                              │The control's value has changed  │ ng─dirty   │ ng─pristine │
                                              ├─────────────────────────────────┼────────────┼─────────────┤
                                              │The control's value is valid.    │ ng─valid   │ ng─invalid  │
                                              └─────────────────────────────────┴────────────┴─────────────┘

                     name="name"
                     └───┬─────┘
                         └──────────── [(ngModel)] on an element requires also the name attribute for that element, used by NG
                                       to register such element with the NgForm directive attached to parent form element.

                     #name="ngModel"˃
                     └───┬─────┘
                         └──────────── tpl reference variable that you can use to access the input
                                       box's Angular control from within the template.
                                       It is set to "ngModel" because that is the value of the NgModel.exportAs property.
                                       This property tells Angular how to link a reference variable to a directive.

                          ┌─────────── Show or hide the error message by binding properties
                          │            of the name control to the message ˂div˃ element's hidden property
                   ┌──────┴─────────────────────────────┐
              ˂div [hidden]="name.valid || name.pristine" class="alert alert-danger"˃Name is required˂/div˃
            ˂/div˃                              └──┬───┘
                                                   └──  pristine == user hasn't changed the value since it was displayed.

            ˂div class="form-group"˃
              ˂label for="alterEgo"˃Alter Ego˂/label˃
              ˂input type="text" class="form-control" id="alterEgo"
                     [(ngModel)]="model.alterEgo" name="alterEgo"˃
            ˂/div˃

            ˂div class="form-group"˃
              ˂label for="power"˃Hero Power˂/label˃
              ˂select class="form-control" id="power"
                      required
                      [(ngModel)]="model.power" name="power"
                      #power="ngModel"˃
                ˂option *ngFor="let pow of powers" [value]="pow"˃{{pow}}˂/option˃
              ˂/select˃
              ˂div [hidden]="power.valid || power.pristine" class="alert alert-danger"˃
                Power is required
              ˂/div˃
            ˂/div˃

            ˂button type="submit" class="btn btn-success" [disabled]="!heroForm.form.valid"˃Submit˂/button˃
                                                          └─ automatically hiddes if ─────┘
                                                             form is invalid

            ˂button type="button" class="btn btn-default" (click)="newHero(); heroForm.reset()"˃New Hero˂/button˃
            ˂i˃with˂/i˃ reset

              
            ˂button type="button" class="btn btn-default" (click)="newHero()"˃New Hero˂/button˃
            ˂i˃without˂/i˃ reset

           ˂!-- NOT SHOWN IN DOCS --˃
            ˂div˃
              ˂hr˃
              Name via form.controls = {{showFormControls(heroForm)}}
            ˂/div˃
           ˂!-- - --˃
          ˂/form˃
        ˂/div˃

        ˂div [hidden]="!submitted"˃
            ˂div class="col-xs-3"˃Name      ˂/div˃ ˂div class="col-xs-9"˃{{ model.name }}˂/div˃
            ˂div class="col-xs-3"˃Alter Ego ˂/div˃ ˂div class="col-xs-9"˃{{ model.alterEgo }}˂/div˃
            ˂div class="col-xs-3"˃Power     ˂/div˃ ˂div class="col-xs-9"˃{{ model.power }}˂/div˃
          ˂button class="btn btn-primary" (click)="submitted=false"˃Edit˂/button˃
        ˂/div˃
      ˂/div˃

  - customizing CSS :
    └ src/assets/forms.css:
    · .ng-valid[required], .ng-valid.required  {
    ·   border-left: 5px solid #42A948; /* green */
    · }
    ·
    · .ng-invalid:not(form)  {
    ·   border-left: 5px solid #a94442; /* red */
    · }
    ·
    ·
    └ src/index.html (styles)
        ˂head˃
        ...
        ˂link rel='stylesheet' type='text/css' href='...' /˃

    but it does trigger a form-submit event because of its type (type="submit").
Dev.cycle
JIT Compilation
@[https://angular.io/guide/aot-compiler]
- Angular provides just-in-time (JIT) compilation for the
  development environment, and ahead-of-time (AOT) compilation
  for the production environment.

Testing platform @[https://angular.io/guide/testing] - Run unit tests on your application parts as they interact with the Angular framework.
Internationalization @[https://angular.io/guide/i18n] - Make your app available in multiple languages with Angular's internationalization (i18n) tools.
Security guidelines @[https://angular.io/guide/security] - Learn about Angular's built-in protections against common web-app vulnerabilities and attacks such as cross-site scripting attacks.
Setup, build, deploy config
ng CLI reference
@[https://angular.io/cli]
- Used to:
  - create projects,
  - generate app. and library code.
  - testing, bundling, deployment.
  - ...

BºPRE-SETUP:º
  $º$ npm install -g @angular/cliº

BºBASIC WORKFLOWº
  $º$ ng new my-first-project\º ←  create, build, and serve (Wait ~ 1 minute to complete)
  $º --strict                 º ←  Opt.  @[https://angular.io/guide/strict-mode] BºForbids "any" typeº
  $ºCREATE ...                º ←  initial app created goes to root project folder
  $ºCREATE ...                º ←  Additional apps/library go to ./projects/
  $º                          º
  $º$ cd my-first-project     º    new, basic project
  $º$ ng serve                º ←BºAutomatic rebuilds on edit!!!
                                   Test server listening at:
                                   http://localhost:4200/

BºApp Layoutº:
  - New app contains:
    - source files for root module
      - root component + root template.
    - /src folder:  contains
      - logic
      - data
      - assets.
  within a project folder, use $º$ ng generate ...º to add new
  components,services, pipe code, directives, ...  (or do it manually)

    See more about the Workspace file structure.

BºWorkspace and project configurationº

  NOTE: ☞ WORKSPACE 1  ←→ 1+ Project
                             ^^^^^^^
                             application or
                             shareable lib

  ${WORKSPACE}
  └ ./angular.json ← workspace per-project defaults for "ng" command
                     like custorm target defaults, ...
                     Edit it manually or through $º$ng config ...º

    See more about Workspace Configuration.
    See the complete schema for angular.json.

  ng syntax:
$º$ ng commandNameOrAlias requiredArg --opt1 --boolOpt2 --noBoolOpt3º
                                      └─────────────┬──────────────┘
                     NOTE: opt.names in angular.json are "camelCase".
                           opt.names in ng command   are "camelCase" or
                                                         "dash-case".

$º$ ng generate  "artifact or library to be generated"º
$º$ ng add       "artifact or library to be added"    º
       └──┬───┘  └──────────────────────────────────┘
          │       each artifact/library defines its
          │       own options in a schematic.
     ┌────┴─────────────────────────────────────────────────────────┐
     - add
     - analytics  https://angular.io/cli/usage-analytics-gathering.
     - build      output to dist/
     - config
     - deploy
     - doc        Opens Official Angular documentation in browser,
                  and searches for a given keyword.
     - e2e        Builds and serves an Angular app, then runs
                Bºend-to-end tests using Protractorº
     - generate   Generates/modifies files based on a schematic.
     - help
     - new
     - run        Runs an Architect target with an optional custom builder
                  configuration defined in your project.
     - serve
     - test
     - update     Updates app and dependencies.
                BºSee @[https://update.angular.io/]º
     - version

     - xi18n      Extracts i18n messages from source code.
  Ex:
$º$ ng build              my-app      -c productionº
                          ^^^^^^
                          generated artifact can also be
                          indicated with --name "my-app"

BºWorkspace, Project Layout
@[https://angular.io/guide/file-structure]

  ${WORKSPACE}/
  └  .editorconfig
  └  .gitignore
  └  README.md
  └  angular.json
  └  package.json       (npm package dependencies)
  └  package-lock.json  (version information for all npm packages installed)
                        (yarn.lock in case o using yarn)
┌ └  src/               src for root-level ºmain application projectº
· └  node_modules/
· └  tsconfig.json      "Solution Style" TypeScript config file. Used by
·                       code editors and TS's language server to inprove dev. experience.
·                      ºNOT used by compilersº. See detailied info about "noImplicitAny",
·                       "suppressImplicitAnyIndexErrors", ... at
·                      @[https://angular.io/guide/typescript-configuration]
· └  tsconfig.base.json base TypeScript config for all (sub)projects in W.S.
· └  tslint.json        Default TSLint config  for all (sub)projects in W.S.
· └ º./projects/º       ← Only for (git SCM) ºmonorepoº. Recommended for:
├    └ my-lib01/src       - shareable libraries
·      └ src/lib              library project's logic and data(components,services,
·      ·                      modules, directives and pipes)
·      └ src/test.ts          main unit-test entry point (normally defaults are OK)
·      └ src/public-api.ts    Specifies all files exported from library.
·      └ karma.conf.js
·      └ ng-package.json      Config file used by ºng-packagrº at build time.
·      └ package.json         npm package dependencies required by library.
·      └ tsconfig.lib.json    Lib-custom TypeScript configuration.
·      └ tsconfig.spec.json   TypeScript configuration for the tests.
·      └ tslint.json
·
├    └ py-app02/src       - enterprises using "monorepo" approach.
·      └ ...               In monorepos all developers in all dev.groups
·      └ e2e/              can see all changes from other devs./dev.groups
·        ...              ºGit becomes the "source-of-true"º.
·                          All projects will share similar parent config.
·                          Add new one as:
·                        $º$ ng generate application projectXX (--strict)
· └ e2e/               BºEnd-to-end test filesº corresponding to root-level
·   ·                    app, along with test-specific configuration files.
·   └  protractor.conf.js  (test-tool config)
·   └  tsconfig.json       (extends tsconfig.json from workspace)
·   └ src/                 
·     └  app.e2e-spec.ts   (end-to-end tests for my-app)
·     └  app.po.ts
·
·
└ ºSOURCE DIRECTORY LAYOUTº
   app/            Angular components, templates, styles, logic and data
   └ app.component.ts     : app root component logic ("AppComponent").
                            Its view becomes root of view-hierarchy
                            └──┬───┘
   └ app.component.html   : ←──┘
   └ app.component.css    :
   └ app.component.spec.ts: unit test for root AppComponent.
   └ app.module.ts        : Defines the root module named "AppModule",
                          Bºtelling Angular how to assemble the whole app.º
                          BºAs you add more components to the app, they mustº
                          Bºbe declared here.º

   assets/         images, ... to be copied as-is
   environments/   build config options for a given target
                   By default:
                   - unnamed standard development
                   - production ("prod")
                   - (custom ones can be defined, like acceptance, ...)
   favicon.ico
   index.html      CLI automatically adds all JavaScript and CSS files
                   when building your app, so you typically there is no
                   need to add any script/link tags manually.
   main.ts       BºApp entry pointº
                   Compiles the application with the JIT compiler and
                   bootstraps the application's root module (AppModule) to
                   run in the browser.
                   - AOT compiler can also be used by appending by using
                   $º$ ng build|serve .... --aotº
   polyfills.ts    Polyfill scripts for browser support.
   styles.sass     Lists CSS files supplying styles for a project.
                   (sass extension can vary depending on defaults for project)
   test.ts       Bºmain entry point for unit testsº.
   package.json    (strict mode onlye)
                   Not used by package managers,
                   it tell tools⅋bundlers whether
                   the code under this directory
                   is free of non-local side-effects.

BºAPPLICATION-SPECIFIC CONFIG FILESº
  .browserslistrc   :  Config sharing of target browsers and Node.js versions
                       among various front-end tools. More info at:
                     @[https://github.com/browserslist/browserslist]
  karma.conf.js     : App-specific Karma configuration.
  tsconfig.app.json : App-specific TypeScript configuration,
                      (TypeScript, ng template compiler options, ...)
                      
  tsconfig.spec.json: TypeScript config. for the app. tests.
  tslint.json       : App-specific TSLint config.
NG+Keycloak AAA
@[https://medium.com/keycloak/secure-angular-app-with-keycloak-63ec934e5093]
  
 • Core principle behind OpenID-Connect:
   Delegation of  Authentication/Authorization
                                              
     ┌─────┐          ┌───────┐          ┌────────┐    
     │Alice│          │NG-App │          │Keycloak│    
     └──┬──┘          └───┬───┘          └───┬────┘    
        │  Can I see      │                  │         
        │   this page?    │  Can Alice see   │         
        │────────────────˃│   that page?     │         
        │                 │─────────────────˃│         
        │ Please, enter (login) credentials? │         
        │˂───────────────────────────────────│         
        │ crendentials (password, token, ...)│         
        │───────────────────────────────────˃│         
        │                 │   OK, Alice      │         
        │                 │    can see it    │         
        │   page content  │˂─────────────────│         
        │˂────────────────│                  │         
     ┌──┴──┐          ┌───┴───┐          ┌───┴────┐    
     │Alice│          │NG-App │          │Keycloak│    
     └─────┘          └───────┘          └────────┘    

•BºPRESETUPº
  → Keycloak 
    → Client Config
      → Add Client :
         Client ID      : angular-test-app
         Client protocol: openid-connect
         Root URL       : https://myapp.mydomain.com ← or dev URL 
                                                       (http://localhost:4200)
  → Create new angular app if needed:
    $º$ ng new angular-keycloak  º 
  → Adding official keycloak js adapter
    $º$ npm i keycloak-js --save º

• Modify Angular app and next code to main.ts
  let initOptions = { //keycloak init options
    url    : 'https://0.0.0.0:8445/auth',
    realm  : 'keycloak-demo',
    clientId: 'angular-test-app'
  }
  
  let keycloak = Keycloak(initOptions);
  
 ºkeycloakº
    .init({ onLoad: "login-required" })        //← page load will redirect to
    .success((auth) =˃ {                       //  keycloak Auth. page
      if (!auth) {
        window.location.reload();
        return
      }
      console.log("successful authentication. Bootstrapping now");
      
      platformBrowserDynamic()
        .bootstrapModule(AppModule)            // ← boostrap module
        .catch(err =˃ console.error(err));
  
      localStorage.setItem
        ( "ang-token"        , ºkeycloakº.token);       // Access token
      localStorage.setItem                          
        ( "ang-refresh-token", ºkeycloakº.refreshToken) // Refresh token
  
      setTimeout( refreshToken, 60000 /* 1 min*/ )      // May just each hour/day
    })
    .error(() =˃ { console.error("Authenticated Failed"); });
   
    function refreshToken = () =˃ {
     ºkeycloakº.updateToken(70)
      .success( (bRefreshed) =˃ {
          if (bRefreshed) { /* OK */ return ; }
          console.warn('Token not refreshed, valid for '
              + Math.round(
                 ºkeycloakº.tokenParsed.exp
                +ºkeycloakº.timeSkew
                - new Date().getTime() / 1000) + ' seconds');
        })
     .error(() =˃ { console.error('Failed token refresh'); });
    }


NativeScript (Native Apps Angular)
NativeScript
@[https://docs.nativescript.org/]

- Open source framework for building truly native mobile apps with
  Angular, Vue.js, TypeScript, or JavaScript.

- NativeScript features deep integration with modern Angular with
  full-stack features like integration with the Angular CLI, router
  support, code generation, webpack and more.

BºExternal Resourcesº
@[https://github.com/alexziskind1/nativescript-oauth2] [AAA]
@[https://github.com/jbristowe/awesome-nativescript] !!!
@[https://nativescript.org/blog/adding-analytics-to-your-nativescript-app/]
Recipes
BºINIT SERVICE ON PAGE LOADº
  let window: any;
  @Injectable()
  export class MyService01 {
    constructor() {
    Bºwindow.addEventListener('load'º, function (event) { ...  });
    }
  }

BºRX Observables:º (TODO:Explain)
  import {Subject} from 'rxjs';
  @Injectable()
  export class MyService01 {
    public accountsObservable = newºSubject˂string[]˃º();
    ...
    this.accountsObservable.next(accs); ← Inject new events
                                          (Will be delivered to observers)

  @Component({ ...  })
  export class MyComponent01 {
    watchAccount() {
      this.myService01.accountsObservable
        .subscribe(function(account_l) { ← Subscribe
        ...                              ← Update component / GUI
      });
    }
  }

single-spa: NG+React+Vue integration
@[https://single-spa.js.org]
- Framework freedom:
  Use multiple frameworks in a single-page application, allowing you to split code
  by functionality and have Angular, React, Vue.js, etc. apps all living in harmony.

- Lazy load applications
  Stand up new apps next to the old one. You write the applications, single-spa makes
  them work together and won't load them until they're needed.

- Front-end microservices
  Combine many small apps, empowering teams to choose their technology. Stay nimble as
  your team, product, and tech stack grows and changes over time.
React
Summary
• React as declarative "source-of-trust":
  Summary from: @[https://css-tricks.com/why-javascript-is-eating-html/]
  • In recent years, JS devs. have realized that by defining 
    a page's structure in JS (vs HTML) using framworks like React,
    development and maintenance of user interaction code is
    simplified:
            ┌───────────────────────────────┬─────────────────┐
            │ Designed for                  │ Type            │
    ────────┼───────────────────────────────┼─────────────────┤
    · HTML  │ document structure            │ Declarative     │
    ────────┼───────────────────────────────┼─────────────────┤
    · CSS   │ appearance.                   │ Declarative     │
    ────────┼───────────────────────────────┼─────────────────┤
    · JS    │ behaviour.                    │ Imperative      │
    ────────┼───────────────────────────────┼─────────────────┤
    · React │ model/behaviour/doc structure │ Declarative JS  │
              └────────────┬──────────────┘
            It allows to define document structure based on
            data stored in a single place/source-of-true.

BºBootstrap new React Appº
@[https://github.com/facebook/create-react-app]
  $ npx create-react-app my-app  ← Alt 1 (preinstalled with npm 5.2+)
  $ npm init react-app my-app    ← Alt 2
  $ yarn create react-app my-app ← Alt 3
  bootstrap file output:
  my-app
  ├─ README.md
  ├─ node_modules
  ├─ package.json
  ├─ .gitignore
  ├─ public
  │  ├─ favicon.ico
  │  ├─ index.html
  │  └─ manifest.json
     ├─ App.css
     ├─ App.js
     ├─ App.test.js
     ├─ index.css
     ├─ index.js
     ├─ logo.svg
     ├─ serviceWorker.js
     └─ setupTests.js
  $ cd my-app
  $ npm start


Bº┌───────────────────────────────────────────┐º
Bº│React Summary(@[https://reactjs.org/docs/])│º
Bº└───────────────────────────────────────────┘º

BºJSX summaryº
- Optional but recommened: allows react to report better error/warnings.
- Prevent Injection Attacks from external input (XSS cross-site-scripting,...).

  By default, any values embedded are scaped before rendering

const user = {name: "...", ...}
const element =º(      º            ← JSX expression:
  º˂h1 id="1"˃         º            ← Use quotes to insert string literals as attr.
  º Hello, {user.name}!º            - Closer to JS than to HTML.
  º˂/h1˃;              º              class    → className, tabindex → tabIndex,...
º);                    º            - compiles to:
                                      const element = React.createElement( 'h1', ...);
                                                      ^^^^^^^^^^^^^^^^^^^
                                          after few checks ends up creating and object like
                                          { type: 'h1', props: { ... } }

ReactDOM.render(                    ← Add to ReactDOM
  element,
  document.getElementById('root')
);

BºSimplest React Appº:

- index.html
  ˂div id="root"˃˂/div˃           ← react "root" DOM


  function Welcome(ºpropsº) {            ← BºComponentsº: loosely coupled reusable UI object
    return ˂h1˃Hello, {props.name}˂/h1˃;     props (input) → Component → (output) element and components
  }                   └─────┬────┘           (See section State management for alternative using classes)
                            │                convention: Always start name with capital letter
                            │                            lower case are treated as DOM tags
                            │                            (Ex: ˂div /˃ means HTML div tag)
                            │
       DON'T FORGET: All components must act like pure
                     functions with respect to their props.
                     props must always be treated as read-only
                     by components. Use state to represent
                     data updates from user/network/...

  const element = (                        ← Element build from component
     ˂Welcome name="Sara" /˃ );            ← name="Sara" translated to input props
                                             - smallest "renderable" Bºimmutableº
                                               building block for components
                                             - Translates to plain JS (vs DOM)

  function App() {                         ← App component formed by Welcome comps.
    return (                                 Use like:
      ˂div˃                                  ReactDOM.render(
        ˂Welcome name="Sara"  /˃               ˂App /˃,
        ˂Welcome name="Cahal" /˃               document.getElementById('root')
      ˂/div˃                                 );
    );                                       name convention: component at root == "App"

  ReactDOM.render( ˂App/˃,
    document.getElementById('root')
  );

-BºState Managementº
  class Clockºextends React.Componentº{   ← Alt.2: class declaration for component.
                                            Preferred when managing component internal state
    constructor(props) {
      super(props);                       ← props: immutable internal data of component
      this.state = { date: new Date()}; } ← state:   mutable internal data of component

    render() {
      return (
        ˂div˃
          {props.title} ˂br/˃
          {this.state.getSeconds()}
        ˂/div˃
      );
    }

   ºcomponentDidMount()º{                  ← Lifecycle component hook.
      this.timerID = setInterval(
        () =˃ { this.ºsetStateº({          ← By calling setState reacts will know that
            date: new Date() } )             internal state changed.
        } , 1000)                          RºWARNº: Never change this.state directly
    }                                               after initial setup in constructor
                                           BºNOTEº: State is merged with old one (vs
                                                    replaced with new one)

   ºcomponentWillUnmount()º{               ← Lifecycle component hook.
      clearInterval(this.timerID);
    }
  }

BºNOTE:º[performance] React may batch multiple setState() calls into a single update

RºWARNº: updating new state from props and state:
  RºWrongº:                                BºCorrectº
   (props/state change asynch)              (Use setState( (state,prop) ) )
    this.setState({                          this.setState((state, props) =˃ ({
      counter: this.state.counter              counter: state.counter
             + this.props.increment,                  + props.increment
    });                                      }));



- TODO: Read also advanced guides:
  https://reactjs.org/docs/jsx-in-depth.html#user-defined-components-must-be-capitalized

BºHandling Eventsº

  class Toggle extends React.Component {
    constructor(props) {
      super(props);
      this.state = {isToggleOn: true};
      this.handleClick =                ← Don't forget (not needed with funct.
         this.handleClick.bind(this);     style syntax)
    }                                     Alt. use () =˃ in JSX
                                          onClick={() =˃ this.handleClick()}
                                          (Not recommended, a new callback
                                           created on each new render)
    handleClick() {
      this.setState(
        state =˃ ({ isToggleOn: !state.isToggleOn })
      );
    }

    render() {
      return (
        ˂button onClick={this.handleClick} ˃  ← event always cammelCase(onClick)
          {this.state.isToggleOn ? 'ON' : 'OFF'}
        ˂/button˃
        ˂button
          onClick=
             {this.deleteRow.bind(this, id)} ˃ ← Pass data to handler. Also
            delete {this.id}                     {(e) =˃ this.deleteRow(id, e)}
        ˂/button˃                                (lambda syntax)
      );
    }

BºConditional Renderingº

  function Greeting(props) {
    ...
    if (condition1) { return null;  }  ← Return null to skip rendering
    return (condition1)
      ? ˂Component1 /˃
      : ˂Component2 /˃
  }

BºLists and Keysº
  function NumberList(props) {
    const number_l = props.number_l;
    const listItems = number_l.map(       ← Use standard Ecmascript "map"
          ( (n) =˃ ˂hi key={n.toString()} ← key: optional, helps React idenity added/changed/deleted items
                      ˂li˃{n}˂/li˃ );       Use {index} (not recomended) as a last resort for key value
    return ( ˂ul˃{listItems}˂/ul˃ );        Ussage:
  }                                            const number_l = [1, 2, ...];
                                               ...
                                               ˂NumberList number_l={number_l} /˃

BºFormsº (Controlled Components)

  class NameForm extends React.Component {
    constructor(props) {
      super(props);
      this.state = {value1: '',value2: '',value3: ''};  ← make React component state be the
                                                           "single source of truth" for form inpunts
                                                           value can also refresh some other UI elements.

      this.handleChange = this.handleChange.bind(this); ← Don't forget to bind
      this.handleSubmit = this.handleSubmit.bind(this);
    }

    handleChange(event) {                               ← similar to 2/3
      const T = event.target;
      const value = (T.type === 'checkbox')             ← Example logic.
                    ? T.checked : T.value;
      const name = target.name;                         ← use target.name to known which input was affected
      this.setState({                                     (or a different funct. handler is logic is different).
        [name]: value    });                              ← {[...]:...} ES6 computed prop.name syntax.Equivalent to ES5
                                                            d = {}; d[name]=value; this.setState(d);
      this.setState( {value1: event.target.value} );
    }

    handleSubmit(event) {
      ...
      event.preventDefault();                          ← Don't forget.
    }

    render() {
      return (
        ˂form onSubmit={this.handleSubmit}˃
        ˂label˃Name:
          ˂input type="text" value={this.state.value1}
            name="value1"
            onChange={this.handleChange} /˃
        ˂/label˃
        ˂label˃Essay:
          ˂textarea value={this.state.value2}         ← Notice: textarea content defined by value attribute
            name="value2"                               (vs inner text in standard HTML)
            onChange={this.handleChange} /˃
        ˂/label˃

        ˂label˃ Pick one:
          ˂select value={this.state.value3}           ← Notice: Selected value defined by value attribute
            name="value3"                               (vs 'selected' attribute in option in standard HTML)
            onChange={this.handleChange3}˃              For multiselect:
            ˂option value="value1"˃text1˂/option˃       ˂select multiple={true} value={['B', 'C']}˃
            ˂option value="value2"˃text2˂/option˃
            ˂option value="value3"˃text3˂/option˃
          ˂/select˃
        ˂/label˃
        ˂label˃Upload file:
        ˂input type="file" /˃                          ← read only, uncontrolled by react
        ˂/label˃


        ˂input type="submit" value="Submit" /˃
        ˂/form˃
      );
    }
  }

BºBest patternsº

- If two components need to reflect the same changing data
  put such data as prop (immutable in both) and move the state
  to a container "parent".

BºComposition vs Inheritanceº

- Component composition recommended vs inheritance in order to reuse components.
  (pass them as props.children to other components).

  Sometimes we think about components as being “special cases” of
  other components. For example, we might say that a WelcomeDialog is a
  special case of Dialog.

  In React, this is also achieved by composition, where a more
  “specific” component renders a more “generic” one and
  configures it with props:

  BºAt Facebook, we use React in thousands of components, and we º
  Bºhaven’t found any use cases where we would recommend creatingº
  Bºcomponent inheritance hierarchies.                           º

BºNon-UI functionalityº
  To reuse non-UI functionality between components, we
  suggest extracting it into a separate JavaScript module.
  The components may import it and use that function, object,
  or a class, without extending it.


Preact @[https://github.com/preactjs/preact] Fast 3kB alternative to React with the same modern API. Most UI frameworks are large enough to be the majority of an app's JavaScript size. Preact is different: it's small enough that your code is the largest part of your application. That means less JavaScript to download, parse and execute - leaving more time for your code, so you can build an experience you define without fighting to keep a framework under control.
Formik Forms
@[https://formik.org/]
- orchestrate validation and submission: values/errors/visited fields
- focus on business logic.
- Intuitive: plain React state and props.
-ºeasy to debug, test and reason about.º
- No use of external state management libraries like Redux or MobX.
- Keeps bundle size to a minimum.
React Router
- collection of navigational components that compose declaratively
  with your application for bookmarkable URLs , composable way to
  navigate in React Native, ...
React Suspense
 (alt. to Redux)
@[https://www.infoq.com/news/2018/12/react-suspense-redux-alternative]

"If your primary use-case for Redux is using it as a client-side cache of
server-side data, then Suspense could replace your redux usage. I’d consider
it because you’d have simpler code and the ability to tame all those spinners."
Hooks
Hooks == Reusable+Composable Logic
React Native
@[https://reactnative.dev/]
- Replaces web components by native Android/iOS/... ones.

  import React from 'react';          // ← needed fro JSX
  import { View, Text, Image,         // ← native components
         ScrollView, TextInput }
         from 'react-native';

  const App = () =˃ {
    const [text, setText] = useState('');
    return (
      ˂ScrollView˃                     // Horiz. or Vert. container
        ˂Text˃Some text˂/Text˃
        ˂View˃                         // ← View: UI building block
          ˂Text˃Some more text˂/Text˃
          ˂Image
            source={{
              uri: 'https://.../image.png',
            }}
            style={ { width: 200,
                      height: 200 }}
          /˃
        ˂/View˃

      ˂TextInput
        style={{
            height: 40,
            borderColor: 'gray',
            borderWidth: 1
        }}
        placeholder="..."
        onChangeText={text =˃ setText(text)}
        defaultValue={text}
      /˃
      ˂FlatList                        ←BºWorks very well with long listsº. Unlike
        data={[                           ScrollView, it only renders elements on the
          {key: 'val1'}, {key: 'val2'},   screen.
          {key: 'val3'}, {key: 'val4'},   SectionList preferred to split into logical
          ...                             sections.
        ]}
        renderItem={                   ← Take item as input, outpus formatted output
          ({item}) =˃
             ˂Text style={styles.item}˃
               {item.key}
             ˂/Text˃}
      /˃
      ˂/ScrollView˃
    );
  }
  export default App;

 ------------------------------------------------------------
  React       Android      View            Web
 ------------------------------------------------------------
  View        ViewGroup   UIView           div
 ------------------------------------------------------------
  Text        TextView    UITextView       p
 ------------------------------------------------------------
  Image       ImageView   UIImageView      img
 ------------------------------------------------------------
  ScrollView  ScrollView  UIScrollView     div
 ------------------------------------------------------------
  TextInput   EditText    UITextField      input type="text"
 ------------------------------------------------------------

See also:
@[https://github.com/tldr-pages/tldr/blob/master/pages/common/ignite.md]
- A CLI for React Native boilerplates, plugins, generators, and more.
  More information: https://infinite.red/ignite.

Redux summary
BºOfficial redux templateº:
@[https://github.com/reduxjs/cra-template-redux]
    - already configured with a standard Redux application structure,
      using Redux Toolkit to create the Redux store and logic, and
      React-Redux to connect together the Redux store and the React components.
    $º$ npx create-react-app     \ º ← Quick install
    $º  redux-essentials-example \ º
    $º  --template redux           º


RºWARNº:... if you’re just learning React, don’t make Redux your
        first choice.

@[https://redux.js.org/tutorials/essentials/part-1-overview-concepts]

- Redux: pattern + library for managing and updating application state,
  using events called "actions".
- centralized store for (global) state that needs to be used across your entire
  application, with rules ensuring that the state can only be updated
  in a predictable fashion.

- Redux Toolkit: recommended approach for writing Redux logic.
- Redux DevTools Extension: allows for things like "time-travel debugging".

BºCONCEPTSº
  -ºExtracting state Management from components:º
    function Counter() {                        // ← initial React component.
      const [counter, setCounter] = useState(0) // ← non-redux state management.
                                                     redux-way: extract (shared/global) state
                                                     from the components to "Store".
      ...
      return ( ˂div˃...  ˂/div˃)
    }
    BºBEST PATTERNº: Keep local (non-global/shared) component
                     state inside component (vs Redux state)

  - Redux expects that all state updates are done immutably.

  -ºActionsº: plain JS object representing an application event.
    {
       "type"    : "domain/eventName", ← only required field in action
       "payload" : ...                 ← Optional. payload key name is a convention.
    }

  -ºReducer functionsº, sort of event listener
    (the name comes from its similarity with Array.reduce() )
    - input : (current state, action object)
    - logic : decides how to update the state based ONLY on input state and action
              (or ignore given an input action of no interest)
              - next rules must be respected:
                - not allowed to modify the existing state only clone-and-edit new version.
                - side efffects (asynchronous logic, random values,...) NOT allowed.
    - output: returns new state

    const initialState = { value: 0 }

    function counterReducer(state = initialState, action) {
      if (action.type !== 'counter/increment') { return state; }
      return { value: state.value + 1 }
    }


  -ºStoreº: Global app state (state "moved" from component states)
    import { configureStore } from '@reduxjs/toolkit'

    const getIncrementAction = () =˃ {            ← Utilityºaction creatorº.
      return { type: 'counter/increment' }          (avoid typing/mistakes)
    }

    const store = configureStore(                 ← Store builder
                      { reducer: counterReducer } ← 1+ reducer/s linked to new store
                  )                                 key names will define keys in final state value.
                                                    This code means that we want to have a state.reducder
                                                    section in the Redux state object, and that we want the
                                                    counterReducer function to be in charge of deciding if
                                                    and how to update the state.counter

                                                    A real app using state slides could look like:
                                                    import reducer1 from '../features/users/usersSlice'
                                                    ...
                                                    export default configureStore({
                                                      reducer: {
                                                        users   : reducer1,
                                                        posts   : reducer2,
                                                        comments: reducer3
                                                      }
                                                    })

    ...
    store.getState()                              ← get initial state ({value: 0})
    store.dispatch( getIncrementAction() )        ← -º.dispatch()º method is the only way allowed
                                                      to update the state

    store.getState()                              ← get new state  ({value: 1})


  -ºSelectors functionsº:
    - "utility" functions to extract specific information from a store state. Ex:
    const selectCounterValue = state =˃ state.obj1.obj2.value

  -ºSlicesº:
    - collection of reducer logic and actions for a single app feature
      (typically defined in a single file).
    - name comes from splitting up root-state into multiple "slices".
    - Example from @[https://github.com/reduxjs/cra-template-redux]
      (features/counter/counterSlice.js)
      import { createSlice } from '@reduxjs/toolkit'

      export const counterSlice = createSlice({
        name: 'counter',
        initialState: { value: 0 },
        reducers: { ←·················· UI will dispatch matching action types:
          increment: state =˃ {          {type: "counter/increment"}, {type: "counter/increment"}, ...
            state.value += 1 ←········· RºWARNº: There is some magic here. Code looks to be "mutating" input state.
          },                                     "immer" library detects changes and produces new immutable state
          decrement: state =˃ {                   (middleware automatically added in configureStore)
            state.value -= 1 ←··················  - Writing immutable update logic by hand is hard, and
          incrementByAmount: (state, action) =˃ { Rºaccidentally mutating state in reducers is the single º
            state.value += action.payload         Rºmost common mistake Redux users make.º
          }
        }
      })
      export const { increment, decrement, incrementByAmount } = counterSlice.actions

- Example app: counter allowing to add or subtract from a number as we click buttons.
@[https://redux.js.org/tutorials/essentials/part-2-app-structure]

 ºFile layout:º
  /src
    index.js             ← the starting point for the app
    App.js               ← the top-level React component
    /app
      store.js           ← creates the Redux store instance
                           - store setup can be customized with different
                             kinds of plugins ("middleware" and "enhancers").
    /features
      /counter
        Counter.js       ← a React component that shows the UI for the counter feature
        counterSlice.js  ← exports reducer function with the the Redux logic for "counter" feature

  -BºOur application might be made up of many different features, and eachº
   Bºof those features might have its own reducer function.º

  - createSlice takes care of non-logic centric stuff like
    generation of action type strings/creator functions/objects)
    by just defining an slice name, writing an object with reducer functions.
    (initial state is also needed to init properly).

    - slice_name +"." reducer_key_name → {type: "slice_name/reducer_key_name"}
      Ex: "counter" + "increment"          → {type: "counter/increment"}
    - reducer_function_name →  action_creator_name
      Ex:
      createSlice({
        reducers: {
          increment: state =˃ ... →  counterSlice.actions.increment()
        }
        ...
      })

-ºThunksº
 - specific kind of Redux function tuple that can contain asynchronous logic.
   - PRE-SETUP: add redux-thunk middleware (a type of Redux plugin) at store creation time.
                (automatically added by configureStore).
   - inside    thunk function: takes dispatch and getState as arguments
   - outside creator function: creates and returns the thunk function
   Ex 1: (features/counter/counterSlice.js)

   export const incrementAsync            // thunk can be dispatched like regular action:
      = amount =˃ dispatch =˃ {           `dispatch(incrementAsync(10))`.
     //           └───────────┴················ inside  function
     // └───────┴······························ outside function
     setTimeout(() =˃ {
       dispatch(
         incrementByAmount(amount)         ← Utility action creator
       )                                     returning { type: 'XXX/YYY', payload :... }
     }, 1000 /* millisecs */)
   }

   Ex 2: AJAX call: (features/counter/counterSlice.js)
   const fetchUserById = (userId) =˃ {       // ← outside "thunk creator" function
     return async (dispatch, getState) =˃ {  // ←  inside "thunk function"
       try {
         const user = await userAPI.fetchById(userId)     // ← make an async call in the thunk
         dispatch(userLoaded(user))                       // ← dispatch an action when we get the response back
       } catch (err) {
         ...
       }
     }
   }

  The React Counter Component#

  features/counter/Counter.js
  import React, { useState } from 'react'
  import { useSelector, useDispatch } from 'react-redux'
  import { decrement, increment, ... } from './counterSlice'
  import styles from './Counter.module.css'

  export function Counter() {
    const count = useSelector(selectCount) ←   RºWARN:  components are NOT allowed to import/access the store,º
                              └────┬────┘               use the useSelector(...) injected Redux hook. º*1º
    const dispatch = usedispatch()    └─················selectCount is defined in features/counter/counterSlice.js:
    const [incrementAmount, setIncrementAmount]         const selectCount = (state) =˃ { state.counter.value }
       = useState('2')                                  (It could also be defined inline)
    return ( ... {count}                              BºAt every dispatched action (store updated),    º
                                                      Bºthe useSelector hook  will re-run the selector º
      ˂button                                         Bºand if value has changed, trigger re-rendering.º
        onClick={() =˃ dispatch(increment())} ˃...    ← useDispatch (const dispatch = useDispatch()) is just
      ˂button                                           another Redux hook (º*1º) allowing to dispatch to the
        onClick={() =˃ dispatch(decrement())} ˃...    ← actual (otherwise hidden to component) Redux store
    )                                                 BºNOTE:º components don't care whether we're dispatching a
  }                                                     sync or async (Thunk) methods.
                                                        They only react to input events by dispatching events.


º*1º: Q: how do hooks know what Redux store instance to talk to?
      A: At ºindex.js:º
         ...
         import App from './App'
         import store from './app/store'
         import { Provider } from 'react-redux'

         ReactDOM.render(
           ˂Providerºstore={store}º˃      ←RºDON'T FORGET:º It allows to pass down/link/inject
             ˂App /˃                         the Redux store to redux hooks in components.
           ˂/Provider˃,
           document.getElementById('root')
         )

BºAdvanced Redux use-cases:º
@[https://medium.com/@dan_abramov/you-might-not-need-redux-be46360cf367]
  - Persist state to a local storage and then boot up from it, out of the box.
  - Pre-fill state on the server, send it to the client in HTML, and
    boot up from it, out of the box.
  - Serialize user actions and attach them, together with a state
    snapshot, to automated bug reports, so that the product developers
    can replay them to reproduce the errors.
  - Pass action objects over the network to implement collaborative
    environments without dramatic changes to how the code is written.
  - Maintain an undo history or implement optimistic mutations
    without dramatic changes to how the code is written.
  - Travel between the state history in development, and re-evaluate
    the current state from the action history when the code changes, a la
    TDD.
  - Provide full inspection and control capabilities to the
    development tooling so that product developers can build custom tools
    for their apps.
    Provide alternative UIs while reusing most of the business logic.
DevOps
• React+Flux Docker Dev Workflow [TODO]
@[https://medium.com/@tribou/react-and-flux-a-docker-development-workflow-469957f3bbf0]
Server side Tech
API Management
OpenAPI Spec 3.x
@[https://swagger.io/specification/]
• language-agnostic RESTful APIs interface definitionºfor computers and humansº.
• can also be used as documentation.
• External Resources:
  · Collection of OpenAPI Tools: @[https://github.com/OpenAPITools]
    · OpenAPI-diff:
      @[https://github.com/quen2404/openapi-diff]
  · OpenAPI topics @ github:
    @[https://github.com/topics/openapi]
    · ...


Ex OpenAPi Definition:
   | openapi: '3.0.3'
   |
   | info:
   |   title: 'MyRESTService'
   |   description: MyRESTService API Document
   |   version: '0.0.1'
   |
   | servers: [ { url: https://www.mycompany.com/ } ]
   |
   | paths:
   |   '/api/v1/module1/service1':
   |     put:
   |       summary: ...
   |       description: ˃
   |         This is a multi-line markup description
   |          * bullet1
   |          * bullet2
   |       tags: [ MyModule1, Service1, ... ]   ← Orthogonal topics
   |
   |       requestBody:
   |         $ref: '#/components/requestBodies/entity01'
   |       parameters:
   |         - name: SecuritySchemes
   |           in  : header       ← :=  header ← HEAD / GET / PUT / POST 
   |                                  | query  ←        GET / PUT / POST 
   |                                  | body   ←              PUT / POST
   |           description: |
   |             Set Access Token
   |             Format: "Bearer"+[space]+[jwt]
   |           schema:
   |           Oº$ref: "#/components/schemas/entity01"º
   |           required: true
   |
   |         - name: queryParam1
   |           in  : query
   |           required: true
   |           schema:
   |             type: string    ← boolean | number | ...
   |                               { type: string, enum: [asc, desc] }
   |         - name: ...
   |
   |       responses:
   |         '200': { description: 'OK' }
   |         '400': { description: 'KO' }
   |
   |   '/api/v1/module1/service1':
   |     get:
   |       summary: ...
   |       ...
   |       responses:
   |         '200':
   |           description: 'OK'
   |           content:
   |             application/json:
   |               schema:
   |               Oº$ref: '#/components/schemas/entity01'º
   |         ...
   |           
   | components:
   |   schemas:
   |     entity01:
   |       type: object
   |       properties:
   |         blNo           : { type: string }
   |         senderCompanyId: { type: string }
   |         version        : { type: number }
   |
   |   requestBodies:
   |     entity01:
   |       content:
   |         "application/json":
   |           schema:
   |             $ref: '#/components/schemas/entity01'


TOP Open APIs REF: @[https://projects.tmforum.org/wiki/display/API/Open+API+Table] •ºAccount Management APIº standardized mechanism for management of billing and settlement accounts, as well as for financial accounting (account receivable) either in B2B or B2B2C contexts. •ºAppointment APIº standardized APIs to book appointment, including: ✓ parameterized searching for free slots ✓ nature and place of appointment. ✓ ... •ºCustomer Management APIº standardized API for customer and customer account management (creation, update, retrieval, deletion and notification of events). •ºPartnership Type Management APIº Standardized API for CRUD operations on partnership types. It is one of the APIs involved in anºonboarding processº. ✓ Identifies type of partnership among parties (allowed role types list, e.g: [ Buyer, Seller, Developer]. •ºParty Management APIº: Standardized API for CRUD party management. Party := individual | organization •ºParty Role Management APIº standardized API for general CRUD party roles and notification of events. •ºProduct Catalog Management APIº standardized API for adding partners' products to existing Catalog. It brings the capability for Service Providers to directly feed partners systems with the technical description of the products they propose to them. •ºProduct Inventory Management APIº standardized API for CRUD (representation of)product inventory management and product lifecycle event notification. •ºProduct Offering Qualification APIº: One of Pre-Ordering Management API Family. •ºProduct Ordering APIº: standardized API for placing a product order. simple set of operations to interact with CRM/Order negotiation systems in a consistent manner. •ºQuote Management APIº: one of the Pre-Ordering Management APIs. •ºShopping Cart APIº: standardized API for shopping-carts CRUD and events management. used for the temporary selection and reservation of product offerings in e-commerce and retail purchase. •ºTrouble Ticket APIº: standardized API to Trouble Ticket Management Systems CRUD among partners as result of an issue or problem identified by a customer or another system. Examples of Trouble Ticket API clients include CRM applications, network management or fault management systems, or other trouble ticket management systems (e.g. B2B). •ºAgreement Management APIº: standardized API for managing agreements, especially in the context of partnerships between partners. •ºCommunication APIº: create+send communications, notifications, and instructions to Parties, Individuals, Organizations or Users. •ºEntity Catalog Management APIº: The entity catalog is intended to provide any SID entity to consumers via a catalog, with its specification and policy providing governance over its content. The API provides management of the entity specifications and their associations thru CRUD operations. •ºFederated Identity APIº: [aaa] management of principals of any kind (persons, objects, …) and their access to resources in an open environment which can span across different enterprise boundaries. It relies on authentication, authorization and consent mechanisms to protect privacy with a simple and easy user experience. Different parties can provide identity services (operators, social networks, GSMA, …). •ºGeographic Address Management APIº: Standardized client interface to an (worldwide) Address management system, validating and searching for geographic address data: 1) searching an area as a start (city, town ...) 2) zooming on the streets of this area 3) listing all the street segments (numbers) in a street. •ºGeographic Location Management APIº: Provides the information of a geographic region of the entity (customer, equipment, address). •ºGeographic Site Management APIº: CRUD ops to manage sites that can be associated with customers, accounts, service delivery or other entities. •ºLoyalty Management APIº: Supports the management of loyalty program specifications, loyalty program members, their associated products and loyalty accounts with loyalty balances •ºPartnership Type Management APIº: Standardized mechanisms for creating partnership types. It is one of the APIs involved in an onboarding process. •ºParty Interaction Management APIº: A User Interaction captures information about past interactions in order to reuse it in future ones. This allows agents to serve users better by knowing the steps they went through. It also allows customers to see better the actions they have performed and how they interacted with us. •ºParty Management APIº: Provides a standardized API for party CRUD management. •ºParty Role Management APIº Provides a standardized API for general party roles CRUD management. •ºPayment Management APIº: [payments] standardized client interface to Payment Systems for notifying about performed payments or refunds. Examples of Payment API originators (clients) include: Web servers, mobile app servers, Contact center dashboards or retail store systems. •ºPayment Methods APIº: [payments] This API supports the frequently-used payment methods for the customer to choose and pay the usage, including voucher card, coupon, and money transfer. •ºPrepay Balance Management APIº [payments] REST API for Balance Management. It includes the model definition as well as all available operations for prepay balance management. Prepaid subscribers pay fees before using services. Therefore, the subscribers must have sufficient balances. Operators can provide multiple recharge channels for subscribers. Subscribers can pass credit between different subscriptions, therefore transferring the balance from one account to another. •ºPrivacy Management APIº: [privacy] The Privacy management API provides standardized mechanisms for privacy profile types, privacy profiles and privacy agreements such as creation, update, retrieval, deletion and notification of events.. •ºProduct Catalog Management APIº: standardized API for rapidly adding partners' products to an existing Catalog. It brings the capability for Service Providers to directly feed partners systems with the technical description of the products they propose to them. •ºProduct Inventory Management APIº: standardized API for CRUD of representation-of-product in inventory. •ºProduct Offering Qualification APIº: One of Pre-Ordering Management API Family, providing Product Offering commercial eligibility. •ºProduct Ordering APIº: standardized API for placing a product order interacting with CRM/ Order negotiation systems in a consistent manner. •ºQuote Management APIº: [payments] One of the Pre-Ordering Management APIs allowing to place a customer quote with all of the necessary quote parameters. •ºResource Catalog Management APIº: API spec allowing the management of the entire lifecycle of the Resource Catalog elements and the consultation of resource catalog elements during several processes such as ordering process. •ºResource Function Activation and Configuration APIº: This API introduces Resource Function which is used to represent a Network Service as well as a Network Function. The Network Service and Network Function class definitions and associations in TR244 (which, in turn, builds on concepts from the SID addenda on Logical Resource and Service) are utilized to define the Resource Function •ºTrouble Ticket APIº: standardized client interface to Trouble Ticket Management Systems for creating, tracking and managing trouble tickets among partners as a result of an issue or problem identified by a customer or another system. API clients include CRM applications, network management or fault management systems, or other trouble ticket management systems (e.g. B2B). •ºUsage Consumption Management APIº: [monetization] API allowing real-time view of the balance of the various buckets (SMS, Voice, Data for example) that a user consumes with each of his devices and the usages done out of the bucket. Usage report retrieves the data related to these balances. This API should also allow performing a direct top-up on the balance of a prepaid bucket with voucher references or with a given credit value after a payment done by a credit card or with a credit value transfer. •ºUsage Management APIº: Provides standardized mechanism for collection-of-usages CRUD management. E.g: It allows a service provider to 1) retrieve usage generated by a partner service platform in order to rate it 2) provide rated usage to a partner for consumption follow up purposes. •ºUser Roles⅋Permissions APIº: user role : entity that defines a set of privileges covering various functions and/or manageable assets. (session) User are assigned a given role then it is actually allocated all the privileges defined for that role type and the corresponding permissions are created for that user.
Open Data Protocol
@[https://www.odata.org/]
• ISO/IEC approved, OASIS standard
• It defines aºset of best practices for building and consumingº
 ºRESTful APIs to focus on business logic without worryingº
 ºabout different approaches to define request/response headers,º
 ºstatus codes, HTTP methods, URL conventions, media types,º
 ºpayload formats, query options, etc.º
• OData provides guidance for:
  · tracking changes
  · defining functions/actions for reusable procedures
  · sending asynchronous/batch requests.                           [async]

• OData RESTful APIs are easy to consume.
  - OData metadata, a machine-readable description of the
    data model of the APIs, enables the creation of powerful
    generic client proxies and tools.

• OData Tools include:
  - Visual Studio Code for OData Extension:
    - adds rich support for theºOData query languageº
  - XOData
    - generic online OData API/Service visualizer and explorer.
      It assists in rapid prototyping, verification, testing,
      and documentation of OData APIs. With XOData Chrome App
      it's also possible to explore OData Services deployed
      locally or on private networks.

asyncapi.org/
@[https://www.asyncapi.org/]
• Low level standard (vs OpenAPI high-level/business oriented)
  to architect future event-driven architectures.
• Open source tools to easily build and maintain your event-driven
  architecture. All powered by the AsyncAPI specification, the industry
  standard for defining asynchronous APIs.
• Compatible with OpenAPI Spec, allowing to re-use schema definitions.

See comparative with OpenAPI and CloudEvents at:
@[https://www.asyncapi.com/blog/async_standards_compare]

• Extracted from ebay anouncement to adopt AsyncAPI: 
@[https://www.infoq.com/news/2021/05/ebay-adopts-asyncapi/]
    One of the critical AsyncAPI features that eBay's team has found 
  particularly useful is aºclean separation between channels, º
 ºoperations, and servers.º
  · A channel represents an event stream
  · An operation describes a publish or subscribe process.
  · A server facilitates the message transfer (i.e., the message bus).
  This separation allows a complete representation of producers, consumers, 
  and message schemas, resulting in a standardized model of a 
  message-driven ecosystem.
Mirage: Fast Prototyping
@[https://miragejs.com]

Mirage JS is an API mocking library that lets you build, test and
share a complete working JavaScript application without having to
rely on any backend services.
APIgee: x-Cloud API Mng
- The Cross-Cloud API Management Platform
  https://cloud.google.com/apigee/
NodeJS
NodeJS summary
@[https://nodejs.org]
• Server-side JavaScript platform (Node.js).
  built against modern versions of V8.
• Server API extensions for subprocesses, TTY, TCP servers, ...

Bº##########º
Bº# nodenv #º
Bº##########º
@[https://github.com/nodenv/nodenv]
• Utility to manage multiple Node.js versions installed in parallel.
• Preferred to OS install (apt, dnf, chocolate, ...)

$º$ nodenv install $version º ← Install specific version of Node.js
$º$ nodenv install --list   º ← list of available versions
$º$ nodenv global $version  º ← Use specific version across whole system
$º$ nodenv local  $version  º ← Use specific version within directory
$º$ nodenv version          º ← Display Node.js version for current dir.
$º$ nodenv which $command   º ← Display location of installed command
                                (e.g. npm,yarn,...)



 $º$ node                  º ← Start interactive shell (REPL loop)
 $º$ node path_to_file.js  º ← Run JS file
 $º$ node -e "{{js_code}}" º ← Evaluate JS code
 $º$ node -p "{{js_code}}" º ← Evaluate and print result, useful to see 
                               node's dependencies versions
                               e.g: $º$ node -p "{{process.versions}}" º
                               { http_parser: '2.8.0',
                                 node: '10.16.3',
                                 v8: '6.8.275.32-node.54',
                                 ... 
                                 unicode: '12.1',
                                 ... }

 $º$ node node --no-lazy \ º ← Activate inspector, pausing execution until      [debug]
 $º$ --inspect-brk file.js º   a debugger is connected once source code is 
                               fully parsed

Bº#######º
Bº# npm #º
Bº#######º
@[https://www.npmjs.com/]
• npm : Node Package Manager manage projects and module dependencies.   [devops]
• npm project layout
  ./package.json       ← JSON file with dev/pro. package dependendies
  ./node_modules       ← Installed packages (Add to Rº.gitignoreº, do not commit). 
  ./package-lock.json  ← npm v5+: It describes the exact tree that was generated,
                        ºsuch that subsequent installs are able to generate º
                        ºidentical treesº, regardless of intermediate dependency updates.
                         Must be kept in git (version control) as any other source file.


$º$ npm init              º ← create "package.json" interactively  
$º$ npm install           º ← Download dependencies listed in package.json
$º$ npm install $mod@$ver º ← Download specific package ver. and add it
                              dependencies@package.json
                              · Use '--save-dev' to add to 
                                dev-dependencies@package.json
                              · Use '--global' to install OS system wide

$º$ npm uninstall $mod    º ← Uninstall +remove dependencies@package.json
$º$ npm list              º ← Print tree of locally-installed dependencies
                              · Use --global --depth={{0}} to list
                                top-level globally installed modules

$º$ npm-check             º ← report outdated/incorrect/unused dependencies
                              · Use --skip-unused  to ignore un-used packages
$º$ npm-check --update    º ← Interactively update out-of-date packages
$º$ npm-check --update-allº ← Update all no prompting


$º$ npm-why $mod_name     º ← Identifies why an package is installed.


Bº#################º
Bº# Windows setup #º   [windows][troubleshooting]
Bº#################º
@[https://www.npmjs.com/package/windows-build-tools]
$º$ npm install --global windows-build-tools º
                         └─────────────────┘
NodeJS What's new
• Node 14+
  ·BºOptional chaining operator '?.'º                        [billion_dolar_mistake][qa]
     skip manual null validation when fetching property located deep
     within a chain of connected objects. e.g.:
     const adventurer = {
       name: 'Alice',
       cat: { name: 'Dinah' }
     }
     console.log(adventurer.ºdog?.ºname); ←º?.º Result: undefined (no error)
      console.log(adventurer.dog ⅋⅋       ← manual (non-compact) check (false)
                  adventurer.dog.name);
  RºWARN:º This operator doesn't fix the billion dolar mistake, 
           since check for nulls/undefined is still needed, but
           it makes syntax more compact and clear to read.
  ·BºNullish coalescing logical operator '??'º               [billion_dolar_mistake][qa]
     logical op. returns the operand on its right when
     the operand on its left is null or undefined.
     Otherwise, it returns its left-hand-side operand. e.g:

     let safe_name = nullableEntry ?? "n/a" ← Recomended fallback op. (vs || )
• Node 12: 2019-10 BºLTS version!!!º
@[https://medium.com/@nodejs/introducing-node-js-12-76c41a1b3f3f]
• 30% faster startup generating code cache for built-in libraries 
  in advance at build time, and embed it in the binary.
• better default heap limits based on available mem vs using defaults.
  Particularly useful when processing large data-sets.     [performance]
• new features: 
  ✓ diagnostic report                                      [troubleshooting]
    generate report on demand on certain events
    (production crashes, slow performance, memory leaks,
     high CPU usage, unexpected errors ...). More info at:
     https://medium.com/the-node-js-collection/⏎
       easily-identify-problems-in-node-js-applications⏎
       -with-diagnostic-report-dc82370d8029
  ✓ bundled heap dump capability
    Useful to debug memory problems. More info at:
    https://github.com/nodejs/node/pull/27133 
    https://github.com/nodejs/node/pull/26501
• updates to V8(v 7.4) brings:
  · Async stack traces: 
    https://v8.dev/blog/v8-release-72#async-stack-traces
  · Faster calls with arguments mismatch 
    https://v8.dev/blog/v8-release-74#faster-calls-with-arguments-mismatch
  · Faster await: 
    https://v8.dev/blog/v8-release-73#faster-await
  · Faster javascript parsing: 
    https://v8.dev/blog/v8-release-72#javascript-parsing

• Hello TLS 1.3 introduces and defaults to TLS 1.3        [TLS]
• Native Modules Easier to implement include better support
  in Worker threads, and N-API .
  https://nodejs.org/api/n-api.html#n_api_n_api
• Workers Threads no longer experimental. More info at:
@[https://medium.com/@Trott/using-worker-threads-in-node-js-80494136dbb6]
• Experimental ES6 Module Support                         [es6]
oclif
@[https://oclif.io/]
• Open (console) command line interface Framework to create
  friendly cli tools.
Hapi Web Framework!!! 
• NodeJS web framework.
• See also complementarion Caddy HTTPs server automating
  certificate renewals:
@[../General/cryptography_map.html#caddy_https_server]
• Simple, Secure Framework that Developers Trust
• Originally developed to handle Walmart’s Black Friday scale.
• Recommended by Brendan Eich
  Creator of JavaScript and CEO, Brave
  "...hapi provides the right set of core APIs and extensible
  plugins to support the requirements of a modern service
  - session management, security, connectivity, and testing"

•BºWhen you npm install @hapi/hapi, every single line of code you getº
 Bºhas been verified. (No deep dependency being poorly maintained).  º
 Bºhapi is the only leading node framework without any external code º
 Bºdependencies. None.                                               º

• End-to-end Code Hygiene — hapi requires the most secure settings
  to manage, control, and distribute code, including 2FA for all
  contributors.
• Secure Defaults, Updated Regularly — every hapi component comes     [security]
  with the most secure defaults out-of-the-box. Along with protecting
  server load with payload limits and request timeouts, hapi blocks
  error messages that could leak information or echo back exploits.
• Integrated Authorization and Authentication Architecture — the           [aaa]
  most comprehensive authorization and authentication API available in
  a Node framework.
• Advanced Features — with encrypted and signed cookies, secret or
  key rotation, and HTTP security headers, there are no excuses for
  building insecure applications.
• Reliable, Predictable Ownership – when something goes wrong, you
  know who to contact. Security updates are handled under a strict,
  well-defined protocol.
• Rich ecosystem – hapi’s extensive set of official plugins means
  no more blindly trusting some middleware you found for critical
  functionality just because it has a high count on npm.
• In-house Security Expertise – created by Eran Hammer, the author
  of the OAuth specifications and other identity protocols.
Deno (NodeJS +++)
• extracted from
@[https://www.infoq.com/news/2020/06/deno-1-ready-production/]
  Deno Is Ready for Production  @ma
  • Deno: secure runtime for JS, TS and WebAssembly on V8 engine.
  • created by the original developer of Node.js, Ryan Dahl, to
    address what he called "10 things I regret about
    Node.js".
  • Notable differences for application developers: 
    • single binary application (vs Node.js modular binaries).
    • Avoid complex dependency management solutions like the NPM. 
      Developers declare dependencies in source code using direct URLs.
      • Already 500+ third-party Deno modules available.
      (Rº not compatible with NPM packages written for Node.jsº, but
        porting must be easy).
    • Deno runtime is secure by default. If application needs to      [security]
      access the file system or network, the developer needs to
      declare it explicitly.
Monetization
Web Monetization
@[https://webmonetization.org/]
• JS browser API to allows the creation of a payment
  stream from the user agent to the website.

• Proposed W3C standard at the Web Platform Incubator 
  Community Group.

• SETUP HOW-TO:
  1) Set up a web monetized receiver for receiving payments.
     Most of the times this include signing with some payment
     services, but a crypto-wallet owned by the user could be
     an alternative solution.
     The wallet must support the Interledger protocol ILP.        [protocol]
     account. 

  2) Fetch the ºpayment-pointerº from the ILP wallet. e.g.:
     $wallet.example.com/alice

  3) Create ˂meta˃ tag telling Monetization providers how to pay. e.g.:
     ˂meta name="monetization"                   ← name is always monetization
           content="$wallet.example.com/alice"˃

  4) Add ˂meta˃ tag from step 3 to the ˂head˃ of each page to be monetized.

Coil
@[https://medium.com/coil/coil-building-a-new-business-model-for-the-web-d33124358b6?utm_source=singlepagebookproject]

Innovating on Web Monetization: Coil and Firefox Reality
https://hacks.mozilla.org/2020/03/web-monetization-coil-and-firefox-reality/


Ilp: coilhq/coil-wordpress-plugin: Coil's Wordpress Web Monetization Plugin
@[https://github.com/coilhq/coil-wordpress-plugin]
OpenRTB
Real-time Bidding (RTB) is a way of transacting media that allows an
individual ad impression to be put up for bid in real-time. This is
done through a programmatic on-the-spot auction, which is similar to
how financial markets operate. RTB allows for Addressable
Advertising; the ability to serve ads to consumers directly based on
their demographic, psychographic, or behavioral attributes.

The Real-Time Bidding (RTB) Project, formerly known as the OpenRTB
Consortium, assembled technology leaders from both the Supply and
Demand sides in November 2010 to develop a new API specification for
companies interested in an open protocol for the automated trading of
digital media across a broader range of platforms, devices, and
advertising solutions.

Advanced Libs
Stork: Wasm in-browser Full-text Search!!!
@[https://www.infoq.com/news/2020/03/stork-wasm-rust-text-search/]
Stork, a Rust/Wasm-Based Fast Full-Text Search for the JAMStack
JiSON: context-free
http://zaach.github.io/jison/docs/
Jison takes a context-free grammar as input and outputs a JavaScript
file capable of parsing the language described by that grammar.
You can  then use the generated script to parse inputs and accept,
reject, or perform actions based on the input. If you’re familiar
with Bison or Yacc, or other clones, you’re almost ready to roll.
HTML Editors (in HTML)
• Monaco Editor(used by VSCode,Che...)
  • Blazeling fast web-editor (Used by VSCode, Che, ...)
  @[https://code.visualstudio.com/docs/editor/editingevolved]
• Quill.js WySiWyG Editor
@[https://www.scalablepath.com/blog/using-quill-js-build-wysiwyg-editor-website/]
IA Tools
trackingjs Face detection
@[https://trackingjs.com]
• computer vision algorithms into the browser environment.
• Enables real-time color tracking, face detection and much more.
• lightweight core (~7 KB)
• intuitive interface.
Tensorflow.org
Tensorflow using JS + WebGL
@[https://js.tensorflow.org/]
Face⅋Speech Recog.
@[https://dzone.com/articles/tutorial-how-to-build-a-pwa-with-face-and-speechrecognition?edition=636291]
•ºFace detection API:º
  face recognition in the browser:
@[https://justadudewhohacks.github.io/face-api.js/docs/index.html]
•ºWeb speech API:º
  enables "Speech to text" in the app.
@[https://developer.mozilla.org/en-US/docs/Web/API/Web_Speech_API/Using_the_Web_Speech_API]

  (above APIs can only work when enabling
  "Experimental Web Platform features" in the
  browser via the url: chrome://flags

$º$ git clone https://github.com/petereijgermans11/progressive-web-appº
SEO
SEO Summary
• SEO stands for ºSearch Engine Optimizationº.

Bº############################º
Bº# SEO rules for WHOLE site #º
Bº############################º
  1) Create 1 or more *sitemap.xml
                                   
  2) Create 1 robot.txt

  3) Use HTTPS (vs HTTP)

Bº############################º    
Bº# SEO rules for html pages #º    
Bº###########################º     
  ✓  Use Rich Structured Data to provide indexing metadata.
     For special content (charts, images, media, ...) it is
     specially important. e.g, use schema.org/VideoObject
     to index videos inside pages.

  ✓  Add primary keywords to:       
     • Title Tag / Meta Description
     • URL                           
     • H1, H2 Headings.
     •ºanchor text of internal linksº

  ✓  Add secondary keywords to:
     • Subheadings
     • Alternative text
  ✓  Make page/site mobile friendly
  ✓  Remove broken links

  NOTE: Page load speed does NOT affect SEO indexing, but it can affect
        final users, that will "skip over" slow sites.

Bº#############################º
Bº# Sitemap Protocol standard #º
Bº#############################º
@[https://www.sitemaps.org/protocol.html]
• Sitemaps standard, proposed by Google, helps search engines
  (crawlers and indexers) to inform about URLs metadata
  for a given Web Resource (URL).
  ˂?xml version="1.0" encoding="UTF-8"?˃ ← Max. size: 50MB
  ˂urlset 
      xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"˃
     ˂url˃                               ← one entry per URL. 50.000 urls per XML
        ˂loc˃http://www.foo.com/˂/loc˃   ← non-optional. All loc in
                                           XML must match same host
        ˂lastmod˃2005-01-01˂/lastmod˃    ← Complements If-Modified-Since (304)
                                           HTTP response header (from servers)
        ˂changefreq˃monthly˂/changefreq˃ ← Aproximate hint to search engine
                                           := always | hourly | daily | weekly
                                           | monthly | yearly | never
                                           always : dynamic  content
                                           never  : archived content
         ˂priority˃0.8˂/priority˃        ← 0.0-to-1.0: relative to other site's URLs
                                           (defaults to 0.5)
     ˂/url˃
  ˂/urlset˃ 
  NOTE: additional metadata about alternate language versions, video, image,
        or news-specific pages can be included                            [TODO] 

• sitemaps can be "pushed" directly to different search engines         [devops]
  to trigger fast-indexation (vs waiting for hours/days/weeks for passive
  indexing by web crawlers). e.g,ºGoogle Search Consoleº allows to
  manually submit one or more XML sitemaps for a given domain an see
  indexation results. Also via "PUSH" HTTP request like:

  
$º$ curl https://${searchengine}/ping?sitemap=http://www.example.com/sitemap.gzº
  (via curl, wget, ..., returning HTTP 200 if every works "OK")



  • Asking Google to re-crawl a site:
  @[https://developers.google.com/search/docs/advanced/crawling/ask-google-to-recrawl]
    · There is a quota for submitting individual URLs:
      Alt 1) only for 'owners' Search Console property
             → URL Inspection tool
               → Inspect the URL
                 → Select "Request indexing".  
    
      Alt 2) Submit a sitemap ("many" URLs) 


• About URL encodings:
  all URLs (including Sitemap hosting URL) must be URL-escaped
  by the web server on which they are located.
  
  https.../üm.php⅋q=name 
  https.../%FCm.php⅋q=name         ← Server using ISO-8859-1
  https.../%C3%BCm.php⅋q=name      ← Server using UTF-8
  https.../%C3%BCm.php⅋amp;q=name  ← entity escaped URL

• Sitemapºindexº needed when using more than one Sitemap file.

  ˂?xml version="1.0" encoding="UTF-8"?˃             ← Obligatory when using 2+  
  ˂sitemapindex                                        sitemaps
    xmlns=
      "http://www.sitemaps.org/schemas/sitemap/0.9"˃
     ˂sitemap˃
        ˂loc˃http://foo.com/sitemap1.xml.gz˂/loc˃    ← foo.com must match loc. of 
        ˂lastmod˃2004-10-01T18:23:17+00:00˂/lastmod˃   sitemapindex.
     ˂/sitemap˃
     ˂sitemap˃
        ˂loc˃http://foo.com/sitemap2.xml.gz˂/loc˃
        ˂lastmod˃2005-01-01˂/lastmod˃
     ˂/sitemap˃
  ˂/sitemapindex˃

  Alternatively or in parallel sitemaps can be specified in robots.txt like:
  Sitemap: http://www.example.com/sitemap-host1.xml
  Sitemap: http://www.example.com/sitemap-host2.xml.gz

Rº###########º
Rº# DONT's: #º
Rº###########º
  • Don't forget a "robots.txt" to skip content, define Sitemaps.
  • Don't block a page in robots.txt and include it in an XML sitemap.
  
Rº########################################º
Rº# robots.txt Robots Exclusion Protocol #º
Rº########################################º
    TIP: Must be all lower-case, 
    placed at URL "root"
   ┌(/var/www/html)/robots.txt ─┐ 
   │User-agent: *               ← "*" is an acronym for "any robot".
   │Disallow: /cgi-bin/         │ Any other globing or regular expression in
   │Disallow: /tmp/             │ User-agent or Dissallow: is NOT allowed.
   │Disallow: /~joe/            │ e.g.:  Disallow: /tmp/*.gif is incorrect
*1→│                            │
   │User-agent: BadBot          ← To entiry server from BadBot robot:
   │Disallow: /                 │
*1→│                            │
   │User-agent: Google          ← allow full access to Google robot
   │Disallow:                   │
*1→│                            │
*2→│Sitemap: sitemap01.xml      ← e.g: URL category sitemap
   │Sitemap: sitemap02.xml      ← e.g: URL subcategory sitemap
   │Sitemap: sitemap.cgi        ← Dinamically generated XML sitemap
   └────────────────────────────┘ 

*1: white-lines used to separate different registries. 
   (one for "*", another one for BadBot, and a 3rd one
    for Google in our example)

*2: Different search engines "control pannels" allows to push
    the sitemap directly (vs waiting for random crawling)
  
• NOTE: difference between html ˂meta name=robots˃ and /robots.txt :
  •º/robots.txtº: ignore page, do not even read html headers.
    · /robots.txt file is controlled by web-server/site administrator.

  •º˂meta name="robots" content="noindex,follow"˃º
    · ignore links inside this page.
    · Can be controlled by page-author, overriding
      defaults in robots.txt.
  
• External Resources:
  • A curated list of SEO (Search Engine Optimization) links.
   @[https://github.com/teles/awesome-seo]
    

Bº########################
Bº# Schema.org:          #
Bº# Rich Structured Data #
Bº# for Search Engines   #
Bº########################
 Ref: @[https://www.infoq.com/news/2021/02/seo-structured-data-rich-snippet/]
• Add semantic support to html.
• Used by º10+ million sitesº to markup web pages and email messages.
• activity community maintaining and promoting schemasºfor structured dataº.
• While OpenAPI standard @[#openapi_summary] allows to   [comparative]
  design APIs (requests from client to servers) to  simplify
  implementation of client mobile/web applications, 
  schema.org allows toºsimplify the translation, by search engines/indexers,º
  ofºhtml-markup to structure-data , relationships and actionsº.
• Extensible vocabulary.
•QºGoogle Search Gallery lists 30 rich snippet categoriesº               [TODO]
  with their use cases and specific user interface 
  (articles, books, how-to, recipes, products, job postings,
   events, ...):
  · Each category has a dedicated user interface designed
    to facilitate the search user’s next steps.
    e.g: A news article may be featured in "Top stories" 

  ˂head˃
    ˂title˃...˂/title˃
    ...
    ˂script type="application/ld+json"˃  ← Google's recommended
    {                                       format (vs microdata|rdf)
      "@context": "https://schema.org/",  @[#json-ld_summary]
     º"@type": "Recipe",º
      "name": "Party Coffee Cake",
      "author": {
        "@type": "Person",
        "name": "Mary Stone"
      },
      "datePublished": "2018-03-10",
      "description": "...",
      "prepTime": "PT20M"
    }
    ˂/script˃
    ...
  ˂/head˃

• SCHEMA.ORG TOOLS:
  • @[https://search.google.com/test/rich-results]
  • Google/Bing/Yandex/... Search Consoles:
    site-wide monitoring and testing for rich results.

JSON-LD
@[https://json-ld.org/]                                                   [TODO]
• JSON-based format used to serialize Linked Data primarily targeting
   Web environments in order to build interoperable Web services, and
   to store Linked Data in JSON-based storage engines.
• Provides smooth upgrade path from JSON to JSON-LD.

Non-classified / Radar
HTTP/3 
@[https://www.infoq.com/news/2020/01/http-3-status/]
• HTTP/2 introduced the concept of first-class streams embedded
  in the same TCP connection enabling multiplexing simultaneous 
  request-response exchanges.
• HTTP/2 major flaw: when packet loss increases, performance 
  degrades due to dependency on TCP packet retransmission 
  (HOL blocking): 
  RºWhen packet loss surpasses a given threshold it's slower than º
  RºHTTP/1 multiple parallel TCP connections.º
• QUIC (HTTP/3 or HTTP over UPD) has first-class streams. solving
  HTTP/2 issues. 
axios
@[https://www.npmjs.com/package/axios]
Promise based HTTP client for the browser and node.js
Features
• Make XMLHttpRequests from the browser and
•      http  requests  from node.js
• Supports the Promise API
• Intercept request and response
• Transform request and response data
  (See service workers @[#service_workers_summary]
   for advanced/complementary alternative)
• Cancel requests.
• Automatic transforms for JSON data.
• Client side support for protecting against XSRF                     [security]